From 59b75b5194c6f2a649ca2a4bd6747f74b220d773 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 14:39:10 -0800 Subject: [PATCH 1/3] gsm: clean up disconnect handling Allow subclasses to override disconnect more cleanly so that modem state gets handled correctly when the disconnect is complete. Also fix up PDP Context ID handle (cid) so that subclasses can get the previously-activated context ID when disconnecting, and let the cid be an int since '0' is a valid context number. For the generic devices, this also attempts to actually deactivate the PDP context to ensure that the data session is terminated. --- src/mm-generic-gsm.c | 118 +++++++++++++++++++++++++++++++------------ src/mm-generic-gsm.h | 12 +++-- 2 files changed, 94 insertions(+), 36 deletions(-) diff --git a/src/mm-generic-gsm.c b/src/mm-generic-gsm.c index 5a50b24a..dcb37c32 100644 --- a/src/mm-generic-gsm.c +++ b/src/mm-generic-gsm.c @@ -81,7 +81,7 @@ typedef struct { guint signal_quality_id; time_t signal_quality_timestamp; guint32 signal_quality; - guint32 cid; + gint cid; MMSerialPort *primary; MMSerialPort *secondary; @@ -141,15 +141,7 @@ mm_generic_gsm_new (const char *device, NULL)); } -void -mm_generic_gsm_set_cid (MMGenericGsm *modem, guint32 cid) -{ - g_return_if_fail (MM_IS_GENERIC_GSM (modem)); - - MM_GENERIC_GSM_GET_PRIVATE (modem)->cid = cid; -} - -guint32 +gint mm_generic_gsm_get_cid (MMGenericGsm *modem) { g_return_val_if_fail (MM_IS_GENERIC_GSM (modem), 0); @@ -821,7 +813,7 @@ enable (MMModem *modem, } /* First, reset the previously used CID */ - mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); + priv->cid = -1; if (!mm_serial_port_open (priv->primary, &error)) { MMCallbackInfo *info; @@ -907,7 +899,9 @@ disable (MMModem *modem, MMModemState state; /* First, reset the previously used CID and clean up registration */ - mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); + g_warn_if_fail (priv->cid == -1); + priv->cid = -1; + mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem)); if (priv->poll_id) { @@ -1919,16 +1913,16 @@ connect (MMModem *modem, } static void -disconnect_flash_done (MMSerialPort *port, - GError *error, - gpointer user_data) +disconnect_done (MMModem *modem, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; MMModemState prev_state; - info->error = mm_modem_check_removed (info->modem, error); + info->error = mm_modem_check_removed (modem, error); if (info->error) { - if (info->modem) { + if (info->modem && modem) { /* Reset old state since the operation failed */ prev_state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, MM_GENERIC_GSM_PREV_STATE_TAG)); mm_modem_set_state (MM_MODEM (info->modem), @@ -1936,28 +1930,77 @@ disconnect_flash_done (MMSerialPort *port, MM_MODEM_STATE_REASON_NONE); } } else { - MMGenericGsm *self = MM_GENERIC_GSM (info->modem); + MMGenericGsm *self = MM_GENERIC_GSM (modem); MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); mm_port_set_connected (priv->data, FALSE); + priv->cid = -1; mm_generic_gsm_update_enabled_state (self, FALSE, MM_MODEM_STATE_REASON_NONE); } mm_callback_info_schedule (info); } +static void +disconnect_cgact_done (MMSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + mm_callback_info_schedule ((MMCallbackInfo *) user_data); +} + +static void +disconnect_flash_done (MMSerialPort *port, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMGenericGsmPrivate *priv; + char *command; + + info->error = mm_modem_check_removed (info->modem, error); + if (info->error) { + mm_callback_info_schedule (info); + return; + } + + /* Disconnect the PDP context */ + priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + if (priv->cid >= 0) + command = g_strdup_printf ("+CGACT=0,%d", priv->cid); + else { + /* Disable all PDP contexts */ + command = g_strdup_printf ("+CGACT=0"); + } + + mm_serial_port_queue_command (port, command, 60, disconnect_cgact_done, info); + g_free (command); +} + +static void +real_do_disconnect (MMGenericGsm *self, + gint cid, + MMModemFn callback, + gpointer user_data) +{ + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); + MMCallbackInfo *info; + + info = mm_callback_info_new (MM_MODEM (self), callback, user_data); + mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info); +} + static void disconnect (MMModem *modem, MMModemFn callback, gpointer user_data) { - MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (modem); + MMGenericGsm *self = MM_GENERIC_GSM (modem); + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (self); MMCallbackInfo *info; MMModemState state; - /* First, reset the previously used CID */ - mm_generic_gsm_set_cid (MM_GENERIC_GSM (modem), 0); - info = mm_callback_info_new (modem, callback, user_data); /* Cache the previous state so we can reset it if the operation fails */ @@ -1968,7 +2011,9 @@ disconnect (MMModem *modem, NULL); mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); - mm_serial_port_flash (priv->primary, 1000, disconnect_flash_done, info); + + g_assert (MM_GENERIC_GSM_GET_CLASS (self)->do_disconnect); + MM_GENERIC_GSM_GET_CLASS (self)->do_disconnect (self, priv->cid, disconnect_done, info); } static void @@ -2020,6 +2065,8 @@ scan (MMModemGsmNetwork *modem, /* SetApn */ +#define APN_CID_TAG "generic-gsm-cid" + static void set_apn_done (MMSerialPort *port, GString *response, @@ -2028,11 +2075,12 @@ set_apn_done (MMSerialPort *port, { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - if (error) - info->error = g_error_copy (error); - else - mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem), - GPOINTER_TO_UINT (mm_callback_info_get_data (info, "cid"))); + info->error = mm_modem_check_removed (info->modem, error); + if (!info->error) { + MMGenericGsmPrivate *priv = MM_GENERIC_GSM_GET_PRIVATE (info->modem); + + priv->cid = GPOINTER_TO_INT (mm_callback_info_get_data (info, APN_CID_TAG)); + } mm_callback_info_schedule (info); } @@ -2095,7 +2143,7 @@ cid_range_read (MMSerialPort *port, const char *apn = (const char *) mm_callback_info_get_data (info, "apn"); char *command; - mm_callback_info_set_data (info, "cid", GUINT_TO_POINTER (cid), NULL); + mm_callback_info_set_data (info, APN_CID_TAG, GINT_TO_POINTER (cid), NULL); command = g_strdup_printf ("+CGDCONT=%d,\"IP\",\"%s\"", cid, apn); mm_serial_port_queue_command (port, command, 3, set_apn_done, info); @@ -2112,8 +2160,9 @@ existing_apns_read (MMSerialPort *port, MMCallbackInfo *info = (MMCallbackInfo *) user_data; gboolean found = FALSE; - if (error) - info->error = g_error_copy (error); + info->error = mm_modem_check_removed (info->modem, error); + if (info->error) + goto done; else if (g_str_has_prefix (response->str, "+CGDCONT: ")) { GRegex *r; GMatchInfo *match_info; @@ -2137,7 +2186,7 @@ existing_apns_read (MMSerialPort *port, apn = g_match_info_fetch (match_info, 3); if (!strcmp (apn, new_apn)) { - mm_generic_gsm_set_cid (MM_GENERIC_GSM (info->modem), (guint32) num_cid); + MM_GENERIC_GSM_GET_PRIVATE (info->modem)->cid = num_cid; found = TRUE; } @@ -2165,11 +2214,13 @@ existing_apns_read (MMSerialPort *port, MM_MODEM_ERROR_GENERAL, "Could not parse the response"); +done: if (found || info->error) mm_callback_info_schedule (info); - else + else { /* APN not configured on the card. Get the allowed CID range */ mm_serial_port_queue_command_cached (port, "+CGDCONT=?", 3, cid_range_read, info); + } } static void @@ -2983,6 +3034,7 @@ mm_generic_gsm_class_init (MMGenericGsmClass *klass) klass->do_enable = real_do_enable; klass->do_enable_power_up_done = real_do_enable_power_up_done; + klass->do_disconnect = real_do_disconnect; /* Properties */ g_object_class_override_property (object_class, diff --git a/src/mm-generic-gsm.h b/src/mm-generic-gsm.h index 348ff4f8..9aef615e 100644 --- a/src/mm-generic-gsm.h +++ b/src/mm-generic-gsm.h @@ -79,6 +79,14 @@ typedef struct { GError *error, MMCallbackInfo *info); + /* Called to terminate the active data call and deactivate the given PDP + * context. + */ + void (*do_disconnect) (MMGenericGsm *self, + gint cid, + MMModemFn callback, + gpointer user_data); + /* Called by the generic class to set the allowed operating mode of the device */ void (*set_allowed_mode) (MMGenericGsm *self, MMModemGsmAllowedMode mode, @@ -110,10 +118,8 @@ MMModem *mm_generic_gsm_new (const char *device, void mm_generic_gsm_pending_registration_stop (MMGenericGsm *modem); -void mm_generic_gsm_set_cid (MMGenericGsm *modem, - guint32 cid); +gint mm_generic_gsm_get_cid (MMGenericGsm *modem); -guint32 mm_generic_gsm_get_cid (MMGenericGsm *modem); void mm_generic_gsm_set_reg_status (MMGenericGsm *modem, MMModemGsmNetworkRegStatus status); From 461de7ea0eeab4dfa5827dcce490eded3d729f6e Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 14:42:34 -0800 Subject: [PATCH 2/3] mbm: use new disconnect handling helper --- plugins/mm-modem-mbm.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/plugins/mm-modem-mbm.c b/plugins/mm-modem-mbm.c index 43302e9b..7070f728 100644 --- a/plugins/mm-modem-mbm.c +++ b/plugins/mm-modem-mbm.c @@ -494,23 +494,18 @@ do_connect (MMModem *modem, } static void -disconnect (MMModem *modem, - MMModemFn callback, - gpointer user_data) +do_disconnect (MMGenericGsm *gsm, + gint cid, + MMModemFn callback, + gpointer user_data) { - MMCallbackInfo *info; MMSerialPort *primary; - mm_modem_set_state (modem, MM_MODEM_STATE_DISCONNECTING, MM_MODEM_STATE_REASON_NONE); - - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); + primary = mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY); g_assert (primary); mm_serial_port_queue_command (primary, "*ENAP=0", 3, NULL, NULL); - mm_generic_gsm_update_enabled_state (MM_GENERIC_GSM (modem), FALSE, MM_MODEM_STATE_REASON_NONE); - - info = mm_callback_info_new (modem, callback, user_data); - mm_callback_info_schedule (info); + MM_GENERIC_GSM_CLASS (mm_modem_mbm_parent_class)->do_disconnect (gsm, cid, callback, user_data); } /*****************************************************************************/ @@ -837,7 +832,6 @@ modem_init (MMModem *modem_class) modem_class->grab_port = grab_port; modem_class->disable = disable; modem_class->connect = do_connect; - modem_class->disconnect = disconnect; } static void @@ -871,6 +865,7 @@ mm_modem_mbm_class_init (MMModemMbmClass *klass) object_class->finalize = finalize; gsm_class->do_enable = do_enable; + gsm_class->do_disconnect = do_disconnect; gsm_class->get_allowed_mode = get_allowed_mode; gsm_class->set_allowed_mode = set_allowed_mode; } From e3c87e4e1418a25bb8da9e64eba882d8fa335265 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Wed, 10 Mar 2010 14:42:53 -0800 Subject: [PATCH 3/3] hso: clean up connect and disconnect Disconnect didn't actually work for HSO since it overrode the parent class's connect handler and thus didn't set the right state after the connection was made. It turns out we can use the same logic that 'mbm' does for connection and not have to override quite so much of the parent class. This also splits the authentication and connection parts into two distinct stages, which wasn't the case before but was what was intended. --- plugins/mm-modem-hso.c | 470 ++++++++++++++++++++++------------------- 1 file changed, 253 insertions(+), 217 deletions(-) diff --git a/plugins/mm-modem-hso.c b/plugins/mm-modem-hso.c index a3fb95c4..9e96226b 100644 --- a/plugins/mm-modem-hso.c +++ b/plugins/mm-modem-hso.c @@ -63,6 +63,9 @@ typedef struct { MMCallbackInfo *connect_pending_data; guint connect_pending_id; + char *username; + char *password; + guint32 auth_idx; } MMModemHsoPrivate; @@ -85,6 +88,157 @@ mm_modem_hso_new (const char *device, NULL)); } +/*****************************************************************************/ + +static gint +hso_get_cid (MMModemHso *self) +{ + gint cid; + + cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)); + if (cid < 0) { + g_warn_if_fail (cid >= 0); + cid = 0; + } + + return cid; +} + +static void +auth_done (MMSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMModemHso *self = MM_MODEM_HSO (info->modem); + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + + if (error) { + priv->auth_idx++; + if (auth_commands[priv->auth_idx]) { + /* Try the next auth command */ + _internal_hso_modem_authenticate (self, info); + return; + } else + info->error = g_error_copy (error); + } + + /* Reset to 0 so something gets tried the next connection */ + priv->auth_idx = 0; + mm_callback_info_schedule (info); +} + +static void +_internal_hso_modem_authenticate (MMModemHso *self, MMCallbackInfo *info) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + MMSerialPort *primary; + gint cid; + char *command; + + primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); + g_assert (primary); + + cid = hso_get_cid (self); + + if (!priv->username && !priv->password) + command = g_strdup_printf ("%s=%d,0", auth_commands[priv->auth_idx], cid); + else { + command = g_strdup_printf ("%s=%d,1,\"%s\",\"%s\"", + auth_commands[priv->auth_idx], + cid, + priv->password ? priv->password : "", + priv->username ? priv->username : ""); + + } + + mm_serial_port_queue_command (primary, command, 3, auth_done, info); + g_free (command); +} + +void +mm_hso_modem_authenticate (MMModemHso *self, + const char *username, + const char *password, + MMModemFn callback, + gpointer user_data) +{ + MMModemHsoPrivate *priv; + MMCallbackInfo *info; + + g_return_if_fail (self != NULL); + g_return_if_fail (MM_IS_MODEM_HSO (self)); + g_return_if_fail (callback != NULL); + + info = mm_callback_info_new (MM_MODEM (self), callback, user_data); + + priv = MM_MODEM_HSO_GET_PRIVATE (self); + + g_free (priv->username); + priv->username = (username && strlen (username)) ? g_strdup (username) : NULL; + + g_free (priv->password); + priv->password = (password && strlen (password)) ? g_strdup (password) : NULL; + + _internal_hso_modem_authenticate (self, info); +} + +/*****************************************************************************/ + +static void +connect_pending_done (MMModemHso *self) +{ + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + GError *error = NULL; + + if (priv->connect_pending_data) { + if (priv->connect_pending_data->error) { + error = priv->connect_pending_data->error; + priv->connect_pending_data->error = NULL; + } + + /* Complete the connect */ + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (self), error, priv->connect_pending_data); + priv->connect_pending_data = NULL; + } + + if (priv->connect_pending_id) { + g_source_remove (priv->connect_pending_id); + priv->connect_pending_id = 0; + } +} + +static void +connection_enabled (MMSerialPort *port, + GMatchInfo *match_info, + gpointer user_data) +{ + MMModemHso *self = MM_MODEM_HSO (user_data); + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + char *str; + + str = g_match_info_fetch (match_info, 2); + if (str[0] == '1') + connect_pending_done (self); + else if (str[0] == '3') { + MMCallbackInfo *info = priv->connect_pending_data; + + if (info) { + info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, + "Call setup failed"); + } + + connect_pending_done (self); + } else if (str[0] == '0') { + /* FIXME: disconnected. do something when we have modem status signals */ + } + + g_free (str); +} + +/*****************************************************************************/ + #define IGNORE_ERRORS_TAG "ignore-errors" static void @@ -101,18 +255,6 @@ hso_call_control_done (MMSerialPort *port, mm_callback_info_schedule (info); } -static guint32 -hso_get_cid (MMModemHso *self) -{ - guint32 cid; - - cid = mm_generic_gsm_get_cid (MM_GENERIC_GSM (self)); - if (cid == 0) - cid = 1; - - return cid; -} - static void hso_call_control (MMModemHso *self, gboolean activate, @@ -135,31 +277,30 @@ hso_call_control (MMModemHso *self, } static void -connect_pending_done (MMModemHso *self) +timeout_done (MMModem *modem, + GError *error, + gpointer user_data) { - MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); - - if (priv->connect_pending_data) { - mm_callback_info_schedule (priv->connect_pending_data); - priv->connect_pending_data = NULL; - } - - if (priv->connect_pending_id) { - g_source_remove (priv->connect_pending_id); - priv->connect_pending_id = 0; - } + if (modem) + connect_pending_done (MM_MODEM_HSO (modem)); } static gboolean hso_connect_timed_out (gpointer data) { - MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (data); + MMModemHso *self = MM_MODEM_HSO (data); + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + MMCallbackInfo *info = priv->connect_pending_data; - priv->connect_pending_data->error = g_error_new_literal (MM_SERIAL_ERROR, - MM_SERIAL_RESPONSE_TIMEOUT, - "Connection timed out"); - connect_pending_done (MM_MODEM_HSO (data)); + priv->connect_pending_id = 0; + if (info) { + info->error = g_error_new_literal (MM_SERIAL_ERROR, + MM_SERIAL_RESPONSE_TIMEOUT, + "Connection timed out"); + } + + hso_call_control (self, FALSE, TRUE, timeout_done, self); return FALSE; } @@ -169,33 +310,32 @@ hso_enabled (MMModem *modem, gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + GError *tmp_error; - if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); + tmp_error = mm_modem_check_removed (modem, error); + if (tmp_error) { + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (modem), tmp_error, info); + g_clear_error (&tmp_error); } else { MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (modem); - GSource *source; - source = g_timeout_source_new_seconds (30); - g_source_set_closure (source, g_cclosure_new_object (G_CALLBACK (hso_connect_timed_out), G_OBJECT (modem))); - g_source_attach (source, NULL); priv->connect_pending_data = info; - priv->connect_pending_id = g_source_get_id (source); - g_source_unref (source); + priv->connect_pending_id = g_timeout_add_seconds (30, hso_connect_timed_out, modem); } } static void -clear_old_context (MMModem *modem, - GError *error, - gpointer user_data) +old_context_clear_done (MMModem *modem, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; + GError *tmp_error; - if (error) { - info->error = g_error_copy (error); - mm_callback_info_schedule (info); + tmp_error = mm_modem_check_removed (modem, error); + if (tmp_error) { + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (modem), tmp_error, info); + g_clear_error (&tmp_error); } else { /* Success, activate the PDP context and start the data session */ hso_call_control (MM_MODEM_HSO (modem), TRUE, FALSE, hso_enabled, info); @@ -203,86 +343,38 @@ clear_old_context (MMModem *modem, } static void -auth_done (MMSerialPort *port, - GString *response, - GError *error, - gpointer user_data) +connect_auth_done (MMModem *modem, + GError *error, + gpointer user_data) { MMCallbackInfo *info = (MMCallbackInfo *) user_data; - MMModemHso *self = MM_MODEM_HSO (info->modem); - MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + GError *tmp_error; - if (error) { - priv->auth_idx++; - if (auth_commands[priv->auth_idx]) { - /* Try the next auth command */ - _internal_hso_modem_authenticate (self, info); - } else { - /* Reset to 0 so that something gets tried for the next connection */ - priv->auth_idx = 0; - - info->error = g_error_copy (error); - mm_callback_info_schedule (info); - } + tmp_error = mm_modem_check_removed (modem, error); + if (tmp_error) { + mm_generic_gsm_connect_complete (MM_GENERIC_GSM (modem), tmp_error, info); + g_clear_error (&tmp_error); } else { - priv->auth_idx = 0; - - /* success, kill any existing connections first */ - hso_call_control (self, FALSE, TRUE, clear_old_context, info); + /* Now connect; kill any existing connections first */ + hso_call_control (MM_MODEM_HSO (modem), FALSE, TRUE, old_context_clear_done, info); } } static void -_internal_hso_modem_authenticate (MMModemHso *self, MMCallbackInfo *info) +do_connect (MMModem *modem, + const char *number, + MMModemFn callback, + gpointer user_data) { + MMModemHso *self = MM_MODEM_HSO (modem); MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); - MMSerialPort *primary; - guint32 cid; - char *command; - const char *username, *password; - - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (self), MM_PORT_TYPE_PRIMARY); - g_assert (primary); - - cid = hso_get_cid (self); - - username = mm_callback_info_get_data (info, "username"); - password = mm_callback_info_get_data (info, "password"); - - if (!username && !password) - command = g_strdup_printf ("%s=%d,0", auth_commands[priv->auth_idx], cid); - else { - command = g_strdup_printf ("%s=%d,1,\"%s\",\"%s\"", - auth_commands[priv->auth_idx], - cid, - password ? password : "", - username ? username : ""); - - } - - mm_serial_port_queue_command (primary, command, 3, auth_done, info); - g_free (command); -} - -void -mm_hso_modem_authenticate (MMModemHso *self, - const char *username, - const char *password, - MMModemFn callback, - gpointer user_data) -{ MMCallbackInfo *info; - g_return_if_fail (MM_IS_MODEM_HSO (self)); - g_return_if_fail (callback != NULL); + mm_modem_set_state (modem, MM_MODEM_STATE_CONNECTING, MM_MODEM_STATE_REASON_NONE); - info = mm_callback_info_new (MM_MODEM (self), callback, user_data); - if (username) - mm_callback_info_set_data (info, "username", g_strdup (username), g_free); - if (password) - mm_callback_info_set_data (info, "password", g_strdup (password), g_free); + info = mm_callback_info_new (modem, callback, user_data); - _internal_hso_modem_authenticate (self, info); + mm_hso_modem_authenticate (self, priv->username, priv->password, connect_auth_done, info); } /*****************************************************************************/ @@ -315,9 +407,16 @@ disable (MMModem *modem, MMModemFn callback, gpointer user_data) { + MMModemHso *self = MM_MODEM_HSO (modem); + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); MMCallbackInfo *info; - mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (modem)); + mm_generic_gsm_pending_registration_stop (MM_GENERIC_GSM (self)); + + g_free (priv->username); + priv->username = NULL; + g_free (priv->password); + priv->password = NULL; info = mm_callback_info_new (modem, callback, user_data); @@ -325,18 +424,7 @@ disable (MMModem *modem, hso_call_control (MM_MODEM_HSO (modem), FALSE, TRUE, disable_done, info); } -static void -do_connect (MMModem *modem, - const char *number, - MMModemFn callback, - gpointer user_data) -{ - MMCallbackInfo *info; - - info = mm_callback_info_new (modem, callback, user_data); - mm_callback_info_schedule (info); -} - +/*****************************************************************************/ static void free_dns_array (gpointer data) @@ -366,7 +454,7 @@ get_ip4_config_done (MMSerialPort *port, GArray *dns_array; int i; guint32 tmp; - guint cid; + gint cid; if (error) { info->error = g_error_copy (error); @@ -387,7 +475,7 @@ get_ip4_config_done (MMSerialPort *port, errno = 0; num = strtol (*iter, NULL, 10); - if (errno != 0 || num < 0 || (guint) num != cid) { + if (errno != 0 || num < 0 || (gint) num != cid) { info->error = g_error_new (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, "Unknown CID in OWANDATA response (" "got %d, expected %d)", (guint) num, cid); @@ -429,18 +517,35 @@ get_ip4_config (MMModem *modem, g_free (command); } +/*****************************************************************************/ + static void -disconnect (MMModem *modem, - MMModemFn callback, - gpointer user_data) +disconnect_owancall_done (MMSerialPort *port, + GString *response, + GError *error, + gpointer user_data) +{ + mm_callback_info_schedule ((MMCallbackInfo *) user_data); +} + +static void +do_disconnect (MMGenericGsm *gsm, + gint cid, + MMModemFn callback, + gpointer user_data) { MMCallbackInfo *info; MMSerialPort *primary; + char *command; - info = mm_callback_info_new (modem, callback, user_data); - primary = mm_generic_gsm_get_port (MM_GENERIC_GSM (modem), MM_PORT_TYPE_PRIMARY); + info = mm_callback_info_new (MM_MODEM (gsm), callback, user_data); + + primary = mm_generic_gsm_get_port (gsm, MM_PORT_TYPE_PRIMARY); g_assert (primary); - mm_serial_port_queue_command (primary, "AT_OWANCALL=1,0,0", 3, NULL, info); + + command = g_strdup_printf ("AT_OWANCALL=%d,0,0", cid); + mm_serial_port_queue_command (primary, command, 3, disconnect_owancall_done, info); + g_free (command); } /*****************************************************************************/ @@ -473,47 +578,11 @@ impl_hso_authenticate (MMModemHso *self, mm_hso_modem_authenticate (self, username, password, impl_hso_auth_done, context); } -static void -connection_enabled (MMSerialPort *port, - GMatchInfo *info, - gpointer user_data) -{ - MMModemHso *self = MM_MODEM_HSO (user_data); - MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); - char *str; - - str = g_match_info_fetch (info, 2); - if (str[0] == '1') - connect_pending_done (self); - else if (str[0] == '3') { - MMCallbackInfo *cb_info = priv->connect_pending_data; - - if (cb_info) - cb_info->error = g_error_new_literal (MM_MODEM_ERROR, MM_MODEM_ERROR_GENERAL, - "Call setup failed"); - - connect_pending_done (self); - } else if (str[0] == '0') - /* FIXME: disconnected. do something when we have modem status signals */ - ; - - g_free (str); -} - /*****************************************************************************/ -/* MMModemSimple interface */ - -typedef enum { - SIMPLE_STATE_BEGIN = 0, - SIMPLE_STATE_PARENT_CONNECT, - SIMPLE_STATE_AUTHENTICATE, - SIMPLE_STATE_DONE -} SimpleState; static const char * -simple_get_string_property (MMCallbackInfo *info, const char *name, GError **error) +hso_simple_get_string_property (GHashTable *properties, const char *name, GError **error) { - GHashTable *properties = (GHashTable *) mm_callback_info_get_data (info, "simple-connect-properties"); GValue *value; value = (GValue *) g_hash_table_lookup (properties, name); @@ -530,61 +599,21 @@ simple_get_string_property (MMCallbackInfo *info, const char *name, GError **err return NULL; } -static void -simple_state_machine (MMModem *modem, GError *error, gpointer user_data) -{ - MMCallbackInfo *info = (MMCallbackInfo *) user_data; - MMModemSimple *parent_iface; - const char *username; - const char *password; - GHashTable *properties = (GHashTable *) mm_callback_info_get_data (info, "simple-connect-properties"); - SimpleState state = GPOINTER_TO_UINT (mm_callback_info_get_data (info, "simple-connect-state")); - - if (error) { - info->error = g_error_copy (error); - goto out; - } - - switch (state) { - case SIMPLE_STATE_BEGIN: - state = SIMPLE_STATE_PARENT_CONNECT; - parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (modem)); - parent_iface->connect (MM_MODEM_SIMPLE (modem), properties, simple_state_machine, info); - break; - case SIMPLE_STATE_PARENT_CONNECT: - state = SIMPLE_STATE_AUTHENTICATE; - username = simple_get_string_property (info, "username", &info->error); - password = simple_get_string_property (info, "password", &info->error); - mm_hso_modem_authenticate (MM_MODEM_HSO (modem), username, password, simple_state_machine, info); - break; - case SIMPLE_STATE_AUTHENTICATE: - state = SIMPLE_STATE_DONE; - break; - default: - break; - } - - out: - if (info->error || state == SIMPLE_STATE_DONE) - mm_callback_info_schedule (info); - else - mm_callback_info_set_data (info, "simple-connect-state", GUINT_TO_POINTER (state), NULL); -} - static void simple_connect (MMModemSimple *simple, GHashTable *properties, MMModemFn callback, gpointer user_data) { - MMCallbackInfo *info; + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (simple); + MMCallbackInfo *info = (MMCallbackInfo *) user_data; + MMModemSimple *parent_iface; - info = mm_callback_info_new (MM_MODEM (simple), callback, user_data); - mm_callback_info_set_data (info, "simple-connect-properties", - g_hash_table_ref (properties), - (GDestroyNotify) g_hash_table_unref); + priv->username = g_strdup (hso_simple_get_string_property (properties, "username", NULL)); + priv->password = g_strdup (hso_simple_get_string_property (properties, "password", NULL)); - simple_state_machine (MM_MODEM (simple), NULL, info); + parent_iface = g_type_interface_peek_parent (MM_MODEM_SIMPLE_GET_INTERFACE (simple)); + parent_iface->connect (MM_MODEM_SIMPLE (simple), properties, callback, info); } /*****************************************************************************/ @@ -679,15 +708,20 @@ modem_init (MMModem *modem_class) modem_class->disable = disable; modem_class->connect = do_connect; modem_class->get_ip4_config = get_ip4_config; - modem_class->disconnect = disconnect; modem_class->grab_port = grab_port; } static void finalize (GObject *object) { + MMModemHso *self = MM_MODEM_HSO (object); + MMModemHsoPrivate *priv = MM_MODEM_HSO_GET_PRIVATE (self); + /* Clear the pending connection if necessary */ - connect_pending_done (MM_MODEM_HSO (object)); + connect_pending_done (self); + + g_free (priv->username); + g_free (priv->password); G_OBJECT_CLASS (mm_modem_hso_parent_class)->finalize (object); } @@ -696,11 +730,13 @@ static void mm_modem_hso_class_init (MMModemHsoClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); + MMGenericGsmClass *gsm_class = MM_GENERIC_GSM_CLASS (klass); mm_modem_hso_parent_class = g_type_class_peek_parent (klass); g_type_class_add_private (object_class, sizeof (MMModemHsoPrivate)); /* Virtual methods */ object_class->finalize = finalize; + gsm_class->do_disconnect = do_disconnect; }