aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@lanedo.com>2012-08-22 17:02:18 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-08-23 18:56:22 +0200
commitd8bc27a8c3681693a0c297a965d5f5858258d96a (patch)
tree3b6405933316aeda6946c06a910f2f5b8126daf1
parentd091344da2e50ef4016a87493b06fc54e40a2184 (diff)
sierra: custom 3GPP dialling sequence
-rw-r--r--plugins/sierra/mm-broadband-bearer-sierra.c244
1 files changed, 244 insertions, 0 deletions
diff --git a/plugins/sierra/mm-broadband-bearer-sierra.c b/plugins/sierra/mm-broadband-bearer-sierra.c
index bd7ada57..f18305dc 100644
--- a/plugins/sierra/mm-broadband-bearer-sierra.c
+++ b/plugins/sierra/mm-broadband-bearer-sierra.c
@@ -35,6 +35,246 @@
G_DEFINE_TYPE (MMBroadbandBearerSierra, mm_broadband_bearer_sierra, MM_TYPE_BROADBAND_BEARER);
/*****************************************************************************/
+/* 3GPP Dialing (sub-step of the 3GPP Connection sequence) */
+
+typedef enum {
+ DIAL_3GPP_STEP_FIRST,
+ DIAL_3GPP_STEP_PS_ATTACH,
+ DIAL_3GPP_STEP_AUTHENTICATE,
+ DIAL_3GPP_CONNECT,
+ DIAL_3GPP_LAST
+} Dial3gppStep;
+
+typedef struct {
+ MMBroadbandBearerSierra *self;
+ MMBaseModem *modem;
+ MMAtSerialPort *primary;
+ guint cid;
+ GCancellable *cancellable;
+ GSimpleAsyncResult *result;
+ gboolean is_net_data_port;
+ Dial3gppStep step;
+} Dial3gppContext;
+
+static void
+dial_3gpp_context_complete_and_free (Dial3gppContext *ctx)
+{
+ g_simple_async_result_complete (ctx->result);
+ g_object_unref (ctx->cancellable);
+ g_object_unref (ctx->result);
+ g_object_unref (ctx->primary);
+ g_object_unref (ctx->modem);
+ g_object_unref (ctx->self);
+ g_free (ctx);
+}
+
+static gboolean
+dial_3gpp_finish (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
+}
+
+static void dial_3gpp_context_step (Dial3gppContext *ctx);
+
+static void
+parent_dial_3gpp_ready (MMBroadbandBearer *self,
+ GAsyncResult *res,
+ Dial3gppContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!MM_BROADBAND_BEARER_CLASS (mm_broadband_bearer_sierra_parent_class)->dial_3gpp_finish (self, res, &error)) {
+ g_simple_async_result_take_error (ctx->result, error);
+ dial_3gpp_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Go on */
+ ctx->step++;
+ dial_3gpp_context_step (ctx);
+}
+
+static void
+scact_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ Dial3gppContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error)) {
+ g_simple_async_result_take_error (ctx->result, error);
+ dial_3gpp_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Go on */
+ ctx->step++;
+ dial_3gpp_context_step (ctx);
+}
+
+static void
+authenticate_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ Dial3gppContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error)) {
+ g_simple_async_result_take_error (ctx->result, error);
+ dial_3gpp_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Go on */
+ ctx->step++;
+ dial_3gpp_context_step (ctx);
+}
+
+static void
+cgatt_ready (MMBaseModem *modem,
+ GAsyncResult *res,
+ Dial3gppContext *ctx)
+{
+ GError *error = NULL;
+
+ if (!mm_base_modem_at_command_full_finish (MM_BASE_MODEM (modem), res, &error)) {
+ g_simple_async_result_take_error (ctx->result, error);
+ dial_3gpp_context_complete_and_free (ctx);
+ return;
+ }
+
+ /* Go on */
+ ctx->step++;
+ dial_3gpp_context_step (ctx);
+}
+
+static void
+dial_3gpp_context_step (Dial3gppContext *ctx)
+{
+ if (g_cancellable_is_cancelled (ctx->cancellable)) {
+ g_simple_async_result_set_error (ctx->result,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_CANCELLED,
+ "Dial operation has been cancelled");
+ dial_3gpp_context_complete_and_free (ctx);
+ return;
+ }
+
+ switch (ctx->step) {
+ case DIAL_3GPP_STEP_FIRST:
+ /* Fall down */
+ ctx->step++;
+
+ case DIAL_3GPP_STEP_PS_ATTACH:
+ mm_base_modem_at_command_full (MM_BASE_MODEM (ctx->modem),
+ ctx->primary,
+ "+CGATT=1",
+ 10,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)cgatt_ready,
+ ctx);
+ return;
+
+ case DIAL_3GPP_STEP_AUTHENTICATE:
+ if (ctx->is_net_data_port) {
+ gchar *command;
+ const gchar *user;
+ const gchar *password;
+
+ user = mm_bearer_properties_get_user (mm_bearer_peek_config (MM_BEARER (ctx->self)));
+ password = mm_bearer_properties_get_password (mm_bearer_peek_config (MM_BEARER (ctx->self)));
+
+ if (!user || !password)
+ command = g_strdup_printf ("$QCPDPP=%d,0",
+ ctx->cid);
+ else
+ command = g_strdup_printf ("$QCPDPP=%d,1,\"%s\",\"%s\"",
+ ctx->cid,
+ password,
+ user);
+
+ mm_base_modem_at_command_full (ctx->modem,
+ ctx->primary,
+ command,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)authenticate_ready,
+ ctx);
+ g_free (command);
+ return;
+ }
+
+ case DIAL_3GPP_CONNECT:
+ if (ctx->is_net_data_port) {
+ gchar *command;
+
+ command = g_strdup_printf ("!SCACT=1,%d", ctx->cid);
+ mm_base_modem_at_command_full (ctx->modem,
+ ctx->primary,
+ command,
+ 3,
+ FALSE,
+ NULL, /* cancellable */
+ (GAsyncReadyCallback)scact_ready,
+ ctx);
+ g_free (command);
+ return;
+ }
+
+ /* Chain up parent's dialling if we don't have a net port */
+ MM_BROADBAND_BEARER_CLASS (mm_broadband_bearer_sierra_parent_class)->dial_3gpp (
+ MM_BROADBAND_BEARER (ctx->self),
+ ctx->modem,
+ ctx->primary,
+ NULL, /* parent won't use it anyway */
+ ctx->cid,
+ ctx->cancellable,
+ (GAsyncReadyCallback)parent_dial_3gpp_ready,
+ ctx);
+ return;
+
+ case DIAL_3GPP_LAST:
+ g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
+ dial_3gpp_context_complete_and_free (ctx);
+ return;
+ }
+}
+
+static void
+dial_3gpp (MMBroadbandBearer *self,
+ MMBaseModem *modem,
+ MMAtSerialPort *primary,
+ MMPort *data,
+ guint cid,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ Dial3gppContext *ctx;
+
+ g_assert (primary != NULL);
+
+ ctx = g_slice_new0 (Dial3gppContext);
+ ctx->self = g_object_ref (self);
+ ctx->modem = g_object_ref (modem);
+ ctx->primary = g_object_ref (primary);
+ ctx->cid = cid;
+ ctx->result = g_simple_async_result_new (G_OBJECT (self),
+ callback,
+ user_data,
+ dial_3gpp);
+ ctx->cancellable = g_object_ref (cancellable);
+ ctx->is_net_data_port = !MM_IS_AT_SERIAL_PORT (data);
+ ctx->step = DIAL_3GPP_STEP_FIRST;
+
+ dial_3gpp_context_step (ctx);
+}
+
+/*****************************************************************************/
MMBearer *
mm_broadband_bearer_sierra_new_finish (GAsyncResult *res,
@@ -82,4 +322,8 @@ mm_broadband_bearer_sierra_init (MMBroadbandBearerSierra *self)
static void
mm_broadband_bearer_sierra_class_init (MMBroadbandBearerSierraClass *klass)
{
+ MMBroadbandBearerClass *broadband_bearer_class = MM_BROADBAND_BEARER_CLASS (klass);
+
+ broadband_bearer_class->dial_3gpp = dial_3gpp;
+ broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish;
}