}
-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;
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);
}
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);