]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
P2P: Add VHT support
authorEliad Peller <eliad@wizery.com>
Sun, 27 Oct 2013 18:08:36 +0000 (20:08 +0200)
committerJouni Malinen <j@w1.fi>
Sun, 27 Oct 2013 18:08:36 +0000 (20:08 +0200)
Start GO with VHT support if VHT option was requested
and the appropriate channels are available.

Signed-hostap: Eliad Peller <eliadx.peller@intel.com>

src/p2p/p2p_go_neg.c
src/p2p/p2p_utils.c
wpa_supplicant/ap.c
wpa_supplicant/p2p_supplicant.c
wpa_supplicant/p2p_supplicant.h

index 55b1ed356f5250009b7e55a7f194a82b97cda863..7eaa8dcc26444a1f3db331a5238f76a64412595e 100644 (file)
@@ -412,6 +412,18 @@ void p2p_reselect_channel(struct p2p_data *p2p,
                }
        }
 
+       /* Try a channel where we might be able to use VHT */
+       for (i = 0; i < intersection->reg_classes; i++) {
+               struct p2p_reg_class *c = &intersection->reg_class[i];
+               if (c->reg_class == 128) {
+                       p2p_dbg(p2p, "Pick possible VHT channel (reg_class %u channel %u) from intersection",
+                               c->reg_class, c->channel[0]);
+                       p2p->op_reg_class = c->reg_class;
+                       p2p->op_channel = c->channel[0];
+                       return;
+               }
+       }
+
        /* Try a channel where we might be able to use HT40 */
        for (i = 0; i < intersection->reg_classes; i++) {
                struct p2p_reg_class *c = &intersection->reg_class[i];
index 94b5d0b2849d6566f58407331d3a43239bc7cab7..a3dcdebb0eafa52b8d087b5c779c116dfe7d862b 100644 (file)
@@ -94,6 +94,10 @@ int p2p_channel_to_freq(int op_class, int channel)
                if (channel < 149 || channel > 161)
                        return -1;
                return 5000 + 5 * channel;
+       case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+               if (channel < 36 || channel > 161)
+                       return -1;
+               return 5000 + 5 * channel;
        }
        return -1;
 }
index fdbe248a7369fddd7248dec197c218bc8fbd5c08..b55c068b71e6cc4acea0888f405af472ba06a750 100644 (file)
@@ -42,6 +42,31 @@ static void wpas_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
 #endif /* CONFIG_WPS */
 
 
+static void wpas_conf_ap_vht(struct wpa_supplicant *wpa_s,
+                            struct hostapd_config *conf,
+                            struct hostapd_hw_modes *mode)
+{
+       u8 center_chan = 0;
+       u8 channel = conf->channel;
+
+       if (!conf->secondary_channel)
+               goto no_vht;
+
+       center_chan = wpas_p2p_get_vht80_center(wpa_s, mode, channel);
+       if (!center_chan)
+               goto no_vht;
+
+       /* Use 80 MHz channel */
+       conf->vht_oper_chwidth = 1;
+       conf->vht_oper_centr_freq_seg0_idx = center_chan;
+       return;
+
+no_vht:
+       conf->vht_oper_centr_freq_seg0_idx =
+               channel + conf->secondary_channel * 2;
+}
+
+
 static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                                  struct wpa_ssid *ssid,
                                  struct hostapd_config *conf)
@@ -114,6 +139,11 @@ static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
                                 HT_CAP_INFO_SHORT_GI40MHZ |
                                 HT_CAP_INFO_RX_STBC_MASK |
                                 HT_CAP_INFO_MAX_AMSDU_SIZE);
+
+                       if (mode->vht_capab && ssid->vht) {
+                               conf->ieee80211ac = 1;
+                               wpas_conf_ap_vht(wpa_s, conf, mode);
+                       }
                }
        }
 #endif /* CONFIG_IEEE80211N */
