diff options
author | Akash Aggarwal <quic_akasagga@quicinc.com> | 2022-04-21 19:12:02 +0530 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2022-08-04 14:26:33 +0000 |
commit | 6761fc00996915c8ba3af1934221ecb783e4a30f (patch) | |
tree | 3b81c600bc69cb279ec76f6684a17dd92b3bc510 /src | |
parent | 3893396e200a6bfae508f2a837313ebe3bddd801 (diff) |
broadband-modem-qmi: Move to "registered" state based on DSD System Status for PS domain
"registered" state should not wholly depend on the PS/EPS/5GS domain
state reported by NAS.
It should listen to DSD system status for availabilty of data network
at modem before moving to 'registered' state".
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem-qmi.c | 298 |
1 files changed, 281 insertions, 17 deletions
diff --git a/src/mm-broadband-modem-qmi.c b/src/mm-broadband-modem-qmi.c index 85d6c910..12f30be6 100644 --- a/src/mm-broadband-modem-qmi.c +++ b/src/mm-broadband-modem-qmi.c @@ -119,6 +119,7 @@ struct _MMBroadbandModemQmiPrivate { gboolean unsolicited_registration_events_setup; guint serving_system_indication_id; guint system_info_indication_id; + guint system_status_indication_id; guint network_reject_indication_id; /* CDMA activation helpers */ @@ -169,6 +170,11 @@ struct _MMBroadbandModemQmiPrivate { gboolean profile_manager_unsolicited_events_enabled; gboolean profile_manager_unsolicited_events_setup; guint refresh_indication_id; + + /* Registration helpers */ + gboolean dsd_supported; + gboolean data_rat_available; + MMModem3gppRegistrationState ps_system_reg_state; }; /*****************************************************************************/ @@ -3881,20 +3887,150 @@ common_process_system_info_3gpp (MMBroadbandModemQmi *self, self->priv->current_operator_id = operator_id; } + self->priv->ps_system_reg_state = ps_registration_state; + /* Report new registration states */ mm_iface_modem_3gpp_update_cs_registration_state (MM_IFACE_MODEM_3GPP (self), cs_registration_state); - mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), ps_registration_state); - mm_iface_modem_3gpp_update_eps_registration_state (MM_IFACE_MODEM_3GPP (self), - has_lte_info ? - ps_registration_state : MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN); - mm_iface_modem_3gpp_update_5gs_registration_state (MM_IFACE_MODEM_3GPP (self), - has_nr5g_info ? - ps_registration_state : MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN); + + /* For PS domain, move to registered state only if data rat is available */ + if ((ps_registration_state != MM_MODEM_3GPP_REGISTRATION_STATE_HOME && + ps_registration_state != MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING) || + !self->priv->dsd_supported || self->priv->data_rat_available) { + mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), ps_registration_state); + mm_iface_modem_3gpp_update_eps_registration_state (MM_IFACE_MODEM_3GPP (self), + has_lte_info ? + ps_registration_state : MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN); + mm_iface_modem_3gpp_update_5gs_registration_state (MM_IFACE_MODEM_3GPP (self), + has_nr5g_info ? + ps_registration_state : MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN); + } + mm_iface_modem_3gpp_update_access_technologies (MM_IFACE_MODEM_3GPP (self), act); mm_iface_modem_3gpp_update_location (MM_IFACE_MODEM_3GPP (self), lac, tac, cid); } static void +common_process_system_status_3gpp (MMBroadbandModemQmi *self, + QmiMessageDsdGetSystemStatusOutput *response_output, + QmiIndicationDsdSystemStatusOutput *indication_output) +{ + GArray *available_systems = NULL; + gboolean data_rat_available = FALSE; + gboolean is_lte = FALSE; + gboolean is_nr5g = FALSE; + + if (response_output) { + qmi_message_dsd_get_system_status_output_get_available_systems (response_output, &available_systems, NULL); + + if (available_systems && available_systems->len) { + QmiMessageDsdGetSystemStatusOutputAvailableSystemsSystem *system; + + system = &g_array_index (available_systems, QmiMessageDsdGetSystemStatusOutputAvailableSystemsSystem, 0); + + if (system->technology == QMI_DSD_DATA_SYSTEM_NETWORK_TYPE_3GPP) { + switch (system->rat) { + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_WCDMA: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_TDSCDMA: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_GERAN: + data_rat_available = TRUE; + break; + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_LTE: + data_rat_available = TRUE; + is_lte = TRUE; + break; + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_5G: + data_rat_available = TRUE; + is_nr5g = TRUE; + break; + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_WLAN: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP2_1X: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP2_HRPD: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP2_EHRPD: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP2_WLAN: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_UNKNOWN: + default: + break; + } + } + } + } else { + qmi_indication_dsd_system_status_output_get_available_systems (indication_output, &available_systems, NULL); + + if (available_systems && available_systems->len) { + QmiIndicationDsdSystemStatusOutputAvailableSystemsSystem *system; + + system = &g_array_index (available_systems, QmiIndicationDsdSystemStatusOutputAvailableSystemsSystem, 0); + + if (system->technology == QMI_DSD_DATA_SYSTEM_NETWORK_TYPE_3GPP) { + switch (system->rat) { + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_WCDMA: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_TDSCDMA: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_GERAN: + data_rat_available = TRUE; + break; + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_LTE: + data_rat_available = TRUE; + is_lte = TRUE; + break; + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_5G: + data_rat_available = TRUE; + is_nr5g = TRUE; + break; + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP_WLAN: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP2_1X: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP2_HRPD: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP2_EHRPD: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_3GPP2_WLAN: + case QMI_DSD_RADIO_ACCESS_TECHNOLOGY_UNKNOWN: + default: + break; + } + } + } + } + + self->priv->data_rat_available = data_rat_available; + + if (data_rat_available == TRUE && + (self->priv->ps_system_reg_state == MM_MODEM_3GPP_REGISTRATION_STATE_HOME || + self->priv->ps_system_reg_state == MM_MODEM_3GPP_REGISTRATION_STATE_ROAMING)) { + mm_iface_modem_3gpp_update_ps_registration_state (MM_IFACE_MODEM_3GPP (self), self->priv->ps_system_reg_state); + if (is_lte) + mm_iface_modem_3gpp_update_eps_registration_state (MM_IFACE_MODEM_3GPP (self), self->priv->ps_system_reg_state); + if (is_nr5g) + mm_iface_modem_3gpp_update_5gs_registration_state (MM_IFACE_MODEM_3GPP (self), self->priv->ps_system_reg_state); + } +} + +static void +get_system_status_3gpp_ready (QmiClientDsd *client, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemQmi *self; + QmiMessageDsdGetSystemStatusOutput *output; + GError *error = NULL; + + self = g_task_get_source_object (task); + + output = qmi_client_dsd_get_system_status_finish (client, res, &error); + if (!output || !qmi_message_dsd_get_system_status_output_get_result (output, &error)) { + /* If this command fails, flag that dsd is not unsupported */ + self->priv->dsd_supported = FALSE; + g_error_free (error); + } + + if (output) { + common_process_system_status_3gpp (self, output, NULL); + qmi_message_dsd_get_system_status_output_unref (output); + } + + /* Just ignore errors for now */ + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void get_system_info_ready (QmiClientNas *client, GAsyncResult *res, GTask *task) @@ -3902,6 +4038,7 @@ get_system_info_ready (QmiClientNas *client, MMBroadbandModemQmi *self; QmiMessageNasGetSystemInfoOutput *output; GError *error = NULL; + QmiClient *client_dsd; self = g_task_get_source_object (task); @@ -3945,10 +4082,30 @@ get_system_info_ready (QmiClientNas *client, } common_process_system_info_3gpp (self, output, NULL); + qmi_message_nas_get_system_info_output_unref (output); + + if (self->priv->dsd_supported) { + client_dsd = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_DSD, + MM_PORT_QMI_FLAG_DEFAULT, + &error); + if (!client_dsd) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + qmi_client_dsd_get_system_status (QMI_CLIENT_DSD (client_dsd), + NULL, + 10, + NULL, + (GAsyncReadyCallback)get_system_status_3gpp_ready, + task); + return; + } g_task_return_boolean (task, TRUE); g_object_unref (task); - qmi_message_nas_get_system_info_output_unref (output); } static void @@ -4026,6 +4183,9 @@ static void common_enable_disable_unsolicited_registration_events_serving_system (GTask *task); static void +common_enable_disable_unsolicited_registration_events_system_status (GTask *task); + +static void ri_serving_system_or_system_info_ready (QmiClientNas *client, GAsyncResult *res, GTask *task) @@ -4053,8 +4213,42 @@ ri_serving_system_or_system_info_ready (QmiClientNas *client, mm_obj_dbg (self, "couldn't register serving system indications: '%s', assuming always enabled", error->message); } - if (!ctx->system_info_checked) + if (!ctx->system_info_checked) { ctx->system_info_checked = TRUE; + /* registered system info indications. now try to register for system status indications */ + if (self->priv->dsd_supported) { + common_enable_disable_unsolicited_registration_events_system_status (task); + return; + } + } + + /* Just ignore errors for now */ + self->priv->unsolicited_registration_events_enabled = ctx->enable; + g_task_return_boolean (task, TRUE); + g_object_unref (task); +} + +static void +ri_system_status_ready (QmiClientDsd *client, + GAsyncResult *res, + GTask *task) +{ + MMBroadbandModemQmi *self; + UnsolicitedRegistrationEventsContext *ctx; + g_autoptr(QmiMessageDsdSystemStatusChangeOutput) output = NULL; + g_autoptr(GError) error = NULL; + + self = g_task_get_source_object (task); + ctx = g_task_get_task_data (task); + + output = qmi_client_dsd_system_status_change_finish (client, res, &error); + if (!output || !qmi_message_dsd_system_status_change_output_get_result (output, &error)) { + /* If this command fails, flag that dsd is not unsupported */ + self->priv->dsd_supported = FALSE; + if (ctx->enable) + mm_obj_dbg (self, "couldn't register system status indications: '%s', assuming always enabled", error->message); + g_clear_error (&error); + } /* Just ignore errors for now */ self->priv->unsolicited_registration_events_enabled = ctx->enable; @@ -4082,6 +4276,40 @@ common_enable_disable_unsolicited_registration_events_serving_system (GTask *tas } static void +common_enable_disable_unsolicited_registration_events_system_status (GTask *task) +{ + MMBroadbandModemQmi *self; + QmiClient *client; + UnsolicitedRegistrationEventsContext *ctx; + g_autoptr(QmiMessageDsdSystemStatusChangeInput) input = NULL; + GError *error = NULL; + + self = g_task_get_source_object (task); + + client = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_DSD, + MM_PORT_QMI_FLAG_DEFAULT, + &error); + if (!client) { + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + ctx = g_task_get_task_data (task); + input = qmi_message_dsd_system_status_change_input_new (); + qmi_message_dsd_system_status_change_input_set_register_indication (input, ctx->enable, NULL); + + qmi_client_dsd_system_status_change ( + QMI_CLIENT_DSD (client), + input, + 5, + NULL, + (GAsyncReadyCallback)ri_system_status_ready, + task); +} + +static void common_enable_disable_unsolicited_registration_events_system_info (GTask *task) { UnsolicitedRegistrationEventsContext *ctx; @@ -5117,6 +5345,16 @@ system_info_indication_cb (QmiClientNas *client, } static void +system_status_indication_cb (QmiClientDsd *client, + QmiIndicationDsdSystemStatusOutput *output, + MMBroadbandModemQmi *self) +{ + if (mm_iface_modem_is_3gpp (MM_IFACE_MODEM (self))) + common_process_system_status_3gpp (self, NULL, output); +} + + +static void serving_system_indication_cb (QmiClientNas *client, QmiIndicationNasServingSystemOutput *output, MMBroadbandModemQmi *self) @@ -5162,13 +5400,19 @@ common_setup_cleanup_unsolicited_registration_events (MMBroadbandModemQmi *self, gpointer user_data) { GTask *task; - QmiClient *client = NULL; + QmiClient *client_nas = NULL; + QmiClient *client_dsd = NULL; if (!mm_shared_qmi_ensure_client (MM_SHARED_QMI (self), - QMI_SERVICE_NAS, &client, + QMI_SERVICE_NAS, &client_nas, callback, user_data)) return; + client_dsd = mm_shared_qmi_peek_client (MM_SHARED_QMI (self), + QMI_SERVICE_DSD, + MM_PORT_QMI_FLAG_DEFAULT, + NULL); + task = g_task_new (self, NULL, callback, user_data); if (enable == self->priv->unsolicited_registration_events_setup) { @@ -5186,26 +5430,26 @@ common_setup_cleanup_unsolicited_registration_events (MMBroadbandModemQmi *self, if (enable) { g_assert (self->priv->system_info_indication_id == 0); self->priv->system_info_indication_id = - g_signal_connect (client, + g_signal_connect (client_nas, "system-info", G_CALLBACK (system_info_indication_cb), self); } else { g_assert (self->priv->system_info_indication_id != 0); - g_signal_handler_disconnect (client, self->priv->system_info_indication_id); + g_signal_handler_disconnect (client_nas, self->priv->system_info_indication_id); self->priv->system_info_indication_id = 0; } /* Connect/Disconnect "Serving System" indications */ if (enable) { g_assert (self->priv->serving_system_indication_id == 0); self->priv->serving_system_indication_id = - g_signal_connect (client, + g_signal_connect (client_nas, "serving-system", G_CALLBACK (serving_system_indication_cb), self); } else { g_assert (self->priv->serving_system_indication_id != 0); - g_signal_handler_disconnect (client, self->priv->serving_system_indication_id); + g_signal_handler_disconnect (client_nas, self->priv->serving_system_indication_id); self->priv->serving_system_indication_id = 0; } @@ -5213,16 +5457,33 @@ common_setup_cleanup_unsolicited_registration_events (MMBroadbandModemQmi *self, if (enable) { g_assert (self->priv->network_reject_indication_id == 0); self->priv->network_reject_indication_id = - g_signal_connect (client, + g_signal_connect (client_nas, "network-reject", G_CALLBACK (network_reject_indication_cb), self); } else { g_assert (self->priv->network_reject_indication_id != 0); - g_signal_handler_disconnect (client, self->priv->network_reject_indication_id); + g_signal_handler_disconnect (client_nas, self->priv->network_reject_indication_id); self->priv->network_reject_indication_id = 0; } + /* Connect/Disconnect "System Status" indications */ + if (client_dsd) { + self->priv->dsd_supported = TRUE; + if (enable) { + g_assert (self->priv->system_status_indication_id == 0); + self->priv->system_status_indication_id = + g_signal_connect (client_dsd, + "system-status", + G_CALLBACK (system_status_indication_cb), + self); + } else { + g_assert (self->priv->system_status_indication_id != 0); + g_signal_handler_disconnect (client_dsd, self->priv->system_status_indication_id); + self->priv->system_status_indication_id = 0; + } + } + g_task_return_boolean (task, TRUE); g_object_unref (task); } @@ -12344,6 +12605,7 @@ static const QmiService qmi_services[] = { QMI_SERVICE_LOC, QMI_SERVICE_PDC, QMI_SERVICE_VOICE, + QMI_SERVICE_DSD, }; typedef struct { @@ -12679,6 +12941,8 @@ mm_broadband_modem_qmi_init (MMBroadbandModemQmi *self) self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_BROADBAND_MODEM_QMI, MMBroadbandModemQmiPrivate); + self->priv->ps_system_reg_state = MM_MODEM_3GPP_REGISTRATION_STATE_UNKNOWN; + self->priv->data_rat_available = FALSE; } static void |