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;
2504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 *pos = eid;
2604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
2704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
2804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	    hapd->conf->disable_11ac)
2904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return eid;
3004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
3104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pos++ = WLAN_EID_VHT_CAP;
3204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pos++ = sizeof(*cap);
3304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
3404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	cap = (struct ieee80211_vht_capabilities *) pos;
3504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_memset(cap, 0, sizeof(*cap));
3604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	cap->vht_capabilities_info = host_to_le32(
37292b0c3a742226c295f8db76eaef9e90c90e7513Dmitry Shmidt		hapd->iface->conf->vht_capab);
3804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
3904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	/* Supported MCS set comes from hw */
407a5e50a0554bee77a9da492ea3d86f46147f1671Dmitry Shmidt	os_memcpy(&cap->vht_supported_mcs_set,
4104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	          hapd->iface->current_mode->vht_mcs_set, 8);
4204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
4304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pos += sizeof(*cap);
4404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
4504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return pos;
4604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
4704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
4804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
4904949598a23f501be6eec21697465fd46a28840aDmitry Shmidtu8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
5004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt{
5104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	struct ieee80211_vht_operation *oper;
5204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	u8 *pos = eid;
5304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
5404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
5504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt		return eid;
5604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
5704949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pos++ = WLAN_EID_VHT_OPERATION;
5804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	*pos++ = sizeof(*oper);
5904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
6004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	oper = (struct ieee80211_vht_operation *) pos;
6104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	os_memset(oper, 0, sizeof(*oper));
6204949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
6361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/*
6461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * center freq = 5 GHz + (5 * index)
6561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * So index 42 gives center freq 5.210 GHz
6661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 * which is channel 42 in 5G band
6761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	 */
6861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	oper->vht_op_info_chan_center_freq_seg0_idx =
6961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		hapd->iconf->vht_oper_centr_freq_seg0_idx;
70d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt	oper->vht_op_info_chan_center_freq_seg1_idx =
71d5e4923d04122f81300fa68fb07d64ede28fd44dDmitry Shmidt		hapd->iconf->vht_oper_centr_freq_seg1_idx;
7261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
7304949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
7404949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
7504949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	/* VHT Basic MCS set comes from hw */
7604949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
7761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	oper->vht_basic_mcs_set = host_to_le16(0xfffc);
7804949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	pos += sizeof(*oper);
7904949598a23f501be6eec21697465fd46a28840aDmitry Shmidt
8004949598a23f501be6eec21697465fd46a28840aDmitry Shmidt	return pos;
8104949598a23f501be6eec21697465fd46a28840aDmitry Shmidt}
8261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
8361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
8461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidtu16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
8561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		       const u8 *vht_capab, size_t vht_capab_len)
8661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt{
8761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	/* Disable VHT caps for STAs associated to no-VHT BSSes. */
8861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (!vht_capab ||
8961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
9061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	    hapd->conf->disable_11ac) {
9161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		sta->flags &= ~WLAN_STA_VHT;
9261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		os_free(sta->vht_capabilities);
9361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		sta->vht_capabilities = NULL;
9461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		return WLAN_STATUS_SUCCESS;
9561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
9661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
9761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	if (sta->vht_capabilities == NULL) {
9861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		sta->vht_capabilities =
9961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			os_zalloc(sizeof(struct ieee80211_vht_capabilities));
10061d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		if (sta->vht_capabilities == NULL)
10161d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt			return WLAN_STATUS_UNSPECIFIED_FAILURE;
10261d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	}
10361d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
10461d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	sta->flags |= WLAN_STA_VHT;
10561d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	os_memcpy(sta->vht_capabilities, vht_capab,
10661d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt		  sizeof(struct ieee80211_vht_capabilities));
10761d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt
10861d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt	return WLAN_STATUS_SUCCESS;
10961d9df3e62aaa0e87ad05452fcb95142159a17b6Dmitry Shmidt}
110a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
111bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt
112bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidtu16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
113bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt		       const u8 *vht_oper_notif)
114bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt{
115bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	if (!vht_oper_notif) {
116bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt		sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
117bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt		return WLAN_STATUS_SUCCESS;
118bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	}
119bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt
120bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
121bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	sta->vht_opmode = *vht_oper_notif;
122bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt	return WLAN_STATUS_SUCCESS;
123bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt}
124bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt
125bd14a57187b024f49f5b9ace55ef457d8d04650aDmitry Shmidt
126a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidtvoid hostapd_get_vht_capab(struct hostapd_data *hapd,
127a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			   struct ieee80211_vht_capabilities *vht_cap,
128a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt			   struct ieee80211_vht_capabilities *neg_vht_cap)
129a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt{
13068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	u32 cap, own_cap, sym_caps;
13168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
132a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	if (vht_cap == NULL)
133a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt		return;
134a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt	os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
135a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt
13668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
13768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	own_cap = hapd->iconf->vht_capab;
13868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
13968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* mask out symmetric VHT capabilities we don't support */
14068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
14168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	cap &= ~sym_caps | (own_cap & sym_caps);
14268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
14368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* mask out beamformer/beamformee caps if not supported */
14468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
14568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
14668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			 VHT_CAP_BEAMFORMEE_STS_MAX);
14768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
14868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
14968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
15068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			 VHT_CAP_SOUNDING_DIMENSION_MAX);
15168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
15268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
15368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
15468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
15568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
15668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
15768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
15868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/* mask channel widths we don't support */
15968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
16068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
16168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
16268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
16368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
16468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
16568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt			cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
16668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		}
16768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
16868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	default:
16968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
17068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		break;
17168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	}
17268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
17368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
17468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_SHORT_GI_160;
17568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
17668d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	/*
17768d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
17868d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
17968d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	 */
18068d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_RXSTBC_MASK))
18168d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_TXSTBC;
18268d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	if (!(own_cap & VHT_CAP_TXSTBC))
18368d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt		cap &= ~VHT_CAP_RXSTBC_MASK;
18468d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt
18568d0e3ed07847339aedfac8e02f50db68c702e52Dmitry Shmidt	neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
186a54fa5fb807eaeff45464139b5a7759f060cec68Dmitry Shmidt}
187