xref: /freebsd/sys/net80211/ieee80211_vht.c (revision 752c1d14e398faab8e6f19f99ee29df87ecb05e1)
1 /*-
2  * Copyright (c) 2017 Adrian Chadd <adrian@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 #ifdef __FreeBSD__
28 __FBSDID("$FreeBSD$");
29 #endif
30 
31 /*
32  * IEEE 802.11ac-2013 protocol support.
33  */
34 
35 #include "opt_inet.h"
36 #include "opt_wlan.h"
37 
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/malloc.h>
41 #include <sys/systm.h>
42 #include <sys/endian.h>
43 
44 #include <sys/socket.h>
45 
46 #include <net/if.h>
47 #include <net/if_var.h>
48 #include <net/if_media.h>
49 #include <net/ethernet.h>
50 
51 #include <net80211/ieee80211_var.h>
52 #include <net80211/ieee80211_action.h>
53 #include <net80211/ieee80211_input.h>
54 #include <net80211/ieee80211_vht.h>
55 
56 #define	ADDSHORT(frm, v) do {			\
57 	frm[0] = (v) & 0xff;			\
58 	frm[1] = (v) >> 8;			\
59 	frm += 2;				\
60 } while (0)
61 #define	ADDWORD(frm, v) do {			\
62 	frm[0] = (v) & 0xff;			\
63 	frm[1] = ((v) >> 8) & 0xff;		\
64 	frm[2] = ((v) >> 16) & 0xff;		\
65 	frm[3] = ((v) >> 24) & 0xff;		\
66 	frm += 4;				\
67 } while (0)
68 
69 /*
70  * Immediate TODO:
71  *
72  * + handle WLAN_ACTION_VHT_OPMODE_NOTIF and other VHT action frames
73  * + ensure vhtinfo/vhtcap parameters correctly use the negotiated
74  *   capabilities and ratesets
75  * + group ID management operation
76  */
77 
78 /*
79  * XXX TODO: handle WLAN_ACTION_VHT_OPMODE_NOTIF
80  *
81  * Look at mac80211/vht.c:ieee80211_vht_handle_opmode() for further details.
82  */
83 
84 static int
85 vht_recv_action_placeholder(struct ieee80211_node *ni,
86     const struct ieee80211_frame *wh,
87     const uint8_t *frm, const uint8_t *efrm)
88 {
89 
90 #ifdef IEEE80211_DEBUG
91 	ieee80211_note(ni->ni_vap, "%s: called; fc=0x%.2x/0x%.2x",
92 	    __func__, wh->i_fc[0], wh->i_fc[1]);
93 #endif
94 	return (0);
95 }
96 
97 static int
98 vht_send_action_placeholder(struct ieee80211_node *ni,
99     int category, int action, void *arg0)
100 {
101 
102 #ifdef IEEE80211_DEBUG
103 	ieee80211_note(ni->ni_vap, "%s: called; category=%d, action=%d",
104 	    __func__, category, action);
105 #endif
106 	return (EINVAL);
107 }
108 
109 static void
110 ieee80211_vht_init(void)
111 {
112 
113 	ieee80211_recv_action_register(IEEE80211_ACTION_CAT_VHT,
114 	    WLAN_ACTION_VHT_COMPRESSED_BF, vht_recv_action_placeholder);
115 	ieee80211_recv_action_register(IEEE80211_ACTION_CAT_VHT,
116 	    WLAN_ACTION_VHT_GROUPID_MGMT, vht_recv_action_placeholder);
117 	ieee80211_recv_action_register(IEEE80211_ACTION_CAT_VHT,
118 	    WLAN_ACTION_VHT_OPMODE_NOTIF, vht_recv_action_placeholder);
119 
120 	ieee80211_send_action_register(IEEE80211_ACTION_CAT_VHT,
121 	    WLAN_ACTION_VHT_COMPRESSED_BF, vht_send_action_placeholder);
122 	ieee80211_send_action_register(IEEE80211_ACTION_CAT_VHT,
123 	    WLAN_ACTION_VHT_GROUPID_MGMT, vht_send_action_placeholder);
124 	ieee80211_send_action_register(IEEE80211_ACTION_CAT_VHT,
125 	    WLAN_ACTION_VHT_OPMODE_NOTIF, vht_send_action_placeholder);
126 }
127 
128 SYSINIT(wlan_vht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_vht_init, NULL);
129 
130 void
131 ieee80211_vht_attach(struct ieee80211com *ic)
132 {
133 }
134 
135 void
136 ieee80211_vht_detach(struct ieee80211com *ic)
137 {
138 }
139 
140 void
141 ieee80211_vht_vattach(struct ieee80211vap *vap)
142 {
143 	struct ieee80211com *ic = vap->iv_ic;
144 
145 	if (! IEEE80211_CONF_VHT(ic))
146 		return;
147 
148 	vap->iv_vhtcaps = ic->ic_vhtcaps;
149 	vap->iv_vhtextcaps = ic->ic_vhtextcaps;
150 
151 	/* XXX assume VHT80 support; should really check vhtcaps */
152 	vap->iv_flags_vht =
153 	    IEEE80211_FVHT_VHT
154 	    | IEEE80211_FVHT_USEVHT40
155 	    | IEEE80211_FVHT_USEVHT80;
156 #if 0
157 	/* XXX TODO: enable VHT80+80, VHT160 capabilities */
158 	if (XXX TODO FIXME)
159 		vap->iv_flags_vht |= IEEE80211_FVHT_USEVHT160;
160 	if (XXX TODO FIXME)
161 		vap->iv_flags_vht |= IEEE80211_FVHT_USEVHT80P80;
162 #endif
163 
164 	memcpy(&vap->iv_vht_mcsinfo, &ic->ic_vht_mcsinfo,
165 	    sizeof(struct ieee80211_vht_mcs_info));
166 }
167 
168 void
169 ieee80211_vht_vdetach(struct ieee80211vap *vap)
170 {
171 }
172 
173 #if 0
174 static void
175 vht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode)
176 {
177 }
178 #endif
179 
180 static int
181 vht_mcs_to_num(int m)
182 {
183 
184 	switch (m) {
185 	case IEEE80211_VHT_MCS_SUPPORT_0_7:
186 		return (7);
187 	case IEEE80211_VHT_MCS_SUPPORT_0_8:
188 		return (8);
189 	case IEEE80211_VHT_MCS_SUPPORT_0_9:
190 		return (9);
191 	default:
192 		return (0);
193 	}
194 }
195 
196 void
197 ieee80211_vht_announce(struct ieee80211com *ic)
198 {
199 	int i, tx, rx;
200 
201 	if (! IEEE80211_CONF_VHT(ic))
202 		return;
203 
204 	/* Channel width */
205 	ic_printf(ic, "[VHT] Channel Widths: 20MHz, 40MHz, 80MHz");
206 	if (_IEEE80211_MASKSHIFT(ic->ic_vhtcaps,
207 	    IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) >= 1)
208 		printf(" 160MHz");
209 	if (_IEEE80211_MASKSHIFT(ic->ic_vhtcaps,
210 	    IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) == 2)
211 		printf(" 80+80MHz");
212 	printf("\n");
213 
214 	/* Features */
215 	ic_printf(ic, "[VHT] Features: %b\n", ic->ic_vhtcaps,
216 	    IEEE80211_VHTCAP_BITS);
217 
218 	/* For now, just 5GHz VHT.  Worry about 2GHz VHT later */
219 	for (i = 0; i < 8; i++) {
220 		/* Each stream is 2 bits */
221 		tx = (ic->ic_vht_mcsinfo.tx_mcs_map >> (2*i)) & 0x3;
222 		rx = (ic->ic_vht_mcsinfo.rx_mcs_map >> (2*i)) & 0x3;
223 		if (tx == 3 && rx == 3)
224 			continue;
225 		ic_printf(ic, "[VHT] NSS %d: TX MCS 0..%d, RX MCS 0..%d\n",
226 		    i + 1, vht_mcs_to_num(tx), vht_mcs_to_num(rx));
227 	}
228 }
229 
230 void
231 ieee80211_vht_node_init(struct ieee80211_node *ni)
232 {
233 
234 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
235 	    "%s: called", __func__);
236 	ni->ni_flags |= IEEE80211_NODE_VHT;
237 }
238 
239 void
240 ieee80211_vht_node_cleanup(struct ieee80211_node *ni)
241 {
242 
243 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
244 	    "%s: called", __func__);
245 	ni->ni_flags &= ~IEEE80211_NODE_VHT;
246 	ni->ni_vhtcap = 0;
247 	bzero(&ni->ni_vht_mcsinfo, sizeof(struct ieee80211_vht_mcs_info));
248 }
249 
250 /*
251  * Parse an 802.11ac VHT operation IE.
252  */
253 void
254 ieee80211_parse_vhtopmode(struct ieee80211_node *ni, const uint8_t *ie)
255 {
256 	/* vht operation */
257 	ni->ni_vht_chanwidth = ie[2];
258 	ni->ni_vht_chan1 = ie[3];
259 	ni->ni_vht_chan2 = ie[4];
260 	ni->ni_vht_basicmcs = le16dec(ie + 5);
261 
262 #if 0
263 	printf("%s: chan1=%d, chan2=%d, chanwidth=%d, basicmcs=0x%04x\n",
264 	    __func__, ni->ni_vht_chan1, ni->ni_vht_chan2, ni->ni_vht_chanwidth,
265 	    ni->ni_vht_basicmcs);
266 #endif
267 }
268 
269 /*
270  * Parse an 802.11ac VHT capability IE.
271  */
272 void
273 ieee80211_parse_vhtcap(struct ieee80211_node *ni, const uint8_t *ie)
274 {
275 
276 	/* vht capability */
277 	ni->ni_vhtcap = le32dec(ie + 2);
278 
279 	/* suppmcs */
280 	ni->ni_vht_mcsinfo.rx_mcs_map = le16dec(ie + 6);
281 	ni->ni_vht_mcsinfo.rx_highest = le16dec(ie + 8);
282 	ni->ni_vht_mcsinfo.tx_mcs_map = le16dec(ie + 10);
283 	ni->ni_vht_mcsinfo.tx_highest = le16dec(ie + 12);
284 }
285 
286 int
287 ieee80211_vht_updateparams(struct ieee80211_node *ni,
288     const uint8_t *vhtcap_ie,
289     const uint8_t *vhtop_ie)
290 {
291 
292 	//printf("%s: called\n", __func__);
293 
294 	ieee80211_parse_vhtcap(ni, vhtcap_ie);
295 	ieee80211_parse_vhtopmode(ni, vhtop_ie);
296 	return (0);
297 }
298 
299 void
300 ieee80211_setup_vht_rates(struct ieee80211_node *ni,
301     const uint8_t *vhtcap_ie,
302     const uint8_t *vhtop_ie)
303 {
304 
305 	//printf("%s: called\n", __func__);
306 	/* XXX TODO */
307 }
308 
309 void
310 ieee80211_vht_timeout(struct ieee80211vap *vap)
311 {
312 }
313 
314 void
315 ieee80211_vht_node_join(struct ieee80211_node *ni)
316 {
317 
318 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
319 	    "%s: called", __func__);
320 }
321 
322 void
323 ieee80211_vht_node_leave(struct ieee80211_node *ni)
324 {
325 
326 	IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
327 	    "%s: called", __func__);
328 }
329 
330 /*
331  * Calculate the VHTCAP IE for a given node.
332  *
333  * This includes calculating the capability intersection based on the
334  * current operating mode and intersection of the TX/RX MCS maps.
335  *
336  * The standard only makes it clear about MCS rate negotiation
337  * and MCS basic rates (which must be a subset of the general
338  * negotiated rates).  It doesn't make it clear that the AP should
339  * figure out the minimum functional overlap with the STA and
340  * support that.
341  *
342  * Note: this is in host order, not in 802.11 endian order.
343  *
344  * TODO: ensure I re-read 9.7.11 Rate Selection for VHT STAs.
345  *
346  * TODO: investigate what we should negotiate for MU-MIMO beamforming
347  *       options.
348  *
349  * opmode is '1' for "vhtcap as if I'm a STA", 0 otherwise.
350  */
351 void
352 ieee80211_vht_get_vhtcap_ie(struct ieee80211_node *ni,
353     struct ieee80211_ie_vhtcap *vhtcap, int opmode)
354 {
355 	struct ieee80211vap *vap = ni->ni_vap;
356 //	struct ieee80211com *ic = vap->iv_ic;
357 	uint32_t val, val1, val2;
358 	uint32_t new_vhtcap;
359 	int i;
360 
361 	vhtcap->ie = IEEE80211_ELEMID_VHT_CAP;
362 	vhtcap->len = sizeof(struct ieee80211_ie_vhtcap) - 2;
363 
364 	/*
365 	 * Capabilities - it depends on whether we are a station
366 	 * or not.
367 	 */
368 	new_vhtcap = 0;
369 
370 	/*
371 	 * Station - use our desired configuration based on
372 	 * local config, local device bits and the already-learnt
373 	 * vhtcap/vhtinfo IE in the node.
374 	 */
375 
376 	/* Limit MPDU size to the smaller of the two */
377 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
378 	    IEEE80211_VHTCAP_MAX_MPDU_MASK);
379 	if (opmode == 1) {
380 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
381 		    IEEE80211_VHTCAP_MAX_MPDU_MASK);
382 	}
383 	val = MIN(val1, val2);
384 	new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_MAX_MPDU_MASK);
385 
386 	/* Limit supp channel config */
387 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
388 	    IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK);
389 	if (opmode == 1) {
390 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
391 		    IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK);
392 	}
393 	if ((val2 == 2) &&
394 	    ((vap->iv_flags_vht & IEEE80211_FVHT_USEVHT80P80) == 0))
395 		val2 = 1;
396 	if ((val2 == 1) &&
397 	    ((vap->iv_flags_vht & IEEE80211_FVHT_USEVHT160) == 0))
398 		val2 = 0;
399 	val = MIN(val1, val2);
400 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
401 	     IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK);
402 
403 	/* RX LDPC */
404 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
405 	    IEEE80211_VHTCAP_RXLDPC);
406 	if (opmode == 1) {
407 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
408 		    IEEE80211_VHTCAP_RXLDPC);
409 	}
410 	val = MIN(val1, val2);
411 	new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_RXLDPC);
412 
413 	/* Short-GI 80 */
414 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
415 	    IEEE80211_VHTCAP_SHORT_GI_80);
416 	if (opmode == 1) {
417 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
418 		    IEEE80211_VHTCAP_SHORT_GI_80);
419 	}
420 	val = MIN(val1, val2);
421 	new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_SHORT_GI_80);
422 
423 	/* Short-GI 160 */
424 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
425 	    IEEE80211_VHTCAP_SHORT_GI_160);
426 	if (opmode == 1) {
427 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
428 		    IEEE80211_VHTCAP_SHORT_GI_160);
429 	}
430 	val = MIN(val1, val2);
431 	new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_SHORT_GI_160);
432 
433 	/*
434 	 * STBC is slightly more complicated.
435 	 *
436 	 * In non-STA mode, we just announce our capabilities and that
437 	 * is that.
438 	 *
439 	 * In STA mode, we should calculate our capabilities based on
440 	 * local capabilities /and/ what the remote says. So:
441 	 *
442 	 * + Only TX STBC if we support it and the remote supports RX STBC;
443 	 * + Only announce RX STBC if we support it and the remote supports
444 	 *   TX STBC;
445 	 * + RX STBC should be the minimum of local and remote RX STBC;
446 	 */
447 
448 	/* TX STBC */
449 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
450 	    IEEE80211_VHTCAP_TXSTBC);
451 	if (opmode == 1) {
452 		/* STA mode - enable it only if node RXSTBC is non-zero */
453 		val2 = !! _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
454 		    IEEE80211_VHTCAP_RXSTBC_MASK);
455 	}
456 	val = MIN(val1, val2);
457 	/* XXX For now, use the 11n config flag */
458 	if ((vap->iv_flags_ht & IEEE80211_FHT_STBC_TX) == 0)
459 		val = 0;
460 	new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_TXSTBC);
461 
462 	/* RX STBC1..4 */
463 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
464 	    IEEE80211_VHTCAP_RXSTBC_MASK);
465 	if (opmode == 1) {
466 		/* STA mode - enable it only if node TXSTBC is non-zero */
467 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
468 		   IEEE80211_VHTCAP_TXSTBC);
469 	}
470 	val = MIN(val1, val2);
471 	/* XXX For now, use the 11n config flag */
472 	if ((vap->iv_flags_ht & IEEE80211_FHT_STBC_RX) == 0)
473 		val = 0;
474 	new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_RXSTBC_MASK);
475 
476 	/*
477 	 * Finally - if RXSTBC is 0, then don't enable TXSTBC.
478 	 * Strictly speaking a device can TXSTBC and not RXSTBC, but
479 	 * it would be silly.
480 	 */
481 	if (val == 0)
482 		new_vhtcap &= ~IEEE80211_VHTCAP_TXSTBC;
483 
484 	/*
485 	 * Some of these fields require other fields to exist.
486 	 * So before using it, the parent field needs to be checked
487 	 * otherwise the overridden value may be wrong.
488 	 *
489 	 * For example, if SU beamformee is set to 0, then BF STS
490 	 * needs to be 0.
491 	 */
492 
493 	/* SU Beamformer capable */
494 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
495 	    IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE);
496 	if (opmode == 1) {
497 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
498 		    IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE);
499 	}
500 	val = MIN(val1, val2);
501 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
502 	    IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE);
503 
504 	/* SU Beamformee capable */
505 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
506 	    IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE);
507 	if (opmode == 1) {
508 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
509 		    IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE);
510 	}
511 	val = MIN(val1, val2);
512 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
513 	    IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE);
514 
515 	/* Beamformee STS capability - only if SU beamformee capable */
516 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
517 	    IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK);
518 	if (opmode == 1) {
519 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
520 		    IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK);
521 	}
522 	val = MIN(val1, val2);
523 	if ((new_vhtcap & IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE) == 0)
524 		val = 0;
525 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
526 	    IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK);
527 
528 	/* Sounding dimensions - only if SU beamformer capable */
529 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
530 	    IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK);
531 	if (opmode == 1)
532 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
533 		    IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK);
534 	val = MIN(val1, val2);
535 	if ((new_vhtcap & IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE) == 0)
536 		val = 0;
537 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
538 	    IEEE80211_VHTCAP_SOUNDING_DIMENSIONS_MASK);
539 
540 	/*
541 	 * MU Beamformer capable - only if SU BFF capable, MU BFF capable
542 	 * and STA (not AP)
543 	 */
544 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
545 	    IEEE80211_VHTCAP_MU_BEAMFORMER_CAPABLE);
546 	if (opmode == 1)
547 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
548 		    IEEE80211_VHTCAP_MU_BEAMFORMER_CAPABLE);
549 	val = MIN(val1, val2);
550 	if ((new_vhtcap & IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE) == 0)
551 		val = 0;
552 	if (opmode != 1)	/* Only enable for STA mode */
553 		val = 0;
554 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
555 	   IEEE80211_VHTCAP_SU_BEAMFORMER_CAPABLE);
556 
557 	/*
558 	 * MU Beamformee capable - only if SU BFE capable, MU BFE capable
559 	 * and AP (not STA)
560 	 */
561 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
562 	    IEEE80211_VHTCAP_MU_BEAMFORMEE_CAPABLE);
563 	if (opmode == 1)
564 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
565 		    IEEE80211_VHTCAP_MU_BEAMFORMEE_CAPABLE);
566 	val = MIN(val1, val2);
567 	if ((new_vhtcap & IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE) == 0)
568 		val = 0;
569 	if (opmode != 0)	/* Only enable for AP mode */
570 		val = 0;
571 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
572 	   IEEE80211_VHTCAP_SU_BEAMFORMEE_CAPABLE);
573 
574 	/* VHT TXOP PS */
575 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
576 	    IEEE80211_VHTCAP_VHT_TXOP_PS);
577 	if (opmode == 1)
578 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
579 		    IEEE80211_VHTCAP_VHT_TXOP_PS);
580 	val = MIN(val1, val2);
581 	new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_VHT_TXOP_PS);
582 
583 	/* HTC_VHT */
584 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
585 	    IEEE80211_VHTCAP_HTC_VHT);
586 	if (opmode == 1)
587 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
588 		    IEEE80211_VHTCAP_HTC_VHT);
589 	val = MIN(val1, val2);
590 	new_vhtcap |= _IEEE80211_SHIFTMASK(val, IEEE80211_VHTCAP_HTC_VHT);
591 
592 	/* A-MPDU length max */
593 	/* XXX TODO: we need a userland config knob for this */
594 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
595 	    IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
596 	if (opmode == 1)
597 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
598 		    IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
599 	val = MIN(val1, val2);
600 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
601 	    IEEE80211_VHTCAP_MAX_A_MPDU_LENGTH_EXPONENT_MASK);
602 
603 	/*
604 	 * Link adaptation is only valid if HTC-VHT capable is 1.
605 	 * Otherwise, always set it to 0.
606 	 */
607 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
608 	    IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MASK);
609 	if (opmode == 1)
610 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
611 		    IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MASK);
612 	val = MIN(val1, val2);
613 	if ((new_vhtcap & IEEE80211_VHTCAP_HTC_VHT) == 0)
614 		val = 0;
615 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
616 	    IEEE80211_VHTCAP_VHT_LINK_ADAPTATION_VHT_MASK);
617 
618 	/*
619 	 * The following two options are 0 if the pattern may change, 1 if it
620 	 * does not change.  So, downgrade to the higher value.
621 	 */
622 
623 	/* RX antenna pattern */
624 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
625 	    IEEE80211_VHTCAP_RX_ANTENNA_PATTERN);
626 	if (opmode == 1)
627 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
628 		    IEEE80211_VHTCAP_RX_ANTENNA_PATTERN);
629 	val = MAX(val1, val2);
630 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
631 	    IEEE80211_VHTCAP_RX_ANTENNA_PATTERN);
632 
633 	/* TX antenna pattern */
634 	val2 = val1 = _IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
635 	    IEEE80211_VHTCAP_TX_ANTENNA_PATTERN);
636 	if (opmode == 1)
637 		val2 = _IEEE80211_MASKSHIFT(ni->ni_vhtcap,
638 		    IEEE80211_VHTCAP_TX_ANTENNA_PATTERN);
639 	val = MAX(val1, val2);
640 	new_vhtcap |= _IEEE80211_SHIFTMASK(val,
641 	    IEEE80211_VHTCAP_TX_ANTENNA_PATTERN);
642 
643 	/*
644 	 * MCS set - again, we announce what we want to use
645 	 * based on configuration, device capabilities and
646 	 * already-learnt vhtcap/vhtinfo IE information.
647 	 */
648 
649 	/* MCS set - start with whatever the device supports */
650 	vhtcap->supp_mcs.rx_mcs_map = vap->iv_vht_mcsinfo.rx_mcs_map;
651 	vhtcap->supp_mcs.rx_highest = 0;
652 	vhtcap->supp_mcs.tx_mcs_map = vap->iv_vht_mcsinfo.tx_mcs_map;
653 	vhtcap->supp_mcs.tx_highest = 0;
654 
655 	vhtcap->vht_cap_info = new_vhtcap;
656 
657 	/*
658 	 * Now, if we're a STA, mask off whatever the AP doesn't support.
659 	 * Ie, we continue to state we can receive whatever we can do,
660 	 * but we only announce that we will transmit rates that meet
661 	 * the AP requirement.
662 	 *
663 	 * Note: 0 - MCS0..7; 1 - MCS0..8; 2 - MCS0..9; 3 = not supported.
664 	 * We can't just use MIN() because '3' means "no", so special case it.
665 	 */
666 	if (opmode) {
667 		for (i = 0; i < 8; i++) {
668 			val1 = (vhtcap->supp_mcs.tx_mcs_map >> (i*2)) & 0x3;
669 			val2 = (ni->ni_vht_mcsinfo.tx_mcs_map >> (i*2)) & 0x3;
670 			val = MIN(val1, val2);
671 			if (val1 == 3 || val2 == 3)
672 				val = 3;
673 			vhtcap->supp_mcs.tx_mcs_map &= ~(0x3 << (i*2));
674 			vhtcap->supp_mcs.tx_mcs_map |= (val << (i*2));
675 		}
676 	}
677 }
678 
679 /*
680  * Add a VHTCAP field.
681  *
682  * If in station mode, we announce what we would like our
683  * desired configuration to be.
684  *
685  * Else, we announce our capabilities based on our current
686  * configuration.
687  */
688 uint8_t *
689 ieee80211_add_vhtcap(uint8_t *frm, struct ieee80211_node *ni)
690 {
691 	struct ieee80211_ie_vhtcap vhtcap;
692 	int opmode;
693 
694 	opmode = 0;
695 	if (ni->ni_vap->iv_opmode == IEEE80211_M_STA)
696 		opmode = 1;
697 
698 	ieee80211_vht_get_vhtcap_ie(ni, &vhtcap, opmode);
699 
700 	memset(frm, '\0', sizeof(struct ieee80211_ie_vhtcap));
701 
702 	frm[0] = IEEE80211_ELEMID_VHT_CAP;
703 	frm[1] = sizeof(struct ieee80211_ie_vhtcap) - 2;
704 	frm += 2;
705 
706 	/* 32-bit VHT capability */
707 	ADDWORD(frm, vhtcap.vht_cap_info);
708 
709 	/* suppmcs */
710 	ADDSHORT(frm, vhtcap.supp_mcs.rx_mcs_map);
711 	ADDSHORT(frm, vhtcap.supp_mcs.rx_highest);
712 	ADDSHORT(frm, vhtcap.supp_mcs.tx_mcs_map);
713 	ADDSHORT(frm, vhtcap.supp_mcs.tx_highest);
714 
715 	return (frm);
716 }
717 
718 static uint8_t
719 ieee80211_vht_get_chwidth_ie(struct ieee80211_channel *c)
720 {
721 
722 	/*
723 	 * XXX TODO: look at the node configuration as
724 	 * well?
725 	 */
726 
727 	if (IEEE80211_IS_CHAN_VHT80P80(c))
728 		return IEEE80211_VHT_CHANWIDTH_80P80MHZ;
729 	if (IEEE80211_IS_CHAN_VHT160(c))
730 		return IEEE80211_VHT_CHANWIDTH_160MHZ;
731 	if (IEEE80211_IS_CHAN_VHT80(c))
732 		return IEEE80211_VHT_CHANWIDTH_80MHZ;
733 	if (IEEE80211_IS_CHAN_VHT40(c))
734 		return IEEE80211_VHT_CHANWIDTH_USE_HT;
735 	if (IEEE80211_IS_CHAN_VHT20(c))
736 		return IEEE80211_VHT_CHANWIDTH_USE_HT;
737 
738 	/* We shouldn't get here */
739 	printf("%s: called on a non-VHT channel (freq=%d, flags=0x%08x\n",
740 	    __func__, (int) c->ic_freq, c->ic_flags);
741 	return IEEE80211_VHT_CHANWIDTH_USE_HT;
742 }
743 
744 /*
745  * Note: this just uses the current channel information;
746  * it doesn't use the node info after parsing.
747  *
748  * XXX TODO: need to make the basic MCS set configurable.
749  * XXX TODO: read 802.11-2013 to determine what to set
750  *           chwidth to when scanning.  I have a feeling
751  *           it isn't involved in scanning and we shouldn't
752  *           be sending it; and I don't yet know what to set
753  *           it to for IBSS or hostap where the peer may be
754  *           a completely different channel width to us.
755  */
756 uint8_t *
757 ieee80211_add_vhtinfo(uint8_t *frm, struct ieee80211_node *ni)
758 {
759 	memset(frm, '\0', sizeof(struct ieee80211_ie_vht_operation));
760 
761 	frm[0] = IEEE80211_ELEMID_VHT_OPMODE;
762 	frm[1] = sizeof(struct ieee80211_ie_vht_operation) - 2;
763 	frm += 2;
764 
765 	/* 8-bit chanwidth */
766 	*frm++ = ieee80211_vht_get_chwidth_ie(ni->ni_chan);
767 
768 	/* 8-bit freq1 */
769 	*frm++ = ni->ni_chan->ic_vht_ch_freq1;
770 
771 	/* 8-bit freq2 */
772 	*frm++ = ni->ni_chan->ic_vht_ch_freq2;
773 
774 	/* 16-bit basic MCS set - just MCS0..7 for NSS=1 for now */
775 	ADDSHORT(frm, 0xfffc);
776 
777 	return (frm);
778 }
779 
780 void
781 ieee80211_vht_update_cap(struct ieee80211_node *ni, const uint8_t *vhtcap_ie,
782     const uint8_t *vhtop_ie)
783 {
784 
785 	ieee80211_parse_vhtcap(ni, vhtcap_ie);
786 	ieee80211_parse_vhtopmode(ni, vhtop_ie);
787 }
788 
789 static struct ieee80211_channel *
790 findvhtchan(struct ieee80211com *ic, struct ieee80211_channel *c, int vhtflags)
791 {
792 
793 	return (ieee80211_find_channel(ic, c->ic_freq,
794 	    (c->ic_flags & ~IEEE80211_CHAN_VHT) | vhtflags));
795 }
796 
797 /*
798  * Handle channel promotion to VHT, similar to ieee80211_ht_adjust_channel().
799  */
800 struct ieee80211_channel *
801 ieee80211_vht_adjust_channel(struct ieee80211com *ic,
802     struct ieee80211_channel *chan, int flags)
803 {
804 	struct ieee80211_channel *c;
805 
806 	/* First case - handle channel demotion - if VHT isn't set */
807 	if ((flags & IEEE80211_FVHT_VHT) == 0) {
808 #if 0
809 		printf("%s: demoting channel %d/0x%08x\n", __func__,
810 		    chan->ic_ieee, chan->ic_flags);
811 #endif
812 		c = ieee80211_find_channel(ic, chan->ic_freq,
813 		    chan->ic_flags & ~IEEE80211_CHAN_VHT);
814 		if (c == NULL)
815 			c = chan;
816 #if 0
817 		printf("%s: .. to %d/0x%08x\n", __func__,
818 		    c->ic_ieee, c->ic_flags);
819 #endif
820 		return (c);
821 	}
822 
823 	/*
824 	 * We can upgrade to VHT - attempt to do so
825 	 *
826 	 * Note: we don't clear the HT flags, these are the hints
827 	 * for HT40U/HT40D when selecting VHT40 or larger channels.
828 	 */
829 	/* Start with VHT80 */
830 	c = NULL;
831 	if ((c == NULL) && (flags & IEEE80211_FVHT_USEVHT160))
832 		c = findvhtchan(ic, chan, IEEE80211_CHAN_VHT80);
833 
834 	if ((c == NULL) && (flags & IEEE80211_FVHT_USEVHT80P80))
835 		c = findvhtchan(ic, chan, IEEE80211_CHAN_VHT80P80);
836 
837 	if ((c == NULL) && (flags & IEEE80211_FVHT_USEVHT80))
838 		c = findvhtchan(ic, chan, IEEE80211_CHAN_VHT80);
839 
840 	if ((c == NULL) && (flags & IEEE80211_FVHT_USEVHT40))
841 		c = findvhtchan(ic, chan, IEEE80211_CHAN_VHT40U);
842 	if ((c == NULL) && (flags & IEEE80211_FVHT_USEVHT40))
843 		c = findvhtchan(ic, chan, IEEE80211_CHAN_VHT40D);
844 	/*
845 	 * If we get here, VHT20 is always possible because we checked
846 	 * for IEEE80211_FVHT_VHT above.
847 	 */
848 	if (c == NULL)
849 		c = findvhtchan(ic, chan, IEEE80211_CHAN_VHT20);
850 
851 	if (c != NULL)
852 		chan = c;
853 
854 #if 0
855 	printf("%s: selected %d/0x%08x\n", __func__, c->ic_ieee, c->ic_flags);
856 #endif
857 	return (chan);
858 }
859 
860 /*
861  * Calculate the VHT operation IE for a given node.
862  *
863  * This includes calculating the suitable channel width/parameters
864  * and basic MCS set.
865  *
866  * TODO: ensure I read 9.7.11 Rate Selection for VHT STAs.
867  * TODO: ensure I read 10.39.7 - BSS Basic VHT-MCS and NSS set operation.
868  */
869 void
870 ieee80211_vht_get_vhtinfo_ie(struct ieee80211_node *ni,
871     struct ieee80211_ie_vht_operation *vhtop, int opmode)
872 {
873 	printf("%s: called; TODO!\n", __func__);
874 }
875