]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/hs20_supplicant.c
EAP: Increase the maximum number of message exchanges
[thirdparty/hostap.git] / wpa_supplicant / hs20_supplicant.c
index 1d156776817da186a45601b5032a02bf3f9a7a3c..cb236df18d86b5556031e1fa2e674cf1a8fbacb1 100644 (file)
@@ -49,9 +49,12 @@ struct osu_provider {
        u8 bssid[ETH_ALEN];
        u8 osu_ssid[SSID_MAX_LEN];
        u8 osu_ssid_len;
+       u8 osu_ssid2[SSID_MAX_LEN];
+       u8 osu_ssid2_len;
        char server_uri[256];
        u32 osu_methods; /* bit 0 = OMA-DM, bit 1 = SOAP-XML SPP */
        char osu_nai[256];
+       char osu_nai2[256];
        struct osu_lang_string friendly_name[OSU_MAX_ITEMS];
        size_t friendly_name_count;
        struct osu_lang_string serv_desc[OSU_MAX_ITEMS];
@@ -92,8 +95,7 @@ void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
                return;
        }
 
-       /* Check if Proxy ARP is enabled (2nd byte in the IE) */
-       if (ext_capa[3] & BIT(4))
+       if (wpa_bss_ext_capab(bss, WLAN_EXT_CAPAB_PROXY_ARP))
                filter |= WPA_DATA_FRAME_FILTER_FLAG_ARP |
                        WPA_DATA_FRAME_FILTER_FLAG_NA;
 
@@ -101,15 +103,22 @@ void hs20_configure_frame_filters(struct wpa_supplicant *wpa_s)
 }
 
 
-void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
+void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id, int ap_release)
 {
+       int release;
        u8 conf;
 
+       release = (HS20_VERSION >> 4) + 1;
+       if (ap_release > 0 && release > ap_release)
+               release = ap_release;
+       if (release < 2)
+               pps_mo_id = -1;
+
        wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
        wpabuf_put_u8(buf, pps_mo_id >= 0 ? 7 : 5);
        wpabuf_put_be24(buf, OUI_WFA);
        wpabuf_put_u8(buf, HS20_INDICATION_OUI_TYPE);
-       conf = HS20_VERSION;
+       conf = (release - 1) << 4;
        if (pps_mo_id >= 0)
                conf |= HS20_PPS_MO_ID_PRESENT;
        wpabuf_put_u8(buf, conf);
@@ -118,6 +127,37 @@ void wpas_hs20_add_indication(struct wpabuf *buf, int pps_mo_id)
 }
 
 
+void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
+                                const struct wpa_ssid *ssid)
+{
+       if (!ssid->roaming_consortium_selection ||
+           !ssid->roaming_consortium_selection_len)
+               return;
+
+       wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
+       wpabuf_put_u8(buf, 4 + ssid->roaming_consortium_selection_len);
+       wpabuf_put_be24(buf, OUI_WFA);
+       wpabuf_put_u8(buf, HS20_ROAMING_CONS_SEL_OUI_TYPE);
+       wpabuf_put_data(buf, ssid->roaming_consortium_selection,
+                       ssid->roaming_consortium_selection_len);
+}
+
+
+int get_hs20_version(struct wpa_bss *bss)
+{
+       const u8 *ie;
+
+       if (!bss)
+               return 0;
+
+       ie = wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE);
+       if (!ie || ie[1] < 5)
+               return 0;
+
+       return ((ie[6] >> 4) & 0x0f) + 1;
+}
+
+
 int is_hs20_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
                    struct wpa_bss *bss)
 {
@@ -205,8 +245,8 @@ void hs20_put_anqp_req(u32 stypes, const u8 *payload, size_t payload_len,
 }
 
 
-struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
-                                   size_t payload_len)
+static struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+                                          size_t payload_len)
 {
        struct wpabuf *buf;
 
@@ -248,7 +288,7 @@ int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
        if (buf == NULL)
                return -1;
 
-       res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+       res = gas_query_req(wpa_s->gas, dst, freq, 0, buf, anqp_resp_cb, wpa_s);
        if (res < 0) {
                wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
                wpabuf_free(buf);
@@ -391,7 +431,7 @@ static void hs20_set_osu_access_permission(const char *osu_dir,
                return;
        }
 
-       if (chown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
+       if (lchown(fname, statbuf.st_uid, statbuf.st_gid) < 0) {
                wpa_printf(MSG_WARNING, "Cannot change the ownership for %s",
                           fname);
        }
@@ -429,21 +469,20 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
        dl_list_for_each(icon, &wpa_s->icon_head, struct icon_entry, list) {
                if (icon->dialog_token == dialog_token && !icon->image &&
                    os_memcmp(icon->bssid, sa, ETH_ALEN) == 0) {
-                       icon->image = os_malloc(slen);
+                       icon->image = os_memdup(pos, slen);
                        if (!icon->image)
                                return -1;
-                       os_memcpy(icon->image, pos, slen);
                        icon->image_len = slen;
                        hs20_remove_duplicate_icons(wpa_s, icon);
                        wpa_msg(wpa_s, MSG_INFO,
-                               "RX-HS20-ICON " MACSTR " %s %u",
+                               RX_HS20_ICON MACSTR " %s %u",
                                MAC2STR(sa), icon->file_name,
                                (unsigned int) icon->image_len);
                        return 0;
                }
        }
 
-       wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR " Icon Binary File",
+       wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " Icon Binary File",
                MAC2STR(sa));
 
        if (slen < 4) {
@@ -506,7 +545,7 @@ static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s,
        }
        fclose(f);
 
-       wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP-ICON %s", fname);
+       wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname);
        return 0;
 }
 
