}
-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;
(!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))
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;
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)
{
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;
}
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");
&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, ¶ms.allowed_freqs);
+ }
+
res = hostapd_drv_set_ap(hapd, ¶ms);
hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
if (res)
* 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 {
#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)
{
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)",
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;
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);
}