]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
hostapd: Add vendor specific VHT extension for the 2.4 GHz band
authorYanbo Li <yanbol@qti.qualcomm.com>
Mon, 10 Nov 2014 15:12:29 +0000 (23:12 +0800)
committerJouni Malinen <j@w1.fi>
Tue, 13 Jan 2015 22:59:22 +0000 (00:59 +0200)
This allows vendor specific information element to be used to advertise
support for VHT on 2.4 GHz band. In practice, this is used to enable use
of 256 QAM rates (VHT-MCS 8 and 9) on 2.4 GHz band.

This functionality is disabled by default, but can be enabled with
vendor_vht=1 parameter in hostapd.conf if the driver advertises support
for VHT on either 2.4 or 5 GHz bands.

Signed-off-by: Yanbo Li <yanbol@qti.qualcomm.com>
12 files changed:
hostapd/config_file.c
src/ap/ap_config.h
src/ap/beacon.c
src/ap/hw_features.c
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_vht.c
src/ap/sta_info.c
src/ap/sta_info.h
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h
src/common/ieee802_11_defs.h

index e30efbe31060e599297303c906f20844896753f8..99cd05286247e9dec14b4b636b59ad8c66786708 100644 (file)
@@ -2690,6 +2690,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
        } else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0) {
                conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+       } else if (os_strcmp(buf, "vendor_vht") == 0) {
+               bss->vendor_vht = atoi(pos);
 #endif /* CONFIG_IEEE80211AC */
        } else if (os_strcmp(buf, "max_listen_interval") == 0) {
                bss->max_listen_interval = atoi(pos);
index 58af6cb19f57997c817f2bf89824f182349d6059..e5215c52909b737a452cba1a1b55e4c82ed6dc06 100644 (file)
@@ -551,6 +551,8 @@ struct hostapd_bss_config {
        int mesh;
 
        int radio_measurements;
+
+       int vendor_vht;
 };
 
 
index 4a8703accec39f8f33cfbaa3d287e54fc4594057..b0a74e01dfd853ef54b845344769d9b63b013029 100644 (file)
@@ -379,6 +379,10 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 #endif /* CONFIG_P2P */
        if (hapd->conf->vendor_elements)
                buflen += wpabuf_len(hapd->conf->vendor_elements);
+       if (hapd->conf->vendor_vht) {
+               buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+                       2 + sizeof(struct ieee80211_vht_operation);
+       }
        resp = os_zalloc(buflen);
        if (resp == NULL)
                return NULL;
@@ -446,8 +450,12 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
        pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
                                    &hapd->cs_c_off_proberesp);
 #ifdef CONFIG_IEEE80211AC
-       pos = hostapd_eid_vht_capabilities(hapd, pos);
-       pos = hostapd_eid_vht_operation(hapd, pos);
+       if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+               pos = hostapd_eid_vht_capabilities(hapd, pos);
+               pos = hostapd_eid_vht_operation(hapd, pos);
+       }
+       if (hapd->conf->vendor_vht)
+               pos = hostapd_eid_vendor_vht(hapd, pos);
 #endif /* CONFIG_IEEE80211AC */
 
        /* Wi-Fi Alliance WMM */
@@ -776,6 +784,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 #endif /* CONFIG_P2P */
        if (hapd->conf->vendor_elements)
                tail_len += wpabuf_len(hapd->conf->vendor_elements);
+
+#ifdef CONFIG_IEEE80211AC
+       if (hapd->conf->vendor_vht) {
+               tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+                       2 + sizeof(struct ieee80211_vht_operation);
+       }
+#endif /* CONFIG_IEEE80211AC */
+
        tailpos = tail = os_malloc(tail_len);
        if (head == NULL || tail == NULL) {
                wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -865,8 +881,12 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
        tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
                                        &hapd->cs_c_off_beacon);
 #ifdef CONFIG_IEEE80211AC
-       tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
-       tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+       if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+               tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+               tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+       }
+       if (hapd->conf->vendor_vht)
+               tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
 #endif /* CONFIG_IEEE80211AC */
 
        /* Wi-Fi Alliance WMM */
index 6b0a72d832d8c570e310edc158195e794f3fd3de..f6d79ea6b83a0e432c8f8718aaab3a17775c1ba1 100644 (file)
@@ -641,12 +641,31 @@ static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
 
 static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
 {
-       u32 hw = iface->current_mode->vht_capab;
+       struct hostapd_hw_modes *mode = iface->current_mode;
+       u32 hw = mode->vht_capab;
        u32 conf = iface->conf->vht_capab;
 
        wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
                   hw, conf);
 