@@ -570,7 +609,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
 
        switch (subtype) {
        case HS20_STYPE_CAPABILITY_LIST:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " HS Capability List", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "HS Capability List", pos, slen);
                if (anqp) {
@@ -580,7 +619,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " Operator Friendly Name", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "oper friendly name", pos, slen);
                if (anqp) {
@@ -596,7 +635,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                                "Metrics value from " MACSTR, MAC2STR(sa));
                        break;
                }
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " WAN Metrics %02x:%u:%u:%u:%u:%u", MAC2STR(sa),
                        pos[0], WPA_GET_LE32(pos + 1), WPA_GET_LE32(pos + 5),
                        pos[9], pos[10], WPA_GET_LE16(pos + 11));
@@ -606,7 +645,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_CONNECTION_CAPABILITY:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " Connection Capability", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "conn capability", pos, slen);
                if (anqp) {
@@ -616,7 +655,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_OPERATING_CLASS:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " Operating Class", MAC2STR(sa));
                wpa_hexdump_ascii(MSG_DEBUG, "Operating Class", pos, slen);
                if (anqp) {
@@ -626,7 +665,7 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                }
                break;
        case HS20_STYPE_OSU_PROVIDERS_LIST:
-               wpa_msg(wpa_s, MSG_INFO, "RX-HS20-ANQP " MACSTR
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
                        " OSU Providers list", MAC2STR(sa));
                wpa_s->num_prov_found++;
                if (anqp) {
@@ -646,6 +685,25 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                                               wpa_s, NULL);
                }
                break;
+       case HS20_STYPE_OPERATOR_ICON_METADATA:
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
+                       " Operator Icon Metadata", MAC2STR(sa));
+               wpa_hexdump(MSG_DEBUG, "Operator Icon Metadata", pos, slen);
+               if (anqp) {
+                       wpabuf_free(anqp->hs20_operator_icon_metadata);
+                       anqp->hs20_operator_icon_metadata =
+                               wpabuf_alloc_copy(pos, slen);
+               }
+               break;
+       case HS20_STYPE_OSU_PROVIDERS_NAI_LIST:
+               wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR
+                       " OSU Providers NAI List", MAC2STR(sa));
+               if (anqp) {
+                       wpabuf_free(anqp->hs20_osu_providers_nai_list);
+                       anqp->hs20_osu_providers_nai_list =
+                               wpabuf_alloc_copy(pos, slen);
+               }
+               break;
        default:
                wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype);
                break;
@@ -703,6 +761,8 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
                 wpa_s->conf->osu_dir);
        f = fopen(fname, "w");
        if (f == NULL) {
+               wpa_msg(wpa_s, MSG_INFO,
+                       "Could not write OSU provider information");
                hs20_free_osu_prov(wpa_s);
                wpa_s->fetch_anqp_in_progress = 0;
                return;
@@ -723,8 +783,15 @@ static void hs20_osu_fetch_done(struct wpa_supplicant *wpa_s)
                                wpa_ssid_txt(osu->osu_ssid,
                                             osu->osu_ssid_len));
                }
+               if (osu->osu_ssid2_len) {
+                       fprintf(f, "osu_ssid2=%s\n",
+                               wpa_ssid_txt(osu->osu_ssid2,
+                                            osu->osu_ssid2_len));
+               }
                if (osu->osu_nai[0])
                        fprintf(f, "osu_nai=%s\n", osu->osu_nai);
