void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable) { const u8 *ie; struct wpa_bss *bss = wpa_s->current_bss; struct wpa_ssid *ssid = wpa_s->current_ssid; struct hostapd_hw_modes *hw_mode = NULL; int i; eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL); wpa_s->sme.sched_obss_scan = 0; if (!enable) return; if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) || ssid == NULL || ssid->mode != IEEE80211_MODE_INFRA) return; /* Not using station SME in wpa_supplicant */ if (!wpa_s->hw.modes) return; /* only HT caps in 11g mode are relevant */ for (i = 0; i < wpa_s->hw.num_modes; i++) { hw_mode = &wpa_s->hw.modes[i]; if (hw_mode->mode == HOSTAPD_MODE_IEEE80211G) break; } /* Driver does not support HT40 for 11g or doesn't have 11g. */ if (i == wpa_s->hw.num_modes || !hw_mode || !(hw_mode->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) return; if (bss == NULL || bss->freq < 2400 || bss->freq > 2500) return; /* Not associated on 2.4 GHz band */ /* Check whether AP supports HT40 */ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_CAP); if (!ie || ie[1] < 2 || !(WPA_GET_LE16(ie + 2) & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) return; /* AP does not support HT40 */ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS); if (!ie || ie[1] < 14) return; /* AP does not request OBSS scans */ wpa_s->sme.obss_scan_int = WPA_GET_LE16(ie + 6); if (wpa_s->sme.obss_scan_int < 10) { wpa_printf(MSG_DEBUG, "SME: Invalid OBSS Scan Interval %u " "replaced with the minimum 10 sec", wpa_s->sme.obss_scan_int); wpa_s->sme.obss_scan_int = 10; } wpa_printf(MSG_DEBUG, "SME: OBSS Scan Interval %u sec", wpa_s->sme.obss_scan_int); eloop_register_timeout(wpa_s->sme.obss_scan_int, 0, sme_obss_scan_timeout, wpa_s, NULL); }
static void rx_data_tdls_teardown(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr, const u8 *dst, const u8 *src, const u8 *data, size_t len) { u16 reason; struct ieee802_11_elems elems; struct wlantest_tdls *tdls; if (len < 2) return; reason = WPA_GET_LE16(data); wpa_printf(MSG_DEBUG, "TDLS Teardown " MACSTR " -> " MACSTR " (reason %d)", MAC2STR(src), MAC2STR(dst), reason); if (ieee802_11_parse_elems(data + 2, len - 2, &elems, 1) == ParseFailed || elems.link_id == NULL) return; wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR " initiator STA " MACSTR " responder STA " MACSTR, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); tdls = get_tdls(wt, elems.link_id, 1, bssid); if (tdls) { if (tdls->link_up) add_note(wt, MSG_DEBUG, "TDLS: Link down"); tdls->link_up = 0; tdls->counters[WLANTEST_TDLS_COUNTER_TEARDOWN]++; tdls_verify_mic_teardown(wt, tdls, 4, data, &elems); } }
/** * p2p_parse_p2p_ie - Parse P2P IE * @buf: Concatenated P2P IE(s) payload * @msg: Buffer for returning parsed attributes * Returns: 0 on success, -1 on failure * * Note: Caller is responsible for clearing the msg data structure before * calling this function. */ int p2p_parse_p2p_ie(const struct wpabuf *buf, struct p2p_message *msg) { const u8 *pos = wpabuf_head_u8(buf); const u8 *end = pos + wpabuf_len(buf); wpa_printf(MSG_DEBUG, "P2P: Parsing P2P IE"); while (pos < end) { u16 attr_len; if (pos + 2 >= end) { wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute"); return -1; } attr_len = WPA_GET_LE16(pos + 1); wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u", pos[0], attr_len); if (pos + 3 + attr_len > end) { wpa_printf(MSG_DEBUG, "P2P: Attribute underflow " "(len=%u left=%d)", attr_len, (int) (end - pos - 3)); wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos); return -1; } if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg)) return -1; pos += 3 + attr_len; } return 0; }
void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token, enum gas_query_result result, const struct wpabuf *adv_proto, const struct wpabuf *resp, u16 status_code) { struct wpa_supplicant *wpa_s = ctx; const u8 *pos; const u8 *end; u16 info_id; u16 slen; if (result != GAS_QUERY_SUCCESS) return; pos = wpabuf_head(adv_proto); if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO || pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) { wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement " "Protocol in response"); return; } pos = wpabuf_head(resp); end = pos + wpabuf_len(resp); while (pos < end) { if (pos + 4 > end) { wpa_printf(MSG_DEBUG, "ANQP: Invalid element"); break; } info_id = WPA_GET_LE16(pos); pos += 2; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end) { wpa_printf(MSG_DEBUG, "ANQP: Invalid element length " "for Info ID %u", info_id); break; } interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos, slen); pos += slen; } }
static void rx_anqp_query_list(struct hostapd_data *hapd, const u8 *pos, const u8 *end, struct anqp_query_info *qi) { wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list", (unsigned int) (end - pos) / 2); while (pos + 2 <= end) { rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi); pos += 2; } }
static int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie) { #ifdef CONFIG_IEEE80211W if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) return 0; if (ie->igtk) { const struct wpa_igtk_kde *igtk; u16 keyidx; if (ie->igtk_len != sizeof(*igtk)) return -1; igtk = (const struct wpa_igtk_kde *) ie->igtk; keyidx = WPA_GET_LE16(igtk->keyid); lwip_log("WPA: IGTK keyid %d pn %02x%02x%02x%02x%02x%02x\n", keyidx, MAC2STR(igtk->pn)); wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, WPA_IGTK_LEN); if (keyidx > 4095) { lwip_log("WPA: Invalid IGTK KeyID %d\n", keyidx); return -1; } if (wpa_sm_set_key(sm, WPA_ALG_IGTK, (u8 *) "\xff\xff\xff\xff\xff\xff", keyidx, 0, igtk->pn, sizeof(igtk->pn), igtk->igtk, WPA_IGTK_LEN) < 0) { lwip_log("WPA: Failed to configure IGTK to the driver\n"); return -1; } } if (ie->dhv) { const struct wpa_dhv_kde *dhv; if (ie->dhv_len != sizeof(*dhv)) return -1; dhv = (const struct wpa_dhv_kde *) ie->dhv; wpa_hexdump_key(MSG_DEBUG, "WPA: DHV", dhv->dhv, WPA_DHV_LEN); if (wpa_sm_set_key(sm, WPA_ALG_DHV, (u8 *) "\xff\xff\xff\xff\xff\xff", 0, 0, NULL, 0, dhv->dhv, WPA_DHV_LEN) < 0) { lwip_log("WPA: Failed to configure DHV to the driver\n"); return -1; } } return 0; #else /* CONFIG_IEEE80211W */ return 0; #endif /* CONFIG_IEEE80211W */ }
static int wpa_ft_process_igtk_subelem(struct wpa_sm *sm, const u8 *igtk_elem, size_t igtk_elem_len) { u8 igtk[WPA_IGTK_LEN]; u16 keyidx; if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) return 0; if (igtk_elem == NULL) { wpa_printf(MSG_DEBUG, "FT: No IGTK included in FTIE"); return 0; } wpa_hexdump_key(MSG_DEBUG, "FT: Received IGTK in Reassoc Resp", igtk_elem, igtk_elem_len); if (igtk_elem_len != 2 + 6 + 1 + WPA_IGTK_LEN + 8) { wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem " "length %lu", (unsigned long) igtk_elem_len); return -1; } if (igtk_elem[8] != WPA_IGTK_LEN) { wpa_printf(MSG_DEBUG, "FT: Invalid IGTK sub-elem Key Length " "%d", igtk_elem[8]); return -1; } if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, WPA_IGTK_LEN / 8, igtk_elem + 9, igtk)) { wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " "decrypt IGTK"); return -1; } /* KeyID[2] | IPN[6] | Key Length[1] | Key[16+8] */ keyidx = WPA_GET_LE16(igtk_elem); wpa_hexdump_key(MSG_DEBUG, "FT: IGTK from Reassoc Resp", igtk, WPA_IGTK_LEN); if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr, keyidx, 0, igtk_elem + 2, 6, igtk, WPA_IGTK_LEN) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set IGTK to the " "driver."); return -1; } return 0; }
static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data, size_t len) { const u8 *sta_addr, *target_ap_addr; u16 status; wpa_hexdump(MSG_MSGDUMP, "FT: RX Action", data, len); if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) return; /* only SME case supported for now */ if (len < 1 + 2 * ETH_ALEN + 2) return; if (data[0] != 2) return; /* Only FT Action Response is supported for now */ sta_addr = data + 1; target_ap_addr = data + 1 + ETH_ALEN; status = WPA_GET_LE16(data + 1 + 2 * ETH_ALEN); wpa_printf(MSG_DEBUG, "FT: Received FT Action Response: STA " MACSTR " TargetAP " MACSTR " status %u", MAC2STR(sta_addr), MAC2STR(target_ap_addr), status); if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "FT: Foreign STA Address " MACSTR " in FT Action Response", MAC2STR(sta_addr)); return; } if (status) { wpa_printf(MSG_DEBUG, "FT: FT Action Response indicates " "failure (status code %d)", status); /* TODO: report error to FT code(?) */ return; } if (wpa_ft_process_response(wpa_s->wpa, data + 1 + 2 * ETH_ALEN + 2, len - (1 + 2 * ETH_ALEN + 2), 1, target_ap_addr, NULL, 0) < 0) return; #ifdef CONFIG_SME { struct wpa_bss *bss; bss = wpa_bss_get_bssid(wpa_s, target_ap_addr); if (bss) wpa_s->sme.freq = bss->freq; wpa_s->sme.auth_alg = WPA_AUTH_ALG_FT; sme_associate(wpa_s, WPAS_MODE_INFRA, target_ap_addr, WLAN_AUTH_FT); } #endif /* CONFIG_SME */ }
/* * MIC Calculation / Verification * * for WPA * MICAP = HMAC-MD5(PTK-802.1X-MIC-Key , STA-ID | RSNIEAP | RN | * KeyIDunicast | KeyIDmulticast | RSC | MulticastKeyLength | EGTK) * * for WPA2 * MICAP = HMAC-SHA1(PTK-802.1X-MIC-Key , STA-ID | RSNIEAP | RN | * KeyIDunicast | KeyIDmulticast | RSC | MulticastKeyLength | EGTK) */ static int cckm_verify_mic(struct wpa_sm *sm, struct cckm_ie_rsp *cie, u8* kck) { u8 data[128]; u8 mic[32]; u32 data_len = ETH_ALEN; os_memcpy(data, sm->own_addr, ETH_ALEN); if (sm->ap_rsn_ie && sm->ap_rsn_ie_len) { os_memcpy(data+data_len, sm->ap_rsn_ie, sm->ap_rsn_ie_len); data_len += sm->ap_rsn_ie_len; } else if (sm->ap_wpa_ie && sm->ap_wpa_ie_len) { os_memcpy(data+data_len, sm->ap_wpa_ie, sm->ap_wpa_ie_len); data_len += sm->ap_wpa_ie_len; } else if (sm->assoc_wpa_ie && sm->assoc_wpa_ie_len) { os_memcpy(data + data_len, sm->assoc_wpa_ie, sm->assoc_wpa_ie_len); data_len += sm->assoc_wpa_ie_len; } os_memcpy(data+data_len, cie->rn, 4); data_len += 4; os_memcpy(data+data_len, &cie->unicast_keyid, 12); data_len += 12; os_memcpy(data+data_len, &cie->gtk, WPA_GET_LE16(cie->gtk_len)); data_len += WPA_GET_LE16(cie->gtk_len); if (sm->proto == WPA_PROTO_RSN) { hmac_sha1(kck, 16, data, data_len, mic); } else { hmac_md5(kck, 16, data, data_len, mic); } wpa_hexdump(MSG_DEBUG, "GTK MIC", mic, 8); wpa_hexdump(MSG_DEBUG, "RIE MIC", cie->ap_mic, 8); return os_memcmp(mic, cie->ap_mic, 8); }
int cckm_process_response (struct wpa_sm *sm, u8 *bssid) { struct wpa_ptk lptk; struct wpa_ptk *ptk = &lptk; u32 cckm_rn; struct cckm_ie_rsp *cie = (struct cckm_ie_rsp *)sm->cckm_resp_ie; u8 data[8]; /* Reject Non-CCKM IEs */ if ((cie->elem_id != WLAN_EID_CCKM) || (os_memcmp(cie->oui, "\x00\x40\x96\x00", sizeof(cie->oui)) != 0)) { return -1; } /* Derive PTK from BTK and RN */ cckm_rn = WPA_GET_LE32(cie->rn); wpa_btk_to_ptk(sm->cgk.btk, sizeof(sm->cgk.btk), bssid, cckm_rn, (u8 *)ptk, sizeof(struct wpa_ptk)); if (cckm_verify_mic(sm, cie, ptk->kck)) { wpa_printf(MSG_WARNING, "CCKM Reassociation Response - " "MIC Failure\n"); return -1; } if (sm->pairwise_cipher == WPA_CIPHER_TKIP) { /* Supplicant: swap tx/rx Mic keys */ os_memcpy(data, ptk->u.auth.tx_mic_key, 8); os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8); os_memcpy(ptk->u.auth.rx_mic_key, data, 8); } /* MIC verification successful, store and install PTK */ os_memcpy (&sm->ptk, ptk, sizeof(struct wpa_ptk)); cckm_install_ptk(sm); /* Install GTK */ cckm_install_gtk(sm, cckm_rn, cie->gtk, WPA_GET_LE16(cie->gtk_len), cie->mcast_keyid, cie->rsc, 6); wpa_printf(MSG_INFO, "CCKM-FAST-ROAMING Connection to " MACSTR " Completed", MAC2STR(bssid)); return 0; }
static int ieee80211w_set_keys(struct wpa_sm *sm, struct wpa_eapol_ie_parse *ie) { #ifdef CONFIG_IEEE80211W if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) return 0; if (ie->igtk) { const struct wpa_igtk_kde *igtk; u16 keyidx; if (ie->igtk_len != sizeof(*igtk)) return -1; igtk = (const struct wpa_igtk_kde *) ie->igtk; keyidx = WPA_GET_LE16(igtk->keyid); wpa_printf(MSG_DEBUG, "WPA: IGTK keyid %d " "pn %02x%02x%02x%02x%02x%02x", keyidx, MAC2STR(igtk->pn)); wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK", igtk->igtk, WPA_IGTK_LEN); if (keyidx > 4095) { wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KeyID %d", keyidx); return -1; } if (wpa_sm_set_key(sm, WPA_ALG_IGTK, (u8 *) "\xff\xff\xff\xff\xff\xff", keyidx, 0, igtk->pn, sizeof(igtk->pn), igtk->igtk, WPA_IGTK_LEN) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to configure IGTK" " to the driver"); return -1; } } return 0; #else /* CONFIG_IEEE80211W */ return 0; #endif /* CONFIG_IEEE80211W */ }
static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count) { struct nai_realm *realm; const u8 *pos, *end; u16 i, num; if (anqp == NULL || wpabuf_len(anqp) < 2) return NULL; pos = wpabuf_head_u8(anqp); end = pos + wpabuf_len(anqp); num = WPA_GET_LE16(pos); wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num); pos += 2; if (num * 5 > end - pos) { wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not " "enough data (%u octets) for that many realms", num, (unsigned int) (end - pos)); return NULL; } realm = os_zalloc(num * sizeof(struct nai_realm)); if (realm == NULL) return NULL; for (i = 0; i < num; i++) { pos = nai_realm_parse_realm(&realm[i], pos, end); if (pos == NULL) { nai_realm_free(realm, num); return NULL; } } *count = num; return realm; }
int sme_proc_obss_scan(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; const u8 *ie; u16 ht_cap; u8 chan_list[P2P_MAX_CHANNELS], channel; u8 num_channels = 0, num_intol = 0, i; if (!wpa_s->sme.sched_obss_scan) return 0; wpa_s->sme.sched_obss_scan = 0; if (!wpa_s->current_bss || wpa_s->wpa_state != WPA_COMPLETED) return 1; /* * Check whether AP uses regulatory triplet or channel triplet in * country info. Right now the operating class of the BSS channel * width trigger event is "unknown" (IEEE Std 802.11-2012 10.15.12), * based on the assumption that operating class triplet is not used in * beacon frame. If the First Channel Number/Operating Extension * Identifier octet has a positive integer value of 201 or greater, * then its operating class triplet. * * TODO: If Supported Operating Classes element is present in beacon * frame, have to lookup operating class in Annex E and fill them in * 2040 coex frame. */ ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_COUNTRY); if (ie && (ie[1] >= 6) && (ie[5] >= 201)) return 1; os_memset(chan_list, 0, sizeof(chan_list)); dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { /* Skip other band bss */ if (freq_to_channel(bss->freq, &channel) != WPAS_BAND_2GHZ) continue; ie = wpa_bss_get_ie(bss, WLAN_EID_HT_CAP); ht_cap = (ie && (ie[1] == 26)) ? WPA_GET_LE16(ie + 2) : 0; if (!ht_cap || (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT)) { /* Check whether the channel is already considered */ for (i = 0; i < num_channels; i++) { if (channel == chan_list[i]) break; } if (i != num_channels) continue; if (ht_cap & HT_CAP_INFO_40MHZ_INTOLERANT) num_intol++; chan_list[num_channels++] = channel; } } sme_send_2040_bss_coex(wpa_s, chan_list, num_channels, num_intol); return 1; }
static int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len, struct wpa_ie_data *data) { const struct wpa_ie_hdr *hdr; const u8 *pos; int left; int i, count; os_memset(data, 0, sizeof(*data)); data->proto = WPA_PROTO_WPA; data->pairwise_cipher = WPA_CIPHER_TKIP; data->group_cipher = WPA_CIPHER_TKIP; data->key_mgmt = WPA_KEY_MGMT_IEEE8021X; data->capabilities = 0; data->pmkid = NULL; data->num_pmkid = 0; data->mgmt_group_cipher = 0; if (wpa_ie_len == 0) { /* No WPA IE - fail silently */ return -1; } if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) { wpa_printf(MSG_DEBUG, "%s: ie len too short %lu", __func__, (unsigned long) wpa_ie_len); return -1; } hdr = (const struct wpa_ie_hdr *) wpa_ie; if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC || hdr->len != wpa_ie_len - 2 || RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE || WPA_GET_LE16(hdr->version) != WPA_VERSION) { wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version", __func__); return -1; } pos = (const u8 *) (hdr + 1); left = wpa_ie_len - sizeof(*hdr); if (left >= WPA_SELECTOR_LEN) { data->group_cipher = wpa_selector_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } else if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much", __func__, left); return -1; } if (left >= 2) { data->pairwise_cipher = 0; count = WPA_GET_LE16(pos); pos += 2; left -= 2; if (count == 0 || left < count * WPA_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), " "count %u left %u", __func__, count, left); return -1; } for (i = 0; i < count; i++) { data->pairwise_cipher |= wpa_selector_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)", __func__); return -1; } if (left >= 2) { data->key_mgmt = 0; count = WPA_GET_LE16(pos); pos += 2; left -= 2; if (count == 0 || left < count * WPA_SELECTOR_LEN) { wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), " "count %u left %u", __func__, count, left); return -1; } for (i = 0; i < count; i++) { data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos); pos += WPA_SELECTOR_LEN; left -= WPA_SELECTOR_LEN; } } else if (left == 1) { wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)", __func__); return -1; } if (left >= 2) { data->capabilities = WPA_GET_LE16(pos); pos += 2; left -= 2; } if (left > 0) { wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored", __func__, left); } return 0; }
static int wpa_ft_process_gtk_subelem(struct wpa_sm *sm, const u8 *gtk_elem, size_t gtk_elem_len) { u8 gtk[32]; int keyidx; enum wpa_alg alg; size_t gtk_len, keylen, rsc_len; if (gtk_elem == NULL) { wpa_printf(MSG_DEBUG, "FT: No GTK included in FTIE"); return 0; } wpa_hexdump_key(MSG_DEBUG, "FT: Received GTK in Reassoc Resp", gtk_elem, gtk_elem_len); if (gtk_elem_len < 11 + 24 || (gtk_elem_len - 11) % 8 || gtk_elem_len - 19 > sizeof(gtk)) { wpa_printf(MSG_DEBUG, "FT: Invalid GTK sub-elem " "length %lu", (unsigned long) gtk_elem_len); return -1; } gtk_len = gtk_elem_len - 19; if (aes_unwrap(sm->ptk.kek, sm->ptk.kek_len, gtk_len / 8, gtk_elem + 11, gtk)) { wpa_printf(MSG_WARNING, "FT: AES unwrap failed - could not " "decrypt GTK"); return -1; } keylen = wpa_cipher_key_len(sm->group_cipher); rsc_len = wpa_cipher_rsc_len(sm->group_cipher); alg = wpa_cipher_to_alg(sm->group_cipher); if (alg == WPA_ALG_NONE) { wpa_printf(MSG_WARNING, "WPA: Unsupported Group Cipher %d", sm->group_cipher); return -1; } if (gtk_len < keylen) { wpa_printf(MSG_DEBUG, "FT: Too short GTK in FTIE"); return -1; } /* Key Info[2] | Key Length[1] | RSC[8] | Key[5..32]. */ keyidx = WPA_GET_LE16(gtk_elem) & 0x03; if (gtk_elem[2] != keylen) { wpa_printf(MSG_DEBUG, "FT: GTK length mismatch: received %d " "negotiated %lu", gtk_elem[2], (unsigned long) keylen); return -1; } wpa_hexdump_key(MSG_DEBUG, "FT: GTK from Reassoc Resp", gtk, keylen); if (sm->group_cipher == WPA_CIPHER_TKIP) { /* Swap Tx/Rx keys for Michael MIC */ u8 tmp[8]; os_memcpy(tmp, gtk + 16, 8); os_memcpy(gtk + 16, gtk + 24, 8); os_memcpy(gtk + 24, tmp, 8); } if (wpa_sm_set_key(sm, alg, broadcast_ether_addr, keyidx, 0, gtk_elem + 3, rsc_len, gtk, keylen) < 0) { wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the " "driver."); return -1; } return 0; }
static void learn_kde_keys(struct wlantest_bss *bss, const u8 *buf, size_t len, const u8 *rsc) { struct wpa_eapol_ie_parse ie; if (wpa_supplicant_parse_ies(buf, len, &ie) < 0) { wpa_printf(MSG_INFO, "Failed to parse EAPOL-Key Key Data"); return; } if (ie.wpa_ie) { wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - WPA IE", ie.wpa_ie, ie.wpa_ie_len); } if (ie.rsn_ie) { wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - RSN IE", ie.rsn_ie, ie.rsn_ie_len); } if (ie.gtk) { wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - GTK KDE", ie.gtk, ie.gtk_len); if (ie.gtk_len >= 2 && ie.gtk_len <= 2 + 32) { int id; id = ie.gtk[0] & 0x03; wpa_printf(MSG_DEBUG, "GTK KeyID=%u tx=%u", id, !!(ie.gtk[0] & 0x04)); if ((ie.gtk[0] & 0xf8) || ie.gtk[1]) wpa_printf(MSG_INFO, "GTK KDE: Reserved field " "set: %02x %02x", ie.gtk[0], ie.gtk[1]); wpa_hexdump(MSG_DEBUG, "GTK", ie.gtk + 2, ie.gtk_len - 2); bss->gtk_len[id] = ie.gtk_len - 2; os_memcpy(bss->gtk[id], ie.gtk + 2, ie.gtk_len - 2); bss->rsc[id][0] = rsc[5]; bss->rsc[id][1] = rsc[4]; bss->rsc[id][2] = rsc[3]; bss->rsc[id][3] = rsc[2]; bss->rsc[id][4] = rsc[1]; bss->rsc[id][5] = rsc[0]; bss->gtk_idx = id; wpa_hexdump(MSG_DEBUG, "RSC", bss->rsc[id], 6); } else { wpa_printf(MSG_INFO, "Invalid GTK KDE length %u", (unsigned) ie.gtk_len); } } if (ie.igtk) { wpa_hexdump(MSG_MSGDUMP, "EAPOL-Key Key Data - IGTK KDE", ie.igtk, ie.igtk_len); if (ie.igtk_len == 24) { u16 id; id = WPA_GET_LE16(ie.igtk); if (id > 5) { wpa_printf(MSG_INFO, "Unexpected IGTK KeyID " "%u", id); } else { const u8 *ipn; wpa_printf(MSG_DEBUG, "IGTK KeyID %u", id); wpa_hexdump(MSG_DEBUG, "IPN", ie.igtk + 2, 6); wpa_hexdump(MSG_DEBUG, "IGTK", ie.igtk + 8, 16); os_memcpy(bss->igtk[id], ie.igtk + 8, 16); bss->igtk_set[id] = 1; ipn = ie.igtk + 2; bss->ipn[id][0] = ipn[5]; bss->ipn[id][1] = ipn[4]; bss->ipn[id][2] = ipn[3]; bss->ipn[id][3] = ipn[2]; bss->ipn[id][4] = ipn[1]; bss->ipn[id][5] = ipn[0]; bss->igtk_idx = id; } } else { wpa_printf(MSG_INFO, "Invalid IGTK KDE length %u", (unsigned) ie.igtk_len); } } }
static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction, u16 status_code, const u8 *data, size_t len) { int *groups; wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u " "status code %u", auth_transaction, status_code); if (auth_transaction == 1 && status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ && wpa_s->sme.sae.state == SAE_COMMITTED && wpa_s->current_bss && wpa_s->current_ssid) { int default_groups[] = { 19, 20, 21, 25, 26, 0 }; u16 group; groups = wpa_s->conf->sae_groups; if (!groups || groups[0] <= 0) groups = default_groups; if (len < sizeof(le16)) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: Too short SAE anti-clogging token request"); return -1; } group = WPA_GET_LE16(data); wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE anti-clogging token requested (group %u)", group); if (sae_group_allowed(&wpa_s->sme.sae, groups, group) != WLAN_STATUS_SUCCESS) { wpa_dbg(wpa_s, MSG_ERROR, "SME: SAE group %u of anti-clogging request is invalid", group); return -1; } wpabuf_free(wpa_s->sme.sae_token); wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16), len - sizeof(le16)); sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 1); return 0; } if (auth_transaction == 1 && status_code == WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED && wpa_s->sme.sae.state == SAE_COMMITTED && wpa_s->current_bss && wpa_s->current_ssid) { wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE group not supported"); wpa_s->sme.sae_group_index++; if (sme_set_sae_group(wpa_s) < 0) return -1; /* no other groups enabled */ wpa_dbg(wpa_s, MSG_DEBUG, "SME: Try next enabled SAE group"); sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 1); return 0; } if (status_code != WLAN_STATUS_SUCCESS) return -1; if (auth_transaction == 1) { groups = wpa_s->conf->sae_groups; wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit"); if (wpa_s->current_bss == NULL || wpa_s->current_ssid == NULL) return -1; if (wpa_s->sme.sae.state != SAE_COMMITTED) return -1; if (groups && groups[0] <= 0) groups = NULL; if (sae_parse_commit(&wpa_s->sme.sae, data, len, NULL, NULL, groups) != WLAN_STATUS_SUCCESS) return -1; if (sae_process_commit(&wpa_s->sme.sae) < 0) { wpa_printf(MSG_DEBUG, "SAE: Failed to process peer " "commit"); return -1; } wpabuf_free(wpa_s->sme.sae_token); wpa_s->sme.sae_token = NULL; sme_send_authentication(wpa_s, wpa_s->current_bss, wpa_s->current_ssid, 0); return 0; } else if (auth_transaction == 2) { wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE confirm"); if (wpa_s->sme.sae.state != SAE_CONFIRMED) return -1; if (sae_check_confirm(&wpa_s->sme.sae, data, len) < 0) return -1; wpa_s->sme.sae.state = SAE_ACCEPTED; sae_clear_temp_data(&wpa_s->sme.sae); return 1; } return -1; }
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 *pos, size_t len) { struct osu_provider *prov; const u8 *end = pos + len; u16 len2; const u8 *pos2; u8 uri_len, osu_method_len, osu_nai_len; wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len); prov = os_realloc_array(wpa_s->osu_prov, wpa_s->osu_prov_count + 1, sizeof(*prov)); if (prov == NULL) return; wpa_s->osu_prov = prov; prov = &prov[wpa_s->osu_prov_count]; os_memset(prov, 0, sizeof(*prov)); 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; /* OSU Friendly Name Length */ if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " "Friendly Name Length"); return; } len2 = WPA_GET_LE16(pos); pos += 2; if (len2 > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " "Friendly Name Duples"); return; } pos2 = pos; pos += len2; /* OSU Friendly Name Duples */ while (pos - pos2 >= 4 && prov->friendly_name_count < OSU_MAX_ITEMS) { struct osu_lang_string *f; if (1 + pos2[0] > pos - pos2 || pos2[0] < 3) { wpa_printf(MSG_DEBUG, "Invalid OSU Friendly Name"); break; } f = &prov->friendly_name[prov->friendly_name_count++]; os_memcpy(f->lang, pos2 + 1, 3); os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3); pos2 += 1 + pos2[0]; } /* OSU Server URI */ if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server URI length"); return; } uri_len = *pos++; if (uri_len > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server " "URI"); return; } os_memcpy(prov->server_uri, pos, uri_len); pos += uri_len; /* OSU Method list */ if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method " "list length"); return; } osu_method_len = pos[0]; if (osu_method_len > end - pos - 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method " "list"); return; } pos2 = pos + 1; pos += 1 + osu_method_len; while (pos2 < pos) { if (*pos2 < 32) prov->osu_methods |= BIT(*pos2); pos2++; } /* Icons Available Length */ if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons " "Available Length"); return; } len2 = WPA_GET_LE16(pos); pos += 2; if (len2 > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons " "Available"); return; } pos2 = pos; pos += len2; /* Icons Available */ while (pos2 < pos) { struct osu_icon *icon = &prov->icon[prov->icon_count]; u8 flen; if (2 + 2 + 3 + 1 + 1 > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata"); break; } icon->width = WPA_GET_LE16(pos2); pos2 += 2; icon->height = WPA_GET_LE16(pos2); pos2 += 2; os_memcpy(icon->lang, pos2, 3); pos2 += 3; flen = *pos2++; if (flen > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type"); break; } os_memcpy(icon->icon_type, pos2, flen); pos2 += flen; if (pos - pos2 < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon " "Filename length"); break; } flen = *pos2++; if (flen > pos - pos2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon " "Filename"); break; } os_memcpy(icon->filename, pos2, flen); pos2 += flen; prov->icon_count++; } /* OSU_NAI */ if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI"); return; } osu_nai_len = *pos++; if (osu_nai_len > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI"); return; } os_memcpy(prov->osu_nai, pos, osu_nai_len); pos += osu_nai_len; /* OSU Service Description Length */ if (end - pos < 2) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " "Service Description Length"); return; } len2 = WPA_GET_LE16(pos); pos += 2; if (len2 > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU " "Service Description Duples"); return; } pos2 = pos; pos += len2; /* OSU Service Description Duples */ while (pos - pos2 >= 4 && prov->serv_desc_count < OSU_MAX_ITEMS) { struct osu_lang_string *f; u8 descr_len; descr_len = *pos2++; if (descr_len > pos - pos2 || descr_len < 3) { wpa_printf(MSG_DEBUG, "Invalid OSU Service " "Description"); break; } f = &prov->serv_desc[prov->serv_desc_count++]; os_memcpy(f->lang, pos2, 3); os_memcpy(f->text, pos2 + 3, descr_len - 3); pos2 += descr_len; } wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR, MAC2STR(bss->bssid)); wpa_s->osu_prov_count++; }
void hs20_osu_icon_fetch(struct wpa_supplicant *wpa_s) { struct wpa_bss *bss; struct wpabuf *prov_anqp; const u8 *pos, *end; u16 len; const u8 *osu_ssid; u8 osu_ssid_len; u8 num_providers; hs20_free_osu_prov(wpa_s); dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) { if (bss->anqp == NULL) continue; prov_anqp = bss->anqp->hs20_osu_providers_list; if (prov_anqp == NULL) continue; 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", prov_anqp); pos = wpabuf_head(prov_anqp); end = pos + wpabuf_len(prov_anqp); /* OSU SSID */ if (end - pos < 1) continue; if (1 + pos[0] > end - pos) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for " "OSU SSID"); continue; } osu_ssid_len = *pos++; if (osu_ssid_len > SSID_MAX_LEN) { wpa_printf(MSG_DEBUG, "HS 2.0: Invalid OSU SSID " "Length %u", osu_ssid_len); continue; } osu_ssid = pos; pos += osu_ssid_len; if (end - pos < 1) { wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for " "Number of OSU Providers"); continue; } num_providers = *pos++; wpa_printf(MSG_DEBUG, "HS 2.0: Number of OSU Providers: %u", num_providers); /* OSU Providers */ while (end - pos > 2 && num_providers > 0) { num_providers--; len = WPA_GET_LE16(pos); pos += 2; if (len > (unsigned int) (end - pos)) break; hs20_osu_add_prov(wpa_s, bss, osu_ssid, osu_ssid_len, pos, len); pos += len; } if (pos != end) { wpa_printf(MSG_DEBUG, "HS 2.0: Ignored %d bytes of " "extra data after OSU Providers", (int) (end - pos)); } } wpa_s->fetch_osu_icon_in_progress = 1; hs20_next_osu_icon(wpa_s); }
static void wnm_parse_neighbor_report_elem(struct neighbor_report *rep, u8 id, u8 elen, const u8 *pos) { switch (id) { case WNM_NEIGHBOR_TSF: if (elen < 2 + 2) { wpa_printf(MSG_DEBUG, "WNM: Too short TSF"); break; } rep->tsf_offset = WPA_GET_LE16(pos); rep->beacon_int = WPA_GET_LE16(pos + 2); rep->tsf_present = 1; break; case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING: if (elen < 2) { wpa_printf(MSG_DEBUG, "WNM: Too short condensed " "country string"); break; } os_memcpy(rep->country, pos, 2); rep->country_present = 1; break; case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE: if (elen < 1) { wpa_printf(MSG_DEBUG, "WNM: Too short BSS transition " "candidate"); break; } rep->preference = pos[0]; rep->preference_present = 1; break; case WNM_NEIGHBOR_BSS_TERMINATION_DURATION: rep->bss_term_tsf = WPA_GET_LE64(pos); rep->bss_term_dur = WPA_GET_LE16(pos + 8); rep->bss_term_present = 1; break; case WNM_NEIGHBOR_BEARING: if (elen < 8) { wpa_printf(MSG_DEBUG, "WNM: Too short neighbor " "bearing"); break; } rep->bearing = WPA_GET_LE16(pos); rep->distance = WPA_GET_LE32(pos + 2); rep->rel_height = WPA_GET_LE16(pos + 2 + 4); rep->bearing_present = 1; break; case WNM_NEIGHBOR_MEASUREMENT_PILOT: if (elen < 1) { wpa_printf(MSG_DEBUG, "WNM: Too short measurement " "pilot"); break; } os_free(rep->meas_pilot); rep->meas_pilot = os_zalloc(sizeof(struct measurement_pilot)); if (rep->meas_pilot == NULL) break; rep->meas_pilot->measurement_pilot = pos[0]; rep->meas_pilot->subelem_len = elen - 1; os_memcpy(rep->meas_pilot->subelems, pos + 1, elen - 1); break; case WNM_NEIGHBOR_RRM_ENABLED_CAPABILITIES: if (elen < 5) { wpa_printf(MSG_DEBUG, "WNM: Too short RRM enabled " "capabilities"); break; } os_memcpy(rep->rm_capab, pos, 5); rep->rm_capab_present = 1; break; case WNM_NEIGHBOR_MULTIPLE_BSSID: if (elen < 1) { wpa_printf(MSG_DEBUG, "WNM: Too short multiple BSSID"); break; } os_free(rep->mul_bssid); rep->mul_bssid = os_zalloc(sizeof(struct multiple_bssid)); if (rep->mul_bssid == NULL) break; rep->mul_bssid->max_bssid_indicator = pos[0]; rep->mul_bssid->subelem_len = elen - 1; os_memcpy(rep->mul_bssid->subelems, pos + 1, elen - 1); break; } }
void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s, struct wpa_bss *bss, const u8 *sa, const u8 *data, size_t slen, u8 dialog_token) { const u8 *pos = data; u8 subtype; struct wpa_bss_anqp *anqp = NULL; int ret; if (slen < 2) return; if (bss) anqp = bss->anqp; subtype = *pos++; slen--; pos++; /* Reserved */ slen--; switch (subtype) { case HS20_STYPE_CAPABILITY_LIST: 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) { wpabuf_free(anqp->hs20_capability_list); anqp->hs20_capability_list = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_OPERATOR_FRIENDLY_NAME: 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) { wpabuf_free(anqp->hs20_operator_friendly_name); anqp->hs20_operator_friendly_name = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_WAN_METRICS: wpa_hexdump(MSG_DEBUG, "WAN Metrics", pos, slen); if (slen < 13) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short WAN " "Metrics value from " MACSTR, MAC2STR(sa)); break; } 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)); if (anqp) { wpabuf_free(anqp->hs20_wan_metrics); anqp->hs20_wan_metrics = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_CONNECTION_CAPABILITY: 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) { wpabuf_free(anqp->hs20_connection_capability); anqp->hs20_connection_capability = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_OPERATING_CLASS: 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) { wpabuf_free(anqp->hs20_operating_class); anqp->hs20_operating_class = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_OSU_PROVIDERS_LIST: wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP MACSTR " OSU Providers list", MAC2STR(sa)); wpa_s->num_prov_found++; if (anqp) { wpabuf_free(anqp->hs20_osu_providers_list); anqp->hs20_osu_providers_list = wpabuf_alloc_copy(pos, slen); } break; case HS20_STYPE_ICON_BINARY_FILE: ret = hs20_process_icon_binary_file(wpa_s, sa, pos, slen, dialog_token); if (wpa_s->fetch_osu_icon_in_progress) { hs20_osu_icon_fetch_result(wpa_s, ret); eloop_cancel_timeout(hs20_continue_icon_fetch, wpa_s, NULL); eloop_register_timeout(0, 0, hs20_continue_icon_fetch, wpa_s, NULL); } break; default: wpa_printf(MSG_DEBUG, "HS20: Unsupported subtype %u", subtype); break; } }
void p2p_rx_gas_initial_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 status_code; u16 comeback_delay; u16 slen; u16 update_indic; if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { p2p_dbg(p2p, "Ignore unexpected GAS Initial Response from " MACSTR, MAC2STR(sa)); return; } p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p_clear_timeout(p2p); p2p_dbg(p2p, "Received GAS Initial Response from " MACSTR " (len=%d)", MAC2STR(sa), (int) len); if (len < 5 + 2) { p2p_dbg(p2p, "Too short GAS Initial Response frame"); return; } dialog_token = *pos++; /* TODO: check dialog_token match */ status_code = WPA_GET_LE16(pos); pos += 2; comeback_delay = WPA_GET_LE16(pos); pos += 2; p2p_dbg(p2p, "dialog_token=%u status_code=%u comeback_delay=%u", dialog_token, status_code, comeback_delay); if (status_code) { p2p_dbg(p2p, "Service Discovery failed: status code %u", status_code); return; } if (*pos != WLAN_EID_ADV_PROTO) { p2p_dbg(p2p, "Unexpected IE in GAS Initial Response: %u", *pos); return; } pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { p2p_dbg(p2p, "Invalid IE in GAS Initial Response"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", *pos); return; } pos = next; /* Query Response */ if (pos + 2 > end) { p2p_dbg(p2p, "Too short Query Response"); return; } slen = WPA_GET_LE16(pos); pos += 2; p2p_dbg(p2p, "Query Response Length: %d", slen); if (pos + slen > end) { p2p_dbg(p2p, "Not enough Query Response data"); return; } end = pos + slen; if (comeback_delay) { p2p_dbg(p2p, "Fragmented response - request fragments"); if (p2p->sd_rx_resp) { p2p_dbg(p2p, "Drop old SD reassembly buffer"); wpabuf_free(p2p->sd_rx_resp); p2p->sd_rx_resp = NULL; } p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); return; } /* ANQP Query Response */ if (pos + 4 > end) return; if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end || slen < 3 + 1) { p2p_dbg(p2p, "Invalid ANQP Query Response length"); return; } if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) { p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x", WPA_GET_BE32(pos)); return; } pos += 4; if (pos + 2 > end) return; update_indic = WPA_GET_LE16(pos); p2p_dbg(p2p, "Service Update Indicator: %u", update_indic); pos += 2; p2p->sd_peer = NULL; if (p2p->sd_query) { if (!p2p->sd_query->for_all_peers) { struct p2p_sd_query *q; p2p_dbg(p2p, "Remove completed SD query %p", p2p->sd_query); q = p2p->sd_query; p2p_unlink_sd_query(p2p, p2p->sd_query); p2p_free_sd_query(q); } p2p->sd_query = NULL; } if (p2p->cfg->sd_response) p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, update_indic, pos, end - pos); p2p_continue_find(p2p); }
static int gas_server_rx_initial_req(struct gas_server *gas, const u8 *da, const u8 *sa, const u8 *bssid, int freq, u8 dialog_token, const u8 *data, size_t len) { const u8 *pos, *end, *adv_proto, *query_req; u8 adv_proto_len; u16 query_req_len; struct gas_server_handler *handler; struct wpabuf *resp; wpa_hexdump(MSG_MSGDUMP, "GAS: Received GAS Initial Request frame", data, len); pos = data; end = data + len; if (end - pos < 2 || pos[0] != WLAN_EID_ADV_PROTO) { wpa_printf(MSG_DEBUG, "GAS: No Advertisement Protocol element found"); return -1; } pos++; adv_proto_len = *pos++; if (end - pos < adv_proto_len || adv_proto_len < 2) { wpa_printf(MSG_DEBUG, "GAS: Truncated Advertisement Protocol element"); return -1; } adv_proto = pos; pos += adv_proto_len; wpa_hexdump(MSG_MSGDUMP, "GAS: Advertisement Protocol element", adv_proto, adv_proto_len); if (end - pos < 2) { wpa_printf(MSG_DEBUG, "GAS: No Query Request Length field"); return -1; } query_req_len = WPA_GET_LE16(pos); pos += 2; if (end - pos < query_req_len) { wpa_printf(MSG_DEBUG, "GAS: Truncated Query Request field"); return -1; } query_req = pos; pos += query_req_len; wpa_hexdump(MSG_MSGDUMP, "GAS: Query Request", query_req, query_req_len); if (pos < end) { wpa_hexdump(MSG_MSGDUMP, "GAS: Ignored extra data after Query Request field", pos, end - pos); } dl_list_for_each(handler, &gas->handlers, struct gas_server_handler, list) { if (adv_proto_len < 1 + handler->adv_proto_id_len || os_memcmp(adv_proto + 1, handler->adv_proto_id, handler->adv_proto_id_len) != 0) continue; wpa_printf(MSG_DEBUG, "GAS: Calling handler for the requested Advertisement Protocol ID"); resp = handler->req_cb(handler->ctx, sa, query_req, query_req_len); wpa_hexdump_buf(MSG_MSGDUMP, "GAS: Response from the handler", resp); gas_server_send_resp(gas, handler, sa, freq, dialog_token, resp); return 0; } wpa_printf(MSG_DEBUG, "GAS: No registered handler for the requested Advertisement Protocol ID"); return -1; }
int hostapd_ctrl_iface_status(struct hostapd_data *hapd, char *buf, size_t buflen) { struct hostapd_iface *iface = hapd->iface; struct hostapd_hw_modes *mode = iface->current_mode; int len = 0, ret, j; size_t i; ret = os_snprintf(buf + len, buflen - len, "state=%s\n" "phy=%s\n" "freq=%d\n" "num_sta_non_erp=%d\n" "num_sta_no_short_slot_time=%d\n" "num_sta_no_short_preamble=%d\n" "olbc=%d\n" "num_sta_ht_no_gf=%d\n" "num_sta_no_ht=%d\n" "num_sta_ht_20_mhz=%d\n" "num_sta_ht40_intolerant=%d\n" "olbc_ht=%d\n" "ht_op_mode=0x%x\n", hostapd_state_text(iface->state), iface->phy, iface->freq, iface->num_sta_non_erp, iface->num_sta_no_short_slot_time, iface->num_sta_no_short_preamble, iface->olbc, iface->num_sta_ht_no_gf, iface->num_sta_no_ht, iface->num_sta_ht_20mhz, iface->num_sta_ht40_intolerant, iface->olbc_ht, iface->ht_op_mode); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; if (!iface->cac_started || !iface->dfs_cac_ms) { ret = os_snprintf(buf + len, buflen - len, "cac_time_seconds=%d\n" "cac_time_left_seconds=N/A\n", iface->dfs_cac_ms / 1000); } else { /* CAC started and CAC time set - calculate remaining time */ struct os_reltime now; unsigned int left_time; os_reltime_age(&iface->dfs_cac_start, &now); left_time = iface->dfs_cac_ms / 1000 - now.sec; ret = os_snprintf(buf + len, buflen - len, "cac_time_seconds=%u\n" "cac_time_left_seconds=%u\n", iface->dfs_cac_ms / 1000, left_time); } if (os_snprintf_error(buflen - len, ret)) return len; len += ret; ret = os_snprintf(buf + len, buflen - len, "channel=%u\n" "secondary_channel=%d\n" "ieee80211n=%d\n" "ieee80211ac=%d\n" "beacon_int=%u\n" "dtim_period=%d\n", iface->conf->channel, iface->conf->ieee80211n && !hapd->conf->disable_11n ? iface->conf->secondary_channel : 0, iface->conf->ieee80211n && !hapd->conf->disable_11n, iface->conf->ieee80211ac && !hapd->conf->disable_11ac, iface->conf->beacon_int, hapd->conf->dtim_period); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac) { ret = os_snprintf(buf + len, buflen - len, "vht_oper_chwidth=%d\n" "vht_oper_centr_freq_seg0_idx=%d\n" "vht_oper_centr_freq_seg1_idx=%d\n" "vht_caps_info=%08x\n", iface->conf->vht_oper_chwidth, iface->conf->vht_oper_centr_freq_seg0_idx, iface->conf->vht_oper_centr_freq_seg1_idx, iface->conf->vht_capab); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; } if (iface->conf->ieee80211ac && !hapd->conf->disable_11ac && mode) { u16 rxmap = WPA_GET_LE16(&mode->vht_mcs_set[0]); u16 txmap = WPA_GET_LE16(&mode->vht_mcs_set[4]); ret = os_snprintf(buf + len, buflen - len, "rx_vht_mcs_map=%04x\n" "tx_vht_mcs_map=%04x\n", rxmap, txmap); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; } if (iface->conf->ieee80211n && !hapd->conf->disable_11n) { ret = os_snprintf(buf + len, buflen - len, "ht_caps_info=%04x\n", hapd->iconf->ht_capab); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; } if (iface->conf->ieee80211n && !hapd->conf->disable_11n && mode) { len = hostapd_write_ht_mcs_bitmask(buf, buflen, len, mode->mcs_set); } if (iface->current_rates && iface->num_rates) { ret = os_snprintf(buf + len, buflen - len, "supported_rates="); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; for (j = 0; j < iface->num_rates; j++) { ret = os_snprintf(buf + len, buflen - len, "%s%02x", j > 0 ? " " : "", iface->current_rates[j].rate / 5); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; } ret = os_snprintf(buf + len, buflen - len, "\n"); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; } for (j = 0; mode && j < mode->num_channels; j++) { if (mode->channels[j].freq == iface->freq) { ret = os_snprintf(buf + len, buflen - len, "max_txpower=%u\n", mode->channels[j].max_tx_power); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; break; } } for (i = 0; i < iface->num_bss; i++) { struct hostapd_data *bss = iface->bss[i]; ret = os_snprintf(buf + len, buflen - len, "bss[%d]=%s\n" "bssid[%d]=" MACSTR "\n" "ssid[%d]=%s\n" "num_sta[%d]=%d\n", (int) i, bss->conf->iface, (int) i, MAC2STR(bss->own_addr), (int) i, wpa_ssid_txt(bss->conf->ssid.ssid, bss->conf->ssid.ssid_len), (int) i, bss->num_sta); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; } if (hapd->conf->chan_util_avg_period) { ret = os_snprintf(buf + len, buflen - len, "chan_util_avg=%u\n", iface->chan_util_average); if (os_snprintf_error(buflen - len, ret)) return len; len += ret; } return len; }
static void rx_data_tdls_setup_confirm(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr, const u8 *dst, const u8 *src, const u8 *data, size_t len) { u16 status; struct ieee802_11_elems elems; struct wlantest_tdls *tdls; u8 link_id[3 * ETH_ALEN]; if (len < 3) { add_note(wt, MSG_INFO, "Too short TDLS Setup Confirm " MACSTR " -> " MACSTR, MAC2STR(src), MAC2STR(dst)); return; } status = WPA_GET_LE16(data); wpa_printf(MSG_DEBUG, "TDLS Setup Confirm " MACSTR " -> " MACSTR " (status %d)", MAC2STR(src), MAC2STR(dst), status); if (ieee802_11_parse_elems(data + 3, len - 3, &elems, 1) == ParseFailed || elems.link_id == NULL) { /* Need to match TDLS link based on Dialog Token */ rx_data_tdls_setup_confirm_failure(wt, bssid, src, data[2], status); return; } wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR " initiator STA " MACSTR " responder STA " MACSTR, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); tdls = get_tdls(wt, elems.link_id, 1, bssid); if (tdls == NULL) return; if (status) tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_CONF_FAIL]++; else tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_CONF_OK]++; if (status != WLAN_STATUS_SUCCESS) return; if (elems.ftie && elems.ftie_len >= sizeof(struct rsn_ftie)) { const struct rsn_ftie *f; f = (const struct rsn_ftie *) elems.ftie; if (os_memcmp(tdls->inonce, f->snonce, WPA_NONCE_LEN) != 0) { add_note(wt, MSG_INFO, "Mismatch in TDLS initiator " "nonce"); } if (os_memcmp(tdls->rnonce, f->anonce, WPA_NONCE_LEN) != 0) { add_note(wt, MSG_INFO, "Mismatch in TDLS responder " "nonce"); } } tdls->link_up = 1; if (tdls_derive_tpk(tdls, bssid, elems.ftie, elems.ftie_len) < 1) { if (elems.ftie == NULL) goto remove_reverse; return; } if (tdls_verify_mic(wt, tdls, 3, &elems) == 0) { tdls->dialog_token = data[2]; add_note(wt, MSG_DEBUG, "TDLS: Link up - Dialog Token: %u", tdls->dialog_token); } remove_reverse: /* * The TDLS link itself is bidirectional, but there is explicit * initiator/responder roles. Remove the other direction of the link * (if it exists) to make sure that the link counters are stored for * the current TDLS entery. */ os_memcpy(link_id, elems.link_id, ETH_ALEN); os_memcpy(link_id + ETH_ALEN, elems.link_id + 2 * ETH_ALEN, ETH_ALEN); os_memcpy(link_id + 2 * ETH_ALEN, elems.link_id + ETH_ALEN, ETH_ALEN); tdls = get_tdls(wt, link_id, 0, bssid); if (tdls) { add_note(wt, MSG_DEBUG, "TDLS: Remove reverse link entry"); tdls_deinit(tdls); } }
static void rx_data_tdls_setup_response(struct wlantest *wt, const u8 *bssid, const u8 *sta_addr, const u8 *dst, const u8 *src, const u8 *data, size_t len) { u16 status; struct ieee802_11_elems elems; struct wlantest_tdls *tdls; if (len < 3) { add_note(wt, MSG_INFO, "Too short TDLS Setup Response " MACSTR " -> " MACSTR, MAC2STR(src), MAC2STR(dst)); return; } status = WPA_GET_LE16(data); wpa_printf(MSG_DEBUG, "TDLS Setup Response " MACSTR " -> " MACSTR " (status %d)", MAC2STR(src), MAC2STR(dst), status); if (len < 5 && status == 0) { add_note(wt, MSG_INFO, "Too short TDLS Setup Response " MACSTR " -> " MACSTR, MAC2STR(src), MAC2STR(dst)); return; } if (len < 5 || ieee802_11_parse_elems(data + 5, len - 5, &elems, 1) == ParseFailed || elems.link_id == NULL) { /* Need to match TDLS link based on Dialog Token */ rx_data_tdls_setup_response_failure(wt, bssid, sta_addr, data[2], status); return; } wpa_printf(MSG_DEBUG, "TDLS Link Identifier: BSSID " MACSTR " initiator STA " MACSTR " responder STA " MACSTR, MAC2STR(elems.link_id), MAC2STR(elems.link_id + ETH_ALEN), MAC2STR(elems.link_id + 2 * ETH_ALEN)); tdls = get_tdls(wt, elems.link_id, 1, bssid); if (!tdls) { add_note(wt, MSG_INFO, "No match TDLS context found"); return; } if (status) tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_RESP_FAIL]++; else tdls->counters[WLANTEST_TDLS_COUNTER_SETUP_RESP_OK]++; if (status != WLAN_STATUS_SUCCESS) return; if (elems.ftie && elems.ftie_len >= sizeof(struct rsn_ftie)) { const struct rsn_ftie *f; f = (const struct rsn_ftie *) elems.ftie; if (os_memcmp(tdls->inonce, f->snonce, WPA_NONCE_LEN) != 0) { add_note(wt, MSG_INFO, "Mismatch in TDLS initiator " "nonce"); } os_memcpy(tdls->rnonce, f->anonce, WPA_NONCE_LEN); } if (tdls_derive_tpk(tdls, bssid, elems.ftie, elems.ftie_len) < 1) return; if (tdls_verify_mic(wt, tdls, 2, &elems) == 0) { tdls->dialog_token = data[2]; add_note(wt, MSG_DEBUG, "TDLS: Dialog Token for the link: %u", tdls->dialog_token); } }
void p2p_rx_gas_initial_req(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 slen; int freq; u16 update_indic; if (p2p->cfg->sd_request == NULL) return; if (rx_freq > 0) freq = rx_freq; else freq = p2p_channel_to_freq(p2p->cfg->reg_class, p2p->cfg->channel); if (freq < 0) return; if (len < 1 + 2) return; dialog_token = *pos++; p2p_dbg(p2p, "GAS Initial Request from " MACSTR " (dialog token %u, freq %d)", MAC2STR(sa), dialog_token, rx_freq); if (*pos != WLAN_EID_ADV_PROTO) { p2p_dbg(p2p, "Unexpected IE in GAS Initial Request: %u", *pos); return; } pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { p2p_dbg(p2p, "Invalid IE in GAS Initial Request"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", *pos); return; } pos = next; /* Query Request */ if (pos + 2 > end) return; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end) return; end = pos + slen; /* ANQP Query Request */ if (pos + 4 > end) return; if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end || slen < 3 + 1) { p2p_dbg(p2p, "Invalid ANQP Query Request length"); return; } if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) { p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x", WPA_GET_BE32(pos)); return; } pos += 4; if (pos + 2 > end) return; update_indic = WPA_GET_LE16(pos); p2p_dbg(p2p, "Service Update Indicator: %u", update_indic); pos += 2; p2p->cfg->sd_request(p2p->cfg->cb_ctx, freq, sa, dialog_token, update_indic, pos, end - pos); /* the response will be indicated with a call to p2p_sd_response() */ }
static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd, const u8 *sa, const u8 *data, size_t len) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 slen; struct anqp_query_info qi; const u8 *adv_proto; if (len < 1 + 2) return; os_memset(&qi, 0, sizeof(qi)); dialog_token = *pos++; wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: GAS Initial Request from " MACSTR " (dialog token %u) ", MAC2STR(sa), dialog_token); if (*pos != WLAN_EID_ADV_PROTO) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Unexpected IE in GAS Initial Request: %u", *pos); return; } adv_proto = pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Invalid IE in GAS Initial Request"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { struct wpabuf *buf; wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Unsupported GAS advertisement protocol id %u", *pos); if (sa[0] & 0x01) return; /* Invalid source address - drop silently */ buf = gas_build_initial_resp( dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED, 0, 2 + slen + 2); if (buf == NULL) return; wpabuf_put_data(buf, adv_proto, 2 + slen); wpabuf_put_le16(buf, 0); /* Query Response Length */ hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa, wpabuf_head(buf), wpabuf_len(buf)); wpabuf_free(buf); return; } pos = next; /* Query Request */ if (pos + 2 > end) return; slen = WPA_GET_LE16(pos); pos += 2; if (pos + slen > end) return; end = pos + slen; /* ANQP Query Request */ while (pos < end) { u16 info_id, elen; if (pos + 4 > end) return; info_id = WPA_GET_LE16(pos); pos += 2; elen = WPA_GET_LE16(pos); pos += 2; if (pos + elen > end) { wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request"); return; } switch (info_id) { case ANQP_QUERY_LIST: rx_anqp_query_list(hapd, pos, pos + elen, &qi); break; #ifdef CONFIG_HS20 case ANQP_VENDOR_SPECIFIC: rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi); break; #endif /* CONFIG_HS20 */ default: wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query " "Request element %u", info_id); break; } pos += elen; } gas_serv_req_local_processing(hapd, sa, dialog_token, &qi); }
void p2p_rx_gas_comeback_resp(struct p2p_data *p2p, const u8 *sa, const u8 *data, size_t len, int rx_freq) { const u8 *pos = data; const u8 *end = data + len; const u8 *next; u8 dialog_token; u16 status_code; u8 frag_id; u8 more_frags; u16 comeback_delay; u16 slen; wpa_hexdump(MSG_DEBUG, "P2P: RX GAS Comeback Response", data, len); if (p2p->state != P2P_SD_DURING_FIND || p2p->sd_peer == NULL || os_memcmp(sa, p2p->sd_peer->info.p2p_device_addr, ETH_ALEN) != 0) { p2p_dbg(p2p, "Ignore unexpected GAS Comeback Response from " MACSTR, MAC2STR(sa)); return; } p2p->cfg->send_action_done(p2p->cfg->cb_ctx); p2p_clear_timeout(p2p); p2p_dbg(p2p, "Received GAS Comeback Response from " MACSTR " (len=%d)", MAC2STR(sa), (int) len); if (len < 6 + 2) { p2p_dbg(p2p, "Too short GAS Comeback Response frame"); return; } dialog_token = *pos++; /* TODO: check dialog_token match */ status_code = WPA_GET_LE16(pos); pos += 2; frag_id = *pos & 0x7f; more_frags = (*pos & 0x80) >> 7; pos++; comeback_delay = WPA_GET_LE16(pos); pos += 2; p2p_dbg(p2p, "dialog_token=%u status_code=%u frag_id=%d more_frags=%d " "comeback_delay=%u", dialog_token, status_code, frag_id, more_frags, comeback_delay); /* TODO: check frag_id match */ if (status_code) { p2p_dbg(p2p, "Service Discovery failed: status code %u", status_code); return; } if (*pos != WLAN_EID_ADV_PROTO) { p2p_dbg(p2p, "Unexpected IE in GAS Comeback Response: %u", *pos); return; } pos++; slen = *pos++; next = pos + slen; if (next > end || slen < 2) { p2p_dbg(p2p, "Invalid IE in GAS Comeback Response"); return; } pos++; /* skip QueryRespLenLimit and PAME-BI */ if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) { p2p_dbg(p2p, "Unsupported GAS advertisement protocol id %u", *pos); return; } pos = next; /* Query Response */ if (pos + 2 > end) { p2p_dbg(p2p, "Too short Query Response"); return; } slen = WPA_GET_LE16(pos); pos += 2; p2p_dbg(p2p, "Query Response Length: %d", slen); if (pos + slen > end) { p2p_dbg(p2p, "Not enough Query Response data"); return; } if (slen == 0) { p2p_dbg(p2p, "No Query Response data"); return; } end = pos + slen; if (p2p->sd_rx_resp) { /* * ANQP header is only included in the first fragment; rest of * the fragments start with continue TLVs. */ goto skip_nqp_header; } /* ANQP Query Response */ if (pos + 4 > end) return; if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) { p2p_dbg(p2p, "Unsupported ANQP Info ID %u", WPA_GET_LE16(pos)); return; } pos += 2; slen = WPA_GET_LE16(pos); pos += 2; p2p_dbg(p2p, "ANQP Query Response length: %u", slen); if (slen < 3 + 1) { p2p_dbg(p2p, "Invalid ANQP Query Response length"); return; } if (pos + 4 > end) return; if (WPA_GET_BE32(pos) != P2P_IE_VENDOR_TYPE) { p2p_dbg(p2p, "Unsupported ANQP vendor OUI-type %08x", WPA_GET_BE32(pos)); return; } pos += 4; if (pos + 2 > end) return; p2p->sd_rx_update_indic = WPA_GET_LE16(pos); p2p_dbg(p2p, "Service Update Indicator: %u", p2p->sd_rx_update_indic); pos += 2; skip_nqp_header: if (wpabuf_resize(&p2p->sd_rx_resp, end - pos) < 0) return; wpabuf_put_data(p2p->sd_rx_resp, pos, end - pos); p2p_dbg(p2p, "Current SD reassembly buffer length: %u", (unsigned int) wpabuf_len(p2p->sd_rx_resp)); if (more_frags) { p2p_dbg(p2p, "More fragments remains"); /* TODO: what would be a good size limit? */ if (wpabuf_len(p2p->sd_rx_resp) > 64000) { wpabuf_free(p2p->sd_rx_resp); p2p->sd_rx_resp = NULL; p2p_dbg(p2p, "Too long SD response - drop it"); return; } p2p_send_gas_comeback_req(p2p, sa, dialog_token, rx_freq); return; } p2p->sd_peer = NULL; if (p2p->sd_query) { if (!p2p->sd_query->for_all_peers) { struct p2p_sd_query *q; p2p_dbg(p2p, "Remove completed SD query %p", p2p->sd_query); q = p2p->sd_query; p2p_unlink_sd_query(p2p, p2p->sd_query); p2p_free_sd_query(q); } p2p->sd_query = NULL; } if (p2p->cfg->sd_response) p2p->cfg->sd_response(p2p->cfg->cb_ctx, sa, p2p->sd_rx_update_indic, wpabuf_head(p2p->sd_rx_resp), wpabuf_len(p2p->sd_rx_resp)); wpabuf_free(p2p->sd_rx_resp); p2p->sd_rx_resp = NULL; p2p_continue_find(p2p); }
static int hs20_process_icon_binary_file(struct wpa_supplicant *wpa_s, const u8 *sa, const u8 *pos, size_t slen, u8 dialog_token) { char fname[256]; int png; FILE *f; u16 data_len; struct icon_entry *icon; 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); 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", 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", MAC2STR(sa)); if (slen < 4) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_printf(MSG_DEBUG, "HS 2.0: Download Status Code %u", *pos); if (*pos != 0) return -1; pos++; slen--; if ((size_t) 1 + pos[0] > slen) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_hexdump_ascii(MSG_DEBUG, "Icon Type", pos + 1, pos[0]); png = os_strncasecmp((char *) pos + 1, "image/png", 9) == 0; slen -= 1 + pos[0]; pos += 1 + pos[0]; if (slen < 2) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } data_len = WPA_GET_LE16(pos); pos += 2; slen -= 2; if (data_len > slen) { wpa_dbg(wpa_s, MSG_DEBUG, "HS 2.0: Too short Icon Binary File " "value from " MACSTR, MAC2STR(sa)); return -1; } wpa_printf(MSG_DEBUG, "Icon Binary Data: %u bytes", data_len); if (wpa_s->conf->osu_dir == NULL) return -1; wpa_s->osu_icon_id++; if (wpa_s->osu_icon_id == 0) wpa_s->osu_icon_id++; snprintf(fname, sizeof(fname), "%s/osu-icon-%u.%s", wpa_s->conf->osu_dir, wpa_s->osu_icon_id, png ? "png" : "icon"); f = fopen(fname, "wb"); if (f == NULL) return -1; hs20_set_osu_access_permission(wpa_s->conf->osu_dir, fname); if (fwrite(pos, slen, 1, f) != 1) { fclose(f); unlink(fname); return -1; } fclose(f); wpa_msg(wpa_s, MSG_INFO, RX_HS20_ANQP_ICON "%s", fname); return 0; }