diff options
author | Aleksander Morgado <aleksander@aleksander.es> | 2016-08-22 23:34:53 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2016-10-12 13:24:09 +0200 |
commit | 5a9f093839029c10791fbc67047c3b4843a53063 (patch) | |
tree | 54a235dbfdb7e7d94cba44112d6a4c43294cba00 | |
parent | 75ad9bf98be802bec12b0c8ba0ed9fd95ce8902f (diff) | |
download | ModemManager-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.c | 7 | ||||
-rw-r--r-- | src/mm-modem-helpers.c | 44 | ||||
-rw-r--r-- | src/mm-modem-helpers.h | 4 | ||||
-rw-r--r-- | src/tests/test-modem-helpers.c | 39 |
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)); |