From: Aditya Kumar Singh Date: Fri, 6 Sep 2024 13:23:57 +0000 (+0530) Subject: nl80211: Handle radar event properly during MLO X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bfc89d757b723eecfac034c15f6ab0e6ae7dd2ed;p=thirdparty%2Fhostap.git nl80211: Handle radar event properly during MLO Currently, the driver while sending an NL80211_CMD_RADAR_DETECT command does not send a link ID at all. Hence the condition on whether the link ID is passed is not required. At the same time, for certain commands, if_idx will not be given and hence the event will be routed to the drv's first BSS only which might not have any 5 GHz link. Hence there is need to refactor the logic for such cases and identify the intended BSS properly and then pass the event to it. Hence, * identify the link ID based on the freq info present in the event. * identify the correct BSS to which the event should be routed in case the event comes without any if_idx. * check for the underlying link even when the link is not operating on the same frequency for events like NL80211_RADAR_NOP_FINISHED. Signed-off-by: Aditya Kumar Singh --- diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index 849666f5c..e50a81483 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -2510,29 +2510,62 @@ static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv, } -static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, - struct nlattr **tb) +static void nl80211_process_radar_event(struct i802_bss *bss, + union wpa_event_data *data, + enum nl80211_radar_event event_type) { + wpa_printf(MSG_DEBUG, + "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz, link_id=%d", + data->dfs_event.freq, data->dfs_event.ht_enabled, + data->dfs_event.chan_offset, data->dfs_event.chan_width, + data->dfs_event.cf1, data->dfs_event.cf2, + data->dfs_event.link_id); + + switch (event_type) { + case NL80211_RADAR_DETECTED: + wpa_supplicant_event(bss->ctx, EVENT_DFS_RADAR_DETECTED, data); + break; + case NL80211_RADAR_CAC_FINISHED: + wpa_supplicant_event(bss->ctx, EVENT_DFS_CAC_FINISHED, data); + break; + case NL80211_RADAR_CAC_ABORTED: + wpa_supplicant_event(bss->ctx, EVENT_DFS_CAC_ABORTED, data); + break; + case NL80211_RADAR_NOP_FINISHED: + wpa_supplicant_event(bss->ctx, EVENT_DFS_NOP_FINISHED, data); + break; + case NL80211_RADAR_PRE_CAC_EXPIRED: + wpa_supplicant_event(bss->ctx, EVENT_DFS_PRE_CAC_EXPIRED, + data); + break; + case NL80211_RADAR_CAC_STARTED: + wpa_supplicant_event(bss->ctx, EVENT_DFS_CAC_STARTED, data); + break; + default: + wpa_printf(MSG_DEBUG, + "nl80211: Unknown radar event %d received", + event_type); + break; + } +} + + +static void nl80211_radar_event(struct i802_bss *bss, struct nlattr **tb) +{ + struct wpa_driver_nl80211_data *drv = bss->drv; union wpa_event_data data; enum nl80211_radar_event event_type; + struct i802_bss *bss_iter; + int i; + bool hit = false; if (!tb[NL80211_ATTR_WIPHY_FREQ] || !tb[NL80211_ATTR_RADAR_EVENT]) return; os_memset(&data, 0, sizeof(data)); - data.dfs_event.link_id = NL80211_DRV_LINK_ID_NA; data.dfs_event.freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]); event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]); - if (tb[NL80211_ATTR_MLO_LINK_ID]) { - data.dfs_event.link_id = - nla_get_u8(tb[NL80211_ATTR_MLO_LINK_ID]); - } else if (data.dfs_event.freq) { - data.dfs_event.link_id = - nl80211_get_link_id_by_freq(drv->first_bss, - data.dfs_event.freq); - } - /* Check HT params */ if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { data.dfs_event.ht_enabled = 1; @@ -2563,38 +2596,68 @@ static void nl80211_radar_event(struct wpa_driver_nl80211_data *drv, if (tb[NL80211_ATTR_CENTER_FREQ2]) data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]); + /* Find a link match based on the frequency. If NL80211_DRV_LINK_ID_NA + * is returned, either a match was not found or the BSS could be + * operating as a non-MLO. */ + data.dfs_event.link_id = nl80211_get_link_id_by_freq( + bss, data.dfs_event.freq); + if (data.dfs_event.link_id == NL80211_DRV_LINK_ID_NA) { + /* For non-MLO operation, frequency should still match */ + if (!bss->valid_links && + bss->links[0].freq == data.dfs_event.freq) + return nl80211_process_radar_event(bss, &data, + event_type); + } + wpa_printf(MSG_DEBUG, - "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz, link_id=%d", - data.dfs_event.freq, data.dfs_event.ht_enabled, - data.dfs_event.chan_offset, data.dfs_event.chan_width, - data.dfs_event.cf1, data.dfs_event.cf2, - data.dfs_event.link_id); + "nl80211: Checking suitable BSS for the DFS event"); + + /* It is possible to have the event without ifidx and wdev_id, e.g., + * with NL80211_RADAR_NOP_FINISHED and NL80211_RADAR_PRE_CAC_EXPIRED. + * Hence need to check on all BSSs. */ + for (bss_iter = drv->first_bss; bss_iter; bss_iter = bss_iter->next) { + data.dfs_event.link_id = nl80211_get_link_id_by_freq( + bss_iter, data.dfs_event.freq); + if (data.dfs_event.link_id == NL80211_DRV_LINK_ID_NA) { + /* For non-MLO operation, frequency should still match + */ + if (!bss_iter->valid_links && + bss_iter->links[0].freq == data.dfs_event.freq) + return nl80211_process_radar_event( + bss_iter, &data, event_type); + } - switch (event_type) { - case NL80211_RADAR_DETECTED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_RADAR_DETECTED, &data); - break; - case NL80211_RADAR_CAC_FINISHED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_FINISHED, &data); - break; - case NL80211_RADAR_CAC_ABORTED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_ABORTED, &data); - break; - case NL80211_RADAR_NOP_FINISHED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_NOP_FINISHED, &data); - break; - case NL80211_RADAR_PRE_CAC_EXPIRED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_PRE_CAC_EXPIRED, - &data); - break; - case NL80211_RADAR_CAC_STARTED: - wpa_supplicant_event(drv->ctx, EVENT_DFS_CAC_STARTED, &data); - break; - default: - wpa_printf(MSG_DEBUG, "nl80211: Unknown radar event %d " - "received", event_type); - break; + /* For event like NL80211_RADAR_NOP_FINISHED, frequency + * information will not match exactly the link frequency. Hence, + * if the link frequency is 5 GHz, pass the event to it. + */ + for_each_link_default(bss_iter->valid_links, i, 0) { + if (bss_iter->links[i].freq < 5180 || + bss_iter->links[i].freq > 5900) + continue; + + data.dfs_event.link_id = bss_iter->valid_links ? + i : NL80211_DRV_LINK_ID_NA; + + /* Cannot just return after one match since if split + * hardware is participating in MLO, possibly the event + * is for 5 GHz upper band and this iteration has picked + * a 5 GHz low band link, but 5 GHz freq check will be + * true for both. Hence, iterate on all possible links. + * The handler should take care whether the event is + * actually for it. */ + nl80211_process_radar_event(bss_iter, &data, + event_type); + + hit = true; + } } + + if (hit) + return; + + wpa_printf(MSG_DEBUG, "nl80211: DFS event on unknown freq on %s", + bss->ifname); } @@ -4120,7 +4183,7 @@ static void do_process_drv_event(struct i802_bss *bss, int cmd, mlme_event_ft_event(drv, tb); break; case NL80211_CMD_RADAR_DETECT: - nl80211_radar_event(drv, tb); + nl80211_radar_event(bss, tb); break; case NL80211_CMD_STOP_AP: nl80211_stop_ap(bss, tb);