]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P: DFS offload for the autonomous GO
authorHu Wang <huw@codeaurora.org>
Tue, 6 Jul 2021 07:30:25 +0000 (15:30 +0800)
committerJouni Malinen <j@w1.fi>
Tue, 7 Sep 2021 14:40:25 +0000 (17:40 +0300)
Enhance the P2P_GROUP_ADD command to support DFS channel with 80 and 160
MHz bandwidth to be used for autonomous GO when using offloaded DFS.

For example, 'P2P_GROUP_ADD freq=5500 max_oper_chwidth=80 ht40 vht'

- Previous behavior: AP fallback to channel 100 using 20 MHz with
  "No VHT higher bandwidth support for the selected channel 100"
- Enhanced behavior: AP starts on channel 100 using 80 MHz with
  "VHT center channel 106 for 80 or 80+80 MHz bandwidth"

This functionality is on top of the driver's capability to offload DFS,
which is advertized through WPA_DRIVER_FLAGS_DFS_OFFLOAD.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
wpa_supplicant/ctrl_iface.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/wpa_supplicant_i.h

index bc8caae506224897c4a470e5c13c6559497a8263..5b74ddcdf62bf5a7e8cbcbe7c7924580a72434cd 100644 (file)
@@ -1531,6 +1531,16 @@ int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
 }
 
 
+/*
+ * 802.11-2020: Table E-4 - Global operating classes
+ * DFS_50_100_Behavior: 118, 119, 120, 121, 122, 123
+ */
+int is_dfs_global_op_class(u8 op_class)
+{
+    return (op_class >= 118) && (op_class <= 123);
+}
+
+
 static int is_11b(u8 rate)
 {
        return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
index e9d7293e791c381ec460328f55bcf1af5511cfa8..e4e4c613e9c6d6abf42d2cd3afc6c57327718ba8 100644 (file)
@@ -218,6 +218,7 @@ int ieee80211_chaninfo_to_channel(unsigned int freq, enum chan_width chanwidth,
                                  int sec_channel, u8 *op_class, u8 *channel);
 int ieee80211_is_dfs(int freq, const struct hostapd_hw_modes *modes,
                     u16 num_modes);
+int is_dfs_global_op_class(u8 op_class);
 enum phy_type ieee80211_get_phy_type(int freq, int ht, int vht);
 
 int supp_rates_11b_only(struct ieee802_11_elems *elems);
index c4f54ae889027e87dba78c9a2425b7038c43be15..15a7ba2b9d456ce1b06bb0fb1c3aa07c20162be1 100644 (file)
@@ -6931,6 +6931,10 @@ static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
        if (allow_6ghz && chwidth == 40)
                max_oper_chwidth = CHANWIDTH_40MHZ_6GHZ;
 
+       /* Allow DFS to be used for Autonomous GO */
+       wpa_s->p2p_go_allow_dfs = !!(wpa_s->drv_flags &
+                                    WPA_DRIVER_FLAGS_DFS_OFFLOAD);
+
        if (group_id >= 0)
                return p2p_ctrl_group_add_persistent(wpa_s, group_id,
                                                     freq, freq2, ht40, vht,
index 8864d7a848b9b75c66a7fcc4df417b0f28bd614a..cc8db35242000d287e39700cbea2ac8a479a5149 100644 (file)
@@ -1038,6 +1038,7 @@ static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
        wpa_s->p2p_group_common_freqs = NULL;
        wpa_s->p2p_group_common_freqs_num = 0;
        wpa_s->p2p_go_do_acs = 0;
+       wpa_s->p2p_go_allow_dfs = 0;
 
        wpa_s->waiting_presence_resp = 0;
 
@@ -3585,12 +3586,12 @@ static enum chan_allowed has_channel(struct wpa_global *global,
                if ((unsigned int) mode->channels[i].freq == freq) {
                        if (flags)
                                *flags = mode->channels[i].flag;
-                       if (mode->channels[i].flag &
-                           (HOSTAPD_CHAN_DISABLED |
-                            HOSTAPD_CHAN_RADAR))
+                       if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
                                return NOT_ALLOWED;
                        if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
                                return NO_IR;
+                       if (mode->channels[i].flag & HOSTAPD_CHAN_RADAR)
+                               return RADAR;
                        return ALLOWED;
                }
        }
@@ -3650,7 +3651,8 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
                                                chans, num_chans);
        if (!center_chan)
                return NOT_ALLOWED;
-       if (!is_6ghz && center_chan >= 58 && center_chan <= 138)
+       if (!wpa_s->p2p_go_allow_dfs &&
+           !is_6ghz && center_chan >= 58 && center_chan <= 138)
                return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
 
        /* check all the channels are available */
@@ -3661,6 +3663,8 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
                                  &flags);
                if (res == NOT_ALLOWED)
                        return NOT_ALLOWED;
