Toby-L201 connect failure Ubuntu 18.04 Modem Manager 1.10.6 Linux Kernel Version 4.20.7

Ulrich Mohr u.mohr at semex-engcon.com
Tue Dec 10 11:02:21 UTC 2019


Hey,

I tried to reconstruct what I did to work around the problem.

1. When dial in takes place, I check upfront whether there is an active 
context that matches the requested one. If there is one, I use it, and 
skip activating another one. This prevents creating a secondary context 
when the default context is already active (which might fail as shown by 
the recent bug report -- some providers do not allow a secondary 
context, e.g. vodafone DE).

2. I seen cases where the default context does not match the APN at all. 
In this case, the first step would not detect the active context as the 
right one and create a second one. In case I've seen that, the creation 
of the second context succeeded, but the context is not used by the 
modem (because ublox does not set routes to the secondary context). 
Therefore, I also adapt the routes in the modem to match the new context.

I think that what I did is far from perfects, because theses two 
measures will fail when only one context is allowed AND the default 
context does not match the default one (although I never seen this so 
far). Also, it is not the recommended way from the ublox manuals, since 
they request to use set default eps bearer in case the network provided 
one does not work.

I attach the patch I use at the moment (based on version 1.7.999.) 
Please be aware that this also includes (inactive) code from other 
things I tried, e.g. setting the default bearer as requested by the 
ublox manuals.

That's unfortunately all I can provide at the moment, sorry for that.

Best regards,

Uli

Am 10.12.2019 um 10:23 schrieb Aleksander Morgado:
> On Fri, Dec 6, 2019 at 9:11 AM Ulrich Mohr <u.mohr at semex-engcon.com> wrote:
>> Hi,
>>
>> I am not sure, but I think that this is a problem with the UBlox modems I was facing before with a TOBY 210.
>>
>> The problem is that the modem does an automatic registration on the LTE network using its default APN (that it gets from the network, when I understand right). That is what you see (m2m.com.attz.mnc170.mcc310.gprs) as context 4:  (which is the default LTE bearer on TOBY). Unfortunately, that does not match the one your have given manually, so ModemManager tries to build up a connection using the secondary context with the APN settings you have given -- which fails, because the service provider does not allow a secondary connection while the first one is active.
>>
>> What I am not completely clear about is, under which circumstances you get such a long default APN name (not matching the 'official' ones) from the network.
>>
> The "long" name you get is when the bearer is already connected to
> that APN, so the name includes the MCCMNC of the operator.
> ModemManager already does a "loose" matching of the APNs and they
> should already match that one in context 4 if available:
> https://gitlab.freedesktop.org/mobile-broadband/ModemManager/blob/master/src/mm-modem-helpers.c#L1506
>
> As you said, MM should have attempted to use context #4 instead of #1
> as #4 was already connected. The problem is that the logic looking for
> which context to use stops as soon as it finds a matching one, and in
> this case it found #1 before #4. We could extend the logic to "prefer"
> an APN that is reported with MCCMNC if there are more than one
> matching, and I believe that should work.
>
>> @Aleksander: See https://lists.freedesktop.org/archives/modemmanager-devel/2018-August/006633.html
>>
>> I heavily change the ublox plugin to work around that -- unfortunately I never found the time to bring it to a deliverable state, and at the moment, I can't even remember what exactly I did. But I can provide the sources if needed....
> Yes, please, can you do that?
>
>
-- 
Best regards / Mit freundlichen Grüßen / Salutations distinguées

Ulrich Mohr

SEMEX-EngCon GmbH
Carl-Merz-Strass 26
76275 Ettlingen
Phone: +49 (0) 7243 5143596
email:  u.mohr at semex-engcon.com
___________________________________________
Executive board: A. Stiegler, H.-J. Nitzpon
Commercial register: Mannheim, HRB 718881
Company domicile: Ettlingen

