}
+static int hostapd_ctrl_iface_set_bw(struct hostapd_iface *iface, char *pos)
+{
+#ifdef NEED_AP_MLME
+ struct hostapd_freq_params freq_params;
+ int ret;
+ enum oper_chan_width chanwidth;
+ u8 chan, oper_class;
+
+ if (!(iface->drv_flags2 & WPA_DRIVER_FLAGS2_AP_CHANWIDTH_CHANGE))
+ return -1;
+
+ ret = hostapd_parse_freq_params(pos, &freq_params, iface->freq);
+ if (ret)
+ return ret;
+
+ chanwidth = hostapd_chan_width_from_freq_params(&freq_params);
+
+ if (ieee80211_freq_to_channel_ext(
+ freq_params.freq,
+ freq_params.sec_channel_offset,
+ chanwidth, &oper_class,
+ &chan) == NUM_HOSTAPD_MODES) {
+ wpa_printf(MSG_DEBUG,
+ "invalid channel: (freq=%d, sec_channel_offset=%d, vht_enabled=%d, he_enabled=%d)",
+ freq_params.freq,
+ freq_params.sec_channel_offset,
+ freq_params.vht_enabled,
+ freq_params.he_enabled);
+ return -1;
+ }
+
+ freq_params.channel = chan;
+
+ /* FIXME: What if the newly extended channel overlaps radar ranges? */
+
+ ret = hostapd_change_config_freq(iface->bss[0], iface->conf,
+ &freq_params, NULL);
+ if (ret)
+ return ret;
+
+ ieee802_11_set_beacons(iface);
+ return 0;
+
+#else /* NEED_AP_MLME */
+ return -1;
+#endif /* NEED_AP_MLME */
+}
+
+
static int hostapd_ctrl_iface_mib(struct hostapd_data *hapd, char *reply,
int reply_size, const char *param)
{
} else if (os_strncmp(buf, "REGISTER_FRAME ", 15) == 0) {
if (hostapd_ctrl_register_frame(hapd, buf + 16) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "SET_BW ", 7) == 0) {
+ /* note: preserve the space for hostapd_parse_freq_params() */
+ if (hostapd_ctrl_iface_set_bw(hapd->iface, buf + 6))
+ reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
}
+static int hostapd_cli_cmd_set_bw(struct wpa_ctrl *ctrl,
+ int argc, char *argv[])
+{
+ return hostapd_cli_cmd(ctrl, "SET_BW", 0, argc, argv);
+}
+
+
static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
#endif /* CONFIG_IEEE80211AX */
{ "notify_cw_change", hostapd_cli_cmd_notify_cw_change, NULL,
"<channel_width> = 0 - 20 MHz, 1 - 40 MHz, 2 - 80 MHz, 3 - 160 MHz" },
+ { "set_bw", hostapd_cli_cmd_set_bw, NULL,
+ "[sec_channel_offset=] [center_freq1=]\n"
+ " [center_freq2=] [bandwidth=] [ht|vht]\n"
+ " = change channel bandwidth" },
{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif, NULL,
"<addr> <url>\n"
" = send WNM-Notification Subscription Remediation Request" },
* the same hw_mode. Any other changes to MAC parameters or provided settings
* are not supported.
*/
-static int hostapd_change_config_freq(struct hostapd_data *hapd,
- struct hostapd_config *conf,
- struct hostapd_freq_params *params,
- struct hostapd_freq_params *old_params)
+int hostapd_change_config_freq(struct hostapd_data *hapd,
+ struct hostapd_config *conf,
+ struct hostapd_freq_params *params,
+ struct hostapd_freq_params *old_params)
{
int channel;
u8 seg0 = 0, seg1 = 0;
enum smps_mode smps_mode,
enum chan_width chan_width, u8 rx_nss);
+int hostapd_change_config_freq(struct hostapd_data *hapd,
+ struct hostapd_config *conf,
+ struct hostapd_freq_params *params,
+ struct hostapd_freq_params *old_params);
#ifdef CONFIG_FST
void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
struct fst_wpa_obj *iface_obj);
#define WPA_DRIVER_FLAGS2_P2P_FEATURE_V2 0x0000000002000000ULL
/** Driver supports P2P PCC mode */
#define WPA_DRIVER_FLAGS2_P2P_FEATURE_PCC_MODE 0x0000000004000000ULL
+/** Driver supports arbitrary channel width changes in AP mode */
+#define WPA_DRIVER_FLAGS2_AP_CHANWIDTH_CHANGE 0x0000000008000000ULL
+
u64 flags2;
#define FULL_AP_CLIENT_STATE_SUPP(drv_flags) \
if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
- if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
+ if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE) {
capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
+ capa->flags2 |= WPA_DRIVER_FLAGS2_AP_CHANWIDTH_CHANGE;
+ }
if (flags & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) {
wpa_printf(MSG_DEBUG, "nl80211: TDLS channel switch");
if hapd.get_status_field("secondary_channel") != "-1":
raise Exception("Unexpected secondary_channel (did not re-enable 40 MHz)")
+def test_ap_ht_20_40_switch(dev, apdev):
+ """Do a bandwidth switch from 20 to 40 MHz without doing a CSA"""
+ clear_scan_cache(apdev[0])
+ params = {"ssid": "ht_20_40",
+ "channel": "6",
+ "ht_capab": "[HT40-]"}
+ hapd = hostapd.add_ap(apdev[0], params)
+ if hapd.get_status_field("secondary_channel") != "-1":
+ raise Exception("Unexpected secondary_channel")
+
+ dev[0].connect("ht_20_40", key_mgmt="NONE", scan_freq="2437")
+ if hapd.get_status_field("secondary_channel") != "-1":
+ raise Exception("Unexpected secondary_channel")
+
+ hapd.request("SET_BW bandwidth=20 ht")
+ time.sleep(1)
+ if hapd.get_status_field("secondary_channel") != "0":
+ raise Exception("Unexpected secondary_channel")
+ sig = dev[0].request('SIGNAL_POLL').splitlines()
+ expected = (
+ 'FREQUENCY=2437',
+ 'WIDTH=20 MHz',
+ 'CENTER_FRQ1=2437',
+ )
+ for e in expected:
+ if not e in sig:
+ raise Exception("%s not found in %r" % (e, sig))
+
+ hapd.request("SET_BW bandwidth=40 sec_channel_offset=-1 ht")
+ time.sleep(1)
+ if hapd.get_status_field("secondary_channel") != "-1":
+ raise Exception("Unexpected secondary_channel")
+ sig = dev[0].request('SIGNAL_POLL').splitlines()
+ expected = (
+ 'FREQUENCY=2437',
+ 'WIDTH=40 MHz',
+ 'CENTER_FRQ1=2427',
+ )
+ for e in expected:
+ if not e in sig:
+ raise Exception("%s not found in %r" % (e, sig))
+
def test_ap_ht_40mhz_intolerant_sta_deinit(dev, apdev):
"""Associated STA indicating 40 MHz intolerant and hostapd deinit"""
clear_scan_cache(apdev[0])
time.sleep(1)
finally:
clear_regdom(hapd, dev)
+
+def test_ap_vht_bwswitch(dev, apdev):
+ """Do a bandwidth switch without a CSA"""
+ try:
+ params = {"ssid": "vht",
+ "country_code": "FI",
+ "hw_mode": "a",
+ "channel": "36",
+ "ht_capab": "[HT40+]",
+ "ieee80211n": "1",
+ "ieee80211ac": "1",
+ "vht_oper_chwidth": "1",
+ "vht_capab": "[MAX-MPDU-11454]",
+ "vht_oper_centr_freq_seg0_idx": "42"}
+ hapd = hostapd.add_ap(apdev[0], params)
+
+ dev[0].connect("vht", key_mgmt="NONE", scan_freq='5180')
+
+ for request, expected in [
+ (None,
+ ('FREQUENCY=5180', 'WIDTH=80 MHz', 'CENTER_FRQ1=5210')),
+ ('center_freq1=5210 sec_channel_offset=1 bandwidth=40 ht vht',
+ ('FREQUENCY=5180', 'WIDTH=40 MHz', 'CENTER_FRQ1=5190')),
+ ('center_freq1=5210 sec_channel_offset=0 bandwidth=20 ht vht',
+ ('FREQUENCY=5180', 'WIDTH=20 MHz', 'CENTER_FRQ1=5180')),
+ ('bandwidth=80 sec_channel_offset=1 center_freq1=5210 ht vht',
+ ('FREQUENCY=5180', 'WIDTH=80 MHz', 'CENTER_FRQ1=5210')),
+ ]:
+ if request is not None:
+ if 'OK' not in hapd.request("SET_BW " + request):
+ raise Exception("SET_BW request failed")
+ time.sleep(1)
+ sig = dev[0].request('SIGNAL_POLL').splitlines()
+ for e in expected:
+ if not e in sig:
+ raise Exception("%s not found in %r" % (e, sig))
+ finally:
+ clear_regdom(hapd, dev)