|
@@ -599,19 +599,29 @@ static struct nai_realm_eap * nai_realm_find_eap(struct wpa_cred *cred,
|
|
|
|
|
|
static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
|
|
|
{
|
|
|
- u8 plmn[3];
|
|
|
+ u8 plmn[3], plmn2[3];
|
|
|
const u8 *pos, *end;
|
|
|
u8 udhl;
|
|
|
|
|
|
- /* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
|
|
|
+ /*
|
|
|
+ * See Annex A of 3GPP TS 24.234 v8.1.0 for description. The network
|
|
|
+ * operator is allowed to include only two digits of the MNC, so allow
|
|
|
+ * matches based on both two and three digit MNC assumptions. Since some
|
|
|
+ * SIM/USIM cards may not expose MNC length conveniently, we may be
|
|
|
+ * provided the default MNC length 3 here and as such, checking with MNC
|
|
|
+ * length 2 is justifiable even though 3GPP TS 24.234 does not mention
|
|
|
+ * that case. Anyway, MCC/MNC pair where both 2 and 3 digit MNC is used
|
|
|
+ * with otherwise matching values would not be good idea in general, so
|
|
|
+ * this should not result in selecting incorrect networks.
|
|
|
+ */
|
|
|
+ /* Match with 3 digit MNC */
|
|
|
plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
|
|
|
- plmn[1] = imsi[2] - '0';
|
|
|
- /* default to MNC length 3 if unknown */
|
|
|
- if (mnc_len != 2)
|
|
|
- plmn[1] |= (imsi[5] - '0') << 4;
|
|
|
- else
|
|
|
- plmn[1] |= 0xf0;
|
|
|
+ plmn[1] = (imsi[2] - '0') | ((imsi[5] - '0') << 4);
|
|
|
plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
|
|
|
+ /* Match with 2 digit MNC */
|
|
|
+ plmn2[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
|
|
|
+ plmn2[1] = (imsi[2] - '0') | 0xf0;
|
|
|
+ plmn2[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
|
|
|
|
|
|
if (anqp == NULL)
|
|
|
return 0;
|
|
@@ -631,6 +641,10 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
|
|
|
}
|
|
|
end = pos + udhl;
|
|
|
|
|
|
+ wpa_printf(MSG_DEBUG, "Interworking: Matching against MCC/MNC alternatives: %02x:%02x:%02x or %02x:%02x:%02x (IMSI %s, MNC length %d)",
|
|
|
+ plmn[0], plmn[1], plmn[2], plmn2[0], plmn2[1], plmn2[2],
|
|
|
+ imsi, mnc_len);
|
|
|
+
|
|
|
while (pos + 2 <= end) {
|
|
|
u8 iei, len;
|
|
|
const u8 *l_end;
|
|
@@ -643,14 +657,20 @@ static int plmn_id_match(struct wpabuf *anqp, const char *imsi, int mnc_len)
|
|
|
if (iei == 0 && len > 0) {
|
|
|
/* PLMN List */
|
|
|
u8 num, i;
|
|
|
+ wpa_hexdump(MSG_DEBUG, "Interworking: PLMN List information element",
|
|
|
+ pos, len);
|
|
|
num = *pos++;
|
|
|
for (i = 0; i < num; i++) {
|
|
|
- if (pos + 3 > end)
|
|
|
+ if (pos + 3 > l_end)
|
|
|
break;
|
|
|
- if (os_memcmp(pos, plmn, 3) == 0)
|
|
|
+ if (os_memcmp(pos, plmn, 3) == 0 ||
|
|
|
+ os_memcmp(pos, plmn2, 3) == 0)
|
|
|
return 1; /* Found matching PLMN */
|
|
|
pos += 3;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ wpa_hexdump(MSG_DEBUG, "Interworking: Unrecognized 3GPP information element",
|
|
|
+ pos, len);
|
|
|
}
|
|
|
|
|
|
pos = l_end;
|
|
@@ -1337,6 +1357,8 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
|
|
|
char *sep;
|
|
|
const char *imsi;
|
|
|
int mnc_len;
|
|
|
+ char imsi_buf[16];
|
|
|
+ size_t msin_len;
|
|
|
|
|
|
#ifdef PCSC_FUNCS
|
|
|
if (cred->pcsc && wpa_s->conf->pcsc_reader && wpa_s->scard &&
|
|
@@ -1363,7 +1385,14 @@ static struct wpa_cred * interworking_credentials_available_3gpp(
|
|
|
(sep - cred->imsi != 5 && sep - cred->imsi != 6))
|
|
|
continue;
|
|
|
mnc_len = sep - cred->imsi - 3;
|
|
|
- imsi = cred->imsi;
|
|
|
+ os_memcpy(imsi_buf, cred->imsi, 3 + mnc_len);
|
|
|
+ sep++;
|
|
|
+ msin_len = os_strlen(cred->imsi);
|
|
|
+ if (3 + mnc_len + msin_len >= sizeof(imsi_buf) - 1)
|
|
|
+ msin_len = sizeof(imsi_buf) - 3 - mnc_len - 1;
|
|
|
+ os_memcpy(&imsi_buf[3 + mnc_len], sep, msin_len);
|
|
|
+ imsi_buf[3 + mnc_len + msin_len] = '\0';
|
|
|
+ imsi = imsi_buf;
|
|
|
|
|
|
#if defined(PCSC_FUNCS) || defined(CONFIG_EAP_PROXY)
|
|
|
compare:
|