]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Allowed frequency list configuration for AP operation
authorVeerendranath Jakkam <quic_vjakkam@quicinc.com>
Mon, 3 Apr 2023 02:41:36 +0000 (08:11 +0530)
committerJouni Malinen <j@w1.fi>
Wed, 19 Apr 2023 08:32:07 +0000 (11:32 +0300)
Add support to configure the allowed frequency list for AP operation
using a QCA vendor interface before NL80211_CMD_NEW_BEACON/
NL80211_CMD_START_AP. hostapd generates the allowed frequency list by
intersecting user configured frequency list and all the frequencies
advertised by the driver including disabled channels. If user doesn't
specify allowed frequency list, all the frequencies advertised by the
driver, including disabled channels, will be configured.

Signed-off-by: Veerendranath Jakkam <quic_vjakkam@quicinc.com>
src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/beacon.c
src/drivers/driver.h
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_capa.c

index f77f738e4c317f06f217e0ccca5ee70a13f69b66..aa4dbe9eba423d59e94ead7764470ccf230be8ba 100644 (file)
@@ -883,10 +883,10 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd,
 }
 
 
-static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
-                                            struct hostapd_hw_modes *mode,
-                                            int acs_ch_list_all,
-                                            int **freq_list)
+void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
+                                     struct hostapd_hw_modes *mode,
+                                     int acs_ch_list_all, bool allow_disabled,
+                                     int **freq_list)
 {
        int i;
 
@@ -912,7 +912,7 @@ static void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
                     (!hapd->iface->conf->ieee80211ax &&
                      !hapd->iface->conf->ieee80211be)))
                        continue;
-               if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+               if ((!(chan->flag & HOSTAPD_CHAN_DISABLED) || allow_disabled) &&
                    !(hapd->iface->conf->acs_exclude_dfs &&
                      (chan->flag & HOSTAPD_CHAN_RADAR)) &&
                    !(chan->max_tx_power < hapd->iface->conf->min_tx_power))
@@ -969,7 +969,7 @@ int hostapd_drv_do_acs(struct hostapd_data *hapd)
                    selected_mode != mode->mode)
                        continue;
                hostapd_get_hw_mode_any_channels(hapd, mode, acs_ch_list_all,
-                                                &freq_list);
+                                                false, &freq_list);
        }
 
        params.freq_list = freq_list;
index 93b2244990ce8567ca17232aa114939eaf83f9f3..023cbf1f89c9f52de642a3a5c5ebc7c645de44dd 100644 (file)
@@ -156,6 +156,11 @@ int hostapd_drv_set_qos_map(struct hostapd_data *hapd, const u8 *qos_map_set,
 
 void hostapd_get_ext_capa(struct hostapd_iface *iface);
 
+void hostapd_get_hw_mode_any_channels(struct hostapd_data *hapd,
+                                     struct hostapd_hw_modes *mode,
+                                     int acs_ch_list_all, bool allow_disabled,
+                                     int **freq_list);
+
 static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
                                                  int enabled)
 {
index d66d831735ecf6edae81cbf585412964102613f6..de944fed37136e73e3ea6df1b42af49652e2e0d5 100644 (file)
@@ -2058,6 +2058,8 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params)
        os_free(params->unsol_bcast_probe_resp_tmpl);
        params->unsol_bcast_probe_resp_tmpl = NULL;
 #endif /* CONFIG_IEEE80211AX */
+       os_free(params->allowed_freqs);
+       params->allowed_freqs = NULL;
 }
 
 
@@ -2069,7 +2071,8 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
        struct hostapd_config *iconf = iface->conf;
        struct hostapd_hw_modes *cmode = iface->current_mode;
        struct wpabuf *beacon, *proberesp, *assocresp;
-       int res, ret = -1;
+       int res, ret = -1, i;
+       struct hostapd_hw_modes *mode;
 
        if (!hapd->drv_priv) {
                wpa_printf(MSG_ERROR, "Interface is disabled");
@@ -2144,6 +2147,19 @@ static int __ieee802_11_set_beacon(struct hostapd_data *hapd)
                                    &cmode->eht_capab[IEEE80211_MODE_AP]) == 0)
                params.freq = &freq;
 
+       for (i = 0; i < hapd->iface->num_hw_features; i++) {
+               mode = &hapd->iface->hw_features[i];
+
+               if (iconf->hw_mode != HOSTAPD_MODE_IEEE80211ANY &&
+                   iconf->hw_mode != mode->mode)
+                       continue;
+
+               hostapd_get_hw_mode_any_channels(hapd, mode,
+                                                !(iconf->acs_freq_list.num ||
+                                                  iconf->acs_ch_list.num),
+                                                true, &params.allowed_freqs);
+       }
+
        res = hostapd_drv_set_ap(hapd, &params);
        hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
        if (res)
