diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c index 02da25b71..355df150c 100644 --- a/src/ap/ap_drv_ops.c +++ b/src/ap/ap_drv_ops.c @@ -454,19 +454,76 @@ int hostapd_flush(struct hostapd_data *hapd) int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, - int channel, int ht_enabled, int sec_channel_offset) + int channel, int ht_enabled, int vht_enabled, + int sec_channel_offset, int vht_oper_chwidth, + int center_segment0, int center_segment1) { struct hostapd_freq_params data; - if (hapd->driver == NULL) - return 0; - if (hapd->driver->set_freq == NULL) - return 0; + int tmp; + os_memset(&data, 0, sizeof(data)); data.mode = mode; data.freq = freq; data.channel = channel; data.ht_enabled = ht_enabled; + data.vht_enabled = vht_enabled; data.sec_channel_offset = sec_channel_offset; + data.center_freq1 = freq + sec_channel_offset * 10; + data.center_freq2 = 0; + data.bandwidth = sec_channel_offset ? 40 : 20; + + /* + * This validation code is probably misplaced, maybe it should be + * in src/ap/hw_features.c and check the hardware support as well. + */ + if (data.vht_enabled) switch (vht_oper_chwidth) { + case VHT_CHANWIDTH_USE_HT: + if (center_segment1) + return -1; + if (5000 + center_segment0 * 5 != data.center_freq1) + return -1; + break; + case VHT_CHANWIDTH_80P80MHZ: + if (center_segment1 == center_segment0 + 4 || + center_segment1 == center_segment0 - 4) + return -1; + data.center_freq2 = 5000 + center_segment1 * 5; + /* fall through */ + case VHT_CHANWIDTH_80MHZ: + data.bandwidth = 80; + if (vht_oper_chwidth == 1 && center_segment1) + return -1; + if (vht_oper_chwidth == 3 && !center_segment1) + return -1; + if (!sec_channel_offset) + return -1; + /* primary 40 part must match the HT configuration */ + tmp = (30 + freq - 5000 - center_segment0 * 5)/20; + tmp /= 2; + if (data.center_freq1 != 5000 + + center_segment0 * 5 - 20 + 40 * tmp) + return -1; + data.center_freq1 = 5000 + center_segment0 * 5; + break; + case VHT_CHANWIDTH_160MHZ: + data.bandwidth = 160; + if (center_segment1) + return -1; + if (!sec_channel_offset) + return -1; + /* primary 40 part must match the HT configuration */ + tmp = (70 + freq - 5000 - center_segment0 * 5)/20; + tmp /= 2; + if (data.center_freq1 != 5000 + + center_segment0 * 5 - 60 + 40 * tmp) + return -1; + data.center_freq1 = 5000 + center_segment0 * 5; + break; + } + if (hapd->driver == NULL) + return 0; + if (hapd->driver->set_freq == NULL) + return 0; return hapd->driver->set_freq(hapd->drv_priv, &data); } diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h index 9c53b99d8..768a0ba64 100644 --- a/src/ap/ap_drv_ops.h +++ b/src/ap/ap_drv_ops.h @@ -55,7 +55,9 @@ int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd, const u8 *addr, int idx, u8 *seq); int hostapd_flush(struct hostapd_data *hapd); int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq, - int channel, int ht_enabled, int sec_channel_offset); + int channel, int ht_enabled, int vht_enabled, + int sec_channel_offset, int vht_oper_chwidth, + int center_segment0, int center_segment1); int hostapd_set_rts(struct hostapd_data *hapd, int rts); int hostapd_set_frag(struct hostapd_data *hapd, int frag); int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr, diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c index cef9dafc5..92fda5693 100644 --- a/src/ap/hostapd.c +++ b/src/ap/hostapd.c @@ -894,7 +894,11 @@ int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err) if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq, hapd->iconf->channel, hapd->iconf->ieee80211n, - hapd->iconf->secondary_channel)) { + hapd->iconf->ieee80211ac, + hapd->iconf->secondary_channel, + hapd->iconf->vht_oper_chwidth, + hapd->iconf->vht_oper_centr_freq_seg0_idx, + hapd->iconf->vht_oper_centr_freq_seg1_idx)) { wpa_printf(MSG_ERROR, "Could not set channel for " "kernel driver"); return -1; diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h index e873545f6..f72c0d40c 100644 --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -712,6 +712,12 @@ struct ieee80211_vht_operation { #define VHT_CAP_RX_ANTENNA_PATTERN ((u32) BIT(28)) #define VHT_CAP_TX_ANTENNA_PATTERN ((u32) BIT(29)) +/* VHT channel widths */ +#define VHT_CHANWIDTH_USE_HT 0 +#define VHT_CHANWIDTH_80MHZ 1 +#define VHT_CHANWIDTH_160MHZ 2 +#define VHT_CHANWIDTH_80P80MHZ 3 + #define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs) * 00:50:F2 */ #define WPA_IE_VENDOR_TYPE 0x0050f201 diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 7ee71aaac..62f621fa0 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -907,10 +907,19 @@ struct hostapd_freq_params { int mode; int freq; int channel; + /* for HT */ int ht_enabled; int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled, * secondary channel below primary, 1 = HT40 * enabled, secondary channel above primary */ + + /* for VHT */ + int vht_enabled; + + /* valid for both HT and VHT, center_freq2 is non-zero + * only for bandwidth 80 and an 80+80 channel */ + int center_freq1, center_freq2; + int bandwidth; }; enum wpa_driver_if_type {