Home | History | Annotate | Download | only in ap
      1 /*
      2  * hostapd / IEEE 802.11ac VHT
      3  * Copyright (c) 2002-2009, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of BSD license
      7  *
      8  * See README and COPYING for more details.
      9  */
     10 
     11 #include "utils/includes.h"
     12 
     13 #include "utils/common.h"
     14 #include "common/ieee802_11_defs.h"
     15 #include "hostapd.h"
     16 #include "ap_config.h"
     17 #include "sta_info.h"
     18 #include "beacon.h"
     19 #include "ieee802_11.h"
     20 
     21 
     22 u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
     23 {
     24 	struct ieee80211_vht_capabilities *cap;
     25 	u8 *pos = eid;
     26 
     27 	if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
     28 	    hapd->conf->disable_11ac)
     29 		return eid;
     30 
     31 	*pos++ = WLAN_EID_VHT_CAP;
     32 	*pos++ = sizeof(*cap);
     33 
     34 	cap = (struct ieee80211_vht_capabilities *) pos;
     35 	os_memset(cap, 0, sizeof(*cap));
     36 	cap->vht_capabilities_info = host_to_le32(
     37 		hapd->iface->conf->vht_capab);
     38 
     39 	/* Supported MCS set comes from hw */
     40 	os_memcpy(&cap->vht_supported_mcs_set,
     41 	          hapd->iface->current_mode->vht_mcs_set, 8);
     42 
     43 	pos += sizeof(*cap);
     44 
     45 	return pos;
     46 }
     47 
     48 
     49 u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
     50 {
     51 	struct ieee80211_vht_operation *oper;
     52 	u8 *pos = eid;
     53 
     54 	if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
     55 		return eid;
     56 
     57 	*pos++ = WLAN_EID_VHT_OPERATION;
     58 	*pos++ = sizeof(*oper);
     59 
     60 	oper = (struct ieee80211_vht_operation *) pos;
     61 	os_memset(oper, 0, sizeof(*oper));
     62 
     63 	/*
     64 	 * center freq = 5 GHz + (5 * index)
     65 	 * So index 42 gives center freq 5.210 GHz
     66 	 * which is channel 42 in 5G band
     67 	 */
     68 	oper->vht_op_info_chan_center_freq_seg0_idx =
     69 		hapd->iconf->vht_oper_centr_freq_seg0_idx;
     70 	oper->vht_op_info_chan_center_freq_seg1_idx =
     71 		hapd->iconf->vht_oper_centr_freq_seg1_idx;
     72 
     73 	oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
     74 
     75 	/* VHT Basic MCS set comes from hw */
     76 	/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
     77 	oper->vht_basic_mcs_set = host_to_le16(0xfffc);
     78 	pos += sizeof(*oper);
     79 
     80 	return pos;
     81 }
     82 
     83 
     84 u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
     85 		       const u8 *vht_capab, size_t vht_capab_len)
     86 {
     87 	/* Disable VHT caps for STAs associated to no-VHT BSSes. */
     88 	if (!vht_capab ||
     89 	    vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
     90 	    hapd->conf->disable_11ac) {
     91 		sta->flags &= ~WLAN_STA_VHT;
     92 		os_free(sta->vht_capabilities);
     93 		sta->vht_capabilities = NULL;
     94 		return WLAN_STATUS_SUCCESS;
     95 	}
     96 
     97 	if (sta->vht_capabilities == NULL) {
     98 		sta->vht_capabilities =
     99 			os_zalloc(sizeof(struct ieee80211_vht_capabilities));
    100 		if (sta->vht_capabilities == NULL)
    101 			return WLAN_STATUS_UNSPECIFIED_FAILURE;
    102 	}
    103 
    104 	sta->flags |= WLAN_STA_VHT;
    105 	os_memcpy(sta->vht_capabilities, vht_capab,
    106 		  sizeof(struct ieee80211_vht_capabilities));
    107 
    108 	return WLAN_STATUS_SUCCESS;
    109 }
    110 
    111 
    112 u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
    113 		       const u8 *vht_oper_notif)
    114 {
    115 	if (!vht_oper_notif) {
    116 		sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
    117 		return WLAN_STATUS_SUCCESS;
    118 	}
    119 
    120 	sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
    121 	sta->vht_opmode = *vht_oper_notif;
    122 	return WLAN_STATUS_SUCCESS;
    123 }
    124 
    125 
    126 void hostapd_get_vht_capab(struct hostapd_data *hapd,
    127 			   struct ieee80211_vht_capabilities *vht_cap,
    128 			   struct ieee80211_vht_capabilities *neg_vht_cap)
    129 {
    130 	u32 cap, own_cap, sym_caps;
    131 
    132 	if (vht_cap == NULL)
    133 		return;
    134 	os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
    135 
    136 	cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
    137 	own_cap = hapd->iconf->vht_capab;
    138 
    139 	/* mask out symmetric VHT capabilities we don't support */
    140 	sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
    141 	cap &= ~sym_caps | (own_cap & sym_caps);
    142 
    143 	/* mask out beamformer/beamformee caps if not supported */
    144 	if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
    145 		cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
    146 			 VHT_CAP_BEAMFORMEE_STS_MAX);
    147 
    148 	if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
    149 		cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
    150 			 VHT_CAP_SOUNDING_DIMENSION_MAX);
    151 
    152 	if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
    153 		cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
    154 
    155 	if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
    156 		cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
    157 
    158 	/* mask channel widths we don't support */
    159 	switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
    160 	case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
    161 		break;
    162 	case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
    163 		if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
    164 			cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
    165 			cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
    166 		}
    167 		break;
    168 	default:
    169 		cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
    170 		break;
    171 	}
    172 
    173 	if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
    174 		cap &= ~VHT_CAP_SHORT_GI_160;
    175 
    176 	/*
    177 	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
    178 	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
    179 	 */
    180 	if (!(own_cap & VHT_CAP_RXSTBC_MASK))
    181 		cap &= ~VHT_CAP_TXSTBC;
    182 	if (!(own_cap & VHT_CAP_TXSTBC))
    183 		cap &= ~VHT_CAP_RXSTBC_MASK;
    184 
    185 	neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
    186 }
    187