summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVeerendranath Jakkam <quic_vjakkam@quicinc.com>2023-04-03 08:11:36 +0530
committerJouni Malinen <j@w1.fi>2023-04-19 11:32:07 +0300
commit9932ff30c46b3c68abe717f7a0011412f5d1c344 (patch)
tree77c591b880e445f57cdbe1b97d1536678b3f031a
parent9bad3c975d0f9a4a9256ad0430a4051208753ca5 (diff)
downloadhostap-9932ff30c46b3c68abe717f7a0011412f5d1c344.tar.gz
Allowed frequency list configuration for AP operation
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>
-rw-r--r--src/ap/ap_drv_ops.c12
-rw-r--r--src/ap/ap_drv_ops.h5
-rw-r--r--src/ap/beacon.c18
-rw-r--r--src/drivers/driver.h10
-rw-r--r--src/drivers/driver_nl80211.c52
-rw-r--r--src/drivers/driver_nl80211.h1
-rw-r--r--src/drivers/driver_nl80211_capa.c3
7 files changed, 94 insertions, 7 deletions
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index f77f738e4..aa4dbe9eb 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -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;
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 93b224499..023cbf1f8 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -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)
{
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index d66d83173..de944fed3 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -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)
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index bcb0c92d6..101f98a72 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -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 {
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 467f46cf4..28f50f11c 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -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)",
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
index 8bfbdd571..38b59ab50 100644
--- a/src/drivers/driver_nl80211.h
+++ b/src/drivers/driver_nl80211.h
@@ -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;
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
index 27ab1d9c2..b904398ca 100644
--- a/src/drivers/driver_nl80211_capa.c
+++ b/src/drivers/driver_nl80211_capa.c
@@ -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);
}