]> git.ipfire.org Git - thirdparty/hostap.git/blobdiff - wpa_supplicant/hs20_supplicant.c
OCE: Mandate PMF for WPA2 association with OCE AP
[thirdparty/hostap.git] / wpa_supplicant / hs20_supplicant.c
index b02923964d594cc00308689bb4d455a0f3e60265..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);
@@ -134,6 +143,21 @@ void wpas_hs20_add_roam_cons_sel(struct wpabuf *buf,
 }
 
 
+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)
 {
@@ -407,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);
        }
@@ -671,6 +695,15 @@ void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
                                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;
@@ -750,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,
@@ -815,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;
@@ -836,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) {
@@ -1017,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",
@@ -1070,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;
                }
 
@@ -1079,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;