Line data Source code
1 : /*
2 : * hostapd / IEEE 802.11ac VHT
3 : * Copyright (c) 2002-2009, Jouni Malinen <j@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 46 : u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
23 : {
24 : struct ieee80211_vht_capabilities *cap;
25 46 : struct hostapd_hw_modes *mode = hapd->iface->current_mode;
26 46 : u8 *pos = eid;
27 :
28 46 : if (!mode)
29 0 : return eid;
30 :
31 50 : if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
32 4 : mode->vht_capab == 0 && hapd->iface->hw_features) {
33 : int i;
34 :
35 0 : for (i = 0; i < hapd->iface->num_hw_features; i++) {
36 0 : if (hapd->iface->hw_features[i].mode ==
37 : HOSTAPD_MODE_IEEE80211A) {
38 0 : mode = &hapd->iface->hw_features[i];
39 0 : break;
40 : }
41 : }
42 : }
43 :
44 46 : *pos++ = WLAN_EID_VHT_CAP;
45 46 : *pos++ = sizeof(*cap);
46 :
47 46 : cap = (struct ieee80211_vht_capabilities *) pos;
48 46 : os_memset(cap, 0, sizeof(*cap));
49 46 : cap->vht_capabilities_info = host_to_le32(
50 : hapd->iface->conf->vht_capab);
51 :
52 : /* Supported MCS set comes from hw */
53 46 : os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
54 :
55 46 : pos += sizeof(*cap);
56 :
57 46 : return pos;
58 : }
59 :
60 :
61 46 : u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
62 : {
63 : struct ieee80211_vht_operation *oper;
64 46 : u8 *pos = eid;
65 :
66 46 : *pos++ = WLAN_EID_VHT_OPERATION;
67 46 : *pos++ = sizeof(*oper);
68 :
69 46 : oper = (struct ieee80211_vht_operation *) pos;
70 46 : os_memset(oper, 0, sizeof(*oper));
71 :
72 : /*
73 : * center freq = 5 GHz + (5 * index)
74 : * So index 42 gives center freq 5.210 GHz
75 : * which is channel 42 in 5G band
76 : */
77 46 : oper->vht_op_info_chan_center_freq_seg0_idx =
78 46 : hapd->iconf->vht_oper_centr_freq_seg0_idx;
79 46 : oper->vht_op_info_chan_center_freq_seg1_idx =
80 46 : hapd->iconf->vht_oper_centr_freq_seg1_idx;
81 :
82 46 : oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
83 :
84 : /* VHT Basic MCS set comes from hw */
85 : /* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
86 46 : oper->vht_basic_mcs_set = host_to_le16(0xfffc);
87 46 : pos += sizeof(*oper);
88 :
89 46 : return pos;
90 : }
91 :
92 :
93 2078 : u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
94 : const u8 *vht_capab, size_t vht_capab_len)
95 : {
96 : /* Disable VHT caps for STAs associated to no-VHT BSSes. */
97 2078 : if (!vht_capab ||
98 12 : vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
99 12 : hapd->conf->disable_11ac) {
100 2066 : sta->flags &= ~WLAN_STA_VHT;
101 2066 : os_free(sta->vht_capabilities);
102 2066 : sta->vht_capabilities = NULL;
103 2066 : return WLAN_STATUS_SUCCESS;
104 : }
105 :
106 12 : if (sta->vht_capabilities == NULL) {
107 12 : sta->vht_capabilities =
108 12 : os_zalloc(sizeof(struct ieee80211_vht_capabilities));
109 12 : if (sta->vht_capabilities == NULL)
110 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
111 : }
112 :
113 12 : sta->flags |= WLAN_STA_VHT;
114 12 : os_memcpy(sta->vht_capabilities, vht_capab,
115 : sizeof(struct ieee80211_vht_capabilities));
116 :
117 12 : return WLAN_STATUS_SUCCESS;
118 : }
119 :
120 :
121 2 : u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
122 : const u8 *ie, size_t len)
123 : {
124 : const u8 *vht_capab;
125 : unsigned int vht_capab_len;
126 :
127 3 : if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
128 1 : hapd->conf->disable_11ac)
129 : goto no_capab;
130 :
131 : /* The VHT Capabilities element embedded in vendor VHT */
132 1 : vht_capab = ie + 5;
133 1 : if (vht_capab[0] != WLAN_EID_VHT_CAP)
134 0 : goto no_capab;
135 1 : vht_capab_len = vht_capab[1];
136 2 : if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
137 1 : (int) vht_capab_len > ie + len - vht_capab - 2)
138 : goto no_capab;
139 1 : vht_capab += 2;
140 :
141 1 : if (sta->vht_capabilities == NULL) {
142 1 : sta->vht_capabilities =
143 1 : os_zalloc(sizeof(struct ieee80211_vht_capabilities));
144 1 : if (sta->vht_capabilities == NULL)
145 0 : return WLAN_STATUS_UNSPECIFIED_FAILURE;
146 : }
147 :
148 1 : sta->flags |= WLAN_STA_VHT | WLAN_STA_VENDOR_VHT;
149 1 : os_memcpy(sta->vht_capabilities, vht_capab,
150 : sizeof(struct ieee80211_vht_capabilities));
151 1 : return WLAN_STATUS_SUCCESS;
152 :
153 : no_capab:
154 1 : sta->flags &= ~WLAN_STA_VENDOR_VHT;
155 1 : return WLAN_STATUS_SUCCESS;
156 : }
157 :
158 :
159 4 : u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
160 : {
161 4 : u8 *pos = eid;
162 :
163 4 : if (!hapd->iface->current_mode)
164 0 : return eid;
165 :
166 4 : *pos++ = WLAN_EID_VENDOR_SPECIFIC;
167 4 : *pos++ = (5 + /* The Vendor OUI, type and subtype */
168 : 2 + sizeof(struct ieee80211_vht_capabilities) +
169 : 2 + sizeof(struct ieee80211_vht_operation));
170 :
171 4 : WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
172 4 : pos += 4;
173 4 : *pos++ = VENDOR_VHT_SUBTYPE;
174 4 : pos = hostapd_eid_vht_capabilities(hapd, pos);
175 4 : pos = hostapd_eid_vht_operation(hapd, pos);
176 :
177 4 : return pos;
178 : }
179 :
180 :
181 2078 : u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
182 : const u8 *vht_oper_notif)
183 : {
184 2078 : if (!vht_oper_notif) {
185 2078 : sta->flags &= ~WLAN_STA_VHT_OPMODE_ENABLED;
186 2078 : return WLAN_STATUS_SUCCESS;
187 : }
188 :
189 0 : sta->flags |= WLAN_STA_VHT_OPMODE_ENABLED;
190 0 : sta->vht_opmode = *vht_oper_notif;
191 0 : return WLAN_STATUS_SUCCESS;
192 : }
193 :
194 :
195 13 : void hostapd_get_vht_capab(struct hostapd_data *hapd,
196 : struct ieee80211_vht_capabilities *vht_cap,
197 : struct ieee80211_vht_capabilities *neg_vht_cap)
198 : {
199 : u32 cap, own_cap, sym_caps;
200 :
201 13 : if (vht_cap == NULL)
202 13 : return;
203 13 : os_memcpy(neg_vht_cap, vht_cap, sizeof(*neg_vht_cap));
204 :
205 13 : cap = le_to_host32(neg_vht_cap->vht_capabilities_info);
206 13 : own_cap = hapd->iconf->vht_capab;
207 :
208 : /* mask out symmetric VHT capabilities we don't support */
209 13 : sym_caps = VHT_CAP_SHORT_GI_80 | VHT_CAP_SHORT_GI_160;
210 13 : cap &= ~sym_caps | (own_cap & sym_caps);
211 :
212 : /* mask out beamformer/beamformee caps if not supported */
213 13 : if (!(own_cap & VHT_CAP_SU_BEAMFORMER_CAPABLE))
214 13 : cap &= ~(VHT_CAP_SU_BEAMFORMEE_CAPABLE |
215 : VHT_CAP_BEAMFORMEE_STS_MAX);
216 :
217 13 : if (!(own_cap & VHT_CAP_SU_BEAMFORMEE_CAPABLE))
218 13 : cap &= ~(VHT_CAP_SU_BEAMFORMER_CAPABLE |
219 : VHT_CAP_SOUNDING_DIMENSION_MAX);
220 :
221 13 : if (!(own_cap & VHT_CAP_MU_BEAMFORMER_CAPABLE))
222 13 : cap &= ~VHT_CAP_MU_BEAMFORMEE_CAPABLE;
223 :
224 13 : if (!(own_cap & VHT_CAP_MU_BEAMFORMEE_CAPABLE))
225 13 : cap &= ~VHT_CAP_MU_BEAMFORMER_CAPABLE;
226 :
227 : /* mask channel widths we don't support */
228 13 : switch (own_cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK) {
229 : case VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ:
230 0 : break;
231 : case VHT_CAP_SUPP_CHAN_WIDTH_160MHZ:
232 0 : if (cap & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ) {
233 0 : cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
234 0 : cap |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
235 : }
236 0 : break;
237 : default:
238 13 : cap &= ~VHT_CAP_SUPP_CHAN_WIDTH_MASK;
239 13 : break;
240 : }
241 :
242 13 : if (!(cap & VHT_CAP_SUPP_CHAN_WIDTH_MASK))
243 13 : cap &= ~VHT_CAP_SHORT_GI_160;
244 :
245 : /*
246 : * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
247 : * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
248 : */
249 13 : if (!(own_cap & VHT_CAP_RXSTBC_MASK))
250 12 : cap &= ~VHT_CAP_TXSTBC;
251 13 : if (!(own_cap & VHT_CAP_TXSTBC))
252 12 : cap &= ~VHT_CAP_RXSTBC_MASK;
253 :
254 13 : neg_vht_cap->vht_capabilities_info = host_to_le32(cap);
255 : }
|