-------------- next part --------------
diff '--exclude=.git*' '--exclude=Makefile*' '--exclude=config*' -ur ModemManager-1.8/plugins/ublox/77-mm-ublox-port-types.rules ModemManager-1.7.990/plugins/ublox/77-mm-ublox-port-types.rules
--- ModemManager-1.8/plugins/ublox/77-mm-ublox-port-types.rules	2019-04-24 08:27:00.498976998 +0200
+++ ModemManager-1.7.990/plugins/ublox/77-mm-ublox-port-types.rules	2018-11-05 14:40:13.000000000 +0100
@@ -17,4 +17,22 @@
 ATTRS{idVendor}=="1546", ATTRS{idProduct}=="1010", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_UBLOX_PRIMARY_PORT}="1"
 ATTRS{idVendor}=="1546", ATTRS{idProduct}=="1010", ENV{.MM_USBIFNUM}=="08", ENV{ID_MM_PORT_IGNORE}="1"
 
-LABEL="mm_ublox_port_types_end"
\ No newline at end of file
+
+# Sara U270 port types
+#  ttyACM0 (if #0): secondary
+#  ttyACM1 (if #2): primary
+#  ttyACM2 (if #4): additional AT port
+#  ttyACM2 (if #6): GNSS tunneling
+#  ttyACM2 (if #8): primary log
+#  ttyACM2 (if #10): secondary log
+#  ttyACM2 (if #12): SAP
+
+ATTRS{idVendor}=="1546", ATTRS{idProduct}=="1102", ENV{.MM_USBIFNUM}=="00", ENV{ID_MM_UBLOX_SECONDARY_PORT}="1"
+ATTRS{idVendor}=="1546", ATTRS{idProduct}=="1102", ENV{.MM_USBIFNUM}=="02", ENV{ID_MM_UBLOX_PRIMARY_PORT}="1"
+ATTRS{idVendor}=="1546", ATTRS{idProduct}=="1102", ENV{.MM_USBIFNUM}=="06", ENV{ID_MM_PORT_IGNORE}="1"
+ATTRS{idVendor}=="1546", ATTRS{idProduct}=="1102", ENV{.MM_USBIFNUM}=="08", ENV{ID_MM_PORT_IGNORE}="1"
+ATTRS{idVendor}=="1546", ATTRS{idProduct}=="1102", ENV{.MM_USBIFNUM}=="0a", ENV{ID_MM_PORT_IGNORE}="1"
+ATTRS{idVendor}=="1546", ATTRS{idProduct}=="1102", ENV{.MM_USBIFNUM}=="0c", ENV{ID_MM_PORT_IGNORE}="1"
+
+
+LABEL="mm_ublox_port_types_end"
diff '--exclude=.git*' '--exclude=Makefile*' '--exclude=config*' -ur ModemManager-1.8/plugins/ublox/mm-broadband-bearer-ublox.c ModemManager-1.7.990/plugins/ublox/mm-broadband-bearer-ublox.c
--- ModemManager-1.8/plugins/ublox/mm-broadband-bearer-ublox.c	2019-04-24 08:27:00.502975000 +0200
+++ ModemManager-1.7.990/plugins/ublox/mm-broadband-bearer-ublox.c	2018-11-15 12:17:38.492286436 +0100
@@ -69,6 +69,7 @@
     gboolean                auth_required;
     /* For IPv4 settings */
     MMBearerIpConfig       *ip_config;
+    GError                 *pending_error;
 } CommonConnectContext;
 
 static void
@@ -81,6 +82,8 @@
     g_object_unref (ctx->self);
     g_object_unref (ctx->modem);
     g_object_unref (ctx->primary);
+    if (ctx->pending_error)
+        g_error_free(ctx->pending_error);
     g_slice_free (CommonConnectContext, ctx);
 }
 
@@ -102,6 +105,7 @@
     ctx->modem   = g_object_ref (modem);
     ctx->primary = g_object_ref (primary);
     ctx->cid     = cid;
+    ctx->pending_error = NULL;
 
     task = g_task_new (self, cancellable, callback, user_data);
     g_task_set_task_data (task, ctx, (GDestroyNotify) common_connect_context_free);
@@ -124,6 +128,31 @@
     return task;
 }
 
