diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2016-11-24 10:31:15 +0100 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2017-01-04 14:11:17 +0100 |
commit | f7ca0124b0a1d5013c1f0fd6f9e5b182d6cdef60 (patch) | |
tree | 0473cd298e945795b2fafd35dc9c2ff50a2cd7b7 /plugins | |
parent | 955b46daf96c841a6ffbccc80f73e7d852c430d7 (diff) |
cinterion: rework 3GPP connection sequence
Group together all connection related logic (e.g. context) and define
the context steps directly within the connection sequence processing.
Also, don't initially run a disconnection before the connection; if that
logic is ever needed we should likely have it in the generic modem, not
done per plugin.
And error out early if not asking for IPv4.
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/cinterion/mm-broadband-bearer-cinterion.c | 521 |
1 files changed, 227 insertions, 294 deletions
diff --git a/plugins/cinterion/mm-broadband-bearer-cinterion.c b/plugins/cinterion/mm-broadband-bearer-cinterion.c index a7b04bf7..95da54a0 100644 --- a/plugins/cinterion/mm-broadband-bearer-cinterion.c +++ b/plugins/cinterion/mm-broadband-bearer-cinterion.c @@ -89,47 +89,12 @@ get_usb_interface_config_index (MMPort *data, /*****************************************************************************/ /* Common enums and structs */ -typedef enum { - BEARER_CINTERION_AUTH_UNKNOWN = -1, - BEARER_CINTERION_AUTH_NONE = 0, - BEARER_CINTERION_AUTH_PAP = 1, - BEARER_CINTERION_AUTH_CHAP = 2, - BEARER_CINTERION_AUTH_MSCHAPV2 = 3, -} BearerCinterionAuthType; - -typedef enum { - CONNECT_3GPP_CONTEXT_STEP_INIT = 0, - CONNECT_3GPP_CONTEXT_STEP_AUTH, - CONNECT_3GPP_CONTEXT_STEP_PDP_CTX, - CONNECT_3GPP_CONTEXT_STEP_START_SWWAN, - CONNECT_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION, - CONNECT_3GPP_CONTEXT_STEP_IP_CONFIG, - CONNECT_3GPP_CONTEXT_STEP_FINALIZE_BEARER, -} Connect3gppContextStep; - -typedef struct { - MMBroadbandBearerCinterion *self; - MMBaseModem *modem; - MMPortSerialAt *primary; - MMPort *data; - gint usb_interface_config_index; - Connect3gppContextStep connect; - MMBearerIpConfig *ipv4_config; - GCancellable *cancellable; - GSimpleAsyncResult *result; -} Connect3gppContext; - struct _MMBroadbandBearerCinterionPrivate { /* Flag for network-initiated disconnect */ guint network_disconnect_pending_id; }; /*****************************************************************************/ -/* Common 3GPP Function Declarations */ -static void connect_3gpp_context_step (Connect3gppContext *ctx); -static void connect_3gpp_context_complete_and_free (Connect3gppContext *ctx); - -/*****************************************************************************/ /* Common - Helper Functions*/ static gint @@ -172,12 +137,19 @@ verify_connection_state_from_swwan_response (GList *result, GError **error) } } - /*****************************************************************************/ -/* Connect - Helper Functions*/ +/* Auth helpers */ + +typedef enum { + BEARER_CINTERION_AUTH_UNKNOWN = -1, + BEARER_CINTERION_AUTH_NONE = 0, + BEARER_CINTERION_AUTH_PAP = 1, + BEARER_CINTERION_AUTH_CHAP = 2, + BEARER_CINTERION_AUTH_MSCHAPV2 = 3, +} BearerCinterionAuthType; static BearerCinterionAuthType -cinterion_parse_auth_type (MMBearerAllowedAuth mm_auth) +parse_auth_type (MMBearerAllowedAuth mm_auth) { switch (mm_auth) { case MM_BEARER_ALLOWED_AUTH_NONE: @@ -193,6 +165,71 @@ cinterion_parse_auth_type (MMBearerAllowedAuth mm_auth) } } +static gchar * +build_auth_string (MMBearerProperties *config, + gint usb_interface_config_index) +{ + const gchar *user; + const gchar *passwd; + MMBearerAllowedAuth auth; + BearerCinterionAuthType encoded_auth = BEARER_CINTERION_AUTH_UNKNOWN; + + user = mm_bearer_properties_get_user (config); + passwd = mm_bearer_properties_get_password (config); + + /* Normal use case is no user & pass so return as quick as possible */ + if (!user && !passwd) + return NULL; + + auth = mm_bearer_properties_get_allowed_auth (config); + encoded_auth = parse_auth_type (auth); + + /* Default to no authentication if not specified */ + if (encoded_auth == BEARER_CINTERION_AUTH_UNKNOWN) { + encoded_auth = BEARER_CINTERION_AUTH_NONE; + mm_dbg ("Unable to detect authentication type. Defaulting to 'none'"); + } + + /* TODO: Haven't tested this as I can't get a hold of a SIM w/ this feature atm. + * Write Command + * AT^SGAUTH=<cid>[, <auth_type>[, <passwd>, <user>]] + * Response(s) + * OK + * ERROR + * +CME ERROR: <err> + */ + return g_strdup_printf ("^SGAUTH=%u,%d,%s,%s", + usb_interface_configs[usb_interface_config_index].pdp_context, + encoded_auth, + passwd, + user); +} + +/*****************************************************************************/ +/* Connect 3GPP */ + +typedef enum { + CONNECT_3GPP_CONTEXT_STEP_FIRST = 0, + CONNECT_3GPP_CONTEXT_STEP_AUTH, + CONNECT_3GPP_CONTEXT_STEP_PDP_CTX, + CONNECT_3GPP_CONTEXT_STEP_START_SWWAN, + CONNECT_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION, + CONNECT_3GPP_CONTEXT_STEP_IP_CONFIG, + CONNECT_3GPP_CONTEXT_STEP_LAST, +} Connect3gppContextStep; + +typedef struct { + MMBroadbandBearerCinterion *self; + MMBaseModem *modem; + MMPortSerialAt *primary; + MMPort *data; + gint usb_interface_config_index; + Connect3gppContextStep step; + MMBearerIpConfig *ipv4_config; + GCancellable *cancellable; + GSimpleAsyncResult *result; +} Connect3gppContext; + static void connect_3gpp_context_complete_and_free (Connect3gppContext *ctx) { @@ -208,9 +245,9 @@ connect_3gpp_context_complete_and_free (Connect3gppContext *ctx) } static MMBearerConnectResult * -connect_3gpp_finish (MMBroadbandBearer *self, - GAsyncResult *res, - GError **error) +connect_3gpp_finish (MMBroadbandBearer *self, + GAsyncResult *res, + GError **error) { if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) return NULL; @@ -218,43 +255,24 @@ connect_3gpp_finish (MMBroadbandBearer *self, return mm_bearer_connect_result_ref (g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res))); } +static void connect_3gpp_context_step (Connect3gppContext *ctx); + static void -get_cmd_write_response_ctx_connect (MMBaseModem *modem, - GAsyncResult *res, - Connect3gppContext *ctx) +swwan_connect_check_status_ready (MMBaseModem *modem, + GAsyncResult *res, + Connect3gppContext *ctx) { - /* Only use this to parse responses that respond 'Ok' or 'ERROR' */ - GError *error = NULL; - - /* Check to see if the command had an error */ - mm_base_modem_at_command_finish (modem, res, &error); + const gchar *response; + GList *response_parsed = NULL; + GError *error = NULL; - /* We expect either OK or an error */ - if (error != NULL) { + response = mm_base_modem_at_command_full_finish (modem, res, &error); + if (!response) { g_simple_async_result_take_error (ctx->result, error); connect_3gpp_context_complete_and_free (ctx); return; } - g_clear_error (&error); - - /*GOTO next step */ - ctx->connect++; - connect_3gpp_context_step (ctx); -} - -static void -get_swwan_read_response_ctx_connect (MMBaseModem *modem, - GAsyncResult *res, - Connect3gppContext *ctx) -{ - const gchar *response; - GError *error = NULL; - GList *response_parsed = NULL; - - /* Get the SWWAN read response */ - response = mm_base_modem_at_command_finish (modem, res, &error); - /* Error if parsing SWWAN read response fails */ if (!mm_cinterion_parse_swwan_response (response, &response_parsed, &error)) { g_simple_async_result_take_error (ctx->result, error); @@ -262,109 +280,44 @@ get_swwan_read_response_ctx_connect (MMBaseModem *modem, return; } - /*Check parsed SWWAN reponse to see if we are now connected */ - if (verify_connection_state_from_swwan_response(response_parsed, &error)) { + /* Check parsed SWWAN reponse to see if we are now connected */ + if (verify_connection_state_from_swwan_response (response_parsed, &error)) { g_simple_async_result_take_error (ctx->result, error); connect_3gpp_context_complete_and_free (ctx); + g_list_free (response_parsed); return; } - g_list_free(response_parsed); - g_clear_error (&error); + g_list_free (response_parsed); - /* GOTO next step */ - ctx->connect++; + /* Go to next step */ + ctx->step++; connect_3gpp_context_step (ctx); } static void -setup_ip_settings (Connect3gppContext *ctx) -{ - MMBearerIpFamily ip_family; - - ip_family = mm_bearer_properties_get_ip_type (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); - - if (ip_family == MM_BEARER_IP_FAMILY_NONE || - ip_family == MM_BEARER_IP_FAMILY_ANY) { - gchar *ip_family_str; - - ip_family = mm_base_bearer_get_default_ip_family (MM_BASE_BEARER (ctx->self)); - ip_family_str = mm_bearer_ip_family_build_string_from_mask (ip_family); - mm_dbg ("No specific IP family requested, defaulting to %s", - ip_family_str); - g_free (ip_family_str); - } - - /* Default to automatic/DHCP addressing */ - ctx->ipv4_config = mm_bearer_ip_config_new (); - mm_bearer_ip_config_set_method (ctx->ipv4_config, MM_BEARER_IP_METHOD_DHCP); -} - -static gchar * -build_cinterion_auth_string (Connect3gppContext *ctx) +common_connect_operation_ready (MMBaseModem *modem, + GAsyncResult *res, + Connect3gppContext *ctx) { - const gchar *user = NULL; - const gchar *passwd = NULL; - MMBearerAllowedAuth auth; - BearerCinterionAuthType encoded_auth = BEARER_CINTERION_AUTH_UNKNOWN; - gchar *command = NULL; - - user = mm_bearer_properties_get_user (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); - passwd = mm_bearer_properties_get_password (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); - - /* Normal use case is no user & pass so return as quick as possible */ - if (!user && !passwd) - return NULL; - - auth = mm_bearer_properties_get_allowed_auth (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); - encoded_auth = cinterion_parse_auth_type (auth); + GError *error = NULL; - /* Default to no authentication if not specified */ - if (encoded_auth == BEARER_CINTERION_AUTH_UNKNOWN) { - encoded_auth = BEARER_CINTERION_AUTH_NONE; - mm_dbg ("Unable to detect authentication type. Defaulting to 'none'"); + if (!mm_base_modem_at_command_full_finish (modem, res, &error)) { + g_simple_async_result_take_error (ctx->result, error); + connect_3gpp_context_complete_and_free (ctx); + return; } - /* TODO: Haven't tested this as I can't get a hold of a SIM w/ this feature atm. - * Write Command - * AT^SGAUTH=<cid>[, <auth_type>[, <passwd>, <user>]] - * Response(s) - * OK - * ERROR - * +CME ERROR: <err> - */ - command = g_strdup_printf ("^SGAUTH=%u,%d,%s,%s", - usb_interface_configs[ctx->usb_interface_config_index].pdp_context, - encoded_auth, - passwd, - user); - - return command; -} - -static gchar * -build_cinterion_pdp_context_string (Connect3gppContext *ctx) -{ - const gchar *apn = NULL; - gchar *command; - - apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); - - /* TODO: Get IP type if protocol was specified. Hardcoded to IPV4 for now */ - - command = g_strdup_printf ("+CGDCONT=%u,\"IP\",\"%s\"", - usb_interface_configs[ctx->usb_interface_config_index].pdp_context, - apn ? apn : ""); - - return command; + /* Go to next step */ + ctx->step++; + connect_3gpp_context_step (ctx); } static void handle_cancel_connect (Connect3gppContext *ctx) { - gchar *command; + gchar *command; - /* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */ command = g_strdup_printf ("^SWWAN=0,%u,%u", usb_interface_configs[ctx->usb_interface_config_index].pdp_context, usb_interface_configs[ctx->usb_interface_config_index].swwan_index); @@ -380,192 +333,172 @@ handle_cancel_connect (Connect3gppContext *ctx) NULL, NULL); - g_simple_async_result_set_error (ctx->result, - MM_CORE_ERROR, - MM_CORE_ERROR_CANCELLED, - "Cinterion connection operation has been cancelled"); + g_simple_async_result_set_error (ctx->result, MM_CORE_ERROR, MM_CORE_ERROR_CANCELLED, + "Connection operation has been cancelled"); connect_3gpp_context_complete_and_free (ctx); - -} - -static void -create_cinterion_bearer (Connect3gppContext *ctx) -{ - if (ctx->ipv4_config) { - g_simple_async_result_set_op_res_gpointer ( - ctx->result, - mm_bearer_connect_result_new (ctx->data, ctx->ipv4_config, NULL), - (GDestroyNotify)mm_bearer_connect_result_unref); - } - else { - g_simple_async_result_set_error (ctx->result, - MM_CORE_ERROR, - MM_CORE_ERROR_WRONG_STATE, - "Cinterion connection failed to set IP protocol"); - } -} - -/*****************************************************************************/ -/* Connect - AT Command Wrappers*/ - -static void -send_swwan_read_command_ctx_connect (Connect3gppContext *ctx) -{ - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - "^SWWAN?", - 5, - FALSE, - FALSE, - NULL, - (GAsyncReadyCallback)get_swwan_read_response_ctx_connect, - ctx); -} - - -static void -send_write_command_ctx_connect (Connect3gppContext *ctx, - gchar **command) -{ - mm_base_modem_at_command_full (ctx->modem, - ctx->primary, - *command, - 10,/*Seen it take 5 seconds :0 */ - FALSE, - FALSE, - NULL, - (GAsyncReadyCallback)get_cmd_write_response_ctx_connect, - ctx); -} - -static void -send_swwan_connect_command_ctx_connect (Connect3gppContext *ctx) -{ - /* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */ - gchar *command; - command = g_strdup_printf ("^SWWAN=1,%u,%u", - usb_interface_configs[ctx->usb_interface_config_index].pdp_context, - usb_interface_configs[ctx->usb_interface_config_index].swwan_index); - - send_write_command_ctx_connect(ctx, &command); - - g_free (command); -} - -static void -send_swwan_disconnect_command_ctx_connect (Connect3gppContext *ctx) -{ - /* 3rd context -> 1st wwan adapt / 1st context -> 2nd wwan adapt */ - gchar *command; - command = g_strdup_printf ("^SWWAN=0,%u,%u", - usb_interface_configs[ctx->usb_interface_config_index].pdp_context, - usb_interface_configs[ctx->usb_interface_config_index].swwan_index); - - send_write_command_ctx_connect(ctx, &command); - - g_free (command); } -/*****************************************************************************/ -/* Connect - Bearer */ - static void connect_3gpp_context_step (Connect3gppContext *ctx) { /* Check for cancellation */ if (g_cancellable_is_cancelled (ctx->cancellable)) { - handle_cancel_connect(ctx); + handle_cancel_connect (ctx); return; } - mm_dbg ("Connect Step:%i", ctx->connect); - /* Network-initiated disconnect should not be outstanding at this point, - because it interferes with the connect attempt.*/ + * because it interferes with the connect attempt.*/ g_assert (ctx->self->priv->network_disconnect_pending_id == 0); - switch (ctx->connect) { - case CONNECT_3GPP_CONTEXT_STEP_INIT: + switch (ctx->step) { + case CONNECT_3GPP_CONTEXT_STEP_FIRST: { + MMBearerIpFamily ip_family; + + /* Only IPv4 supported by this bearer implementation for now */ + ip_family = mm_bearer_properties_get_ip_type (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); + if (ip_family == MM_BEARER_IP_FAMILY_NONE || ip_family == MM_BEARER_IP_FAMILY_ANY) { + gchar *ip_family_str; + + ip_family = mm_base_bearer_get_default_ip_family (MM_BASE_BEARER (ctx->self)); + ip_family_str = mm_bearer_ip_family_build_string_from_mask (ip_family); + mm_dbg ("No specific IP family requested, defaulting to %s", ip_family_str); + g_free (ip_family_str); + } - /* Insure no connection is currently - * active with the bearer we're creating.*/ - send_swwan_disconnect_command_ctx_connect (ctx); + if (ip_family != MM_BEARER_IP_FAMILY_IPV4) { + g_simple_async_result_set_error (ctx->result, + MM_CORE_ERROR, + MM_CORE_ERROR_UNSUPPORTED, + "Only IPv4 is supported by this modem"); + connect_3gpp_context_complete_and_free (ctx); + return; + } - return; + /* Fall down to next step */ + ctx->step++; + } case CONNECT_3GPP_CONTEXT_STEP_AUTH: { + gchar *command; - gchar *command = NULL; - - command = build_cinterion_auth_string (ctx); - - mm_dbg ("Auth String:%s", command); - - /* Send SGAUTH write, if User & Pass are provided. - * advance to next state by callback */ - if (command != NULL) { - mm_dbg ("Sending auth"); - - send_write_command_ctx_connect (ctx, &command); + command = build_auth_string (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)), + ctx->usb_interface_config_index); + + if (command) { + mm_dbg ("cinterion connect step 1/6: authenticating..."); + /* Send SGAUTH write, if User & Pass are provided. + * advance to next state by callback */ + mm_base_modem_at_command_full (ctx->modem, + ctx->primary, + command, + 10, + FALSE, + FALSE, + NULL, + (GAsyncReadyCallback) common_connect_operation_ready, + ctx); g_free (command); return; } - /* GOTO next step - Fall down below */ - ctx->connect++; + /* Fall down to next step */ + mm_dbg ("cinterion connect step 1/6: authentication not required"); + ctx->step++; } case CONNECT_3GPP_CONTEXT_STEP_PDP_CTX: { - gchar *command = NULL; + gchar *command; + const gchar *apn; - command = build_cinterion_pdp_context_string (ctx); + apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))); - /*Set the PDP context with cgdcont.*/ - send_write_command_ctx_connect (ctx, &command); + mm_dbg ("cinterion connect step 2/6: configuring PDP context %u with APN '%s'", + usb_interface_configs[ctx->usb_interface_config_index].pdp_context, apn); + /* TODO: Get IP type if protocol was specified. Hardcoded to IPV4 for now */ + command = g_strdup_printf ("+CGDCONT=%u,\"IP\",\"%s\"", + usb_interface_configs[ctx->usb_interface_config_index].pdp_context, + apn ? apn : ""); + mm_base_modem_at_command_full (ctx->modem, + ctx->primary, + command, + 5, + FALSE, + FALSE, + NULL, + (GAsyncReadyCallback) common_connect_operation_ready, + ctx); g_free (command); return; } - case CONNECT_3GPP_CONTEXT_STEP_START_SWWAN: - - send_swwan_connect_command_ctx_connect (ctx); + case CONNECT_3GPP_CONTEXT_STEP_START_SWWAN: { + gchar *command; + mm_dbg ("cinterion connect step 3/6: starting SWWAN interface %u connection...", + usb_interface_configs[ctx->usb_interface_config_index].swwan_index); + command = g_strdup_printf ("^SWWAN=1,%u,%u", + usb_interface_configs[ctx->usb_interface_config_index].pdp_context, + usb_interface_configs[ctx->usb_interface_config_index].swwan_index); + mm_base_modem_at_command_full (ctx->modem, + ctx->primary, + command, + 90, + FALSE, + FALSE, + NULL, + (GAsyncReadyCallback) common_connect_operation_ready, + ctx); + g_free (command); return; + } case CONNECT_3GPP_CONTEXT_STEP_VALIDATE_CONNECTION: - - send_swwan_read_command_ctx_connect (ctx); - + mm_dbg ("cinterion connect step 4/6: checking SWWAN interface %u status...", + usb_interface_configs[ctx->usb_interface_config_index].swwan_index); + mm_base_modem_at_command_full (ctx->modem, + ctx->primary, + "^SWWAN?", + 5, + FALSE, + FALSE, + NULL, + (GAsyncReadyCallback) swwan_connect_check_status_ready, + ctx); return; - case CONNECT_3GPP_CONTEXT_STEP_IP_CONFIG: - setup_ip_settings (ctx); - - /* GOTO next step - Fall down below */ - ctx->connect++; - case CONNECT_3GPP_CONTEXT_STEP_FINALIZE_BEARER: - /* Setup bearer */ - create_cinterion_bearer (ctx); + case CONNECT_3GPP_CONTEXT_STEP_IP_CONFIG: + mm_dbg ("cinterion connect step 5/6: creating IP config..."); + /* Default to automatic/DHCP addressing */ + ctx->ipv4_config = mm_bearer_ip_config_new (); + mm_bearer_ip_config_set_method (ctx->ipv4_config, MM_BEARER_IP_METHOD_DHCP); + /* Fall down to next step */ + ctx->step++; + case CONNECT_3GPP_CONTEXT_STEP_LAST: + mm_dbg ("cinterion connect step 6/6: finished"); + g_simple_async_result_set_op_res_gpointer (ctx->result, + mm_bearer_connect_result_new (ctx->data, ctx->ipv4_config, NULL), + (GDestroyNotify) mm_bearer_connect_result_unref); connect_3gpp_context_complete_and_free (ctx); return; } } static void -connect_3gpp (MMBroadbandBearer *self, - MMBroadbandModem *modem, - MMPortSerialAt *primary, - MMPortSerialAt *secondary, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +connect_3gpp (MMBroadbandBearer *self, + MMBroadbandModem *modem, + MMPortSerialAt *primary, + MMPortSerialAt *secondary, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { - Connect3gppContext *ctx; - MMPort *port; - gint usb_interface_config_index; - GError *error = NULL; + Connect3gppContext *ctx; + MMPort *port; + gint usb_interface_config_index; + GError *error = NULL; g_assert (primary != NULL); - /* Get a Net port to setup the connection on */ + /* Get a tet port to setup the connection on */ port = mm_base_modem_peek_best_data_port (MM_BASE_MODEM (modem), MM_PORT_TYPE_NET); if (!port) { g_simple_async_report_error_in_idle (G_OBJECT (self), @@ -601,7 +534,7 @@ connect_3gpp (MMBroadbandBearer *self, ctx->primary = g_object_ref (primary); /* Initialize */ - ctx->connect = CONNECT_3GPP_CONTEXT_STEP_INIT; + ctx->step = CONNECT_3GPP_CONTEXT_STEP_FIRST; /* Run! */ connect_3gpp_context_step (ctx); |