index c22113a04f809ff62aa958779871e5deaed85c6e..0ebf332ca51c27df6b64d0356dced6ef91babedd 100644 (file)
@@ -3038,7 +3038,7 @@ struct p2p_oper_class_map {
        u8 min_chan;
        u8 max_chan;
        u8 inc;
-       enum { BW20, BW40PLUS, BW40MINUS } bw;
+       enum { BW20, BW40PLUS, BW40MINUS, BW80 } bw;
 };
 
 static struct p2p_oper_class_map op_class[] = {
@@ -3053,10 +3053,81 @@ static struct p2p_oper_class_map op_class[] = {
        { HOSTAPD_MODE_IEEE80211A, 117, 40, 48, 8, BW40MINUS },
        { HOSTAPD_MODE_IEEE80211A, 126, 149, 157, 8, BW40PLUS },
        { HOSTAPD_MODE_IEEE80211A, 127, 153, 161, 8, BW40MINUS },
+
+       /*
+        * IEEE P802.11ac/D7.0 Table E-4 actually talks about channel center
+        * frequency index 42, 58, 106, 122, 138, 155 with channel spacing of
+        * 80 MHz, but currently use the following definition for simplicity
+        * (these center frequencies are not actual channels, which makes
+        * has_channel() fail). wpas_p2p_verify_80mhz() should take care of
+        * removing invalid channels.
+        */
+       { HOSTAPD_MODE_IEEE80211A, 128, 36, 161, 4, BW80 },
        { -1, 0, 0, 0, 0, BW20 }
 };
 
 
+static int wpas_p2p_get_center_80mhz(struct wpa_supplicant *wpa_s,
+                                    struct hostapd_hw_modes *mode,
+                                    u8 channel)
+{
+       u8 center_channels[] = { 42, 58, 106, 122, 138, 155 };
+       unsigned int i;
+
+       if (mode->mode != HOSTAPD_MODE_IEEE80211A)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(center_channels); i++)
+               /*
+                * In 80 MHz, the bandwidth "spans" 12 channels (e.g., 36-48),
+                * so the center channel is 6 channels away from the start/end.
+                */
+               if (channel >= center_channels[i] - 6 &&
+                   channel <= center_channels[i] + 6)
+                       return center_channels[i];
+
+       return 0;
+}
+
+
+static enum chan_allowed wpas_p2p_verify_80mhz(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_80mhz(wpa_s, mode, channel);
+       if (!center_chan)
+               return NOT_ALLOWED;
+       if (center_chan >= 58 && center_chan <= 138)
+               return NOT_ALLOWED; /* Do not allow DFS channels for P2P */
+
+       /* check all the channels are available */
+       for (i = 0; i < 4; i++) {
+               int adj_chan = center_chan - 6 + i * 4;
+
+               res = has_channel(wpa_s->global, mode, adj_chan, &flags);
+               if (res == NOT_ALLOWED)
+                       return NOT_ALLOWED;
+               if (res == PASSIVE_ONLY)
+                       ret = PASSIVE_ONLY;
+
+               if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
+                       return NOT_ALLOWED;
+               if (i == 1 && !(flags & HOSTAPD_CHAN_VHT_30_50))
+                       return NOT_ALLOWED;
+               if (i == 2 && !(flags & HOSTAPD_CHAN_VHT_50_30))
+                       return NOT_ALLOWED;
+               if (i == 3 && !(flags & HOSTAPD_CHAN_VHT_70_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)
@@ -3073,6 +3144,8 @@ static enum chan_allowed wpas_p2p_verify_channel(struct wpa_supplicant *wpa_s,
                if (!(flag & HOSTAPD_CHAN_HT40PLUS))
                        return NOT_ALLOWED;
                res2 = has_channel(wpa_s->global, mode, channel + 4, NULL);
+       } else if (bw == BW80) {
+               res2 = wpas_p2p_verify_80mhz(wpa_s, mode, channel, bw);
        }
 
        if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
@@ -3173,6 +3246,16 @@ int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
 }
 
 
+int wpas_p2p_get_vht80_center(struct wpa_supplicant *wpa_s,
+                             struct hostapd_hw_modes *mode, u8 channel)
+{
+       if (!wpas_p2p_verify_channel(wpa_s, mode, channel, BW80))
+               return 0;
+
+       return wpas_p2p_get_center_80mhz(wpa_s, mode, channel);
+}
+
+
 static int wpas_get_noa(void *ctx, const u8 *interface_addr, u8 *buf,
                        size_t buf_len)
 {
index c0ad29eaee60ce7876196dd1ba2f73b7599d6ab2..785062d988de874de39cfbf0b118dd01036924a9 100644 (file)
@@ -152,6 +152,8 @@ void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
 int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
 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);
 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,