+
+#define SETDEFAULTBEARER (0)
+#define SETROUTE (1)
+
+#if SETDEFAULTBEARER
+static MMBearerIpFamily
+select_bearer_ip_family (MMBroadbandBearer *self)
+{
+    MMBearerIpFamily ip_family;
+
+    ip_family = mm_bearer_properties_get_ip_type (mm_base_bearer_peek_config (MM_BASE_BEARER (self)));
+    if (ip_family == MM_BEARER_IP_FAMILY_NONE || ip_family == MM_BEARER_IP_FAMILY_ANY) {
+        gchar *default_family;
+
+        ip_family = mm_base_bearer_get_default_ip_family (MM_BASE_BEARER (self));
+        default_family = mm_bearer_ip_family_build_string_from_mask (ip_family);
+        mm_dbg ("No specific IP family requested, defaulting to %s", default_family);
+        g_free (default_family);
+    }
+
+    return ip_family;
+}
+#endif
+
+
 /*****************************************************************************/
 /* 3GPP IP config (sub-step of the 3GPP Connection sequence) */
 
@@ -327,6 +356,69 @@
     return MM_PORT (g_task_propagate_pointer (G_TASK (res), error));
 }
 
+
+#if DEACTIVATESUB
+static void
+cgact_activate_ready (MMBaseModem  *modem,
+                      GAsyncResult *res,
+                      GTask        *task);
+
+
+static void
+cgact_query_ready (MMBaseModem  *modem,
+                            GAsyncResult *res,
+                            GTask        *task)
+{
+    const gchar              *response;
+    GError                   *error = NULL;
+    GList                    *pdp_active_list = NULL;
+    GList                    *l;
+
+    CommonConnectContext *ctx;
+
+    ctx = (CommonConnectContext *) g_task_get_task_data (task);
+
+    response = mm_base_modem_at_command_finish (modem, res, &error);
+    if (response)
+        pdp_active_list = mm_3gpp_parse_cgact_read_response (response, &error);
+
+    if (error) {
+        g_assert (!pdp_active_list);
+        g_prefix_error (&error, "Couldn't check current list of active PDP contexts: ");
+        g_task_return_error (task, error);
+        g_object_unref (task);
+        return;
+    }
+
+    for (l = pdp_active_list; l; l = g_list_next (l)) {
+        MM3gppPdpContextActive *pdp_active;
+
+        /* We look for he just assume the first active PDP context found is the one we're
+         * looking for. */
+        pdp_active = (MM3gppPdpContextActive *)(l->data);
+        if ((pdp_active->cid != ctx->cid) && (pdp_active->active)){
+	    gchar *cmd;
+	    mm_dbg("Found other active PDP context with CID=%d, disable it!\n", pdp_active->cid);
+	    cmd = g_strdup_printf ("+CGACT=0,%u", pdp_active->cid);
+	    mm_base_modem_at_command (MM_BASE_MODEM (ctx->modem),
+                              cmd,
+                              40,
+                              FALSE,
+                              (GAsyncReadyCallback) cgact_activate_ready,
+                              task);
+    	    g_free (cmd);
+            mm_3gpp_pdp_context_active_list_free (pdp_active_list);
+            return;
+        }
+    }
+    mm_3gpp_pdp_context_active_list_free (pdp_active_list);
+
+
+    g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref);
+    g_object_unref (task);
+}
+
+
 static void
 cgact_activate_ready (MMBaseModem  *modem,
                       GAsyncResult *res,
@@ -339,13 +431,166 @@
     ctx = (CommonConnectContext *) g_task_get_task_data (task);
 
     response = mm_base_modem_at_command_finish (modem, res, &error);
-    if (!response)
+    if (response) {
+        mm_base_modem_at_command (MM_BASE_MODEM (modem),
+                                   "+CGACT?",
+                                   40,
+                                   FALSE, /* allow cached */
+                                   (GAsyncReadyCallback) cgact_query_ready,
+                                   task);
+
+        return;
+    }
+
+    if (!response) {
         g_task_return_error (task, error);
-    else
-        g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref);
+        g_object_unref (task);
+    }
+}
+
+#endif
+
+#if SETROUTE
+
+static void uiproute_ready(MMBaseModem  *modem,
+                      GAsyncResult *res,
+                      GTask        *task)
+{
+    CommonConnectContext *ctx;
+    ctx = (CommonConnectContext *) g_task_get_task_data (task);
+
+
+    g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref);
+    g_object_unref (task);
+
+}
+
+
+
+static void
+activate_uipaddr_ready(MMBaseModem  *modem,
+                      GAsyncResult *res,
+                      GTask        *task)
+{
+    const gchar          *response;
+    GError               *error = NULL;
+    CommonConnectContext *ctx;
+    gchar                *cmd;
+    gchar                *gw_ipv4_address;
+
+    ctx = (CommonConnectContext *) g_task_get_task_data (task);
+
+    response = mm_base_modem_at_command_finish (modem, res, &error);
+    if (!response) {
+        g_task_return_error (task, error);
+        g_object_unref (task);
+	return;
+    }
+
+    mm_ublox_parse_uipaddr_response (response,
+                                     NULL, /* cid */
+                                     NULL, /* if_name */
+                                     &gw_ipv4_address,
+                                     NULL, /* ipv4_subnet */
+                                     NULL, /* ipv6_global_address */
+                                     NULL, /* ipv6_link_local_address */
+                                     &error);
+
+
+    cmd = g_strdup_printf ("+UIPROUTE=\"add default gw %s\"", gw_ipv4_address);
+    mm_dbg ("setting default route #%u...", ctx->cid);
+    mm_base_modem_at_command (MM_BASE_MODEM (ctx->modem),
+                              cmd,
+                              120,
+                              FALSE,
+                              (GAsyncReadyCallback) uiproute_ready,
+                              task);
+
+    g_free(gw_ipv4_address);
+    g_free(cmd);
+}
+
+
+static void
+cgact_activate_ready (MMBaseModem  *modem,
+                      GAsyncResult *res,
+                      GTask        *task)
+{
+    const gchar          *response;
+    GError               *error = NULL;
+    CommonConnectContext *ctx;
+    gchar                *cmd;
+
+    ctx = (CommonConnectContext *) g_task_get_task_data (task);
+
+    response = mm_base_modem_at_command_finish (modem, res, &error);
+    if (!response) {
+        g_task_return_error (task, error);
+        g_object_unref (task);
+	return;
+    }
+
+
+    cmd = g_strdup_printf ("+UIPADDR=%u", ctx->cid);
+    mm_base_modem_at_command (MM_BASE_MODEM (modem),
+                              cmd,
+                              40,
+                              FALSE, /* allow cached */
+                              (GAsyncReadyCallback) activate_uipaddr_ready,
+                              task);
+    g_free(cmd);
+
+}
+
+static void
+activate_3gpp (GTask *task)
+{
+    CommonConnectContext *ctx;
+    gchar                *cmd;
+
+    ctx = (CommonConnectContext *) g_task_get_task_data (task);
+
+    cmd = g_strdup_printf ("+CGACT=1,%u", ctx->cid);
+    mm_dbg ("activating PDP context #%u...", ctx->cid);
+
+    mm_base_modem_at_command (MM_BASE_MODEM (ctx->modem),
+                              cmd,
+                              120,
+                              FALSE,
+                              (GAsyncReadyCallback) cgact_activate_ready,
+                              task);
+    g_free (cmd);
+}
+
+#else
+
+
+static void
+cgact_activate_ready (MMBaseModem  *modem,
+                      GAsyncResult *res,
+                      GTask        *task)
+{
+
+    const gchar          *response;
+    GError               *error = NULL;
+    CommonConnectContext *ctx;
+    ctx = (CommonConnectContext *) g_task_get_task_data (task);
+
+
+    response = mm_base_modem_at_command_finish (modem, res, &error);
+    if (!response) {
+        g_task_return_error (task, error);
+        g_object_unref (task);
+        return;
+    }
+
+
+    g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref);
     g_object_unref (task);
 }
 
