104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt/*
204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * hostapd / IEEE 802.11ac VHT
304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt *
504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * This program is free software; you can redistribute it and/or modify
604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * it under the terms of BSD license
704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt *
804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt * See README and COPYING for more details.
904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt */
1004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
1104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "utils/includes.h"
1204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
1304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "utils/common.h"
1404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "common/ieee802_11_defs.h"
1504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "hostapd.h"
1604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "ap_config.h"
1704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "sta_info.h"
1804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "beacon.h"
1904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt#include "ieee802_11.h"
2004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2204949598a23f501be6eec21697465fd46a28840aDmitry Shmidtu8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
2304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
2404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct ieee80211_vht_capabilities *cap;
252f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	struct hostapd_hw_modes *mode = hapd->iface->current_mode;
2604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 *pos = eid;
2704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
282f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (!mode)
2904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return eid;
3004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
312f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
322f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	    mode->vht_capab == 0 && hapd->iface->hw_features) {
332f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		int i;
342f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
352f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		for (i = 0; i < hapd->iface->num_hw_features; i++) {
362f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			if (hapd->iface->hw_features[i].mode ==
372f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			    HOSTAPD_MODE_IEEE80211A) {
382f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				mode = &hapd->iface->hw_features[i];
392f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt				break;
402f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			}
412f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		}
422f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
432f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
4404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pos++ = WLAN_EID_VHT_CAP;
4504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pos++ = sizeof(*cap);
4604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
4704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	cap = (struct ieee80211_vht_capabilities *) pos;
4804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_memset(cap, 0, sizeof(*cap));
4904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	cap->vht_capabilities_info = host_to_le32(
50292b0c3a742226c295f8db76eaef9e90c90e7513Dmitry Shmidt		hapd->iface->conf->vht_capab);
5104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
5204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	/* Supported MCS set comes from hw */
532f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
5404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
5504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pos += sizeof(*cap);
5604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
5704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return pos;
5804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
5904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
6004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidtu8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
6304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct ieee80211_vht_operation *oper;
6404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 *pos = eid;
6504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
6604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pos++ = WLAN_EID_VHT_OPERATION;
6704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pos++ = sizeof(*oper);
6804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
6904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	oper = (struct ieee80211_vht_operation *) pos;
7004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_memset(oper, 0, sizeof(*oper));
7104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/*
7361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * center freq = 5 GHz + (5 * index)
7461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * So index 42 gives center freq 5.210 GHz
7561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * which is channel 42 in 5G band
7661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 */
7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	oper->vht_op_info_chan_center_freq_seg0_idx =
7861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		hapd->iconf->vht_oper_centr_freq_seg0_idx;
79d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	oper->vht_op_info_chan_center_freq_seg1_idx =
80d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		hapd->iconf->vht_oper_centr_freq_seg1_idx;
8161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
8204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
8304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
8404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	/* VHT Basic MCS set comes from hw */
8504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
8661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	oper->vht_basic_mcs_set = host_to_le16(0xfffc);
8704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pos += sizeof(*oper);
8804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
8904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return pos;
9004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
9161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
9261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
93203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidtstatic int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
94203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			       const u8 *sta_vht_capab)
95203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt{
96203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	const struct ieee80211_vht_capabilities *vht_cap;
97203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	struct ieee80211_vht_capabilities ap_vht_cap;
98203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	u16 sta_rx_mcs_set, ap_tx_mcs_set;
99203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	int i;
100203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
101203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	if (!mode)
102203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		return 1;
103203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
104203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	/*
105203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 * Disable VHT caps for STAs for which there is not even a single
106203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 * allowed MCS in any supported number of streams, i.e., STA is
107203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 * advertising 3 (not supported) as VHT MCS rates for all supported
108203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 * stream cases.
109203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	 */
110203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set,
111203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		  sizeof(ap_vht_cap.vht_supported_mcs_set));
112203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab;
113203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
114203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	/* AP Tx MCS map vs. STA Rx MCS map */
115203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map);
116203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map);
117203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
118203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) {
119203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		if ((ap_tx_mcs_set & (0x3 << (i * 2))) == 3)
120203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			continue;
121203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
122203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		if ((sta_rx_mcs_set & (0x3 << (i * 2))) == 3)
123203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt			continue;
124203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
125203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		return 1;
126203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	}
127203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
128203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	wpa_printf(MSG_DEBUG,
129203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt		   "No matching VHT MCS found between AP TX and STA RX");
130203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	return 0;
131203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt}
132203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
133203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt
13461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtu16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
1359d9e60286e05ae45025b672636490bd12586138dDmitry Shmidt		       const u8 *vht_capab)
13661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
13761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/* Disable VHT caps for STAs associated to no-VHT BSSes. */
13861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!vht_capab ||
139203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	    hapd->conf->disable_11ac ||
140203eadb9eda41a1dde4a583edb4684319e3f399eDmitry Shmidt	    !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
14161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		sta->flags &= ~WLAN_STA_VHT;
14261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		os_free(sta->vht_capabilities);
14361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		sta->vht_capabilities = NULL;
14461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return WLAN_STATUS_SUCCESS;
14561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
14661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
14761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (sta->vht_capabilities == NULL) {
14861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		sta->vht_capabilities =
14961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			os_zalloc(sizeof(struct ieee80211_vht_capabilities));
15061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (sta->vht_capabilities == NULL)
15161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return WLAN_STATUS_UNSPECIFIED_FAILURE;
15261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
15361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
15461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	sta->flags |= WLAN_STA_VHT;
15561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	os_memcpy(sta->vht_capabilities, vht_capab,
15661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		  sizeof(struct ieee80211_vht_capabilities));
15761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
15861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return WLAN_STATUS_SUCCESS;
15961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
160a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
161bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt
1622f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidtu16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
1632f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			const u8 *ie, size_t len)
1642f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt{
1652f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	const u8 *vht_capab;
1662f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	unsigned int vht_capab_len;
1672f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
1682f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
1692f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	    hapd->conf->disable_11ac)
1702f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		goto no_capab;
1712f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
1722f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	/* The VHT Capabilities element embedded in vendor VHT */
1732f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	vht_capab = ie + 5;
1742f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (vht_capab[0] != WLAN_EID_VHT_CAP)
1752f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		goto no_capab;
1762f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	vht_capab_len = vht_capab[1];
1772f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
1782f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	    (int) vht_capab_len > ie + len - vht_capab - 2)
1792f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		goto no_capab;
1802f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	vht_capab += 2;
1812f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
1822f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (sta->vht_capabilities == NULL) {
1832f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		sta->vht_capabilities =
1842f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			os_zalloc(sizeof(struct ieee80211_vht_capabilities));
1852f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		if (sta->vht_capabilities == NULL)
1862f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt			return WLAN_STATUS_UNSPECIFIED_FAILURE;
1872f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	}
1882f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
1892f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT;
1902f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	os_memcpy(sta->vht_capabilities, vht_capab,
1912f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		  sizeof(struct ieee80211_vht_capabilities));
1922f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	return WLAN_STATUS_SUCCESS;
1932f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
1942f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidtno_capab:
1952f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	sta->flags &= ~WLAN_STA_VENDOR_VHT;
1962f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	return WLAN_STATUS_SUCCESS;
1972f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt}
1982f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
1992f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
2002f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidtu8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
2012f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt{
2022f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	u8 *pos = eid;
2032f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
2042f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	if (!hapd->iface->current_mode)
2052f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		return eid;
2062f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
2072f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
2082f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	*pos++ = (5 +		/* The Vendor OUI, type and subtype */
2092f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		  2 + sizeof(struct ieee80211_vht_capabilities) +
2102f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt		  2 + sizeof(struct ieee80211_vht_operation));
2112f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
2122f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
2132f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	pos += 4;
2142f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	*pos++ = VENDOR_VHT_SUBTYPE;
2152f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	pos = hostapd_eid_vht_capabilities(hapd, pos);
2162f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	pos = hostapd_eid_vht_operation(hapd, pos);
2172f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
2182f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt	return pos;
2192f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt}
2202f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
2212f74e36e84064ffa32f82f3decf36b653c7e4fadDmitry Shmidt
222bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidtu16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
223bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt		       const u8 *vht_oper_notif)
224bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt{
225bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	if (!vht_oper_notif) {
226bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt		sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
227bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt		return WLAN_STATUS_SUCCESS;
228bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	}
229bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt
230bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
231bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	sta->vht_opmode = *vht_oper_notif;
232bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	return WLAN_STATUS_SUCCESS;
233bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt}
234bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt
235bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt
236a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtvoid hostapd_get_vht_capab(struct hostapd_data *hapd,
237a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			   struct ieee80211_vht_capabilities *vht_cap,
238a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			   struct ieee80211_vht_capabilities *neg_vht_cap)
239a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
24068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	u32 cap, own_cap, sym_caps;
24168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
242a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (vht_cap == NULL)
243a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return;
244a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
245a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
24668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
24768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	own_cap = hapd->iconf->vht_capab;
24868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
24968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* mask out symmetric VHT capabilities we don't support */
25068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
25168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	cap &= ~sym_caps | (own_cap & sym_caps);
25268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
25368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* mask out beamformer/beamformee caps if not supported */
25468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
25568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
25668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			 VHT_CAP_BEAMFORMEE_STS_MAX);
25768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
25868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
25968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
26068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			 VHT_CAP_SOUNDING_DIMENSION_MAX);
26168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
26268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
26368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
26468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
26568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
26668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
26768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
26868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* mask channel widths we don't support */
26968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
27068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
27168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
27268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
27368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
27468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
27568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
27668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		}
27768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
27868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	default:
27968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
28068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
28168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
28268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
28368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
28468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_SHORT_GI_160;
28568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
28668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
28768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
28868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
28968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
29068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_RXSTBC_MASK))
29168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_TXSTBC;
29268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_TXSTBC))
29368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_RXSTBC_MASK;
29468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
29568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
296a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
297