aboutsummaryrefslogtreecommitdiff
path: root/src/drivers/driver_nl80211_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/driver_nl80211_event.c')
-rw-r--r--src/drivers/driver_nl80211_event.c716
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);