+
+
 static void
 activate_3gpp (GTask *task)
 {
@@ -365,6 +610,8 @@
     g_free (cmd);
 }
 
+#endif
+
 static void
 uauthreq_ready (MMBaseModem  *modem,
                 GAsyncResult *res,
@@ -457,8 +704,8 @@
         cmd = g_strdup_printf ("+UAUTHREQ=%u,%u,%s,%s",
                                ctx->cid,
                                ublox_auth,
-                               quoted_password,
-                               quoted_user);
+                               quoted_user,
+                               quoted_password);
 
         g_free (quoted_user);
         g_free (quoted_password);
@@ -547,6 +794,63 @@
                               task);
 }
 
+
+static void
+cgact_query_active_ready (MMBaseModem  *modem,
+                            GAsyncResult *res,
+                            GTask        *task)
+{
+    const gchar              *response;
+    GError                   *error = NULL;
+    GList                    *pdp_active_list = NULL;
+    GList                    *l;
+
+    CommonConnectContext *ctx;
+
+    ctx = (CommonConnectContext *) g_task_get_task_data (task);
+
+    response = mm_base_modem_at_command_finish (modem, res, &error);
+    if (response)
+        pdp_active_list = mm_3gpp_parse_cgact_read_response (response, &error);
+
+    if (error) {
+        g_assert (!pdp_active_list);
+        g_prefix_error (&error, "Couldn't check current list of active PDP contexts: ");
+        g_task_return_error (task, error);
+        g_object_unref (task);
+        return;
+    }
+
+    for (l = pdp_active_list; l; l = g_list_next (l)) {
+        MM3gppPdpContextActive *pdp_active;
+
+        pdp_active = (MM3gppPdpContextActive *)(l->data);
+        if ((pdp_active->cid == ctx->cid) && pdp_active->active) {
+            mm_dbg("Requested PDP %d already active, skip activation", pdp_active->cid);
+    	    mm_3gpp_pdp_context_active_list_free (pdp_active_list);
+            g_task_return_pointer (task, g_object_ref (ctx->data), g_object_unref);
+            g_object_unref (task);
+            return;
+        }
+    }
+    mm_3gpp_pdp_context_active_list_free (pdp_active_list);
+    check_supported_authentication_methods (task);
+}
+
+
+static void
+cgact_query_active (MMBaseModem  *modem,
+                      GTask        *task)
+{
+    mm_base_modem_at_command (MM_BASE_MODEM (modem),
+                              "+CGACT?",
+                              40,
+                              FALSE, /* allow cached */
+                              (GAsyncReadyCallback) cgact_query_active_ready,
+                              task);
+}
+
+
 static void
 dial_3gpp (MMBroadbandBearer   *self,
            MMBaseModem         *modem,
@@ -568,7 +872,7 @@
                                           user_data)))
         return;
 