+               if (res == RADAR)
+                       ret = RADAR;
                if (res == NO_IR)
                        ret = NO_IR;
                if (!is_6ghz) {
@@ -3742,6 +3746,8 @@ static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
                if (res == NOT_ALLOWED)
                        return NOT_ALLOWED;
 
+               if (res == RADAR)
+                       ret = RADAR;
                if (res == NO_IR)
                        ret = NO_IR;
 
@@ -3828,6 +3834,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
                return NOT_ALLOWED;
        if (res == NO_IR || res2 == NO_IR)
                return NO_IR;
+       if (res == RADAR || res2 == RADAR)
+               return RADAR;
        return res;
 }
 
@@ -3936,7 +3944,11 @@ int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s,
                u16 ch;
                int chan = channel;
 
-               if (o->p2p == NO_P2P_SUPP ||
+               /* Allow DFS channels marked as NO_P2P_SUPP to be used with
+                * driver offloaded DFS. */
+               if ((o->p2p == NO_P2P_SUPP &&
+                    (!is_dfs_global_op_class(o->op_class) ||
+                     !wpa_s->p2p_go_allow_dfs)) ||
                    (is_6ghz_op_class(o->op_class) &&
                     wpa_s->conf->p2p_6ghz_disable))
                        continue;
@@ -3959,6 +3971,11 @@ int wpas_p2p_get_sec_channel_offset_40mhz(struct wpa_supplicant *wpa_s,
                                        return get_6ghz_sec_channel(channel);
                                return (o->bw == BW40MINUS) ? -1 : 1;
                        }
+                       if (ret == RADAR && wpa_s->p2p_go_allow_dfs) {
+                               /* Allow RADAR channels used for driver
+                                * offloaded DFS */
+                               return (o->bw == BW40MINUS) ? -1 : 1;
+                       }
                }
        }
        return 0;
@@ -3971,8 +3988,10 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
 {
        const u8 *chans;
        size_t num_chans;
+       enum chan_allowed ret;
 
-       if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80))
+       ret = wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW80);
+       if (!(ret == ALLOWED || (ret == RADAR && wpa_s->p2p_go_allow_dfs)))
                return 0;
 
        if (is_6ghz_op_class(op_class)) {
@@ -3993,8 +4012,10 @@ int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
 {
        const u8 *chans;
        size_t num_chans;
+       enum chan_allowed ret;
 
-       if (!wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160))
+       ret = wpas_p2p_verify_channel(wpa_s, mode, op_class, channel, BW160);
+       if (!(ret == ALLOWED || (ret == RADAR && wpa_s->p2p_go_allow_dfs)))
                return 0;
        if (is_6ghz_op_class(op_class)) {
                chans = center_channels_6ghz_160mhz;
@@ -6766,6 +6787,11 @@ wpas_p2p_get_group_iface(struct wpa_supplicant *wpa_s, int addr_allocated,
                wpa_s->p2p_go_do_acs = 0;
        }
 
+       if (go && wpa_s->p2p_go_allow_dfs) {
+               group_wpa_s->p2p_go_allow_dfs = wpa_s->p2p_go_allow_dfs;
+               wpa_s->p2p_go_allow_dfs = 0;
+       }
+
        wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Use separate group interface %s",
                group_wpa_s->ifname);
        group_wpa_s->p2p_first_connection_timeout = 0;
index f4b3e03804af52c5ff4925018e541bf7d5ae7d6f..951d3ee1ba499a4524c6fb1fc0184ff273a90c8b 100644 (file)
@@ -1125,6 +1125,7 @@ struct wpa_supplicant {
        unsigned int p2p_disable_ip_addr_req:1;
        unsigned int p2ps_method_config_any:1;
        unsigned int p2p_cli_probe:1;
+       unsigned int p2p_go_allow_dfs:1;
        enum hostapd_hw_mode p2p_go_acs_band;
        int p2p_persistent_go_freq;
        int p2p_persistent_id;
@@ -1675,7 +1676,7 @@ void wpas_update_mbo_connect_params(struct wpa_supplicant *wpa_s);
 
 /* op_classes.c */
 enum chan_allowed {
-       NOT_ALLOWED, NO_IR, ALLOWED
+       NOT_ALLOWED, NO_IR, RADAR, ALLOWED
 };
 
 enum chan_allowed verify_channel(struct hostapd_hw_modes *mode, u8 op_class,