+       if (mode->mode == HOSTAPD_MODE_IEEE80211G &&
+           iface->conf->bss[0]->vendor_vht &&
+           mode->vht_capab == 0 && iface->hw_features) {
+               int i;
+
+               for (i = 0; i < iface->num_hw_features; i++) {
+                       if (iface->hw_features[i].mode ==
+                           HOSTAPD_MODE_IEEE80211A) {
+                               mode = &iface->hw_features[i];
+                               hw = mode->vht_capab;
+                               wpa_printf(MSG_DEBUG,
+                                          "update hw vht capab based on 5 GHz band: 0x%x",
+                                          hw);
+                               break;
+                       }
+               }
+       }
+
 #define VHT_CAP_CHECK(cap) \
        do { \
                if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
index 3d4488a1c7a5daea95ab538e1f5336aaafe8da48..89911b1fdd42fd9bced9ade35be26387c411098a 100644 (file)
@@ -1327,6 +1327,13 @@ static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
                               "mandatory VHT PHY - reject association");
                return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
        }
+
+       if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
+               resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
+                                          elems.vendor_vht_len);
+               if (resp != WLAN_STATUS_SUCCESS)
+                       return resp;
+       }
 #endif /* CONFIG_IEEE80211AC */
 
 #ifdef CONFIG_P2P
@@ -1616,8 +1623,10 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
 #endif /* CONFIG_IEEE80211N */
 
 #ifdef CONFIG_IEEE80211AC
-       p = hostapd_eid_vht_capabilities(hapd, p);
-       p = hostapd_eid_vht_operation(hapd, p);
+       if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+               p = hostapd_eid_vht_capabilities(hapd, p);
+               p = hostapd_eid_vht_operation(hapd, p);
+       }
 #endif /* CONFIG_IEEE80211AC */
 
        p = hostapd_eid_ext_capab(hapd, p);
@@ -1625,6 +1634,11 @@ static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
        if (sta->qos_map_enabled)
                p = hostapd_eid_qos_map_set(hapd, p);
 
+#ifdef CONFIG_IEEE80211AC
+       if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
+               p = hostapd_eid_vendor_vht(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
        if (sta->flags & WLAN_STA_WMM)
                p = hostapd_eid_wmm(hapd, p);
 
index beaeac50053a169d25550f72623ee62d42131f75..41c27d906e72a7eb2c96a13c8c75c6f79fbcb1fa 100644 (file)
@@ -51,6 +51,7 @@ u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid);
 int hostapd_ht_operation_update(struct hostapd_iface *iface);
 void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
                                  const u8 *addr, const u8 *trans_id);
@@ -62,6 +63,9 @@ void hostapd_get_vht_capab(struct hostapd_data *hapd,
                           struct ieee80211_vht_capabilities *neg_vht_cap);
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
                      const u8 *ht_capab, size_t ht_capab_len);
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+                       const u8 *ie, size_t len);
+
 void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
 void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
 void ht40_intolerant_remove(struct hostapd_iface *iface, struct sta_info *sta);
index 437cf5031054b4cfea8744bf3a2bc67822ded51a..89c14ec87906d38383439a2dcdc49560f663448a 100644 (file)
 u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
 {
        struct ieee80211_vht_capabilities *cap;
+       struct hostapd_hw_modes *mode = hapd->iface->current_mode;
        u8 *pos = eid;
 
-       if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
-           hapd->conf->disable_11ac)
+       if (!mode)
                return eid;
 
+       if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
+           mode->vht_capab == 0 && hapd->iface->hw_features) {
+               int i;
+
+               for (i = 0; i < hapd->iface->num_hw_features; i++) {
+                       if (hapd->iface->hw_features[i].mode ==
+                           HOSTAPD_MODE_IEEE80211A) {
+                               mode = &hapd->iface->hw_features[i];
+                               break;
+                       }
+               }
+       }
+
        *pos++ = WLAN_EID_VHT_CAP;
        *pos++ = sizeof(*cap);
 
@@ -37,8 +50,7 @@ u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
                hapd->iface->conf->vht_capab);
 
        /* Supported MCS set comes from hw */
-       os_memcpy(&cap->vht_supported_mcs_set,
-                 hapd->iface->current_mode->vht_mcs_set, 8);
+       os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
 
        pos += sizeof(*cap);
 
@@ -51,9 +63,6 @@ u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
        struct ieee80211_vht_operation *oper;
        u8 *pos = eid;
 
-       if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
-               return eid;
-
        *pos++ = WLAN_EID_VHT_OPERATION;
        *pos++ = sizeof(*oper);
 