-    check_supported_authentication_methods (task);
+    cgact_query_active(modem, task);
 }
 
 /*****************************************************************************/
@@ -632,6 +936,277 @@
     g_free (cmd);
 }
 
+#if SETDEFAULTBEARER
+
+typedef struct {
+    MMBroadbandBearer *self;
+    MMBaseModem       *modem;
+    MMPortSerialAt     *primary;
+    GCancellable       *cancellable;
+    MMBearerIpFamily ip_family;
+} CidSelection3gppUBloxContext;
+
+
+static void
+cid_selection_3gpp_ublox_context_free (CidSelection3gppUBloxContext *ctx)
+{
+    g_object_unref (ctx->self);
+    g_object_unref (ctx->modem);
+    g_object_unref (ctx->primary);
+    g_object_unref (ctx->cancellable);
+    g_slice_free (CidSelection3gppUBloxContext, ctx);
+}
+
+
+static void
+select_cid_end (MMBroadbandBearer *self,
+                GAsyncResult *res,
+                GTask        *task)
+{
+    guint cid;
+    GError  *error = NULL;
+
+    mm_dbg ("Return from parent CID selection (%p, %p, %p)", self, res, task);
+
+    cid = MM_BROADBAND_BEARER_CLASS(mm_broadband_bearer_ublox_parent_class)->cid_selection_3gpp_finish(self, res, &error);
+    mm_dbg("Called base finish successfully (%d, %p)", cid, error);
+    if (error) {
+        g_task_return_error(task, error);
+    } else {
+        g_task_return_int(task, (gssize) cid);
+    }
+    g_object_unref(task);
+}
+
+
+static void
+select_cfun1_ready (MMBaseModem  *modem,
+                    GAsyncResult *res,
+                    GTask        *task)
+{
+    GError                  *error = NULL;
+    CidSelection3gppUBloxContext *ctx;
+
+    ctx = (CidSelection3gppUBloxContext *) g_task_get_task_data (task);
+
+    mm_base_modem_at_command_full_finish (ctx->modem, res, &error);
+    if (error) {
+        mm_warn ("Couldn't set default APN to use: '%s'", error->message);
+        g_task_return_error (task, error);
+        g_object_unref (task);
+        return;
+    }
+
+    mm_dbg ("Call parent CID selection");
+    MM_BROADBAND_BEARER_CLASS(mm_broadband_bearer_ublox_parent_class)->cid_selection_3gpp(ctx->self, ctx->modem, ctx->primary, ctx->cancellable, (GAsyncReadyCallback)select_cid_end, task);
+}
+
+static void
+select_cid_ready (MMBaseModem  *modem,
+                    GAsyncResult *res,
+                    GTask        *task)
+{
+    gchar *command;
+
+    GError                  *error = NULL;
+    CidSelection3gppUBloxContext *ctx;
+
+    ctx = (CidSelection3gppUBloxContext *) g_task_get_task_data (task);
+
+    mm_base_modem_at_command_full_finish (ctx->modem, res, &error);
+    if (error) {
+        mm_warn ("Couldn't set default APN to use: '%s'", error->message);
+        g_task_return_error (task, error);
+        g_object_unref (task);
+        return;
+    }
+
+    command = g_strdup_printf ("+CFUN=1");
+    mm_base_modem_at_command_full (ctx->modem,
+                                   ctx->primary,
+                                   command,
+                                   3,
+                                   FALSE,
+                                   FALSE, /* raw */
+                                   NULL, /* cancellable */
+                                   (GAsyncReadyCallback) select_cfun1_ready,
+                                   task);
+    g_free (command);
+}
+
+
+
+static void
+select_cfun4_ready (MMBaseModem  *modem,
+                    GAsyncResult *res,
+                    GTask        *task)
+{
+    gchar *apn;
+    gchar *user;
+    gchar *password;
+    gchar *command;
+    const gchar             *pdp_type;
+
+    GError                  *error = NULL;
+    CidSelection3gppUBloxContext *ctx;
+    MMBearerProperties * bearer_config;
+
+
+    ctx = (CidSelection3gppUBloxContext *) g_task_get_task_data (task);
+
+    mm_base_modem_at_command_full_finish (ctx->modem, res, &error);
+    if (error) {
+        mm_warn ("Couldn't set default APN to use: '%s'", error->message);
+        g_task_return_error (task, error);
+        g_object_unref (task);
+        return;
+    }
+
+
+    /* Validate requested PDP type */
+    pdp_type = mm_3gpp_get_pdp_type_from_ip_family (ctx->ip_family);
+    if (!pdp_type) {
+        gchar * str;
+
+        str = mm_bearer_ip_family_build_string_from_mask (ctx->ip_family);
+        g_task_return_new_error (task,
+                                 MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+                                 "Unsupported IP type requested: '%s'", str);
+        g_object_unref (task);
+        g_free (str);
+        return;
+    }
+
+    bearer_config = mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self));
+    apn = mm_port_serial_at_quote_string (mm_bearer_properties_get_apn (bearer_config));
+    user = mm_port_serial_at_quote_string (mm_bearer_properties_get_user (bearer_config));
+    password = mm_port_serial_at_quote_string (mm_bearer_properties_get_password (bearer_config));
+
+    command = g_strdup_printf ("+UCGDFLT=1,\"%s\",%s,,,,,,,,,,,,,,,,,,%d,%s,%s", pdp_type, apn, mm_bearer_properties_get_allowed_auth (bearer_config), user, password);
+    mm_dbg("Cmd: %s", command);
+    g_free (apn);
+    g_free (user);
+    g_free (password);
+    mm_base_modem_at_command_full (ctx->modem,
+                                   ctx->primary,
+                                   command,
+                                   3,
+                                   FALSE,
+                                   FALSE, /* raw */
+                                   NULL, /* cancellable */
+                                   (GAsyncReadyCallback) select_cid_ready,
+                                   task);
+    g_free (command);
+}
+
+
+static guint
+cid_selection_3gpp_finish (MMBroadbandBearer  *self,
+                           GAsyncResult       *res,
+                           GError            **error)
+{
+    gssize cid;
+
+    /* We return 0 as an invalid CID, not -1 */
+    cid = g_task_propagate_int (G_TASK (res), error);
+    return (guint) (cid < 0 ? 0 : cid);
+}
+
+static void
+read_default_eps (MMBaseModem  *modem,
+                    GAsyncResult *res,
+                    GTask        *task)
+{
+    gchar *command;
+    gchar *apn;
+    MMBearerIpFamily ip_family;
+    const gchar              *response;
+    gboolean found_apn = FALSE;
+
+    GError                  *error = NULL;
+    CidSelection3gppUBloxContext *ctx;
+
+    ctx = (CidSelection3gppUBloxContext *) g_task_get_task_data (task);
+
+    response = mm_base_modem_at_command_finish (modem, res, &error);
+    if (error) {
+        mm_warn ("Couldn't set default APN to use: '%s'", error->message);
+        g_task_return_error (task, error);
+        g_object_unref (task);
+        return;
+    }
+
+
+    mm_3gpp_parse_ucgdflt_read_response(response, &ip_family, &apn, &error);
+    if (ip_family  == ctx->ip_family) {
+        if (mm_3gpp_cmp_apn_name (apn, mm_bearer_properties_get_apn (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self))))) {
+            found_apn = TRUE;
+        }
+    }
+    if (apn) {
+        g_free(apn);
+    }
+
+    if (!found_apn) {
+
+         command = g_strdup_printf ("+CFUN=4");
+	 mm_base_modem_at_command_full (ctx->modem,
+                                   ctx->primary,
+                                   command,
+                                   3,
+                                   FALSE,
+                                   FALSE, /* raw */
+                                   NULL, /* cancellable */
+                                   (GAsyncReadyCallback) select_cfun4_ready,
+                                   task);
+        g_free (command);
+
+    } else {
+        mm_dbg ("Call parent CID selection");
+        MM_BROADBAND_BEARER_CLASS(mm_broadband_bearer_ublox_parent_class)->cid_selection_3gpp(ctx->self, ctx->modem, ctx->primary, ctx->cancellable, (GAsyncReadyCallback)select_cid_end, task);
+    }
+}
+
+
+static void  cid_selection_3gpp (MMBroadbandBearer *self,
+                                 MMBaseModem *modem,
+                                 MMPortSerialAt *primary,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data) {
+
+
+    GTask                   *task;
+    CidSelection3gppUBloxContext *ctx;
+    gchar *command;
+
+    ctx = g_slice_new0 (CidSelection3gppUBloxContext);
+    ctx->self        = g_object_ref (self);
+    ctx->modem       = g_object_ref (modem);
+    ctx->primary     = g_object_ref (primary);
+    ctx->cancellable = g_object_ref (cancellable);
+    ctx->ip_family = select_bearer_ip_family (self);
+
+    task = g_task_new (self, cancellable, callback, user_data);
+    g_task_set_task_data (task, ctx, (GDestroyNotify) cid_selection_3gpp_ublox_context_free);
+
+
+    command = g_strdup_printf("+UCGDFLT?");
+    mm_base_modem_at_command_full(ctx->modem,
+				  ctx->primary,
+                                  command,
+                                  3,
+                                  FALSE,
+                                  FALSE,
+                                  NULL,
+                                  (GAsyncReadyCallback) read_default_eps,
+                                  task);
+    g_free( command);
+}
+
+
+#endif
+
 /*****************************************************************************/
 /* Reload statistics */
 
