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