122a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul/* 2e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell * hostapd / IEEE 802.11ac VHT 3e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 4e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell * 522a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul * This program is free software; you can redistribute it and/or modify 622144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes * it under the terms of BSD license 7b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul * 822144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes * See README and COPYING for more details. 9e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell */ 10e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 11e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell#include "utils/includes.h" 12e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 13e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell#include "utils/common.h" 14e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell#include "common/ieee802_11_defs.h" 1522144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes#include "hostapd.h" 16e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell#include "ap_config.h" 17e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell#include "sta_info.h" 1822144ab7552f0799bcfca506bf4ffa7f70a06649Gareth Hughes#include "beacon.h" 19e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell#include "ieee802_11.h" 20e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 21e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 22e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwellu8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid) 23e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell{ 24e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell struct ieee80211_vht_capabilities *cap; 25e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell u8 *pos = eid; 26e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 27e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode || 28e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell hapd->conf->disable_11ac) 2946b0988c673b28e072fd0cbf477632a9ab6f9f18Keith Whitwell return eid; 30e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 31e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell *pos++ = WLAN_EID_VHT_CAP; 320070d398d13759adc519f9bc764ffd39bc88890eBrian Paul *pos++ = sizeof(*cap); 33cd03ed4f54444d96e4e47cdb118a3dfd94d92bb0Keith Whitwell 34e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell cap = (struct ieee80211_vht_capabilities *) pos; 35cd03ed4f54444d96e4e47cdb118a3dfd94d92bb0Keith Whitwell os_memset(cap, 0, sizeof(*cap)); 36b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul cap->vht_capabilities_info = host_to_le32( 37b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul hapd->iface->conf->vht_capab); 38e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 39e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell /* Supported MCS set comes from hw */ 40b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul os_memcpy(&cap->vht_supported_mcs_set, 41b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul hapd->iface->current_mode->vht_mcs_set, 8); 42b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 43b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul pos += sizeof(*cap); 44b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 45b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul return pos; 46b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul} 47b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 48e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 49b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paulu8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid) 50b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul{ 51b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul struct ieee80211_vht_operation *oper; 52b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul u8 *pos = eid; 53b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 54b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac) 55b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul return eid; 56b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 57b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul *pos++ = WLAN_EID_VHT_OPERATION; 58b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul *pos++ = sizeof(*oper); 59b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 60e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell oper = (struct ieee80211_vht_operation *) pos; 61e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell os_memset(oper, 0, sizeof(*oper)); 62e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 63b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul /* 64e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell * center freq = 5 GHz + (5 * index) 65b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul * So index 42 gives center freq 5.210 GHz 66b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul * which is channel 42 in 5G band 67e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell */ 68b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul oper->vht_op_info_chan_center_freq_seg0_idx = 69cd03ed4f54444d96e4e47cdb118a3dfd94d92bb0Keith Whitwell hapd->iconf->vht_oper_centr_freq_seg0_idx; 70b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul oper->vht_op_info_chan_center_freq_seg1_idx = 71e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell hapd->iconf->vht_oper_centr_freq_seg1_idx; 72b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 73e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth; 74b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 75b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul /* VHT Basic MCS set comes from hw */ 76b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */ 77b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul oper->vht_basic_mcs_set = host_to_le16(0xfffc); 78b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul pos += sizeof(*oper); 79b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 8077df88727cb0a423dd5cb41498c2302d9df4fce7Brian Paul return pos; 81a670c1280b78e6da3b298b61f623e4c733c6be94Brian Paul} 82a670c1280b78e6da3b298b61f623e4c733c6be94Brian Paul 83b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 84b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paulu16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta, 85b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul const u8 *vht_capab, size_t vht_capab_len) 8677df88727cb0a423dd5cb41498c2302d9df4fce7Brian Paul{ 87b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul /* Disable VHT caps for STAs associated to no-VHT BSSes. */ 88b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul if (!vht_capab || 89b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul vht_capab_len < sizeof(struct ieee80211_vht_capabilities) || 9077df88727cb0a423dd5cb41498c2302d9df4fce7Brian Paul hapd->conf->disable_11ac) { 91b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul sta->flags &= ~WLAN_STA_VHT; 92b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul os_free(sta->vht_capabilities); 93b7f5e92f1749ce4601a758f66ddc64959f11742bBrian Paul sta->vht_capabilities = NULL; 94b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul return WLAN_STATUS_SUCCESS; 95b7f5e92f1749ce4601a758f66ddc64959f11742bBrian Paul } 96b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 97b7f5e92f1749ce4601a758f66ddc64959f11742bBrian Paul if (sta->vht_capabilities == NULL) { 98b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul sta->vht_capabilities = 99b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul os_zalloc(sizeof(struct ieee80211_vht_capabilities)); 100b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul if (sta->vht_capabilities == NULL) 10177df88727cb0a423dd5cb41498c2302d9df4fce7Brian Paul return WLAN_STATUS_UNSPECIFIED_FAILURE; 102a670c1280b78e6da3b298b61f623e4c733c6be94Brian Paul } 103a670c1280b78e6da3b298b61f623e4c733c6be94Brian Paul 104b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul sta->flags |= WLAN_STA_VHT; 105b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul os_memcpy(sta->vht_capabilities, vht_capab, 106b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul sizeof(struct ieee80211_vht_capabilities)); 10777df88727cb0a423dd5cb41498c2302d9df4fce7Brian Paul 108b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul return WLAN_STATUS_SUCCESS; 109b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul} 110b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 11177df88727cb0a423dd5cb41498c2302d9df4fce7Brian Paul 112b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paulu16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta, 113b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul const u8 *vht_oper_notif) 114b7f5e92f1749ce4601a758f66ddc64959f11742bBrian Paul{ 115b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul if (!vht_oper_notif) { 116b7f5e92f1749ce4601a758f66ddc64959f11742bBrian Paul sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED; 117b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul return WLAN_STATUS_SUCCESS; 118b7f5e92f1749ce4601a758f66ddc64959f11742bBrian Paul } 119b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 120b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED; 121e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell sta->vht_opmode = *vht_oper_notif; 122e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell return WLAN_STATUS_SUCCESS; 123e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell} 124e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 125b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul 126b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paulvoid hostapd_get_vht_capab(struct hostapd_data *hapd, 127b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul struct ieee80211_vht_capabilities *vht_cap, 128b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul struct ieee80211_vht_capabilities *neg_vht_cap) 129b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul{ 13022a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul u32 cap, own_cap, sym_caps; 13122a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 13222a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul if (vht_cap == NULL) 13322a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul return; 134e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap)); 135e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 136e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell cap = le_to_host32(neg_vht_cap->vht_capabilities_info); 13722a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul own_cap = hapd->iconf->vht_capab; 13822a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 13922a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul /* mask out symmetric VHT capabilities we don't support */ 14022a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160; 141e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell cap &= ~sym_caps | (own_cap & sym_caps); 142e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell 143e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell /* mask out beamformer/beamformee caps if not supported */ 14422a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE)) 14522a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE | 14622a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul VHT_CAP_BEAMFORMEE_STS_MAX); 14722a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 14822a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE)) 14922a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE | 15022a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul VHT_CAP_SOUNDING_DIMENSION_MAX); 15122a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 15222a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE)) 15322a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE; 15422a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 15522a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE)) 15622a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE; 15722a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 15822a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul /* mask channel widths we don't support */ 159b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) { 160e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ: 161e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell break; 162e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ: 16322a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) { 16422a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ; 16522a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; 16622a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul } 16722a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul break; 16822a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul default: 16922a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK; 17022a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul break; 17122a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul } 17222a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 17322a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK)) 17422a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap &= ~VHT_CAP_SHORT_GI_160; 17522a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 17622a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul /* 17722a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul * if we don't support RX STBC, mask out TX STBC in the STA's HT caps 178e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell * if we don't support TX STBC, mask out RX STBC in the STA's HT caps 179e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell */ 180b37a084357dd08573b86d6d8c5ba43d65bdc1bd7Brian Paul if (!(own_cap & VHT_CAP_RXSTBC_MASK)) 181e3a051e0538a605551f4d58294c94f5eb00ed07fKeith Whitwell cap &= ~VHT_CAP_TXSTBC; 18222a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul if (!(own_cap & VHT_CAP_TXSTBC)) 18322a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul cap &= ~VHT_CAP_RXSTBC_MASK; 18422a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul 18522a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul neg_vht_cap->vht_capabilities_info = host_to_le32(cap); 18622a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul} 18722a47c5251ee7b91dc8f7f4f7dbeb3ad5a117b70Brian Paul