@@ -904,6 +1479,11 @@
     broadband_bearer_class->dial_3gpp_finish = dial_3gpp_finish;
     broadband_bearer_class->get_ip_config_3gpp = get_ip_config_3gpp;
     broadband_bearer_class->get_ip_config_3gpp_finish = get_ip_config_3gpp_finish;
+#if SETDEFAULTBEARER
+    broadband_bearer_class->cid_selection_3gpp = cid_selection_3gpp;
+    broadband_bearer_class->cid_selection_3gpp_finish = cid_selection_3gpp_finish;
+#endif
+    klass->cid_selection_parent = broadband_bearer_class->cid_selection_3gpp;
 
     properties[PROP_USB_PROFILE] =
         g_param_spec_enum (MM_BROADBAND_BEARER_UBLOX_USB_PROFILE,
diff '--exclude=.git*' '--exclude=Makefile*' '--exclude=config*' -ur ModemManager-1.8/plugins/ublox/mm-broadband-bearer-ublox.h ModemManager-1.7.990/plugins/ublox/mm-broadband-bearer-ublox.h
--- ModemManager-1.8/plugins/ublox/mm-broadband-bearer-ublox.h	2019-04-24 08:27:00.502975000 +0200
+++ ModemManager-1.7.990/plugins/ublox/mm-broadband-bearer-ublox.h	2018-11-05 14:40:13.000000000 +0100
@@ -46,6 +46,14 @@
 
 struct _MMBroadbandBearerUbloxClass {
     MMBroadbandBearerClass parent;
+
+    void  (* cid_selection_parent) (MMBroadbandBearer *self,
+                                         MMBaseModem *modem,
+                                         MMPortSerialAt *primary,
+                                         GCancellable *cancellable,
+                                         GAsyncReadyCallback callback,
+                                         gpointer user_data);
+
 };
 
 GType mm_broadband_bearer_ublox_get_type (void);
diff '--exclude=.git*' '--exclude=Makefile*' '--exclude=config*' -ur ModemManager-1.8/src/mm-modem-helpers.c ModemManager-1.7.990/src/mm-modem-helpers.c
--- ModemManager-1.8/src/mm-modem-helpers.c	2019-04-24 08:27:00.566943000 +0200
+++ ModemManager-1.7.990/src/mm-modem-helpers.c	2018-11-05 14:40:13.000000000 +0100
@@ -1441,6 +1441,56 @@
     return (a->cid - b->cid);
 }
 
