nl80211: Add VHT 160 MHz channel flags
authorAhmad Kholaif <akholaif@qca.qualcomm.com>
Wed, 28 Oct 2015 21:14:10 +0000 (14:14 -0700)
committerJouni Malinen <j@w1.fi>
Wed, 25 Nov 2015 17:01:14 +0000 (19:01 +0200)
This extends the previous design that covered only the VHT 80 MHz cases
for VHT channel flags. New functions are introduced to allow 160 MHz
bandwidth cases to determine the center channel and check availability
of a 160 MHz channel.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/drivers/driver.h
src/drivers/driver_nl80211_capa.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h

index d3f7057..e925a59 100644 (file)
 #define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
 #define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
 
+#define HOSTAPD_CHAN_VHT_10_150 0x00100000
+#define HOSTAPD_CHAN_VHT_30_130 0x00200000
+#define HOSTAPD_CHAN_VHT_50_110 0x00400000
+#define HOSTAPD_CHAN_VHT_70_90  0x00800000
+#define HOSTAPD_CHAN_VHT_90_70  0x01000000
+#define HOSTAPD_CHAN_VHT_110_50 0x02000000
+#define HOSTAPD_CHAN_VHT_130_30 0x04000000
+#define HOSTAPD_CHAN_VHT_150_10 0x08000000
+
 /**
  * enum reg_change_initiator - Regulatory change initiator
  */
index 25fed11..1b5752f 100644 (file)
@@ -1418,7 +1418,7 @@ static void nl80211_reg_rule_sec(struct nlattr *tb[],
 
 
 static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
-                                int end)
+                                int end, int max_bw)
 {
        int c;
 
@@ -1435,6 +1435,32 @@ static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
 
                if (chan->freq - 70 >= start && chan->freq + 10 <= end)
                        chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+
+               if (max_bw >= 160) {
+                       if (chan->freq - 10 >= start && chan->freq + 150 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_10_150;
+
+                       if (chan->freq - 30 >= start && chan->freq + 130 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_30_130;
+
+                       if (chan->freq - 50 >= start && chan->freq + 110 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_50_110;
+
+                       if (chan->freq - 70 >= start && chan->freq + 90 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_70_90;
+
+                       if (chan->freq - 90 >= start && chan->freq + 70 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_90_70;
+
+                       if (chan->freq - 110 >= start && chan->freq + 50 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_110_50;
+
+                       if (chan->freq - 130 >= start && chan->freq + 30 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_130_30;
+
+                       if (chan->freq - 150 >= start && chan->freq + 10 <= end)
+                               chan->flag |= HOSTAPD_CHAN_VHT_150_10;
+               }
        }
 }
 
@@ -1465,7 +1491,7 @@ static void nl80211_reg_rule_vht(struct nlattr *tb[],
                if (!results->modes[m].vht_capab)
                        continue;
 
-               nl80211_set_vht_mode(&results->modes[m], start, end);
+               nl80211_set_vht_mode(&results->modes[m], start, end, max_bw);
        }
 }
 
index bf0336f..020a469 100644 (file)
@@ -3417,6 +3417,75 @@ static enum chan_allowed wpas_p2p_verify_80mhz(struct wpa_supplicant *wpa_s,
 }
 
 
+static int wpas_p2p_get_center_160mhz(struct wpa_supplicant *wpa_s,
+                                    struct hostapd_hw_modes *mode,
+                                    u8 channel)
+{
+       u8 center_channels[] = { 50, 114 };
+       unsigned int i;
+
+       if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+               /*
+                * In 160 MHz, the bandwidth "spans" 28 channels (e.g., 36-64),
+                * so the center channel is 14 channels away from the start/end.
+                */
+               if (channel >= center_channels[i] - 14 &&
+                   channel <= center_channels[i] + 14)
+                       return center_channels[i];
+
+       return 0;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_160mhz(struct wpa_supplicant *wpa_s,
+                                              struct hostapd_hw_modes *mode,
+                                              u8 channel, u8 bw)
+{
+       u8 center_chan;
+       int i, flags;
+       enum chan_allowed res, ret = ALLOWED;
+
+       center_chan = wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+       if (!center_chan)
+               return NOT_ALLOWED;
+       /* VHT 160 MHz uses DFS channels in most countries. */
+
+       /* Check all the channels are available */
+       for (i = 0; i < 8; i++) {
+               int adj_chan = center_chan - 14 + i * 4;
+
+               res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+               if (res == NOT_ALLOWED)
+                       return NOT_ALLOWED;
+
+               if (res == NO_IR)
+                       ret = NO_IR;
+
+               if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_150))
+                       return NOT_ALLOWED;
+               if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_130))
+                       return NOT_ALLOWED;
+               if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_110))
+                       return NOT_ALLOWED;
+               if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_90))
+                       return NOT_ALLOWED;
+               if (i == 4 && !(flags & HOSTAPD_CHAN_VHT_90_70))
+                       return NOT_ALLOWED;
+               if (i == 5 && !(flags & HOSTAPD_CHAN_VHT_110_50))
+                       return NOT_ALLOWED;
+               if (i == 6 && !(flags & HOSTAPD_CHAN_VHT_130_30))
+                       return NOT_ALLOWED;
+               if (i == 7 && !(flags & HOSTAPD_CHAN_VHT_150_10))
+                       return NOT_ALLOWED;
+       }
+
+       return ret;
+}
+
+
 static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
                                                 struct hostapd_hw_modes *mode,
                                                 u8 channel, u8 bw)
@@ -3435,6 +3504,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
                res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
        } else if (bw == BW80) {
                res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
+       } else if (bw == BW160) {
+               res2 = wpas_p2p_verify_160mhz(wpa_s, mode, channel, bw);
        }
 
        if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3548,6 +3619,15 @@ int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
 }
 
 
+int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
+                              struct hostapd_hw_modes *mode, u8 channel)
+{
+       if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW160))
+               return 0;
+       return wpas_p2p_get_center_160mhz(wpa_s, mode, channel);
+}
+
+
 static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
                        size_t buf_len)
 {
index 56e6834..259d604 100644 (file)
@@ -140,6 +140,8 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
                           struct hostapd_hw_modes *mode, u8 channel);
 int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
                              struct hostapd_hw_modes *mode, u8 channel);
+int wpas_p2p_get_vht160_center(struct wpa_supplicant *wpa_s,
+                              struct hostapd_hw_modes *mode, u8 channel);
 unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
 void wpas_p2p_new_psk_cb(struct wpa_supplicant *wpa_s, const u8 *mac_addr,
                         const u8 *p2p_dev_addr,