]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
nl80211: Handle radar event properly during MLO
authorAditya Kumar Singh <quic_adisi@quicinc.com>
Fri, 6 Sep 2024 13:23:57 +0000 (18:53 +0530)
committerJouni Malinen <j@w1.fi>
Mon, 7 Oct 2024 19:31:04 +0000 (22:31 +0300)
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 <quic_adisi@quicinc.com>
src/drivers/driver_nl80211_event.c

index 849666f5c46377099aba93f794581e9d1ad4055f..e50a81483c420200db570081428a75b2b76db8e5 100644 (file)
@@ -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);