+
+
+gboolean
+mm_3gpp_parse_ucgdflt_read_response (const gchar *reply,
+                                     MMBearerIpFamily * ip_family,
+                                     gchar ** apn,
+                                     GError **error)
+{
+    GError *inner_error = NULL;
+    GRegex *r;
+    GMatchInfo *match_info;
+    *apn = NULL;
+
+    r = g_regex_new ("\\+UCGDFLT:\\s*([^, \\)]*)\\s*,([^, \\)]*)\\s*",
+                     G_REGEX_DOLLAR_ENDONLY | G_REGEX_RAW,
+                     0, &inner_error);
+    if (r) {
+        g_regex_match_full (r, reply, strlen (reply), 0, 0, &match_info, &inner_error);
+
+        while (!inner_error &&
+               g_match_info_matches (match_info)) {
+            gchar *str;
+
+            mm_dbg("Match %s %s\n", mm_get_string_unquoted_from_match_info (match_info, 1),mm_get_string_unquoted_from_match_info (match_info, 2));
+            str = mm_get_string_unquoted_from_match_info (match_info, 1);
+            *ip_family = mm_3gpp_get_ip_family_from_pdp_type (str);
+            g_free(str);
+
+            *apn = mm_get_string_unquoted_from_match_info (match_info, 2);
+            g_match_info_next (match_info, &inner_error);
+        }
+
+        g_match_info_free (match_info);
+        g_regex_unref (r);
+    }
+
+    if (inner_error) {
+	if (apn) {
+	    g_free(apn);
+        }
+        g_propagate_error (error, inner_error);
+        g_prefix_error (error, "Couldn't properly parse default eps bearer. ");
+        return FALSE;
+    }
+    mm_dbg("udcgdflt response: %s -> %s, %d", reply, *apn, *ip_family);
+
+    return TRUE;
+}
+
+
 GList *
 mm_3gpp_parse_cgdcont_read_response (const gchar *reply,
                                      GError **error)
diff '--exclude=.git*' '--exclude=Makefile*' '--exclude=config*' -ur ModemManager-1.8/src/mm-modem-helpers.h ModemManager-1.7.990/src/mm-modem-helpers.h
--- ModemManager-1.8/src/mm-modem-helpers.h	2019-04-24 08:27:00.566943000 +0200
+++ ModemManager-1.7.990/src/mm-modem-helpers.h	2018-11-05 14:40:13.000000000 +0100
@@ -152,6 +152,15 @@
 gboolean mm_3gpp_cmp_apn_name (const gchar *requested,
                                const gchar *existing);
 
+
+gboolean
+mm_3gpp_parse_ucgdflt_read_response (const gchar *reply,
+                                     MMBearerIpFamily * ip_family,
+                                     gchar ** apn,
+                                     GError **error);
+
+
+
 /* AT+CGDCONT=? (PDP context format) test parser */
 typedef struct {
     guint min_cid;


More information about the ModemManager-devel mailing list