@@ -109,6 +118,66 @@ u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
 }
 
 
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+                       const u8 *ie, size_t len)
+{
+       const u8 *vht_capab;
+       unsigned int vht_capab_len;
+
+       if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
+           hapd->conf->disable_11ac)
+               goto no_capab;
+
+       /* The VHT Capabilities element embedded in vendor VHT */
+       vht_capab = ie + 5;
+       if (vht_capab[0] != WLAN_EID_VHT_CAP)
+               goto no_capab;
+       vht_capab_len = vht_capab[1];
+       if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+           vht_capab_len > ie + len - vht_capab - 2)
+               goto no_capab;
+       vht_capab += 2;
+
+       if (sta->vht_capabilities == NULL) {
+               sta->vht_capabilities =
+                       os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+               if (sta->vht_capabilities == NULL)
+                       return WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT;
+       os_memcpy(sta->vht_capabilities, vht_capab,
+                 sizeof(struct ieee80211_vht_capabilities));
+       return WLAN_STATUS_SUCCESS;
+
+no_capab:
+       sta->flags &= ~WLAN_STA_VENDOR_VHT;
+       return WLAN_STATUS_SUCCESS;
+}
+
+
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
+{
+       u8 *pos = eid;
+
+       if (!hapd->iface->current_mode)
+               return eid;
+
+       *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+       *pos++ = (5 +           /* The Vendor OUI, type and subtype */
+                 2 + sizeof(struct ieee80211_vht_capabilities) +
+                 2 + sizeof(struct ieee80211_vht_operation));
+
+       WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
+       pos += 4;
+       *pos++ = VENDOR_VHT_SUBTYPE;
+       pos = hostapd_eid_vht_capabilities(hapd, pos);
+       pos = hostapd_eid_vht_operation(hapd, pos);
+
+       return pos;
+}
+
+
 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
                       const u8 *vht_oper_notif)
 {
index 1c2197a42d3295612f3296683616cbe07ffbeb51..f4de14093b9271e30e412dc8282c8a539d82f2dd 100644 (file)
@@ -1101,7 +1101,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
        int res;
 
        buf[0] = '\0';
-       res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+       res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
                          (flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
                          (flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
                          (flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1119,6 +1119,7 @@ int ap_sta_flags_txt(u32 flags, char *buf, size_t buflen)
                          (flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
                          (flags & WLAN_STA_GAS ? "[GAS]" : ""),
                          (flags & WLAN_STA_VHT ? "[VHT]" : ""),
+                         (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
                          (flags & WLAN_STA_WNM_SLEEP_MODE ?
                           "[WNM_SLEEP_MODE]" : ""));
        if (os_snprintf_error(buflen, res))
index 588a9e2f295ba06a74910e02081d030951f17dc5..59d0e2915d5f62ceeb624934fe927ad78a75ab6f 100644 (file)
@@ -35,6 +35,7 @@
 #define WLAN_STA_VHT BIT(18)
 #define WLAN_STA_WNM_SLEEP_MODE BIT(19)
 #define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
+#define WLAN_STA_VENDOR_VHT BIT(21)
 #define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
 #define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
index e1d45cf96a9f2672d20e979442cf39f49a7792d3..ed8d46619ad779e0aea53ccc7ac5a3cb08fe2f23 100644 (file)
@@ -128,6 +128,15 @@ static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
                        elems->vendor_ht_cap = pos;
                        elems->vendor_ht_cap_len = elen;
                        break;
+               case VENDOR_VHT_TYPE:
+                       if (elen > 4 &&
+                           (pos[4] == VENDOR_VHT_SUBTYPE ||
+                            pos[4] == VENDOR_VHT_SUBTYPE2)) {
+                               elems->vendor_vht = pos;
+                               elems->vendor_vht_len = elen;
+                       } else
+                               return -1;
+                       break;
                default:
                        wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
                                   "information element ignored "
index 2357afc5c68720d4b6eacf59690b248d88384af8..05fe32b450c1a024fb955eb1a82d337382053ac1 100644 (file)
@@ -35,6 +35,7 @@ struct ieee802_11_elems {
        const u8 *vht_operation;
        const u8 *vht_opmode_notif;
        const u8 *vendor_ht_cap;
+       const u8 *vendor_vht;
        const u8 *p2p;
        const u8 *wfd;
        const u8 *link_id;
@@ -71,6 +72,7 @@ struct ieee802_11_elems {
        u8 vht_capabilities_len;
        u8 vht_operation_len;
        u8 vendor_ht_cap_len;
+       u8 vendor_vht_len;
        u8 p2p_len;
        u8 wfd_len;
        u8 interworking_len;
index dfe0fafd3ad11d69e181682a42067c57ad6c66c6..803b8ccc85470d37aba0a37431aa02161c9edf05 100644 (file)
@@ -1155,6 +1155,9 @@ enum plink_action_field {
 };
 
 #define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+#define VENDOR_VHT_TYPE                0x04
+#define VENDOR_VHT_SUBTYPE     0x08
+#define VENDOR_VHT_SUBTYPE2    0x00
 
 #define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */