diff options
Diffstat (limited to 'src/drivers/driver_nl80211_event.c')
-rw-r--r-- | src/drivers/driver_nl80211_event.c | 716 |
1 files changed, 653 insertions, 63 deletions
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 177c31d7..14d78427 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -171,6 +171,19 @@ static const char * nl80211_command_to_string(enum nl80211_commands cmd) C2S(NL80211_CMD_UNPROT_BEACON) C2S(NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS) C2S(NL80211_CMD_SET_SAR_SPECS) + C2S(NL80211_CMD_OBSS_COLOR_COLLISION) + C2S(NL80211_CMD_COLOR_CHANGE_REQUEST) + C2S(NL80211_CMD_COLOR_CHANGE_STARTED) + C2S(NL80211_CMD_COLOR_CHANGE_ABORTED) + C2S(NL80211_CMD_COLOR_CHANGE_COMPLETED) + C2S(NL80211_CMD_SET_FILS_AAD) + C2S(NL80211_CMD_ASSOC_COMEBACK) + C2S(NL80211_CMD_ADD_LINK) + C2S(NL80211_CMD_REMOVE_LINK) + C2S(NL80211_CMD_ADD_LINK_STA) + C2S(NL80211_CMD_MODIFY_LINK_STA) + C2S(NL80211_CMD_REMOVE_LINK_STA) + C2S(NL80211_CMD_SET_HW_TIMESTAMP) C2S(__NL80211_CMD_AFTER_LAST) } #undef C2S @@ -314,7 +327,7 @@ static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv, } event.assoc_info.freq = drv->assoc_freq; - drv->first_bss->freq = drv->assoc_freq; + drv->first_bss->flink->freq = drv->assoc_freq; nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params); @@ -407,11 +420,302 @@ convert_connect_fail_reason_codes(enum qca_sta_connect_fail_reason_codes } } + +static void +nl80211_parse_qca_vendor_mlo_link_info(struct driver_sta_mlo_info *mlo, + struct nlattr *mlo_links) +{ + struct nlattr *link; + int rem_links; + + nla_for_each_nested(link, mlo_links, rem_links) { + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAX + 1]; + int link_id; + + nla_parse(tb,QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAX, nla_data(link), + nla_len(link), NULL); + + if (!tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID] || + !tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR] || + !tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID]) + continue; + + link_id = nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_ID]); + if (link_id >= MAX_NUM_MLD_LINKS) + continue; + + mlo->valid_links |= BIT(link_id); + os_memcpy(mlo->links[link_id].addr, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_MAC_ADDR]), + ETH_ALEN); + os_memcpy(mlo->links[link_id].bssid, + nla_data(tb[QCA_WLAN_VENDOR_ATTR_MLO_LINK_BSSID]), + ETH_ALEN); + wpa_printf(MSG_DEBUG, "nl80211: MLO link[%u] addr " MACSTR + " bssid " MACSTR, + link_id, MAC2STR(mlo->links[link_id].addr), + MAC2STR(mlo->links[link_id].bssid)); + } +} + #endif /* CONFIG_DRIVER_NL80211_QCA */ +static void nl80211_parse_mlo_link_info(struct driver_sta_mlo_info *mlo, + struct nlattr *mlo_links) +{ + struct nlattr *link; + int rem_links; + + nla_for_each_nested(link, mlo_links, rem_links) { + struct nlattr *tb[NL80211_ATTR_MAX + 1]; + int link_id; + + nla_parse(tb, NL80211_ATTR_MAX, nla_data(link), nla_len(link), + NULL); + + if (!tb[NL80211_ATTR_MLO_LINK_ID] || !tb[NL80211_ATTR_MAC] || + !tb[NL80211_ATTR_BSSID]) + continue; + + link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); + if (link_id >= MAX_NUM_MLD_LINKS) + continue; + + if (tb[NL80211_ATTR_STATUS_CODE]) { + /* Set requested links only when status indicated */ + mlo->req_links |= BIT(link_id); + if (nla_get_u16(tb[NL80211_ATTR_STATUS_CODE]) == + WLAN_STATUS_SUCCESS) + mlo->valid_links |= BIT(link_id); + } else { + mlo->valid_links |= BIT(link_id); + } + + os_memcpy(mlo->links[link_id].addr, + nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN); + os_memcpy(mlo->links[link_id].bssid, + nla_data(tb[NL80211_ATTR_BSSID]), ETH_ALEN); + wpa_printf(MSG_DEBUG, "nl80211: MLO link[%u] addr " MACSTR + " bssid " MACSTR, + link_id, MAC2STR(mlo->links[link_id].addr), + MAC2STR(mlo->links[link_id].bssid)); + } +} + + +struct links_info { + /* bitmap of link IDs in Per-STA profile subelements */ + u16 non_assoc_links; + u8 addr[MAX_NUM_MLD_LINKS][ETH_ALEN]; +}; + + +static void nl80211_get_basic_mle_links_info(const u8 *mle, size_t mle_len, + struct links_info *info) +{ + size_t rem_len; + const u8 *pos; + + if (mle_len < MULTI_LINK_CONTROL_LEN + 1 || + mle_len - MULTI_LINK_CONTROL_LEN < mle[MULTI_LINK_CONTROL_LEN]) + return; + + /* Skip Common Info */ + pos = mle + MULTI_LINK_CONTROL_LEN + mle[MULTI_LINK_CONTROL_LEN]; + rem_len = mle_len - + (MULTI_LINK_CONTROL_LEN + mle[MULTI_LINK_CONTROL_LEN]); + + /* Parse Subelements */ + while (rem_len > 2) { + size_t ie_len = 2 + pos[1]; + + if (rem_len < ie_len) + break; + + if (pos[0] == MULTI_LINK_SUB_ELEM_ID_PER_STA_PROFILE) { + u8 link_id; + const u8 *sta_profile; + u16 sta_ctrl; + + if (pos[1] < BASIC_MLE_STA_PROF_STA_MAC_IDX + ETH_ALEN) + goto next_subelem; + + sta_profile = &pos[2]; + sta_ctrl = WPA_GET_LE16(sta_profile); + link_id = sta_ctrl & BASIC_MLE_STA_CTRL_LINK_ID_MASK; + if (link_id >= MAX_NUM_MLD_LINKS) + goto next_subelem; + + if (!(sta_ctrl & BASIC_MLE_STA_CTRL_PRES_STA_MAC)) + goto next_subelem; + + info->non_assoc_links |= BIT(link_id); + os_memcpy(info->addr[link_id], + &sta_profile[BASIC_MLE_STA_PROF_STA_MAC_IDX], + ETH_ALEN); + } +next_subelem: + pos += ie_len; + rem_len -= ie_len; + } +} + + +static int nl80211_update_rejected_links_info(struct driver_sta_mlo_info *mlo, + struct nlattr *req_ie, + struct nlattr *resp_ie) +{ + int i; + struct wpabuf *mle; + struct ieee802_11_elems req_elems, resp_elems; + struct links_info req_info, resp_info; + + if (!req_ie || !resp_ie) { + wpa_printf(MSG_INFO, + "nl80211: MLO: (Re)Association Request/Response frame elements not available"); + return -1; + } + + if (ieee802_11_parse_elems(nla_data(req_ie), nla_len(req_ie), + &req_elems, 0) == ParseFailed || + ieee802_11_parse_elems(nla_data(resp_ie), nla_len(resp_ie), + &resp_elems, 0) == ParseFailed) { + wpa_printf(MSG_INFO, + "nl80211: MLO: Failed to parse (Re)Association Request/Response elements"); + return -1; + } + + mle = ieee802_11_defrag_mle(&req_elems, MULTI_LINK_CONTROL_TYPE_BASIC); + if (!mle) { + wpa_printf(MSG_INFO, + "nl80211: MLO: Basic Multi-Link element not found in Association Request"); + return -1; + } + os_memset(&req_info, 0, sizeof(req_info)); + nl80211_get_basic_mle_links_info(wpabuf_head(mle), wpabuf_len(mle), + &req_info); + wpabuf_free(mle); + + mle = ieee802_11_defrag_mle(&resp_elems, MULTI_LINK_CONTROL_TYPE_BASIC); + if (!mle) { + wpa_printf(MSG_ERROR, + "nl80211: MLO: Basic Multi-Link element not found in Association Response"); + return -1; + } + os_memset(&resp_info, 0, sizeof(resp_info)); + nl80211_get_basic_mle_links_info(wpabuf_head(mle), wpabuf_len(mle), + &resp_info); + wpabuf_free(mle); + + if (req_info.non_assoc_links != resp_info.non_assoc_links) { + wpa_printf(MSG_ERROR, + "nl80211: MLO: Association Request and Response links bitmaps not equal (0x%x != 0x%x)", + req_info.non_assoc_links, + resp_info.non_assoc_links); + return -1; + } + + mlo->req_links = BIT(mlo->assoc_link_id) | req_info.non_assoc_links; + if ((mlo->req_links & mlo->valid_links) != mlo->valid_links) { + wpa_printf(MSG_ERROR, + "nl80211: MLO: Accepted links are not a subset of requested links (req_links=0x%x valid_links=0x%x non_assoc_links=0x%x assoc_link_id=0x%x)", + mlo->req_links, mlo->valid_links, + req_info.non_assoc_links, BIT(mlo->assoc_link_id)); + return -1; + } + + /* Get MLO links info for rejected links */ + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + if (!((mlo->req_links & ~mlo->valid_links) & BIT(i))) + continue; + + os_memcpy(mlo->links[i].bssid, resp_info.addr[i], ETH_ALEN); + os_memcpy(mlo->links[i].addr, req_info.addr[i], ETH_ALEN); + } + + return 0; +} + + +static int nl80211_get_assoc_link_id(const u8 *data, u8 len) +{ + u16 control; + + if (len < 2) + return -1; + + control = WPA_GET_LE16(data); + if (!(control & BASIC_MULTI_LINK_CTRL_PRES_LINK_ID)) + return -1; + +#define BASIC_ML_IE_COMMON_INFO_LINK_ID_IDX \ + (2 + /* Multi-Link Control field */ \ + 1 + /* Common Info Length field (Basic) */ \ + ETH_ALEN) /* MLD MAC Address field (Basic) */ + if (len <= BASIC_ML_IE_COMMON_INFO_LINK_ID_IDX) + return -1; + + return data[BASIC_ML_IE_COMMON_INFO_LINK_ID_IDX] & 0x0F; +} + + +static void nl80211_parse_mlo_info(struct wpa_driver_nl80211_data *drv, + bool qca_roam_auth, + struct nlattr *addr, + struct nlattr *mlo_links, + struct nlattr *req_ie, + struct nlattr *resp_ie) +{ + const u8 *ml_ie; + struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info; + int res; + + if (!addr || !mlo_links || !resp_ie) + return; + + ml_ie = get_ml_ie(nla_data(resp_ie), nla_len(resp_ie), + MULTI_LINK_CONTROL_TYPE_BASIC); + if (!ml_ie) + return; + + res = nl80211_get_assoc_link_id(&ml_ie[3], ml_ie[1] - 1); + if (res < 0 || res >= MAX_NUM_MLD_LINKS) { + wpa_printf(MSG_DEBUG, + "nl80211: Could not find a valid association Link ID (res=%d)", + res); + return; + } + drv->sta_mlo_info.assoc_link_id = res; + + os_memcpy(mlo->ap_mld_addr, nla_data(addr), ETH_ALEN); + wpa_printf(MSG_DEBUG, "nl80211: AP MLD MAC Address " MACSTR, + MAC2STR(mlo->ap_mld_addr)); + + if (!qca_roam_auth) + nl80211_parse_mlo_link_info(mlo, mlo_links); +#ifdef CONFIG_DRIVER_NL80211_QCA + if (qca_roam_auth) + nl80211_parse_qca_vendor_mlo_link_info(mlo, mlo_links); +#endif /* CONFIG_DRIVER_NL80211_QCA */ + + if (!(mlo->valid_links & BIT(mlo->assoc_link_id)) || + (!mlo->req_links && + nl80211_update_rejected_links_info(mlo, req_ie, resp_ie))) { + wpa_printf(MSG_INFO, "nl80211: Invalid MLO connection info"); + mlo->valid_links = 0; + return; + } + + os_memcpy(drv->bssid, mlo->links[drv->sta_mlo_info.assoc_link_id].bssid, + ETH_ALEN); + os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN); +} + + static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, - enum nl80211_commands cmd, struct nlattr *status, + enum nl80211_commands cmd, bool qca_roam_auth, + struct nlattr *status, struct nlattr *addr, struct nlattr *req_ie, struct nlattr *resp_ie, struct nlattr *timed_out, @@ -423,7 +727,8 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, struct nlattr *subnet_status, struct nlattr *fils_erp_next_seq_num, struct nlattr *fils_pmk, - struct nlattr *fils_pmkid) + struct nlattr *fils_pmkid, + struct nlattr *mlo_links) { union wpa_event_data event; const u8 *ssid = NULL; @@ -515,7 +820,10 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, } drv->associated = 1; - if (addr) { + os_memset(&drv->sta_mlo_info, 0, sizeof(drv->sta_mlo_info)); + nl80211_parse_mlo_info(drv, qca_roam_auth, addr, mlo_links, req_ie, + resp_ie); + if (!drv->sta_mlo_info.valid_links && addr) { os_memcpy(drv->bssid, nla_data(addr), ETH_ALEN); os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN); } @@ -544,7 +852,7 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, } event.assoc_info.freq = nl80211_get_assoc_freq(drv); - drv->first_bss->freq = drv->assoc_freq; + drv->first_bss->flink->freq = drv->assoc_freq; if ((!ssid || ssid[1] == 0 || ssid[1] > 32) && (ssid_len = nl80211_get_assoc_ssid(drv, drv->ssid)) > 0) { @@ -666,6 +974,9 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) case CHAN_WIDTH_80P80: freq1 = cf1 - 30; break; + case CHAN_WIDTH_320: + freq1 = cf1 - 150; + break; case CHAN_WIDTH_UNKNOWN: case CHAN_WIDTH_2160: case CHAN_WIDTH_4320: @@ -680,9 +991,11 @@ static int calculate_chan_offset(int width, int freq, int cf1, int cf2) static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, - struct nlattr *ifindex, struct nlattr *freq, - struct nlattr *type, struct nlattr *bw, - struct nlattr *cf1, struct nlattr *cf2, + struct nlattr *ifindex, struct nlattr *link, + struct nlattr *freq, struct nlattr *type, + struct nlattr *bw, struct nlattr *cf1, + struct nlattr *cf2, + struct nlattr *punct_bitmap, int finished) { struct i802_bss *bss; @@ -738,6 +1051,8 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, data.ch_switch.freq = nla_get_u32(freq); data.ch_switch.ht_enabled = ht_enabled; data.ch_switch.ch_offset = chan_offset; + if (punct_bitmap) + data.ch_switch.punct_bitmap = (u16) nla_get_u32(punct_bitmap); if (bw) data.ch_switch.ch_width = convert2width(nla_get_u32(bw)); if (cf1) @@ -746,7 +1061,26 @@ static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv, data.ch_switch.cf2 = nla_get_u32(cf2); if (finished) - bss->freq = data.ch_switch.freq; + bss->flink->freq = data.ch_switch.freq; + + if (link) { + u8 link_id = nla_get_u8(link); + + if (link_id < MAX_NUM_MLD_LINKS && + drv->sta_mlo_info.valid_links & BIT(link_id)) { + data.ch_switch.link_id = link_id; + drv->sta_mlo_info.links[link_id].freq = + data.ch_switch.freq; + wpa_supplicant_event( + bss->ctx, + finished ? EVENT_LINK_CH_SWITCH : + EVENT_LINK_CH_SWITCH_STARTED, &data); + } + + if (link_id != drv->sta_mlo_info.assoc_link_id) + return; + } + drv->assoc_freq = data.ch_switch.freq; wpa_supplicant_event(bss->ctx, finished ? @@ -781,7 +1115,8 @@ static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv, static void mlme_event_mgmt(struct i802_bss *bss, struct nlattr *freq, struct nlattr *sig, - const u8 *frame, size_t len) + const u8 *frame, size_t len, + int link_id) { struct wpa_driver_nl80211_data *drv = bss->drv; const struct ieee80211_mgmt *mgmt; @@ -819,6 +1154,8 @@ static void mlme_event_mgmt(struct i802_bss *bss, event.rx_mgmt.frame_len = len; event.rx_mgmt.ssi_signal = ssi_signal; event.rx_mgmt.drv_priv = bss; + event.rx_mgmt.link_id = link_id; + wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event); } @@ -916,8 +1253,11 @@ static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv, * ignore_next_local_deauth as well, to avoid next local * deauth event be wrongly ignored. */ - if (!os_memcmp(mgmt->sa, drv->first_bss->addr, - ETH_ALEN)) { + if (os_memcmp(mgmt->sa, drv->first_bss->addr, + ETH_ALEN) == 0 || + (!is_zero_ether_addr(drv->first_bss->prev_addr) && + os_memcmp(mgmt->sa, drv->first_bss->prev_addr, + ETH_ALEN) == 0)) { wpa_printf(MSG_DEBUG, "nl80211: Received a locally generated deauth event. Clear ignore_next_local_deauth flag"); drv->ignore_next_local_deauth = 0; @@ -1070,11 +1410,14 @@ static void mlme_event(struct i802_bss *bss, struct nlattr *addr, struct nlattr *timed_out, struct nlattr *freq, struct nlattr *ack, struct nlattr *cookie, struct nlattr *sig, - struct nlattr *wmm, struct nlattr *req_ie) + struct nlattr *wmm, struct nlattr *req_ie, + struct nlattr *link) { struct wpa_driver_nl80211_data *drv = bss->drv; + u16 stype = 0, auth_type = 0; const u8 *data; size_t len; + int link_id; if (timed_out && addr) { mlme_timeout_event(drv, cmd, addr); @@ -1088,6 +1431,11 @@ static void mlme_event(struct i802_bss *bss, return; } + if (link) + link_id = nla_get_u8(link); + else + link_id = -1; + data = nla_data(frame); len = nla_len(frame); if (len < 4 + 2 * ETH_ALEN) { @@ -1098,15 +1446,38 @@ static void mlme_event(struct i802_bss *bss, return; } wpa_printf(MSG_MSGDUMP, "nl80211: MLME event %d (%s) on %s(" MACSTR - ") A1=" MACSTR " A2=" MACSTR, cmd, + ") A1=" MACSTR " A2=" MACSTR " on link_id=%d", cmd, nl80211_command_to_string(cmd), bss->ifname, MAC2STR(bss->addr), MAC2STR(data + 4), - MAC2STR(data + 4 + ETH_ALEN)); - if (cmd != NL80211_CMD_FRAME_TX_STATUS && !(data[4] & 0x01) && - os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 && - (is_zero_ether_addr(bss->rand_addr) || - os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) && - os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0) { + MAC2STR(data + 4 + ETH_ALEN), link_id); + + /* PASN Authentication frame can be received with a different source MAC + * address. Allow NL80211_CMD_FRAME event with foreign addresses also. + */ + if (cmd == NL80211_CMD_FRAME && len >= 24) { + const struct ieee80211_mgmt *mgmt; + u16 fc; + + mgmt = (const struct ieee80211_mgmt *) data; + fc = le_to_host16(mgmt->frame_control); + stype = WLAN_FC_GET_STYPE(fc); + auth_type = le_to_host16(mgmt->u.auth.auth_alg); + } + + if (cmd == NL80211_CMD_FRAME && stype == WLAN_FC_STYPE_AUTH && + auth_type == host_to_le16(WLAN_AUTH_PASN)) { + wpa_printf(MSG_DEBUG, + "nl80211: %s: Allow PASN frame for foreign address", + bss->ifname); + } else if (cmd != NL80211_CMD_FRAME_TX_STATUS && + !(data[4] & 0x01) && + os_memcmp(bss->addr, data + 4, ETH_ALEN) != 0 && + (is_zero_ether_addr(bss->rand_addr) || + os_memcmp(bss->rand_addr, data + 4, ETH_ALEN) != 0) && + os_memcmp(bss->addr, data + 4 + ETH_ALEN, ETH_ALEN) != 0 && + (is_zero_ether_addr(drv->first_bss->prev_addr) || + os_memcmp(bss->prev_addr, data + 4 + ETH_ALEN, + ETH_ALEN) != 0)) { wpa_printf(MSG_MSGDUMP, "nl80211: %s: Ignore MLME frame event " "for foreign address", bss->ifname); return; @@ -1132,7 +1503,7 @@ static void mlme_event(struct i802_bss *bss, break; case NL80211_CMD_FRAME: mlme_event_mgmt(bss, freq, sig, nla_data(frame), - nla_len(frame)); + nla_len(frame), link_id); break; case NL80211_CMD_FRAME_TX_STATUS: mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame), @@ -1212,7 +1583,7 @@ static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv, if (freq) { wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz", freq); - drv->first_bss->freq = freq; + drv->first_bss->flink->freq = freq; } os_memset(&event, 0, sizeof(event)); @@ -1328,7 +1699,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, struct nlattr *nl; int rem; struct scan_info *info; -#define MAX_REPORT_FREQS 100 +#define MAX_REPORT_FREQS 110 int freqs[MAX_REPORT_FREQS]; int num_freqs = 0; @@ -1360,7 +1731,7 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, } } if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) { - char msg[500], *pos, *end; + char msg[MAX_REPORT_FREQS * 5 + 1], *pos, *end; int res; pos = msg; @@ -1375,11 +1746,12 @@ static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted, if (!os_snprintf_error(end - pos, res)) pos += res; num_freqs++; - if (num_freqs == MAX_REPORT_FREQS - 1) + if (num_freqs == MAX_REPORT_FREQS) break; } info->freqs = freqs; info->num_freqs = num_freqs; + msg[sizeof(msg) - 1] = '\0'; wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s", msg); } @@ -1483,11 +1855,11 @@ static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv, * nl80211_get_link_signal() and nl80211_get_link_noise() set default * values in case querying the driver fails. */ - res = nl80211_get_link_signal(drv, &ed.signal_change); + res = nl80211_get_link_signal(drv, drv->bssid, &ed.signal_change.data); if (res == 0) { - wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %d", - ed.signal_change.current_signal, - ed.signal_change.current_txrate); + wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm txrate: %lu", + ed.signal_change.data.signal, + ed.signal_change.data.current_tx_rate); } else { wpa_printf(MSG_DEBUG, "nl80211: Querying the driver for signal info failed"); @@ -2085,7 +2457,7 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]); wpa_printf(MSG_DEBUG, " * roam BSSID " MACSTR, MAC2STR(bssid)); - mlme_event_connect(drv, NL80211_CMD_ROAM, NULL, + mlme_event_connect(drv, NL80211_CMD_ROAM, true, NULL, tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE], @@ -2097,7 +2469,16 @@ static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv, tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_SUBNET_STATUS], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_FILS_ERP_NEXT_SEQ_NUM], tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMK], - tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID]); + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PMKID], + tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MLO_LINKS]); + +#ifdef ANDROID +#ifdef ANDROID_LIB_EVENT + wpa_driver_nl80211_driver_event( + drv, OUI_QCA, QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH, + data, len); +#endif /* ANDROID_LIB_EVENT */ +#endif /* ANDROID */ } @@ -2108,7 +2489,6 @@ qca_nl80211_key_mgmt_auth_handler(struct wpa_driver_nl80211_data *drv, if (!drv->roam_indication_done) { wpa_printf(MSG_DEBUG, "nl80211: Pending roam indication, delay processing roam+auth vendor event"); - os_get_reltime(&drv->pending_roam_ind_time); os_free(drv->pending_roam_data); drv->pending_roam_data = os_memdup(data, len); @@ -2364,6 +2744,82 @@ static void qca_nl80211_p2p_lo_stop_event(struct wpa_driver_nl80211_data *drv, wpa_supplicant_event(drv->ctx, EVENT_P2P_LO_STOP, &event); } + +#ifdef CONFIG_PASN + +static void qca_nl80211_pasn_auth(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + int ret = -EINVAL; + struct nlattr *attr; + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_MAX + 1]; + struct nlattr *cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX + 1]; + unsigned int n_peers = 0, idx = 0; + int rem_conf; + enum qca_wlan_vendor_pasn_action action; + union wpa_event_data event; + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_PASN_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS] || + !tb[QCA_WLAN_VENDOR_ATTR_PASN_ACTION]) { + return; + } + + os_memset(&event, 0, sizeof(event)); + action = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_PASN_ACTION]); + switch (action) { + case QCA_WLAN_VENDOR_PASN_ACTION_AUTH: + event.pasn_auth.action = PASN_ACTION_AUTH; + break; + case QCA_WLAN_VENDOR_PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT: + event.pasn_auth.action = + PASN_ACTION_DELETE_SECURE_RANGING_CONTEXT; + break; + default: + return; + } + + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS], rem_conf) + n_peers++; + + if (n_peers > WPAS_MAX_PASN_PEERS) { + wpa_printf(MSG_DEBUG, "nl80211: PASN auth: too many peers (%d)", + n_peers); + return; + } + + nla_for_each_nested(attr, tb[QCA_WLAN_VENDOR_ATTR_PASN_PEERS], + rem_conf) { + struct nlattr *nl_src, *nl_peer; + + ret = nla_parse_nested(cfg, QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAX, + attr, NULL); + if (ret) + return; + nl_src = cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_SRC_ADDR]; + nl_peer = cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_MAC_ADDR]; + if (nl_src) + os_memcpy(event.pasn_auth.peer[idx].own_addr, + nla_data(nl_src), ETH_ALEN); + if (nl_peer) + os_memcpy(event.pasn_auth.peer[idx].peer_addr, + nla_data(nl_peer), ETH_ALEN); + if (cfg[QCA_WLAN_VENDOR_ATTR_PASN_PEER_LTF_KEYSEED_REQUIRED]) + event.pasn_auth.peer[idx].ltf_keyseed_required = true; + idx++; + } + event.pasn_auth.num_peers = n_peers; + + wpa_printf(MSG_DEBUG, + "nl80211: PASN auth action: %u, num_bssids: %d", + event.pasn_auth.action, + event.pasn_auth.num_peers); + wpa_supplicant_event(drv->ctx, EVENT_PASN_AUTH, &event); +} + +#endif /* CONFIG_PASN */ + #endif /* CONFIG_DRIVER_NL80211_QCA */ @@ -2400,6 +2856,11 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, case QCA_NL80211_VENDOR_SUBCMD_P2P_LISTEN_OFFLOAD_STOP: qca_nl80211_p2p_lo_stop_event(drv, data, len); break; +#ifdef CONFIG_PASN + case QCA_NL80211_VENDOR_SUBCMD_PASN: + qca_nl80211_pasn_auth(drv, data, len); + break; +#endif /* CONFIG_PASN */ #endif /* CONFIG_DRIVER_NL80211_QCA */ default: wpa_printf(MSG_DEBUG, @@ -2410,7 +2871,7 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, } -#ifdef CONFIG_DRIVER_NL80211_BRCM +#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA) static void brcm_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv, const u8 *data, size_t len) @@ -2488,7 +2949,7 @@ static void nl80211_vendor_event_brcm(struct wpa_driver_nl80211_data *drv, } } -#endif /* CONFIG_DRIVER_NL80211_BRCM */ +#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, @@ -2527,7 +2988,13 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, #ifdef ANDROID #ifdef ANDROID_LIB_EVENT - wpa_driver_nl80211_driver_event(drv, vendor_id, subcmd, data, len); + /* Postpone QCA roam+auth event indication to the point when both that + * and the NL80211_CMD_ROAM event have been received (see calls to + * qca_nl80211_key_mgmt_auth() and drv->pending_roam_data). */ + if (!(vendor_id == OUI_QCA && + subcmd == QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH)) + wpa_driver_nl80211_driver_event(drv, vendor_id, subcmd, data, + len); #endif /* ANDROID_LIB_EVENT */ #endif /* ANDROID */ @@ -2535,11 +3002,11 @@ static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv, case OUI_QCA: nl80211_vendor_event_qca(drv, subcmd, data, len); break; -#ifdef CONFIG_DRIVER_NL80211_BRCM +#if defined(CONFIG_DRIVER_NL80211_BRCM) || defined(CONFIG_DRIVER_NL80211_SYNA) case OUI_BRCM: nl80211_vendor_event_brcm(drv, subcmd, data, len); break; -#endif /* CONFIG_DRIVER_NL80211_BRCM */ +#endif /* CONFIG_DRIVER_NL80211_BRCM || CONFIG_DRIVER_NL80211_SYNA */ default: wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event"); break; @@ -2663,6 +3130,7 @@ static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv, { union wpa_event_data event; enum nl80211_external_auth_action act; + char mld_addr[50]; if (!tb[NL80211_ATTR_AKM_SUITES] || !tb[NL80211_ATTR_EXTERNAL_AUTH_ACTION] || @@ -2693,10 +3161,21 @@ static void nl80211_external_auth(struct wpa_driver_nl80211_data *drv, event.external_auth.bssid = nla_data(tb[NL80211_ATTR_BSSID]); + mld_addr[0] = '\0'; + if (tb[NL80211_ATTR_MLD_ADDR]) { + event.external_auth.mld_addr = + nla_data(tb[NL80211_ATTR_MLD_ADDR]); + os_snprintf(mld_addr, sizeof(mld_addr), ", MLD ADDR: " MACSTR, + MAC2STR(event.external_auth.mld_addr)); + } + wpa_printf(MSG_DEBUG, - "nl80211: External auth action: %u, AKM: 0x%x", + "nl80211: External auth action: %u, AKM: 0x%x, SSID: %s, BSSID: " MACSTR "%s", event.external_auth.action, - event.external_auth.key_mgmt_suite); + event.external_auth.key_mgmt_suite, + wpa_ssid_txt(event.external_auth.ssid, + event.external_auth.ssid_len), + MAC2STR(event.external_auth.bssid), mld_addr); wpa_supplicant_event(drv->ctx, EVENT_EXTERNAL_AUTH, &event); } @@ -2705,6 +3184,11 @@ static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv, struct nlattr **tb) { const u8 *addr; + union wpa_event_data event; + const u8 *connected_addr = drv->sta_mlo_info.valid_links ? + drv->sta_mlo_info.ap_mld_addr : drv->bssid; + + os_memset(&event, 0, sizeof(event)); if (!tb[NL80211_ATTR_MAC] || nla_len(tb[NL80211_ATTR_MAC]) != ETH_ALEN) { @@ -2714,15 +3198,23 @@ static void nl80211_port_authorized(struct wpa_driver_nl80211_data *drv, } addr = nla_data(tb[NL80211_ATTR_MAC]); - if (os_memcmp(addr, drv->bssid, ETH_ALEN) != 0) { + if (os_memcmp(addr, connected_addr, ETH_ALEN) != 0) { wpa_printf(MSG_DEBUG, "nl80211: Ignore port authorized event for " MACSTR " (not the currently connected BSSID " MACSTR ")", - MAC2STR(addr), MAC2STR(drv->bssid)); + MAC2STR(addr), MAC2STR(connected_addr)); return; } - wpa_supplicant_event(drv->ctx, EVENT_PORT_AUTHORIZED, NULL); + if (tb[NL80211_ATTR_TD_BITMAP]) { + event.port_authorized.td_bitmap_len = + nla_len(tb[NL80211_ATTR_TD_BITMAP]); + if (event.port_authorized.td_bitmap_len > 0) + event.port_authorized.td_bitmap = + nla_data(tb[NL80211_ATTR_TD_BITMAP]); + } + + wpa_supplicant_event(drv->ctx, EVENT_PORT_AUTHORIZED, &event); } @@ -2782,6 +3274,9 @@ static void nl80211_sta_opmode_change_event(struct wpa_driver_nl80211_data *drv, case NL80211_CHAN_WIDTH_160: ed.sta_opmode.chan_width = CHAN_WIDTH_160; break; + case NL80211_CHAN_WIDTH_320: + ed.sta_opmode.chan_width = CHAN_WIDTH_320; + break; default: ed.sta_opmode.chan_width = CHAN_WIDTH_UNKNOWN; break; @@ -2801,6 +3296,8 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv, { u8 *src_addr; u16 ethertype; + enum frame_encryption encrypted; + int link_id; if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_FRAME] || @@ -2809,6 +3306,13 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv, src_addr = nla_data(tb[NL80211_ATTR_MAC]); ethertype = nla_get_u16(tb[NL80211_ATTR_CONTROL_PORT_ETHERTYPE]); + encrypted = nla_get_flag(tb[NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT]) ? + FRAME_NOT_ENCRYPTED : FRAME_ENCRYPTED; + + if (tb[NL80211_ATTR_MLO_LINK_ID]) + link_id = nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); + else + link_id = -1; switch (ethertype) { case ETH_P_RSN_PREAUTH: @@ -2817,12 +3321,14 @@ static void nl80211_control_port_frame(struct wpa_driver_nl80211_data *drv, MAC2STR(src_addr)); break; case ETH_P_PAE: - drv_event_eapol_rx(drv->ctx, src_addr, - nla_data(tb[NL80211_ATTR_FRAME]), - nla_len(tb[NL80211_ATTR_FRAME])); + drv_event_eapol_rx2(drv->ctx, src_addr, + nla_data(tb[NL80211_ATTR_FRAME]), + nla_len(tb[NL80211_ATTR_FRAME]), + encrypted, link_id); break; default: - wpa_printf(MSG_INFO, "nl80211: Unxpected ethertype 0x%04x from " + wpa_printf(MSG_INFO, + "nl80211: Unexpected ethertype 0x%04x from " MACSTR " over control port", ethertype, MAC2STR(src_addr)); break; @@ -2871,9 +3377,12 @@ static void nl80211_frame_wait_cancel(struct wpa_driver_nl80211_data *drv, } } wpa_printf(MSG_DEBUG, - "nl80211: TX frame wait expired for cookie 0x%llx%s", + "nl80211: TX frame wait expired for cookie 0x%llx%s%s", (long long unsigned int) cookie, - match ? " (match)" : ""); + match ? " (match)" : "", + drv->send_frame_cookie == cookie ? " (match-saved)" : ""); + if (drv->send_frame_cookie == cookie) + drv->send_frame_cookie = (u64) -1; if (!match) return; @@ -2887,6 +3396,69 @@ static void nl80211_frame_wait_cancel(struct wpa_driver_nl80211_data *drv, } +static void nl80211_assoc_comeback(struct wpa_driver_nl80211_data *drv, + struct nlattr *mac, struct nlattr *timeout) +{ + if (!mac || !timeout) + return; + wpa_printf(MSG_DEBUG, "nl80211: Association comeback requested by " + MACSTR " (timeout: %u ms)", + MAC2STR((u8 *) nla_data(mac)), nla_get_u32(timeout)); +} + + +#ifdef CONFIG_IEEE80211AX + +static void nl80211_obss_color_collision(struct wpa_driver_nl80211_data *drv, + struct nlattr *tb[]) +{ + union wpa_event_data data; + + if (!tb[NL80211_ATTR_OBSS_COLOR_BITMAP]) + return; + + os_memset(&data, 0, sizeof(data)); + data.bss_color_collision.bitmap = + nla_get_u64(tb[NL80211_ATTR_OBSS_COLOR_BITMAP]); + + wpa_printf(MSG_DEBUG, "nl80211: BSS color collision - bitmap %08llx", + (long long unsigned int) data.bss_color_collision.bitmap); + wpa_supplicant_event(drv->ctx, EVENT_BSS_COLOR_COLLISION, &data); +} + + +static void +nl80211_color_change_announcement_started(struct wpa_driver_nl80211_data *drv) +{ + union wpa_event_data data = {}; + + wpa_printf(MSG_DEBUG, "nl80211: CCA started"); + wpa_supplicant_event(drv->ctx, EVENT_CCA_STARTED_NOTIFY, &data); +} + + +static void +nl80211_color_change_announcement_aborted(struct wpa_driver_nl80211_data *drv) +{ + union wpa_event_data data = {}; + + wpa_printf(MSG_DEBUG, "nl80211: CCA aborted"); + wpa_supplicant_event(drv->ctx, EVENT_CCA_ABORTED_NOTIFY, &data); +} + + +static void +nl80211_color_change_announcement_completed(struct wpa_driver_nl80211_data *drv) +{ + union wpa_event_data data = {}; + + wpa_printf(MSG_DEBUG, "nl80211: CCA completed"); + wpa_supplicant_event(drv->ctx, EVENT_CCA_NOTIFY, &data); +} + +#endif /* CONFIG_IEEE80211AX */ + + static void do_process_drv_event(struct i802_bss *bss, int cmd, struct nlattr **tb) { @@ -2901,17 +3473,10 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, if (cmd == NL80211_CMD_ROAM && (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) { if (drv->pending_roam_data) { - struct os_reltime now, age; - - os_get_reltime(&now); - os_reltime_sub(&now, &drv->pending_roam_ind_time, &age); - if (age.sec == 0 && age.usec < 100000) { - wpa_printf(MSG_DEBUG, - "nl80211: Process pending roam+auth vendor event"); - qca_nl80211_key_mgmt_auth( - drv, drv->pending_roam_data, - drv->pending_roam_data_len); - } + wpa_printf(MSG_DEBUG, + "nl80211: Process pending roam+auth vendor event"); + qca_nl80211_key_mgmt_auth(drv, drv->pending_roam_data, + drv->pending_roam_data_len); os_free(drv->pending_roam_data); drv->pending_roam_data = NULL; return; @@ -3009,11 +3574,12 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, tb[NL80211_ATTR_COOKIE], tb[NL80211_ATTR_RX_SIGNAL_DBM], tb[NL80211_ATTR_STA_WME], - tb[NL80211_ATTR_REQ_IE]); + tb[NL80211_ATTR_REQ_IE], + tb[NL80211_ATTR_MLO_LINK_ID]); break; case NL80211_CMD_CONNECT: case NL80211_CMD_ROAM: - mlme_event_connect(drv, cmd, + mlme_event_connect(drv, cmd, false, tb[NL80211_ATTR_STATUS_CODE], tb[NL80211_ATTR_MAC], tb[NL80211_ATTR_REQ_IE], @@ -3025,26 +3591,31 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, NULL, tb[NL80211_ATTR_FILS_ERP_NEXT_SEQ_NUM], tb[NL80211_ATTR_PMK], - tb[NL80211_ATTR_PMKID]); + tb[NL80211_ATTR_PMKID], + tb[NL80211_ATTR_MLO_LINKS]); break; case NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: mlme_event_ch_switch(drv, tb[NL80211_ATTR_IFINDEX], + tb[NL80211_ATTR_MLO_LINK_ID], tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], tb[NL80211_ATTR_CHANNEL_WIDTH], tb[NL80211_ATTR_CENTER_FREQ1], tb[NL80211_ATTR_CENTER_FREQ2], + tb[NL80211_ATTR_PUNCT_BITMAP], 0); break; case NL80211_CMD_CH_SWITCH_NOTIFY: mlme_event_ch_switch(drv, tb[NL80211_ATTR_IFINDEX], + tb[NL80211_ATTR_MLO_LINK_ID], tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE], tb[NL80211_ATTR_CHANNEL_WIDTH], tb[NL80211_ATTR_CENTER_FREQ1], tb[NL80211_ATTR_CENTER_FREQ2], + tb[NL80211_ATTR_PUNCT_BITMAP], 1); break; case NL80211_CMD_DISCONNECT: @@ -3136,6 +3707,24 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, case NL80211_CMD_FRAME_WAIT_CANCEL: nl80211_frame_wait_cancel(drv, tb[NL80211_ATTR_COOKIE]); break; + case NL80211_CMD_ASSOC_COMEBACK: + nl80211_assoc_comeback(drv, tb[NL80211_ATTR_MAC], + tb[NL80211_ATTR_TIMEOUT]); + break; +#ifdef CONFIG_IEEE80211AX + case NL80211_CMD_OBSS_COLOR_COLLISION: + nl80211_obss_color_collision(drv, tb); + break; + case NL80211_CMD_COLOR_CHANGE_STARTED: + nl80211_color_change_announcement_started(drv); + break; + case NL80211_CMD_COLOR_CHANGE_ABORTED: + nl80211_color_change_announcement_aborted(drv); + break; + case NL80211_CMD_COLOR_CHANGE_COMPLETED: + nl80211_color_change_announcement_completed(drv); + break; +#endif /* CONFIG_IEEE80211AX */ default: wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event " "(cmd=%d)", cmd); @@ -3214,7 +3803,8 @@ int process_bss_event(struct nl_msg *msg, void *arg) tb[NL80211_ATTR_WIPHY_FREQ], tb[NL80211_ATTR_ACK], tb[NL80211_ATTR_COOKIE], tb[NL80211_ATTR_RX_SIGNAL_DBM], - tb[NL80211_ATTR_STA_WME], NULL); + tb[NL80211_ATTR_STA_WME], NULL, + tb[NL80211_ATTR_MLO_LINK_ID]); break; case NL80211_CMD_UNEXPECTED_FRAME: nl80211_spurious_frame(bss, tb, 0); |