From faa410292676aed1559aee2272e65709632ec6ea Mon Sep 17 00:00:00 2001 From: Yi-Chia Hsieh Date: Tue, 14 Feb 2023 15:07:58 -0800 Subject: [PATCH] WNM: Event report handling for BSS color collision and in-use Add support for WNM event report handling for the BSS color collision and in use events. Co-developed-by: Ryder Lee Signed-off-by: Yi-Chia Hsieh Signed-off-by: Ryder Lee --- src/ap/wnm_ap.c | 131 +++++++++++++++++++++++++++++++++++ src/common/ieee802_11_defs.h | 36 ++++++++++ 2 files changed, 167 insertions(+) diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c index 23a352c9b..153ee4033 100644 --- a/src/ap/wnm_ap.c +++ b/src/ap/wnm_ap.c @@ -643,6 +643,133 @@ static void ieee802_11_rx_wnm_coloc_intf_report(struct hostapd_data *hapd, } + +static const char * wnm_event_type2str(enum wnm_event_report_type wtype) +{ +#define W2S(wtype) case WNM_EVENT_TYPE_ ## wtype: return #wtype; + switch (wtype) { + W2S(TRANSITION) + W2S(RSNA) + W2S(P2P_LINK) + W2S(WNM_LOG) + W2S(BSS_COLOR_COLLISION) + W2S(BSS_COLOR_IN_USE) + } + return "UNKNOWN"; +#undef W2S +} + + +static void ieee802_11_rx_wnm_event_report(struct hostapd_data *hapd, + const u8 *addr, const u8 *buf, + size_t len) +{ + struct sta_info *sta; + u8 dialog_token; + struct wnm_event_report_element *report_ie; + const u8 *pos = buf, *end = buf + len; + const size_t fixed_field_len = 3; /* Event Token/Type/Report Status */ +#ifdef CONFIG_IEEE80211AX + const size_t tsf_len = 8; + u8 color; + u64 bitmap; +#endif /* CONFIG_IEEE80211AX */ + + if (end - pos < 1 + 2) { + wpa_printf(MSG_DEBUG, + "WNM: Ignore too short WNM Event Report frame from " + MACSTR, MAC2STR(addr)); + return; + } + + dialog_token = *pos++; + report_ie = (struct wnm_event_report_element *) pos; + + if (end - pos < 2 + report_ie->len || + report_ie->len < fixed_field_len) { + wpa_printf(MSG_DEBUG, + "WNM: Ignore truncated WNM Event Report frame from " + MACSTR, MAC2STR(addr)); + return; + } + + if (report_ie->eid != WLAN_EID_EVENT_REPORT || + report_ie->status != WNM_STATUS_SUCCESSFUL) + return; + + wpa_printf(MSG_DEBUG, "WNM: Received WNM Event Report frame from " + MACSTR " dialog_token=%u event_token=%u type=%d (%s)", + MAC2STR(addr), dialog_token, report_ie->token, + report_ie->type, wnm_event_type2str(report_ie->type)); + + pos += 2 + fixed_field_len; + wpa_hexdump(MSG_MSGDUMP, "WNM: Event Report", pos, end - pos); + + sta = ap_get_sta(hapd, addr); + if (!sta || !(sta->flags & WLAN_STA_ASSOC)) { + wpa_printf(MSG_DEBUG, "Station " MACSTR + " not found for received WNM Event Report", + MAC2STR(addr)); + return; + } + + switch (report_ie->type) { +#ifdef CONFIG_IEEE80211AX + case WNM_EVENT_TYPE_BSS_COLOR_COLLISION: + if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax) + return; + if (report_ie->len < + fixed_field_len + tsf_len + 8) { + wpa_printf(MSG_DEBUG, + "WNM: Too short BSS color collision event report from " + MACSTR, MAC2STR(addr)); + return; + } + bitmap = WPA_GET_LE64(report_ie->u.bss_color_collision.color_bitmap); + wpa_printf(MSG_DEBUG, + "WNM: BSS color collision bitmap 0x%llx reported by " + MACSTR, (unsigned long long) bitmap, MAC2STR(addr)); + hostapd_switch_color(hapd->iface->bss[0], bitmap); + break; + case WNM_EVENT_TYPE_BSS_COLOR_IN_USE: + if (!hapd->iconf->ieee80211ax || hapd->conf->disable_11ax) + return; + if (report_ie->len < fixed_field_len + tsf_len + 1) { + wpa_printf(MSG_DEBUG, + "WNM: Too short BSS color in use event report from " + MACSTR, MAC2STR(addr)); + return; + } + color = report_ie->u.bss_color_in_use.color; + if (color > 63) { + wpa_printf(MSG_DEBUG, + "WNM: Invalid BSS color %u report from " + MACSTR, color, MAC2STR(addr)); + return; + } + if (color == 0) { + wpa_printf(MSG_DEBUG, + "WNM: BSS color use report canceled by " + MACSTR, MAC2STR(addr)); + /* TODO: Clear stored color from the collision bitmap + * if there are no other users for it. */ + return; + } + wpa_printf(MSG_DEBUG, "WNM: BSS color %u use report by " + MACSTR, color, MAC2STR(addr)); + hapd->color_collision_bitmap |= 1ULL << color; + break; +#endif /* CONFIG_IEEE80211AX */ + default: + wpa_printf(MSG_DEBUG, + "WNM Event Report type=%d (%s) not supported", + report_ie->type, + wnm_event_type2str(report_ie->type)); + break; + } +} + + int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, const struct ieee80211_mgmt *mgmt, size_t len) { @@ -658,6 +785,10 @@ int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd, plen = len - IEEE80211_HDRLEN - 2; switch (action) { + case WNM_EVENT_REPORT: + ieee802_11_rx_wnm_event_report(hapd, mgmt->sa, payload, + plen); + return 0; case WNM_BSS_TRANS_MGMT_QUERY: ieee802_11_rx_bss_trans_mgmt_query(hapd, mgmt->sa, payload, plen); diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index 21b48ac52..6306ef9a0 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -1959,6 +1959,42 @@ enum wnm_notification_Type { WNM_NOTIF_TYPE_VENDOR_SPECIFIC = 221, }; +struct wnm_event_report_element { + u8 eid; /* WLAN_EID_EVENT_REPORT */ + u8 len; + u8 token; + u8 type; + u8 status; + /* Followed by conditional fields */ + union { + struct { + u8 tsf[8]; /* Event TSF */ + u8 color_bitmap[8]; /* Event Report field */ + } STRUCT_PACKED bss_color_collision; + struct { + u8 tsf[8]; /* Event TSF */ + u8 color; /* Event Report field */ + } STRUCT_PACKED bss_color_in_use; + } u; +} STRUCT_PACKED; + +enum wnm_event_report_status { + WNM_STATUS_SUCCESSFUL = 0, + WNM_STATUS_REQ_FAILED = 1, + WNM_STATUS_REQ_REFUSED = 2, + WNM_STATUS_REQ_INCAPABLE = 3, + WNM_STATUS_FREQUENT_TRANSITION = 4, +}; + +enum wnm_event_report_type { + WNM_EVENT_TYPE_TRANSITION = 0, + WNM_EVENT_TYPE_RSNA = 1, + WNM_EVENT_TYPE_P2P_LINK = 2, + WNM_EVENT_TYPE_WNM_LOG = 3, + WNM_EVENT_TYPE_BSS_COLOR_COLLISION = 4, + WNM_EVENT_TYPE_BSS_COLOR_IN_USE = 5, +}; + /* Channel Switch modes (802.11h) */ #define CHAN_SWITCH_MODE_ALLOW_TX 0 #define CHAN_SWITCH_MODE_BLOCK_TX 1