+               if (osu->osu_nai2[0])
+                       fprintf(f, "osu_nai2=%s\n", osu->osu_nai2);
                for (j = 0; j < osu->friendly_name_count; j++) {
                        fprintf(f, "friendly_name=%s:%s\n",
                                osu->friendly_name[j].lang,
@@ -788,6 +855,7 @@ void hs20_next_osu_icon(struct wpa_supplicant *wpa_s)
 
 static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                              const u8 *osu_ssid, u8 osu_ssid_len,
+                             const u8 *osu_ssid2, u8 osu_ssid2_len,
                              const u8 *pos, size_t len)
 {
        struct osu_provider *prov;
@@ -809,6 +877,9 @@ static void hs20_osu_add_prov(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
        os_memcpy(prov->bssid, bss->bssid, ETH_ALEN);
        os_memcpy(prov->osu_ssid, osu_ssid, osu_ssid_len);
        prov->osu_ssid_len = osu_ssid_len;
+       if (osu_ssid2)
+               os_memcpy(prov->osu_ssid2, osu_ssid2, osu_ssid2_len);
+       prov->osu_ssid2_len = osu_ssid2_len;
 
        /* OSU Friendly Name Length */
        if (end - pos < 2) {
@@ -990,18 +1061,30 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
        struct wpabuf *prov_anqp;
        const u8 *pos, *end;
        u16 len;
-       const u8 *osu_ssid;
-       u8 osu_ssid_len;
+       const u8 *osu_ssid, *osu_ssid2;
+       u8 osu_ssid_len, osu_ssid2_len;
        u8 num_providers;
 
        hs20_free_osu_prov(wpa_s);
 
        dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+               struct wpa_ie_data data;
+               const u8 *ie;
+
                if (bss->anqp == NULL)
                        continue;
                prov_anqp = bss->anqp->hs20_osu_providers_list;
                if (prov_anqp == NULL)
                        continue;
+               ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+               if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &data) == 0 &&
+                   (data.key_mgmt & WPA_KEY_MGMT_OSEN)) {
+                       osu_ssid2 = bss->ssid;
+                       osu_ssid2_len = bss->ssid_len;
+               } else {
+                       osu_ssid2 = NULL;
+                       osu_ssid2_len = 0;
+               }
                wpa_printf(MSG_DEBUG, "HS 2.0: Parsing OSU Providers list from "
                           MACSTR, MAC2STR(bss->bssid));
                wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers list",
@@ -1043,7 +1126,8 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
                        if (len > (unsigned int) (end - pos))
                                break;
                        hs20_osu_add_prov(wpa_s, bss, osu_ssid,
-                                         osu_ssid_len, pos, len);
+                                         osu_ssid_len, osu_ssid2,
+                                         osu_ssid2_len, pos, len);
                        pos += len;
                }
 
@@ -1052,6 +1136,35 @@ void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s)
                                   "extra data after OSU Providers",
                                   (int) (end - pos));
                }
+
+               prov_anqp = bss->anqp->hs20_osu_providers_nai_list;
+               if (!prov_anqp)
+                       continue;
+               wpa_printf(MSG_DEBUG,
+                          "HS 2.0: Parsing OSU Providers NAI List from "
+                          MACSTR, MAC2STR(bss->bssid));
+               wpa_hexdump_buf(MSG_DEBUG, "HS 2.0: OSU Providers NAI List",
+                               prov_anqp);
+               pos = wpabuf_head(prov_anqp);
+               end = pos + wpabuf_len(prov_anqp);
+               num_providers = 0;
+               while (end - pos > 0) {
+                       len = *pos++;
+                       if (end - pos < len) {
+                               wpa_printf(MSG_DEBUG,
+                                          "HS 2.0: Not enough room for OSU_NAI");
+                               break;
+                       }
+                       if (num_providers >= wpa_s->osu_prov_count) {
+                               wpa_printf(MSG_DEBUG,
+                                          "HS 2.0: Ignore unexpected OSU Provider NAI List entries");
+                               break;
+                       }
+                       os_memcpy(wpa_s->osu_prov[num_providers].osu_nai2,
+                                 pos, len);
+                       pos += len;
+                       num_providers++;
+               }
        }
 
        wpa_s->fetch_osu_icon_in_progress = 1;
@@ -1076,7 +1189,7 @@ static void hs20_osu_scan_res_handler(struct wpa_supplicant *wpa_s,
 }
 
 
-int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
+int hs20_fetch_osu(struct wpa_supplicant *wpa_s, int skip_scan)
 {
        if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
                wpa_printf(MSG_DEBUG, "HS 2.0: Cannot start fetch_osu - "
@@ -1107,7 +1220,16 @@ int hs20_fetch_osu(struct wpa_supplicant *wpa_s)
        wpa_msg(wpa_s, MSG_INFO, "Starting OSU provisioning information fetch");
        wpa_s->num_osu_scans = 0;
        wpa_s->num_prov_found = 0;
-       hs20_start_osu_scan(wpa_s);
+       if (skip_scan) {
+               wpa_s->network_select = 0;
+               wpa_s->fetch_all_anqp = 1;
+               wpa_s->fetch_osu_info = 1;
+               wpa_s->fetch_osu_icon_in_progress = 0;
+
+               interworking_start_fetch_anqp(wpa_s);
+       } else {
+               hs20_start_osu_scan(wpa_s);
+       }
 
        return 0;
 }
@@ -1196,6 +1318,18 @@ void hs20_rx_deauth_imminent_notice(struct wpa_supplicant *wpa_s, u8 code,
 }
 
 
+void hs20_rx_t_c_acceptance(struct wpa_supplicant *wpa_s, const char *url)
+{
+       if (!wpa_sm_pmf_enabled(wpa_s->wpa)) {
+               wpa_printf(MSG_DEBUG,
+                          "HS 2.0: Ignore Terms and Conditions Acceptance since PMF was not enabled");
+               return;
+       }
+
+       wpa_msg(wpa_s, MSG_INFO, HS20_T_C_ACCEPTANCE "%s", url);
+}
+
+
 void hs20_init(struct wpa_supplicant *wpa_s)
 {
        dl_list_init(&wpa_s->icon_head);