/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * mbimcli -- Command line interface to control MBIM devices * * Copyright (C) 2018 Google LLC * Copyright (C) 2018 Aleksander Morgado */ #include "config.h" #include #include #include #include #include #include #include #include #include "mbim-common.h" #include "mbimcli.h" #include "mbimcli-helpers.h" /* Context */ typedef struct { MbimDevice *device; GCancellable *cancellable; } Context; static Context *ctx; /* Options */ static gchar *query_pco_str; static gboolean query_lte_attach_configuration_flag; static gboolean query_lte_attach_status_flag; /* support for the deprecated name */ static gboolean query_lte_attach_info_flag; static gboolean query_sys_caps_flag; static gboolean query_device_caps_flag; static gchar *query_slot_info_status_str; static gboolean query_device_slot_mappings_flag; static gchar *set_device_slot_mappings_str; static gboolean query_location_info_status_flag; static gboolean query_provisioned_contexts_flag; static gchar *set_provisioned_contexts_str; static gboolean query_base_stations_flag; static gchar *query_version_str; static gboolean query_registration_parameters_flag; static gchar *set_registration_parameters_str; static gboolean query_modem_configuration_flag; static gboolean query_wake_reason_flag; static gboolean query_pco_arg_parse (const gchar *option_name, const gchar *value, gpointer user_data, GError **error); static GOptionEntry entries[] = { { "ms-query-pco", 0, G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, G_CALLBACK (query_pco_arg_parse), "Query PCO value (SessionID is optional, defaults to 0)", "[SessionID]" }, { "ms-query-lte-attach-configuration", 0, 0, G_OPTION_ARG_NONE, &query_lte_attach_configuration_flag, "Query LTE attach configuration", NULL }, { "ms-query-lte-attach-status", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &query_lte_attach_status_flag, NULL, NULL }, { "ms-query-lte-attach-info", 0, 0, G_OPTION_ARG_NONE, &query_lte_attach_info_flag, "Query LTE attach status information", NULL }, { "ms-query-sys-caps", 0, 0, G_OPTION_ARG_NONE, &query_sys_caps_flag, "Query system capabilities", NULL }, { "ms-query-device-caps", 0,0, G_OPTION_ARG_NONE, &query_device_caps_flag, "Query device capabilities", NULL }, { "ms-query-slot-info-status", 0, 0, G_OPTION_ARG_STRING, &query_slot_info_status_str, "Query slot information status", "[SlotIndex]" }, { "ms-set-device-slot-mappings", 0, 0, G_OPTION_ARG_STRING, &set_device_slot_mappings_str, "Set device slot mappings for each executor", "[(SlotIndex)[,(SlotIndex)[,...]]]" }, { "ms-query-device-slot-mappings", 0, 0, G_OPTION_ARG_NONE, &query_device_slot_mappings_flag, "Query device slot mappings", NULL }, { "ms-query-location-info-status", 0, 0, G_OPTION_ARG_NONE, &query_location_info_status_flag, "Query location info status", NULL }, { "ms-set-provisioned-contexts", 0, 0, G_OPTION_ARG_STRING, &set_provisioned_contexts_str, "Set provisioned contexts (allowed keys: operation, context-type, ip-type, state, roaming-control, media-type, source, auth, compression, username, password, access-string)", "[\"key=value,...\"]" }, { "ms-query-provisioned-contexts", 0, 0, G_OPTION_ARG_NONE, &query_provisioned_contexts_flag, "Query provisioned contexts", NULL }, { "ms-query-base-stations-info", 0, 0, G_OPTION_ARG_NONE, &query_base_stations_flag, "Query base stations info", NULL }, { "ms-query-version", 0, 0,G_OPTION_ARG_STRING , &query_version_str, "Exchange supported version information. Since MBIMEx v2.0.", "[(MBIM version),(MBIM extended version)]" }, { "ms-query-registration-parameters", 0, 0, G_OPTION_ARG_NONE, &query_registration_parameters_flag, "Query registration parameters. Since MBIMEx v3.0.", NULL }, { "ms-set-registration-parameters", 0, 0,G_OPTION_ARG_STRING , &set_registration_parameters_str, "Set registration parameters (required keys: mico-mode, drx-cycle, ladn-info, default-pdu-activation-hint, re-register-if-needed). Since MBIMEx v3.0.", "[\"key=value,...\"]" }, { "ms-query-modem-configuration", 0, 0, G_OPTION_ARG_NONE, &query_modem_configuration_flag, "Query modem configuration. Since MBIMEx v3.0.", NULL }, { "ms-query-wake-reason", 0, 0, G_OPTION_ARG_NONE, &query_wake_reason_flag, "Query wake reason. Since MBIMEx v3.0.", NULL }, { NULL, 0, 0, 0, NULL, NULL, NULL } }; static gboolean query_pco_arg_parse (const gchar *option_name, const gchar *value, gpointer user_data, GError **error) { query_pco_str = g_strdup (value ? value : "0"); return TRUE; } GOptionGroup * mbimcli_ms_basic_connect_extensions_get_option_group (void) { GOptionGroup *group; group = g_option_group_new ("ms-basic-connect-extensions", "Microsoft Basic Connect Extensions options:", "Show Microsoft Basic Connect Extensions Service options", NULL, NULL); g_option_group_add_entries (group, entries); return group; } static gboolean session_id_parse (const gchar *str, guint32 *session_id, GError **error) { gchar *endptr = NULL; gint64 n; g_assert (str != NULL); g_assert (session_id != NULL); if (!str[0]) { *session_id = 0; return TRUE; } errno = 0; n = g_ascii_strtoll (str, &endptr, 10); if (errno || n < 0 || n > 255 || ((size_t)(endptr - str) < strlen (str))) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, "couldn't parse session ID '%s' (must be 0 - 255)", str); return FALSE; } *session_id = (guint32) n; return TRUE; } gboolean mbimcli_ms_basic_connect_extensions_options_enabled (void) { static guint n_actions = 0; static gboolean checked = FALSE; if (checked) return !!n_actions; n_actions = (!!query_pco_str + query_lte_attach_configuration_flag + (query_lte_attach_status_flag || query_lte_attach_info_flag) + query_sys_caps_flag + query_device_caps_flag + !!query_slot_info_status_str + !!set_device_slot_mappings_str + query_device_slot_mappings_flag + query_location_info_status_flag + query_provisioned_contexts_flag + !!set_provisioned_contexts_str + query_base_stations_flag + !!query_version_str + query_registration_parameters_flag + !!set_registration_parameters_str + query_modem_configuration_flag + query_wake_reason_flag); if (n_actions > 1) { g_printerr ("error: too many Microsoft Basic Connect Extensions Service actions requested\n"); exit (EXIT_FAILURE); } checked = TRUE; return !!n_actions; } static void context_free (Context *context) { if (!context) return; if (context->cancellable) g_object_unref (context->cancellable); if (context->device) g_object_unref (context->device); g_slice_free (Context, context); } static void shutdown (gboolean operation_status) { /* Cleanup context and finish async operation */ context_free (ctx); mbimcli_async_operation_done (operation_status); } static void query_pco_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; g_autoptr(MbimPcoValue) pco_value = NULL; g_autofree gchar *pco_data = NULL; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully queried PCO\n", mbim_device_get_path_display (device)); if (!mbim_message_ms_basic_connect_extensions_pco_response_parse ( response, &pco_value, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } pco_data = mbim_common_str_hex (pco_value->pco_data_buffer, pco_value->pco_data_size, ' '); g_print ("[%s] PCO:\n" "\t Session ID: '%u'\n" "\tPCO data type: '%s'\n" "\tPCO data size: '%u'\n" "\t PCO data: '%s'\n", mbim_device_get_path_display (device), pco_value->session_id, VALIDATE_UNKNOWN (mbim_pco_type_get_string (pco_value->pco_data_type)), pco_value->pco_data_size, pco_data); shutdown (TRUE); } static void query_lte_attach_configuration_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; g_autoptr(MbimLteAttachConfigurationArray) configurations = NULL; guint32 configuration_count = 0; guint i; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully queried LTE attach configuration\n", mbim_device_get_path_display (device)); if (!mbim_message_ms_basic_connect_extensions_lte_attach_configuration_response_parse ( response, &configuration_count, &configurations, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } #define VALIDATE_NA(str) (str ? str : "n/a") for (i = 0; i < configuration_count; i++) { g_print ("Configuration %u:\n", i); g_print (" IP type: %s\n", mbim_context_ip_type_get_string (configurations[i]->ip_type)); g_print (" Roaming: %s\n", mbim_lte_attach_context_roaming_control_get_string (configurations[i]->roaming)); g_print (" Source: %s\n", mbim_context_source_get_string (configurations[i]->source)); g_print (" Access string: %s\n", VALIDATE_NA (configurations[i]->access_string)); g_print (" Username: %s\n", VALIDATE_NA (configurations[i]->user_name)); g_print (" Password: %s\n", VALIDATE_NA (configurations[i]->password)); g_print (" Compression: %s\n", mbim_compression_get_string (configurations[i]->compression)); g_print (" Auth protocol: %s\n", mbim_auth_protocol_get_string (configurations[i]->auth_protocol)); } #undef VALIDATE_NA shutdown (TRUE); } static void query_lte_attach_info_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; guint32 lte_attach_state; guint32 ip_type; g_autofree gchar *access_string = NULL; g_autofree gchar *user_name = NULL; g_autofree gchar *password = NULL; guint32 compression; guint32 auth_protocol; MbimNwError nw_error = 0; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } /* MBIMEx 3.0 support */ if (mbim_device_check_ms_mbimex_version (device, 3, 0)) { if (!mbim_message_ms_basic_connect_extensions_v3_lte_attach_info_response_parse ( response, <e_attach_state, &nw_error, &ip_type, &access_string, &user_name, &password, &compression, &auth_protocol, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully received v3.0 LTE attach info\n", mbim_device_get_path_display (device)); } /* MBIM 1.0 support */ else { if (!mbim_message_ms_basic_connect_extensions_lte_attach_info_response_parse ( response, <e_attach_state, &ip_type, &access_string, &user_name, &password, &compression, &auth_protocol, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully received v1.0 LTE attach info\n", mbim_device_get_path_display (device)); } #define VALIDATE_NA(str) (str ? str : "n/a") g_print (" Attach state: %s\n", mbim_lte_attach_state_get_string (lte_attach_state)); g_print (" IP type: %s\n", mbim_context_ip_type_get_string (ip_type)); g_print (" Access string: %s\n", VALIDATE_NA (access_string)); g_print (" Username: %s\n", VALIDATE_NA (user_name)); g_print (" Password: %s\n", VALIDATE_NA (password)); g_print (" Compression: %s\n", mbim_compression_get_string (compression)); g_print (" Auth protocol: %s\n", mbim_auth_protocol_get_string (auth_protocol)); if (mbim_device_check_ms_mbimex_version (device, 3, 0)) { if (nw_error == 0) g_print (" Network error: none\n"); else if (nw_error == 0xFFFFFFFF) g_print (" Network error: unknown\n"); else { const gchar *nw_error_str; nw_error_str = mbim_nw_error_get_string (nw_error); if (nw_error_str) g_print (" Network error: %s\n", nw_error_str); else g_print (" Network error: unknown (0x%08x)\n", nw_error); } } #undef VALIDATE_NA shutdown (TRUE); } static void query_sys_caps_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; guint32 number_executors; guint32 number_slots; guint32 concurrency; guint64 modem_id; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully queried sys caps\n", mbim_device_get_path_display (device)); if (!mbim_message_ms_basic_connect_extensions_sys_caps_response_parse ( response, &number_executors, &number_slots, &concurrency, &modem_id, &error)) { g_printerr ("error: couldn't parse response messages: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] System capabilities retrieved:\n" "\t Number of executors: '%u'\n" "\t Number of slots: '%u'\n" "\t Concurrency: '%u'\n" "\t Modem ID: '%" G_GUINT64_FORMAT "'\n", mbim_device_get_path_display (device), number_executors, number_slots, concurrency, modem_id); shutdown (TRUE); } static void query_device_caps_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; MbimDeviceType device_type; const gchar *device_type_str; MbimVoiceClass voice_class; const gchar *voice_class_str; MbimCellularClass cellular_class; g_autofree gchar *cellular_class_str = NULL; MbimSimClass sim_class; g_autofree gchar *sim_class_str = NULL; MbimDataClass data_class = 0; MbimDataClassV3 data_class_v3 = 0; g_autofree gchar *data_class_str = NULL; MbimDataSubclass data_subclass; MbimSmsCaps sms_caps; g_autofree gchar *sms_caps_str = NULL; MbimCtrlCaps ctrl_caps; g_autofree gchar *ctrl_caps_str = NULL; guint32 max_sessions; guint32 wcdma_band_class = 0; guint32 lte_band_class_array_size = 0; g_autofree guint16 *lte_band_class_array = NULL; guint32 nr_band_class_array_size = 0; g_autofree guint16 *nr_band_class_array = NULL; g_autofree gchar *custom_data_class = NULL; g_autofree gchar *device_id = NULL; g_autofree gchar *firmware_info = NULL; g_autofree gchar *hardware_info = NULL; guint32 executor_index; response = mbim_device_command_finish(device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } if (mbim_device_check_ms_mbimex_version (device, 3, 0)) { if (!mbim_message_ms_basic_connect_extensions_v3_device_caps_response_parse ( response, &device_type, &cellular_class, &voice_class, &sim_class, &data_class_v3, &sms_caps, &ctrl_caps, &data_subclass, &max_sessions, &executor_index, &wcdma_band_class, <e_band_class_array_size, <e_band_class_array, &nr_band_class_array_size, &nr_band_class_array, &custom_data_class, &device_id, &firmware_info, &hardware_info, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_debug ("Successfully parsed response as MBIMEx 3.0 Device Caps"); } else { if (!mbim_message_ms_basic_connect_extensions_device_caps_response_parse ( response, &device_type, &cellular_class, &voice_class, &sim_class, &data_class, &sms_caps, &ctrl_caps, &max_sessions, &custom_data_class, &device_id, &firmware_info, &hardware_info, &executor_index, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_debug ("Successfully parsed response as MBIMEx 1.0 Device Caps"); } if (mbim_device_check_ms_mbimex_version (device, 3, 0)) data_class_str = mbim_data_class_v3_build_string_from_mask (data_class_v3); else data_class_str = mbim_data_class_build_string_from_mask (data_class); device_type_str = mbim_device_type_get_string (device_type); cellular_class_str = mbim_cellular_class_build_string_from_mask (cellular_class); voice_class_str = mbim_voice_class_get_string (voice_class); sim_class_str = mbim_sim_class_build_string_from_mask (sim_class); sms_caps_str = mbim_sms_caps_build_string_from_mask (sms_caps); ctrl_caps_str = mbim_ctrl_caps_build_string_from_mask (ctrl_caps); g_print ("[%s] Device capabilities retrieved:\n" "\t Device type: '%s'\n" "\t Cellular class: '%s'\n" "\t Voice class: '%s'\n" "\t SIM class: '%s'\n" "\t Data class: '%s'\n" "\t SMS caps: '%s'\n" "\t Ctrl caps: '%s'\n" "\t Max sessions: '%u'\n" "\tCustom data class: '%s'\n" "\t Device ID: '%s'\n" "\t Firmware info: '%s'\n" "\t Hardware info: '%s'\n" "\t Executor Index: '%u'\n", mbim_device_get_path_display (device), VALIDATE_UNKNOWN (device_type_str), VALIDATE_UNKNOWN (cellular_class_str), VALIDATE_UNKNOWN (voice_class_str), VALIDATE_UNKNOWN (sim_class_str), VALIDATE_UNKNOWN (data_class_str), VALIDATE_UNKNOWN (sms_caps_str), VALIDATE_UNKNOWN (ctrl_caps_str), max_sessions, VALIDATE_UNKNOWN (custom_data_class), VALIDATE_UNKNOWN (device_id), VALIDATE_UNKNOWN (firmware_info), VALIDATE_UNKNOWN (hardware_info), executor_index); if (mbim_device_check_ms_mbimex_version (device, 3, 0)) { g_autofree gchar *data_subclass_str = NULL; guint i; gboolean n_printed; data_subclass_str = mbim_data_subclass_build_string_from_mask (data_subclass); g_print ("\t Data subclass: '%s'\n", data_subclass_str); g_print ("\t WCDMA band class: '"); for (n_printed = 0, i = 0; i < 31; i++) { if (wcdma_band_class & (1 << i)) { g_print ("%s%u", n_printed > 0 ? ", " : "", i + 1); n_printed++; } } g_print ("'\n"); g_print ("\t LTE band class: '"); for (i = 0; i < lte_band_class_array_size; i++) g_print ("%s%" G_GUINT16_FORMAT, i > 0 ? ", " : "", lte_band_class_array[i]); g_print ("'\n"); g_print ("\t NR band class: '"); for (i = 0; i < nr_band_class_array_size; i++) g_print ("%s%" G_GUINT16_FORMAT, i > 0 ? ", " : "", nr_band_class_array[i]); g_print ("'\n"); } shutdown (TRUE); } static gboolean query_slot_information_status_slot_index_parse (const gchar *str, guint32 *slot_index, GError **error) { gchar *endptr = NULL; gint64 n; g_assert (str != NULL); g_assert (slot_index != NULL); if (!str[0]) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, "slot index not given"); return FALSE; } errno = 0; n = g_ascii_strtoll (str, &endptr, 10); if (errno || ((size_t)(endptr - str) < strlen (str))) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, "couldn't parse slot index '%s'", str); return FALSE; } *slot_index = (guint32) n; return TRUE; } static void query_slot_information_status_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; guint32 slot_index; MbimUiccSlotState slot_state; const gchar *slot_state_str; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } if (!mbim_message_ms_basic_connect_extensions_slot_info_status_response_parse ( response, &slot_index, &slot_state, &error)) { g_printerr ("error: conldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } slot_state_str = mbim_uicc_slot_state_get_string (slot_state); g_print ("[%s] Slot info status retrieved:\n" "\t Slot '%u': '%s'\n", mbim_device_get_path_display (device), slot_index, VALIDATE_UNKNOWN (slot_state_str)); shutdown (TRUE); } static gboolean set_device_slot_mappings_input_parse (const gchar *str, GPtrArray **slot_array, GError **error) { g_auto(GStrv) split = NULL; gchar *endptr = NULL; gint64 n; MbimSlot *slot_index; guint32 i = 0; g_assert (slot_array != NULL); split = g_strsplit (str, ",", 0); if (g_strv_length (split) < 1) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, "missing arguments"); return FALSE; } *slot_array = g_ptr_array_new_with_free_func (g_free); while (split[i] != NULL) { errno = 0; n = g_ascii_strtoll (split[i], &endptr, 10); if (errno || n < 0 || n > G_MAXUINT32 || ((size_t)(endptr - split[i]) < strlen (split[i]))) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, "couldn't parse device slot index '%s'", split[i]); return FALSE; } slot_index = g_new (MbimSlot, 1); slot_index->slot = (guint32) n; g_ptr_array_add (*slot_array, slot_index); i++; } return TRUE; } static void query_device_slot_mappings_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; guint32 map_count = 0; g_autoptr(MbimSlotArray) slot_mappings = NULL; guint i; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } if (!mbim_message_ms_basic_connect_extensions_device_slot_mappings_response_parse ( response, &map_count, &slot_mappings, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } if (set_device_slot_mappings_str) { g_print ("[%s] Updated slot mappings retrieved:\n", mbim_device_get_path_display (device)); } else { g_print ("[%s] Slot mappings retrieved:\n", mbim_device_get_path_display (device)); } for (i = 0; i < map_count; i++) { g_print ("\t Executor '%u': slot '%u'\n", i, slot_mappings[i]->slot); } shutdown (TRUE); } static void query_location_info_status_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; guint32 location_area_code = 0; guint32 tracking_area_code = 0; guint32 cell_id = 0; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully queried location info status\n", mbim_device_get_path_display (device)); if (!mbim_message_ms_basic_connect_extensions_location_info_status_response_parse ( response, &location_area_code, &tracking_area_code, &cell_id, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_print (" Location area code: %04X\n", location_area_code); g_print (" Tracking area code: %06X\n", tracking_area_code); g_print (" Cell ID: %08X\n", cell_id); shutdown (TRUE); } typedef struct { MbimContextOperation operation; MbimContextIpType ip_type; MbimContextState state; MbimContextRoamingControl roaming_control; MbimContextMediaType media_type; MbimContextSource source; gchar *access_string; gchar *username; gchar *password; MbimCompression compression; MbimAuthProtocol auth_protocol; MbimContextType context_type; } ProvisionedContextProperties; static void provisioned_context_properties_clear (ProvisionedContextProperties *props) { g_free (props->access_string); g_free (props->username); g_free (props->password); } G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(ProvisionedContextProperties, provisioned_context_properties_clear) static gboolean set_provisioned_contexts_foreach_cb (const gchar *key, const gchar *value, GError **error, ProvisionedContextProperties *props) { if (g_ascii_strcasecmp (key, "operation") == 0) { if (!mbimcli_read_context_operation_from_string (value, &props->operation)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown operation: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "context-type") == 0) { if (!mbimcli_read_context_type_from_string (value, &props->context_type)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown context-type: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "ip-type") == 0) { if (!mbimcli_read_context_ip_type_from_string (value, &props->ip_type)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown ip-type: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "state") == 0) { if (!mbimcli_read_context_state_from_string (value, &props->state)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown state: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "roaming-control") == 0) { if (!mbimcli_read_context_roaming_control_from_string (value, &props->roaming_control)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown roaming-control: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "media-type") == 0) { if (!mbimcli_read_context_media_type_from_string (value, &props->media_type)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown media-type: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "source") == 0) { if (!mbimcli_read_context_source_from_string (value, &props->source)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown source: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "auth") == 0) { if (!mbimcli_read_auth_protocol_from_string (value, &props->auth_protocol)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown auth: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "compression") == 0) { if (!mbimcli_read_compression_from_string (value, &props->compression)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown compression: '%s'", value); return FALSE; } } else if (g_ascii_strcasecmp (key, "username") == 0) { g_free (props->username); props->username = g_strdup (value); } else if (g_ascii_strcasecmp (key, "password") == 0) { g_free (props->password); props->password = g_strdup (value); } else if (g_ascii_strcasecmp (key, "access-string") == 0) { g_free (props->access_string); props->access_string = g_strdup (value); } else { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, "unrecognized option '%s'", key); return FALSE; } return TRUE; } static void provisioned_contexts_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(MbimProvisionedContextElementV2Array) provisioned_contexts = NULL; g_autoptr(GError) error = NULL; guint32 provisioned_contexts_count; guint32 i = 0; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } if (!mbim_message_ms_basic_connect_extensions_provisioned_contexts_response_parse ( response, &provisioned_contexts_count, &provisioned_contexts, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Provisioned contexts (%u):\n", mbim_device_get_path_display (device), provisioned_contexts_count); for (i = 0; i < provisioned_contexts_count; i++) { g_print ("\tContext ID %u:\n" "\t Context type: '%s'\n" "\t IP type: '%s'\n" "\t State: '%s'\n" "\tRoaming control: '%s'\n" "\t Media type: '%s'\n" "\t Source: '%s'\n" "\t Access string: '%s'\n" "\t Username: '%s'\n" "\t Password: '%s'\n" "\t Compression: '%s'\n" "\t Auth protocol: '%s'\n", provisioned_contexts[i]->context_id, VALIDATE_UNKNOWN (mbim_context_type_get_string ( mbim_uuid_to_context_type (&provisioned_contexts[i]->context_type))), VALIDATE_UNKNOWN (mbim_context_ip_type_get_string ( provisioned_contexts[i]->ip_type)), VALIDATE_UNKNOWN (mbim_context_state_get_string ( provisioned_contexts[i]->state)), VALIDATE_UNKNOWN (mbim_context_roaming_control_get_string ( provisioned_contexts[i]->roaming)), VALIDATE_UNKNOWN (mbim_context_media_type_get_string ( provisioned_contexts[i]->media_type)), VALIDATE_UNKNOWN (mbim_context_source_get_string ( provisioned_contexts[i]->source)), VALIDATE_UNKNOWN (provisioned_contexts[i]->access_string), VALIDATE_UNKNOWN (provisioned_contexts[i]->user_name), VALIDATE_UNKNOWN (provisioned_contexts[i]->password), VALIDATE_UNKNOWN (mbim_compression_get_string ( provisioned_contexts[i]->compression)), VALIDATE_UNKNOWN (mbim_auth_protocol_get_string ( provisioned_contexts[i]->auth_protocol))); } shutdown (TRUE); } static void query_base_stations_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; MbimDataClass system_type; MbimDataClassV3 system_type_v3; MbimDataSubclass system_subtype; g_autoptr(MbimCellInfoServingGsm) gsm_serving_cell = NULL; g_autoptr(MbimCellInfoServingUmts) umts_serving_cell = NULL; g_autoptr(MbimCellInfoServingTdscdma) tdscdma_serving_cell = NULL; g_autoptr(MbimCellInfoServingLte) lte_serving_cell = NULL; guint32 gsm_neighboring_cells_count; g_autoptr(MbimCellInfoNeighboringGsmArray) gsm_neighboring_cells = NULL; guint32 umts_neighboring_cells_count; g_autoptr(MbimCellInfoNeighboringUmtsArray) umts_neighboring_cells = NULL; guint32 tdscdma_neighboring_cells_count; g_autoptr(MbimCellInfoNeighboringTdscdmaArray) tdscdma_neighboring_cells = NULL; guint32 lte_neighboring_cells_count; g_autoptr(MbimCellInfoNeighboringLteArray) lte_neighboring_cells = NULL; guint32 cdma_cells_count; g_autoptr(MbimCellInfoCdmaArray) cdma_cells = NULL; guint32 nr_serving_cells_count; g_autoptr(MbimCellInfoServingNrArray) nr_serving_cells = NULL; guint32 nr_neighboring_cells_count; g_autoptr(MbimCellInfoNeighboringNrArray) nr_neighboring_cells = NULL; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } /* MBIMEx 3.0 support */ if (mbim_device_check_ms_mbimex_version (device, 3, 0)) { if (!mbim_message_ms_basic_connect_extensions_v3_base_stations_info_response_parse ( response, &system_type_v3, &system_subtype, &gsm_serving_cell, &umts_serving_cell, &tdscdma_serving_cell, <e_serving_cell, &gsm_neighboring_cells_count, &gsm_neighboring_cells, &umts_neighboring_cells_count, &umts_neighboring_cells, &tdscdma_neighboring_cells_count, &tdscdma_neighboring_cells, <e_neighboring_cells_count, <e_neighboring_cells, &cdma_cells_count, &cdma_cells, &nr_serving_cells_count, &nr_serving_cells, &nr_neighboring_cells_count, &nr_neighboring_cells, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_debug ("Successfully parsed response as MBIMEx 3.0 Base Stations Info"); } /* MBIMEx 1.0 support */ else { if (!mbim_message_ms_basic_connect_extensions_base_stations_info_response_parse ( response, &system_type, &gsm_serving_cell, &umts_serving_cell, &tdscdma_serving_cell, <e_serving_cell, &gsm_neighboring_cells_count, &gsm_neighboring_cells, &umts_neighboring_cells_count, &umts_neighboring_cells, &tdscdma_neighboring_cells_count, &tdscdma_neighboring_cells, <e_neighboring_cells_count, <e_neighboring_cells, &cdma_cells_count, &cdma_cells, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_debug ("Successfully parsed response as MBIMEx 1.0 Base Stations Info"); } #define PRINT_VALIDATED_UINT(number, invalid, format, units) do { \ if (number == invalid) \ g_print ("%s: unknown\n", format); \ else \ g_print ("%s: %u%s\n", format, number, units ? units : ""); \ } while (0) #define PRINT_VALIDATED_UINT64(number, invalid, format, units) do { \ if (number == invalid) \ g_print ("%s: unknown\n", format); \ else \ g_print ("%s: %" G_GUINT64_FORMAT "%s\n", format, number, units ? units : ""); \ } while (0) #define PRINT_VALIDATED_INT(number, invalid, format, units) do { \ if (number == (gint32)invalid) \ g_print ("%s: unknown\n", format); \ else \ g_print ("%s: %d%s\n", format, number, units ? units : ""); \ } while (0) #define PRINT_VALIDATED_SCALED_UINT(number, invalid, scale, format, units) do { \ if (number == 0xFFFFFFFF) \ g_print ("%s: unknown\n", format); \ else \ g_print ("%s: %d%s\n", format, ((gint32)number) + scale, units ? units : ""); \ } while (0) if (mbim_device_check_ms_mbimex_version (device, 3, 0)) { g_autofree gchar *system_type_str = NULL; g_autofree gchar *system_subtype_str = NULL; system_type_str = mbim_data_class_v3_build_string_from_mask (system_type_v3); g_print ("System type: %s\n", system_type_str); system_subtype_str = mbim_data_subclass_build_string_from_mask (system_subtype); g_print ("System subtype: %s\n", VALIDATE_UNKNOWN (system_subtype_str)); } else { g_autofree gchar *system_type_str = NULL; system_type_str = mbim_data_class_build_string_from_mask (system_type); g_print ("System type: %s\n", system_type_str); } if (gsm_serving_cell) { g_print ("GSM serving cell:\n" "\t Provider id: %s\n", VALIDATE_UNKNOWN (gsm_serving_cell->provider_id)); PRINT_VALIDATED_UINT (gsm_serving_cell->location_area_code, 0xFFFFFFFF, "\t LAC", NULL); PRINT_VALIDATED_UINT (gsm_serving_cell->cell_id, 0xFFFFFFFF, "\t Cell ID", NULL); PRINT_VALIDATED_UINT (gsm_serving_cell->timing_advance, 0xFFFFFFFF, "\t Timing advance", " bit periods"); PRINT_VALIDATED_UINT (gsm_serving_cell->arfcn, 0xFFFFFFFF, "\t ARFCN", NULL); PRINT_VALIDATED_UINT (gsm_serving_cell->base_station_id, 0xFFFFFFFF, "\tBase station ID", NULL); PRINT_VALIDATED_SCALED_UINT (gsm_serving_cell->rx_level, 0xFFFFFFFF, -110, "\t Rx level", " dBm"); } else g_print ("GSM serving cell: n/a\n"); if (gsm_neighboring_cells_count && gsm_neighboring_cells) { guint i; g_print ("Neighboring GSM cells: %d\n", gsm_neighboring_cells_count); for (i = 0; i < gsm_neighboring_cells_count; i++) { g_print ("\tNeighboring cell [%u]:\n" "\t\t Provider id: %s\n", i + 1, VALIDATE_UNKNOWN (gsm_neighboring_cells[i]->provider_id)); PRINT_VALIDATED_UINT (gsm_neighboring_cells[i]->location_area_code, 0xFFFFFFFF, "\t\t LAC", NULL); PRINT_VALIDATED_UINT (gsm_neighboring_cells[i]->cell_id, 0xFFFFFFFF, "\t\t Cell ID", NULL); PRINT_VALIDATED_UINT (gsm_neighboring_cells[i]->arfcn, 0xFFFFFFFF, "\t\t ARFCN", NULL); PRINT_VALIDATED_UINT (gsm_neighboring_cells[i]->base_station_id, 0xFFFFFFFF, "\t\tBase station ID", NULL); PRINT_VALIDATED_SCALED_UINT (gsm_neighboring_cells[i]->rx_level, 0xFFFFFFFF, -110, "\t\t Rx level", " dBm"); } } else g_print ("Neighboring GSM cells: n/a\n"); if (umts_serving_cell) { g_print ("UMTS Serving cell:\n" "\t Provider id: %s\n", VALIDATE_UNKNOWN (umts_serving_cell->provider_id)); PRINT_VALIDATED_UINT (umts_serving_cell->location_area_code, 0xFFFFFFFF, "\t LAC", NULL); PRINT_VALIDATED_UINT (umts_serving_cell->cell_id, 0xFFFFFFFF, "\t Cell id", NULL); PRINT_VALIDATED_UINT (umts_serving_cell->frequency_info_ul, 0xFFFFFFFF, "\t Frequency info uplink", NULL); PRINT_VALIDATED_UINT (umts_serving_cell->frequency_info_dl, 0xFFFFFFFF, "\tFrequency info downlink", NULL); PRINT_VALIDATED_UINT (umts_serving_cell->frequency_info_nt, 0xFFFFFFFF, "\t Frequency info TDD", NULL); PRINT_VALIDATED_UINT (umts_serving_cell->uarfcn, 0xFFFFFFFF, "\t UARFCN", NULL); PRINT_VALIDATED_UINT (umts_serving_cell->primary_scrambling_code, 0xFFFFFFFF, "\tPrimary Scrambling Code", NULL); PRINT_VALIDATED_INT (umts_serving_cell->rscp, 0, "\t RSCP", " dBm"); PRINT_VALIDATED_INT (umts_serving_cell->ecno, 1, "\t ECNO", " dBm"); PRINT_VALIDATED_UINT (umts_serving_cell->path_loss, 0xFFFFFFFF, "\t Path loss", NULL); } else g_print ("UMTS serving cell: n/a\n"); if (umts_neighboring_cells_count && umts_neighboring_cells) { guint i; g_print ("Neighboring UMTS cells: %d\n", umts_neighboring_cells_count); for (i = 0; i < umts_neighboring_cells_count; i++) { g_print ("\tNeighboring cell [%u]:\n" "\t\t Provider id: %s\n", i + 1, VALIDATE_UNKNOWN (umts_neighboring_cells[i]->provider_id)); PRINT_VALIDATED_UINT (umts_neighboring_cells[i]->location_area_code, 0xFFFFFFFF, "\t\t LAC", NULL); PRINT_VALIDATED_UINT (umts_neighboring_cells[i]->cell_id, 0xFFFFFFFF, "\t\t Cell id", NULL); PRINT_VALIDATED_UINT (umts_neighboring_cells[i]->uarfcn, 0xFFFFFFFF, "\t\t UARFCN", NULL); PRINT_VALIDATED_UINT (umts_neighboring_cells[i]->primary_scrambling_code, 0xFFFFFFFF, "\t\tPrimary Scrambling Code", NULL); PRINT_VALIDATED_INT (umts_neighboring_cells[i]->rscp, 0, "\t\t RSCP", " dBm"); PRINT_VALIDATED_INT (umts_neighboring_cells[i]->ecno, 1, "\t\t ECNO", " dBm"); PRINT_VALIDATED_UINT (umts_neighboring_cells[i]->path_loss, 0xFFFFFFFF, "\t\t Path loss", NULL); } } else g_print ("Neighboring UMTS cells: n/a\n"); if (tdscdma_serving_cell) { g_print ("TDSCDMA Serving cell:\n" "\t Provider id: %s\n", VALIDATE_UNKNOWN (tdscdma_serving_cell->provider_id)); PRINT_VALIDATED_UINT (tdscdma_serving_cell->location_area_code, 0xFFFFFFFF, "\t LAC", NULL); PRINT_VALIDATED_UINT (tdscdma_serving_cell->cell_id, 0xFFFFFFFF, "\t Cell id", NULL); PRINT_VALIDATED_UINT (tdscdma_serving_cell->uarfcn, 0xFFFFFFFF, "\t UARFCN", NULL); PRINT_VALIDATED_UINT (tdscdma_serving_cell->cell_parameter_id, 0xFFFFFFFF, "\tCell parameter id", NULL); PRINT_VALIDATED_UINT (tdscdma_serving_cell->timing_advance, 0xFFFFFFFF, "\t Timing advance", NULL); PRINT_VALIDATED_INT (tdscdma_serving_cell->rscp, 0xFFFFFFFF, "\t RSCP", " dBm"); PRINT_VALIDATED_UINT (tdscdma_serving_cell->path_loss, 0xFFFFFFFF, "\t Path loss", NULL); } else g_print ("TDSCDMA serving cell: n/a\n"); if (tdscdma_neighboring_cells_count && tdscdma_neighboring_cells) { guint i; g_print ("Neighboring TDSCDMA cells: %d\n", tdscdma_neighboring_cells_count); for (i = 0; i < tdscdma_neighboring_cells_count; i++) { g_print ("\tNeighboring cell [%u]:\n" "\t\t Provider id: %s\n", i + 1, VALIDATE_UNKNOWN (tdscdma_neighboring_cells[i]->provider_id)); PRINT_VALIDATED_UINT (tdscdma_neighboring_cells[i]->location_area_code, 0xFFFFFFFF, "\t\t LAC", NULL); PRINT_VALIDATED_UINT (tdscdma_neighboring_cells[i]->cell_id, 0xFFFFFFFF, "\t\t Cell id", NULL); PRINT_VALIDATED_UINT (tdscdma_neighboring_cells[i]->uarfcn, 0xFFFFFFFF, "\t\t UARFCN", NULL); PRINT_VALIDATED_UINT (tdscdma_neighboring_cells[i]->cell_parameter_id, 0xFFFFFFFF, "\t\tCell parameter id", NULL); PRINT_VALIDATED_UINT (tdscdma_neighboring_cells[i]->timing_advance, 0xFFFFFFFF, "\t\t Timing advance", NULL); PRINT_VALIDATED_INT (tdscdma_neighboring_cells[i]->rscp, 0xFFFFFFFF, "\t\t RSCP", " dBm"); PRINT_VALIDATED_UINT (tdscdma_neighboring_cells[i]->path_loss, 0xFFFFFFFF, "\t\t Path Loss", NULL); } } else g_print ("Neighboring TDSCDMA cells: n/a\n"); if (lte_serving_cell) { g_print ("LTE Serving cell:\n" "\t Provider id: %s\n", VALIDATE_UNKNOWN (lte_serving_cell->provider_id)); PRINT_VALIDATED_UINT (lte_serving_cell->cell_id, 0xFFFFFFFF, "\t Cell id", NULL); PRINT_VALIDATED_UINT (lte_serving_cell->earfcn, 0xFFFFFFFF, "\t EARFCN", NULL); PRINT_VALIDATED_UINT (lte_serving_cell->physical_cell_id, 0xFFFFFFFF, "\t Physical cell id", NULL); PRINT_VALIDATED_UINT (lte_serving_cell->tac, 0xFFFFFFFF, "\t TAC", NULL); PRINT_VALIDATED_INT (lte_serving_cell->rsrp, 0xFFFFFFFF, "\t RSRP", " dBm"); PRINT_VALIDATED_INT (lte_serving_cell->rsrq, 0xFFFFFFFF, "\t RSRQ", " dBm"); PRINT_VALIDATED_UINT (lte_serving_cell->timing_advance, 0xFFFFFFFF, "\t Timing advance", NULL); } else g_print ("LTE serving cell: n/a\n"); if (lte_neighboring_cells_count && lte_neighboring_cells) { guint i; g_print ("Neighboring LTE cells: %d\n", lte_neighboring_cells_count); for (i = 0; i < lte_neighboring_cells_count; i++) { g_print ("\tNeighboring cell [%u]:\n" "\t\t Provider id: %s\n", i + 1, VALIDATE_UNKNOWN (lte_neighboring_cells[i]->provider_id)); PRINT_VALIDATED_UINT (lte_neighboring_cells[i]->cell_id, 0xFFFFFFFF, "\t\t Cell id", NULL); PRINT_VALIDATED_UINT (lte_neighboring_cells[i]->earfcn, 0xFFFFFFFF, "\t\t EARFCN", NULL); PRINT_VALIDATED_UINT (lte_neighboring_cells[i]->physical_cell_id, 0xFFFFFFFF, "\t\t Physical cell id", NULL); PRINT_VALIDATED_UINT (lte_neighboring_cells[i]->tac, 0xFFFFFFFF, "\t\t TAC", NULL); PRINT_VALIDATED_INT (lte_neighboring_cells[i]->rsrp, 0xFFFFFFFF, "\t\t RSRP", " dBm"); PRINT_VALIDATED_INT (lte_neighboring_cells[i]->rsrq, 0xFFFFFFFF, "\t\t RSRQ", " dBm"); } } else g_print ("Neighboring LTE cells: n/a\n"); if (cdma_cells_count && cdma_cells) { guint i; g_print ("CDMA cells: %d\n", cdma_cells_count); for (i = 0; i < cdma_cells_count; i++) g_print ("Cell [%u]:\n" "\t Serving: %s\n", i + 1, cdma_cells[i]->serving_cell_flag ? "yes" : "no"); PRINT_VALIDATED_UINT (cdma_cells[i]->nid, 0xFFFFFFFF, "\t NID", NULL); PRINT_VALIDATED_UINT (cdma_cells[i]->sid, 0xFFFFFFFF, "\t SID", NULL); PRINT_VALIDATED_UINT (cdma_cells[i]->base_station_id, 0xFFFFFFFF, "\tBase station id", NULL); /* TODO: The Base Station Latitude (0-4194303). This is encoded in units of 0.25 seconds, expressed * in two’s complement representation within the low 22 bits of the DWORD. As a signed value, * North latitudes are positive. Use 0xFFFFFFFF when this information is not available. */ PRINT_VALIDATED_UINT (cdma_cells[i]->base_latitude, 0xFFFFFFFF, "\t Base latitude", NULL); /* TODO: The Base Station Longitude (0-8388607). This is encoded in units of 0.25 seconds, expressed * in two’s complement representation within the low 23 bits of the DWORD. As a signed value, East * longitudes are positive. Use 0xFFFFFFFF when this information is not available. */ PRINT_VALIDATED_UINT (cdma_cells[i]->base_longitude, 0xFFFFFFFF, "\t Base longitude", NULL); PRINT_VALIDATED_UINT (cdma_cells[i]->ref_pn, 0xFFFFFFFF, "\t RefPN", NULL); PRINT_VALIDATED_UINT (cdma_cells[i]->gps_seconds, 0xFFFFFFFF, "\t GPS seconds", " seconds"); PRINT_VALIDATED_UINT (cdma_cells[i]->pilot_strength, 0xFFFFFFFF, "\t Pilot strength", NULL); } else g_print ("CDMA cells: n/a\n"); if (nr_serving_cells_count && nr_serving_cells) { guint i; g_print ("Serving NR cells: %d\n", nr_serving_cells_count); for (i = 0; i < nr_serving_cells_count; i++) { g_print ("\tServing cell [%u]:\n" "\t\t Provider id: %s\n", i + 1, VALIDATE_UNKNOWN (nr_serving_cells[i]->provider_id)); PRINT_VALIDATED_UINT64 (nr_serving_cells[i]->nci, 0xFFFFFFFFFFFFFFFF, "\t\t NCI", NULL); PRINT_VALIDATED_UINT (nr_serving_cells[i]->physical_cell_id, 0xFFFFFFFF, "\t\tPhysical cell id", NULL); PRINT_VALIDATED_UINT (nr_serving_cells[i]->nrarfcn, 0xFFFFFFFF, "\t\t NRARFCN", NULL); PRINT_VALIDATED_UINT (nr_serving_cells[i]->tac, 0xFFFFFFFF, "\t\t TAC", NULL); PRINT_VALIDATED_SCALED_UINT (nr_serving_cells[i]->rsrp, 0xFFFFFFFF, -156, "\t\t RSRP", " dBm"); PRINT_VALIDATED_SCALED_UINT (nr_serving_cells[i]->rsrq, 0xFFFFFFFF, -43, "\t\t RSRQ", " dB"); PRINT_VALIDATED_SCALED_UINT (nr_serving_cells[i]->sinr, 0xFFFFFFFF, -23, "\t\t SINR", " dB"); PRINT_VALIDATED_UINT64 (nr_serving_cells[i]->timing_advance, 0xFFFFFFFFFFFFFFFF, "\t\t Timing advance", " us"); } } else g_print ("Serving NR cells: n/a\n"); if (nr_neighboring_cells_count && nr_neighboring_cells) { guint i; g_print ("Neighboring NR cells: %d\n", nr_neighboring_cells_count); for (i = 0; i < nr_neighboring_cells_count; i++) { g_autofree gchar *system_subtype_str = NULL; system_subtype_str = mbim_data_subclass_build_string_from_mask (nr_neighboring_cells[i]->system_sub_type); g_print ("\tNeighboring cell [%u]:\n" "\t\t System subtype: %s\n" "\t\t Provider id: %s\n" "\t\t Cell id: %s\n", i + 1, VALIDATE_UNKNOWN (system_subtype_str), VALIDATE_UNKNOWN (nr_neighboring_cells[i]->provider_id), VALIDATE_UNKNOWN (nr_neighboring_cells[i]->cell_id)); PRINT_VALIDATED_UINT (nr_neighboring_cells[i]->physical_cell_id, 0xFFFFFFFF, "\t\tPhysical cell id", NULL); PRINT_VALIDATED_UINT (nr_neighboring_cells[i]->tac, 0xFFFFFFFF, "\t\t TAC", NULL); PRINT_VALIDATED_SCALED_UINT (nr_neighboring_cells[i]->rsrp, 0xFFFFFFFF, -156, "\t\t RSRP", " dBm"); PRINT_VALIDATED_SCALED_UINT (nr_neighboring_cells[i]->rsrq, 0xFFFFFFFF, -43, "\t\t RSRQ", " dB"); PRINT_VALIDATED_SCALED_UINT (nr_neighboring_cells[i]->sinr, 0xFFFFFFFF, -23, "\t\t SINR", " dB"); } } else g_print ("Neighboring NR cells: n/a\n"); #undef PRINT_VALIDATED_SCALED_UINT #undef PRINT_VALIDATED_UINT64 #undef PRINT_VALIDATED_UINT #undef PRINT_VALIDATED_INT shutdown (TRUE); } static void query_version_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; guint16 mbim_version; guint16 mbim_ext_version; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully exchanged version information\n", mbim_device_get_path_display (device)); if (!mbim_message_ms_basic_connect_extensions_v2_version_response_parse ( response, &mbim_version, &mbim_ext_version, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_print (" MBIM version : %x.%02x\n", mbim_version >> 8, mbim_version & 0xFF); g_print (" MBIM extended version : %x.%02x\n", mbim_ext_version >> 8, mbim_ext_version & 0xFF); shutdown (TRUE); return; } typedef struct { MbimMicoMode mico_mode; gboolean mico_mode_set; MbimDrxCycle drx_cycle; gboolean drx_cycle_set; MbimLadnInfo ladn_info; gboolean ladn_info_set; MbimDefaultPduActivationHint pdu_hint; gboolean pdu_hint_set; gboolean re_register_if_needed; gboolean re_register_if_needed_set; } RegistrationParameters; static gboolean set_registration_parameters_foreach_cb (const gchar *key, const gchar *value, GError **error, RegistrationParameters *params) { if (g_ascii_strcasecmp (key, "mico-mode") == 0) { if (!mbimcli_read_mico_mode_from_string (value, ¶ms->mico_mode)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown mico-mode: '%s'", value); return FALSE; } params->mico_mode_set = TRUE; } else if (g_ascii_strcasecmp (key, "drx-cycle") == 0) { if (!mbimcli_read_drx_cycle_from_string (value, ¶ms->drx_cycle)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown drx-cycle: '%s'", value); return FALSE; } params->drx_cycle_set = TRUE; } else if (g_ascii_strcasecmp (key, "ladn-info") == 0) { if (!mbimcli_read_ladn_info_from_string (value, ¶ms->ladn_info)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown ladn-info: '%s'", value); return FALSE; } params->ladn_info_set = TRUE; } else if (g_ascii_strcasecmp (key, "default-pdu-activation-hint") == 0) { if (!mbimcli_read_default_pdu_activation_hint_from_string (value, ¶ms->pdu_hint)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown default-pdu-activation-hint: '%s'", value); return FALSE; } params->pdu_hint_set = TRUE; } else if (g_ascii_strcasecmp (key, "re-register-if-needed") == 0) { if (!mbimcli_read_boolean_from_string (value, ¶ms->re_register_if_needed)) { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_INVALID_ARGS, "unknown re-register-if-needed: '%s'", value); return FALSE; } params->re_register_if_needed_set = TRUE; } else { g_set_error (error, MBIM_CORE_ERROR, MBIM_CORE_ERROR_FAILED, "unrecognized option '%s'", key); return FALSE; } return TRUE; } static void registration_parameters_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; MbimMicoMode mico_mode; MbimDrxCycle drx_cycle; MbimLadnInfo ladn_info; MbimDefaultPduActivationHint pdu_hint; gboolean re_register_if_nedeed; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully received registration parameters information\n", mbim_device_get_path_display (device)); if (!mbim_message_ms_basic_connect_extensions_v3_registration_parameters_response_parse ( response, &mico_mode, &drx_cycle, &ladn_info, &pdu_hint, &re_register_if_nedeed, NULL, /* ignore unnamed IEs for now */ &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_print ("\t MICO mode: %s\n", mbim_mico_mode_get_string (mico_mode)); g_print ("\t DRX cycle: %s\n", mbim_drx_cycle_get_string (drx_cycle)); g_print ("\t LADN information: %s\n", mbim_ladn_info_get_string (ladn_info)); g_print ("\tDefault PDU activation: %s\n", mbim_default_pdu_activation_hint_get_string (pdu_hint)); g_print ("\t Re-register if needed: %s\n", re_register_if_nedeed ? "yes" : "no"); shutdown (TRUE); } static void query_modem_configuration_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; MbimModemConfigurationStatus configuration_status; g_autofree gchar *configuration_name = NULL; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } if (!mbim_message_ms_basic_connect_extensions_v3_modem_configuration_response_parse ( response, &configuration_status, &configuration_name, NULL, /* ignore unnamed IEs for now */ &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Modem configuration retrieved: \n", mbim_device_get_path_display (device)); g_print ("\tStatus: '%s'\n" "\t Name: '%s'\n", VALIDATE_UNKNOWN (mbim_modem_configuration_status_get_string (configuration_status)), VALIDATE_UNKNOWN (configuration_name)); shutdown (TRUE); } static void query_wake_reason_ready (MbimDevice *device, GAsyncResult *res) { g_autoptr(MbimMessage) response = NULL; g_autoptr(GError) error = NULL; MbimWakeType wake_type; guint32 session_id; MbimTlv *wake_tlv = NULL; response = mbim_device_command_finish (device, res, &error); if (!response || !mbim_message_response_get_result (response, MBIM_MESSAGE_TYPE_COMMAND_DONE, &error)) { g_printerr ("error: operation failed: %s\n", error->message); shutdown (FALSE); return; } if (!mbim_message_ms_basic_connect_extensions_v3_wake_reason_response_parse ( response, &wake_type, &session_id, &wake_tlv, &error)) { g_printerr ("error: couldn't parse response message: %s\n", error->message); shutdown (FALSE); return; } g_print ("[%s] Successfully queried wake reason\n", mbim_device_get_path_display (device)); g_print ("\t Wake type: '%s'\n", mbim_wake_type_get_string (wake_type)); g_print ("\tSession ID: '%u'\n", session_id); if ((wake_type == MBIM_WAKE_TYPE_CID_RESPONSE) || (wake_type == MBIM_WAKE_TYPE_CID_INDICATION)) { const MbimUuid *service = NULL; g_autofree gchar *service_str = NULL; guint32 cid = 0; guint32 payload_size = 0; g_autofree guint8 *payload = NULL; g_autofree gchar *payload_str = NULL; if (!mbim_tlv_wake_command_get (wake_tlv, &service, &cid, &payload_size, &payload, &error)) { g_printerr ("error: couldn't parse wake command TLV: %s\n", error->message); shutdown (FALSE); return; } /* Known payload defined right now only for the Connect CID */ if ((mbim_uuid_to_service (service) == MBIM_SERVICE_BASIC_CONNECT) && (cid == MBIM_CID_BASIC_CONNECT_CONNECT) && (payload_size == 4)) { guint32 activate; memcpy (&activate, payload, payload_size); activate = GUINT32_FROM_LE (activate); if (activate == 0x00000001 || activate == 0x00000000) payload_str = g_strdup (activate ? "activate" : "deactivate"); } if (!payload_str) payload_str = mbim_common_str_hex (payload, payload_size, ':'); service_str = mbim_uuid_get_printable (service); g_print ("\t Service: '%s'\n", service_str); g_print ("\t CID: '0x%08x'\n", cid); g_print ("\t Payload: '%s'\n", payload_str); shutdown (TRUE); return; } if (wake_type == MBIM_WAKE_TYPE_PACKET) { guint32 filter_id = 0; guint32 original_packet_size = 0; guint32 packet_size = 0; g_autofree guint8 *packet = NULL; g_autofree gchar *packet_str = NULL; if (!mbim_tlv_wake_packet_get (wake_tlv, &filter_id, &original_packet_size, &packet_size, &packet, &error)) { g_printerr ("error: couldn't parse wake packet TLV: %s\n", error->message); shutdown (FALSE); return; } packet_str = mbim_common_str_hex (packet, packet_size, ':'); g_print ("\t Filter ID: '%u'\n", filter_id); g_print ("\tOriginal size: '%u'\n", original_packet_size); g_print ("\t Saved size: '%u'\n", packet_size); g_print ("\t Packet: '%s'\n", packet_str); shutdown (TRUE); return; } g_printerr ("error: unknown wake type: 0x%08x\n", wake_type); shutdown (FALSE); } void mbimcli_ms_basic_connect_extensions_run (MbimDevice *device, GCancellable *cancellable) { g_autoptr(MbimMessage) request = NULL; g_autoptr(GError) error = NULL; /* Initialize context */ ctx = g_slice_new (Context); ctx->device = g_object_ref (device); ctx->cancellable = cancellable ? g_object_ref (cancellable) : NULL; /* Request to get PCO? */ if (query_pco_str) { MbimPcoValue pco_value; if (!session_id_parse (query_pco_str, &pco_value.session_id, &error)) { g_printerr ("error: couldn't parse session ID: %s\n", error->message); shutdown (FALSE); return; } pco_value.pco_data_size = 0; pco_value.pco_data_type = MBIM_PCO_TYPE_COMPLETE; pco_value.pco_data_buffer = NULL; g_debug ("Asynchronously querying PCO..."); request = mbim_message_ms_basic_connect_extensions_pco_query_new (&pco_value, NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_pco_ready, NULL); return; } if (query_lte_attach_configuration_flag) { g_debug ("Asynchronously querying LTE attach configuration..."); request = mbim_message_ms_basic_connect_extensions_lte_attach_configuration_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_lte_attach_configuration_ready, NULL); return; } if (query_lte_attach_status_flag || query_lte_attach_info_flag) { g_debug ("Asynchronously querying LTE attach info..."); request = mbim_message_ms_basic_connect_extensions_lte_attach_info_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_lte_attach_info_ready, NULL); return; } if (query_sys_caps_flag) { g_debug ("Asynchronously querying system capabilities..."); request = mbim_message_ms_basic_connect_extensions_sys_caps_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_sys_caps_ready, NULL); return; } if (query_device_caps_flag) { g_debug ("Asynchronously querying device capabilities..."); request = mbim_message_ms_basic_connect_extensions_device_caps_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_device_caps_ready, NULL); return; } if (query_slot_info_status_str) { guint32 slot_index; if (!query_slot_information_status_slot_index_parse (query_slot_info_status_str, &slot_index, &error)) { g_printerr ("error: couldn't parse slot index: %s\n", error->message); shutdown (FALSE); return; } g_debug ("Asynchronously querying slot information status..."); request = mbim_message_ms_basic_connect_extensions_slot_info_status_query_new (slot_index, NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_slot_information_status_ready, NULL); return; } if (set_device_slot_mappings_str) { g_autoptr(GPtrArray) slot_array = NULL; g_print ("Asynchronously set device slot mappings\n"); if (!set_device_slot_mappings_input_parse (set_device_slot_mappings_str, &slot_array, &error)) { g_printerr ("error: couldn't parse setting argument: %s\n", error->message); shutdown (FALSE); return; } request = mbim_message_ms_basic_connect_extensions_device_slot_mappings_set_new (slot_array->len, (const MbimSlot **)slot_array->pdata, NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_device_slot_mappings_ready, NULL); return; } if (query_device_slot_mappings_flag) { g_debug ("Asynchronously querying device slot mappings..."); request = mbim_message_ms_basic_connect_extensions_device_slot_mappings_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_device_slot_mappings_ready, NULL); return; } if (query_location_info_status_flag) { g_debug ("Asynchronously querying location info status..."); request = mbim_message_ms_basic_connect_extensions_location_info_status_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_location_info_status_ready, NULL); return; } if (set_provisioned_contexts_str) { g_auto(ProvisionedContextProperties) props = { .access_string = NULL, .operation = MBIM_CONTEXT_OPERATION_DELETE, .auth_protocol = MBIM_AUTH_PROTOCOL_NONE, .username = NULL, .password = NULL, .ip_type = MBIM_CONTEXT_IP_TYPE_DEFAULT, .state = MBIM_CONTEXT_STATE_DISABLED, .roaming_control = MBIM_CONTEXT_ROAMING_CONTROL_HOME_ONLY, .media_type = MBIM_CONTEXT_MEDIA_TYPE_CELLULAR_ONLY, .source = MBIM_CONTEXT_SOURCE_ADMIN, .compression = MBIM_COMPRESSION_NONE, .context_type = MBIM_CONTEXT_TYPE_INVALID }; if (!mbimcli_parse_key_value_string (set_provisioned_contexts_str, &error, (MbimParseKeyValueForeachFn)set_provisioned_contexts_foreach_cb, &props)) { g_printerr ("error: couldn't parse input string: %s\n", error->message); shutdown (FALSE); return; } request = mbim_message_ms_basic_connect_extensions_provisioned_contexts_set_new ( props.operation, mbim_uuid_from_context_type (props.context_type), props.ip_type, props.state, props.roaming_control, props.media_type, props.source, props.access_string, props.username, props.password, props.compression, props.auth_protocol, &error); if (!request) { g_printerr ("error: couldn't create request: %s\n", error->message); shutdown (FALSE); return; } mbim_device_command (ctx->device, request, 60, ctx->cancellable, (GAsyncReadyCallback)provisioned_contexts_ready, NULL); return; } /* Request to query Provisioned contexts? */ if (query_provisioned_contexts_flag) { g_debug ("Asynchronously query provisioned contexts..."); request = mbim_message_ms_basic_connect_extensions_provisioned_contexts_query_new (NULL); if (!request) { g_printerr ("error: couldn't create request: %s\n", error->message); shutdown (FALSE); return; } mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)provisioned_contexts_ready, NULL); return; } if (query_base_stations_flag) { g_debug ("Asynchronously querying base stations..."); /* default capacity is 15, so use that value when querying */ if (mbim_device_check_ms_mbimex_version (ctx->device, 3, 0)) request = mbim_message_ms_basic_connect_extensions_v3_base_stations_info_query_new (15, 15, 15, 15, 15, 15, NULL); else request = mbim_message_ms_basic_connect_extensions_base_stations_info_query_new (15, 15, 15, 15, 15, NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_base_stations_ready, NULL); return; } if (query_version_str) { guint16 bcd_mbim_version = 0; guint16 bcd_mbim_extended_version = 0; guint8 mbim_version_major = 0; guint8 mbim_version_minor = 0; guint8 mbim_extended_version_major = 0; guint8 mbim_extended_version_minor = 0; g_auto(GStrv) split = NULL; g_auto(GStrv) mbim_version = NULL; g_auto(GStrv) mbim_extended_version = NULL; split = g_strsplit (query_version_str, ",", -1); if (g_strv_length (split) > 2) { g_printerr ("error: couldn't parse input string, too many arguments\n"); return; } if (g_strv_length (split) < 2) { g_printerr ("error: couldn't parse input string, missing arguments\n"); return; } mbim_version = g_strsplit (split[0], ".", -1); if (!mbimcli_read_uint8_from_bcd_string (mbim_version[0], &mbim_version_major) || !mbimcli_read_uint8_from_bcd_string (mbim_version[1], &mbim_version_minor)) { g_printerr ("error: couldn't parse version string\n"); return; } bcd_mbim_version = mbim_version_major << 8 | mbim_version_minor; g_debug ("BCD version built: 0x%x", bcd_mbim_version); mbim_extended_version = g_strsplit (split[1], ".", -1); if (!mbimcli_read_uint8_from_bcd_string (mbim_extended_version[0], &mbim_extended_version_major) || !mbimcli_read_uint8_from_bcd_string (mbim_extended_version[1], &mbim_extended_version_minor)) { g_printerr ("error: couldn't parse extended version string\n"); return; } bcd_mbim_extended_version = mbim_extended_version_major << 8 | mbim_extended_version_minor; g_debug ("BCD extended version built: 0x%x", bcd_mbim_extended_version); g_debug ("Asynchronously querying Version..."); request = mbim_message_ms_basic_connect_extensions_v2_version_query_new (bcd_mbim_version, bcd_mbim_extended_version, NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_version_ready, NULL); return; } if (query_registration_parameters_flag) { g_debug (" Asynchronously querying registration parameters..."); request = mbim_message_ms_basic_connect_extensions_v3_registration_parameters_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)registration_parameters_ready, NULL); return; } if (set_registration_parameters_str) { RegistrationParameters params = { 0 }; if (!mbimcli_parse_key_value_string (set_registration_parameters_str, &error, (MbimParseKeyValueForeachFn)set_registration_parameters_foreach_cb, ¶ms)) { g_printerr ("error: couldn't parse input string: %s\n", error->message); shutdown (FALSE); return; } if (!params.mico_mode_set || !params.drx_cycle_set || !params.ladn_info_set || !params.pdu_hint_set || !params.re_register_if_needed_set) { g_printerr ("error: missing required keys\n"); if (!params.mico_mode_set) g_printerr ("error: key 'mico-mode' is missing\n"); if (!params.drx_cycle_set) g_printerr ("error: key 'drx-cycle' is missing\n"); if (!params.ladn_info_set) g_printerr ("error: key 'ladn-info' is missing\n"); if (!params.pdu_hint_set) g_printerr ("error: key 'default-pdu-activation-hint' is missing\n"); if (!params.re_register_if_needed_set) g_printerr ("error: key 're-register-is-needed' is missing\n"); shutdown (FALSE); return; } g_debug ("Asynchronously set registration parameters\n"); request = (mbim_message_ms_basic_connect_extensions_v3_registration_parameters_set_new ( params.mico_mode, params.drx_cycle, params.ladn_info, params.pdu_hint, params.re_register_if_needed, NULL, /* ignore unnamed IEs for now */ NULL)); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)registration_parameters_ready, NULL); return; } /* Request to query modem configuration? */ if (query_modem_configuration_flag) { g_debug ("Asynchronously query modem configuration\n"); request = mbim_message_ms_basic_connect_extensions_v3_modem_configuration_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_modem_configuration_ready, NULL); return; } /* Request to query Wake Reason? */ if (query_wake_reason_flag) { g_debug ("Asynchronously querying wake reason..."); request = mbim_message_ms_basic_connect_extensions_v3_wake_reason_query_new (NULL); mbim_device_command (ctx->device, request, 10, ctx->cancellable, (GAsyncReadyCallback)query_wake_reason_ready, NULL); return; } g_warn_if_reached (); }