|
@@ -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)
|
|
|
{
|