index bcb0c92d6d0ea79c70e1f3fb66e20b891c25b34d..101f98a72d602ff5c890b28fbc898772a00f1427 100644 (file)
@@ -1748,6 +1748,16 @@ struct wpa_driver_ap_params {
         * The driver will use these to include RNR elements in EMA beacons.
         */
        u8 **rnr_elem_offset;
+
+       /**
+        * allowed_freqs - List of allowed 20 MHz channel center frequencies in
+        * MHz for AP operation. Drivers which support this parameter will
+        * generate a new list based on this provided list by filtering out
+        * channels that cannot be used at that time due to regulatory or other
+        * constraints. The resulting list is used as the list of all allowed
+        * channels whenever performing operations like ACS and DFS.
+        */
+       int *allowed_freqs;
 };
 
 struct wpa_driver_mesh_bss_params {
index 467f46cf4ac1f2333facb438b17af5d302e3dfcf..28f50f11ca14f59548e22e5a446033a125367cbf 100644 (file)
@@ -4753,6 +4753,52 @@ static int nl80211_mbssid(struct nl_msg *msg,
 #endif /* CONFIG_IEEE80211AX */
 
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
+static void qca_set_allowed_ap_freqs(struct wpa_driver_nl80211_data *drv,
+                                   const int *freqs, int num_freqs)
+{
+       struct nl_msg *msg;
+       struct nlattr *params, *freqs_list;
+       int i, ret;
+
+       if (!drv->set_wifi_conf_vendor_cmd_avail || !drv->qca_ap_allowed_freqs)
+               return;
+
+       wpa_printf(MSG_DEBUG, "nl80211: Set AP allowed frequency list");
+
+       if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+           nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+                       QCA_NL80211_VENDOR_SUBCMD_SET_WIFI_CONFIGURATION) ||
+           !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)))
+               goto err;
+
+       freqs_list = nla_nest_start(
+               msg, QCA_WLAN_VENDOR_ATTR_CONFIG_AP_ALLOWED_FREQ_LIST);
+       if (!freqs_list)
+               goto err;
+
+       for (i = 0; i < num_freqs; i++) {
+               if (nla_put_u32(msg, i, freqs[i]))
+                       goto err;
+       }
+
+       nla_nest_end(msg, freqs_list);
+       nla_nest_end(msg, params);
+
+       ret = send_and_recv_msgs(drv, msg, NULL, NULL, NULL, NULL);
+       if (ret)
+               wpa_printf(MSG_ERROR,
+                          "nl80211: Failed set AP alllowed frequency list: %d (%s)",
+                          ret, strerror(-ret));
+
+       return;
+err:
+       nlmsg_free(msg);
+}
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
+
 static int wpa_driver_nl80211_set_ap(void *priv,
                                     struct wpa_driver_ap_params *params)
 {
@@ -5075,6 +5121,12 @@ static int wpa_driver_nl80211_set_ap(void *priv,
                        goto fail;
        }
 
+#ifdef CONFIG_DRIVER_NL80211_QCA
+       if (cmd == NL80211_CMD_NEW_BEACON && params->allowed_freqs)
+               qca_set_allowed_ap_freqs(drv, params->allowed_freqs,
+                                        int_array_len(params->allowed_freqs));
+#endif /* CONFIG_DRIVER_NL80211_QCA */
+
        ret = send_and_recv_msgs_connect_handle(drv, msg, bss, 1);
        if (ret) {
                wpa_printf(MSG_DEBUG, "nl80211: Beacon set failed: %d (%s)",
index 8bfbdd5715e2286bbfd1c956fd215e101bd5acdc..38b59ab5059d37639ae1cb6a7f2219bb33da0144 100644 (file)
@@ -199,6 +199,7 @@ struct wpa_driver_nl80211_data {
        unsigned int uses_6ghz:1;
        unsigned int secure_ranging_ctx_vendor_cmd_avail:1;
        unsigned int puncturing:1;
+       unsigned int qca_ap_allowed_freqs:1;
 
        u64 vendor_scan_cookie;
        u64 remain_on_chan_cookie;
index 27ab1d9c2bfdecfc92dd47768454936bfc341f49..b904398ca32e06a6234354f697869a4551feee26 100644 (file)
@@ -1405,6 +1405,9 @@ static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
                    QCA_WLAN_VENDOR_FEATURE_PROT_RANGE_NEGO_AND_MEASURE_AP,
                    &info))
                drv->capa.flags2 |= WPA_DRIVER_FLAGS2_PROT_RANGE_NEG_AP;
+       if (check_feature(QCA_WLAN_VENDOR_FEATURE_AP_ALLOWED_FREQ_LIST,
+                         &info))
+               drv->qca_ap_allowed_freqs = 1;
        os_free(info.flags);
 }