summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2016-08-22 23:34:53 +0200
committerAleksander Morgado <aleksander@aleksander.es>2016-10-12 13:24:09 +0200
commit5a9f093839029c10791fbc67047c3b4843a53063 (patch)
tree54a235dbfdb7e7d94cba44112d6a4c43294cba00
parent75ad9bf98be802bec12b0c8ba0ed9fd95ce8902f (diff)
downloadModemManager-5a9f093839029c10791fbc67047c3b4843a53063.tar.gz
modem-helpers: implement less strict APN comparison
u-blox modems will append a string showing the MCC and MNC info to the access point name listed in AT+CGDCONT? responses. We will try to detect when that happens, and we just accept the match. The logic doesn't just look for a string prefix; it also looks for the special MCC + MNC suffix, which is much more restrictive, to try to avoid false positives.
-rw-r--r--src/mm-broadband-bearer.c7
-rw-r--r--src/mm-modem-helpers.c44
-rw-r--r--src/mm-modem-helpers.h4
-rw-r--r--src/tests/test-modem-helpers.c39
4 files changed, 91 insertions, 3 deletions
diff --git a/src/mm-broadband-bearer.c b/src/mm-broadband-bearer.c
index 6c910c7c7..1188f60a4 100644
--- a/src/mm-broadband-bearer.c
+++ b/src/mm-broadband-bearer.c
@@ -891,13 +891,14 @@ parse_pdp_list (MMBaseModem *modem,
const gchar *apn;
apn = mm_bearer_properties_get_apn (mm_base_bearer_peek_config (MM_BASE_BEARER (ctx->self)));
- if (apn && !g_ascii_strcasecmp (pdp->apn, apn)) {
+ /* First requested, then existing */
+ if (mm_3gpp_cmp_apn_name (apn, pdp->apn)) {
gchar *ip_family_str;
- /* Found a PDP context with the same CID and PDP type, we'll use it. */
+ /* Found a PDP context with the same APN and PDP type, we'll use it. */
ip_family_str = mm_bearer_ip_family_build_string_from_mask (pdp->pdp_type);
mm_dbg ("Found PDP context with CID %u and PDP type %s for APN '%s'",
- pdp->cid, ip_family_str, pdp->apn);
+ pdp->cid, ip_family_str, apn);
cid = pdp->cid;
ctx->use_existing_cid = TRUE;
g_free (ip_family_str);
diff --git a/src/mm-modem-helpers.c b/src/mm-modem-helpers.c
index eecdc5e53..d51f7782a 100644
--- a/src/mm-modem-helpers.c
+++ b/src/mm-modem-helpers.c
@@ -1031,6 +1031,50 @@ out:
}
/*************************************************************************/
+/* Logic to compare two APN names */
+
+gboolean
+mm_3gpp_cmp_apn_name (const gchar *requested,
+ const gchar *existing)
+{
+ size_t requested_len;
+ size_t existing_len;
+
+ /* Both must be given to compare properly */
+ if (!existing || !existing[0] || !requested || !requested[0])
+ return FALSE;
+
+ requested_len = strlen (requested);
+
+ /*
+ * 1) The requested APN should be at least the prefix of the existing one.
+ */
+ if (g_ascii_strncasecmp (existing, requested, requested_len) != 0)
+ return FALSE;
+
+ /*
+ * 2) If the existing one is actually the same as the requested one (i.e.
+ * there are no more different chars in the existing one), we're done.
+ */
+ if (existing[requested_len] == '\0')
+ return TRUE;
+
+ existing_len = strlen (existing);
+
+ /* 3) Special handling for PDP contexts reported by u-blox modems once the
+ * contexts have been activated at least once:
+ * "ac.vodafone.es.MNC001.MCC214.GPRS" should match "ac.vodafone.es"
+ */
+ if ((existing_len > (requested_len + 14)) &&
+ g_ascii_strncasecmp (&existing[requested_len], ".mnc", 4) == 0 &&
+ g_ascii_strncasecmp (&existing[requested_len + 7], ".mcc", 4) == 0)
+ return TRUE;
+
+ /* No match */
+ return FALSE;
+}
+
+/*************************************************************************/
static void
mm_3gpp_pdp_context_format_free (MM3gppPdpContextFormat *format)
diff --git a/src/mm-modem-helpers.h b/src/mm-modem-helpers.h
index 6565c5839..fb7982fe5 100644
--- a/src/mm-modem-helpers.h
+++ b/src/mm-modem-helpers.h
@@ -127,6 +127,10 @@ gboolean mm_3gpp_parse_cops_read_response (const gchar *response,
MMModemAccessTechnology *out_act,
GError **error);
+/* Logic to compare two APN names */
+gboolean mm_3gpp_cmp_apn_name (const gchar *requested,
+ const gchar *existing);
+
/* AT+CGDCONT=? (PDP context format) test parser */
typedef struct {
guint min_cid;
diff --git a/src/tests/test-modem-helpers.c b/src/tests/test-modem-helpers.c
index f02a0862c..0afa22fc8 100644
--- a/src/tests/test-modem-helpers.c
+++ b/src/tests/test-modem-helpers.c
@@ -1822,6 +1822,43 @@ test_iccid_parse_unquoted_invalid_mii (void *f, gpointer d)
}
/*****************************************************************************/
+/* Test APN cmp */
+
+typedef struct {
+ const gchar *existing;
+ const gchar *requested;
+ gboolean match_expected;
+} TestApnCmp;
+
+static const TestApnCmp test_apn_cmp[] = {
+ { "m2m.com.attz", "m2m.com.attz", TRUE },
+ { "m2m.com.attz", "M2M.COM.ATTZ", TRUE },
+ { "M2M.COM.ATTZ", "m2m.com.attz", TRUE },
+ { "m2m.com.attz.mnc170.mcc310.gprs", "m2m.com.attz", TRUE },
+ { "ac.vodafone.es.MNC001.MCC214.GPRS", "ac.vodafone.es", TRUE },
+ { "m2m.com.attz", "m2m.com.attz.mnc170.mcc310.gprs", FALSE },
+ { "ac.vodafone.es", "ac.vodafone.es.MNC001.MCC214.GPRS", FALSE },
+ { "internet.test", "internet", FALSE },
+ { "internet.test", "INTERNET", FALSE },
+ { "internet.test", "internet.tes", FALSE },
+ { "", "", FALSE },
+};
+
+static void
+test_cmp_apn_name (void)
+{
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_apn_cmp); i++) {
+ g_debug ("Comparing requested '%s' vs existing '%s': %s match",
+ test_apn_cmp[i].requested,
+ test_apn_cmp[i].existing,
+ test_apn_cmp[i].match_expected ? "should" : "shouldn't");
+ g_assert (mm_3gpp_cmp_apn_name (test_apn_cmp[i].requested, test_apn_cmp[i].existing) == test_apn_cmp[i].match_expected);
+ }
+}
+
+/*****************************************************************************/
/* Test CGDCONT test responses */
static void
@@ -3456,6 +3493,8 @@ int main (int argc, char **argv)
g_test_suite_add (suite, TESTCASE (test_cpms_response_empty_fields, NULL));
g_test_suite_add (suite, TESTCASE (test_cpms_query_response, NULL));
+ g_test_suite_add (suite, TESTCASE (test_cmp_apn_name, NULL));
+
g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_single, NULL));
g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_multiple, NULL));
g_test_suite_add (suite, TESTCASE (test_cgdcont_test_response_multiple_and_ignore, NULL));