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