aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--hostapd/config_file.c2
-rw-r--r--src/ap/ap_config.h2
-rw-r--r--src/ap/beacon.c28
-rw-r--r--src/ap/hw_features.c21
-rw-r--r--src/ap/ieee802_11.c18
-rw-r--r--src/ap/ieee802_11.h4
-rw-r--r--src/ap/ieee802_11_vht.c83
-rw-r--r--src/ap/sta_info.c3
-rw-r--r--src/ap/sta_info.h1
-rw-r--r--src/common/ieee802_11_common.c9
-rw-r--r--src/common/ieee802_11_common.h2
-rw-r--r--src/common/ieee802_11_defs.h3
12 files changed, 161 insertions, 15 deletions
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index e30efbe..99cd052 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -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);
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 58af6cb..e5215c5 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -551,6 +551,8 @@ struct hostapd_bss_config {
int mesh;
int radio_measurements;
+
+ int vendor_vht;
};
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 4a8703a..b0a74e0 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -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 */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 6b0a72d..f6d79ea 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -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)) \
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 3d4488a..89911b1 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -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);
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index beaeac5..41c27d9 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -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);
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 437cf50..89c14ec 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -22,12 +22,25 @@
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)
{
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 1c2197a..f4de140 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -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))
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 588a9e2..59d0e29 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -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)
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index e1d45cf..ed8d466 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -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 "
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2357afc..05fe32b 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -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;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index dfe0faf..803b8cc 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -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 */