hostapd: Allow configuring driver to VHT
authorJohannes Berg <johannes.berg@intel.com>
Fri, 28 Dec 2012 15:24:21 +0000 (17:24 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 12 Jan 2013 15:51:52 +0000 (17:51 +0200)
Signed-hostap: Johannes Berg <johannes.berg@intel.com>

src/ap/ap_drv_ops.c
src/ap/ap_drv_ops.h
src/ap/hostapd.c
src/common/ieee802_11_defs.h
src/drivers/driver.h

index 02da25b..355df15 100644 (file)
@@ -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);
 }
 
index 9c53b99..768a0ba 100644 (file)
@@ -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,
index cef9daf..92fda56 100644 (file)
@@ -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;
index e873545..f72c0d4 100644 (file)
@@ -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
index 7ee71aa..62f621f 100644 (file)
@@ -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 {