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.
This commit is contained in:
Aleksander Morgado
2016-10-12 13:24:09 +02:00
parent 75ad9bf98b
commit 5a9f093839
4 changed files with 91 additions and 3 deletions
+4 -3
View File
@@ -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);
+44
View File
@@ -1030,6 +1030,50 @@ out:
return TRUE;
}
/*************************************************************************/
/* 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
+4
View File
@@ -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;
+39
View File
@@ -1821,6 +1821,43 @@ test_iccid_parse_unquoted_invalid_mii (void *f, gpointer d)
g_error_free (error);
}
/*****************************************************************************/
/* 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 */
@@ -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));