The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net80211/ieee80211_ht.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2007-2008 Sam Leffler, Errno Consulting
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 #ifdef __FreeBSD__
   30 __FBSDID("$FreeBSD: stable/12/sys/net80211/ieee80211_ht.c 367373 2020-11-05 12:08:04Z bz $");
   31 #endif
   32 
   33 /*
   34  * IEEE 802.11n protocol support.
   35  */
   36 
   37 #include "opt_inet.h"
   38 #include "opt_wlan.h"
   39 
   40 #include <sys/param.h>
   41 #include <sys/kernel.h>
   42 #include <sys/malloc.h>
   43 #include <sys/systm.h> 
   44 #include <sys/endian.h>
   45  
   46 #include <sys/socket.h>
   47 
   48 #include <net/if.h>
   49 #include <net/if_var.h>
   50 #include <net/if_media.h>
   51 #include <net/ethernet.h>
   52 
   53 #include <net80211/ieee80211_var.h>
   54 #include <net80211/ieee80211_action.h>
   55 #include <net80211/ieee80211_input.h>
   56 
   57 const struct ieee80211_mcs_rates ieee80211_htrates[IEEE80211_HTRATE_MAXSIZE] = {
   58         {  13,  14,   27,   30 },       /* MCS 0 */
   59         {  26,  29,   54,   60 },       /* MCS 1 */
   60         {  39,  43,   81,   90 },       /* MCS 2 */
   61         {  52,  58,  108,  120 },       /* MCS 3 */
   62         {  78,  87,  162,  180 },       /* MCS 4 */
   63         { 104, 116,  216,  240 },       /* MCS 5 */
   64         { 117, 130,  243,  270 },       /* MCS 6 */
   65         { 130, 144,  270,  300 },       /* MCS 7 */
   66         {  26,  29,   54,   60 },       /* MCS 8 */
   67         {  52,  58,  108,  120 },       /* MCS 9 */
   68         {  78,  87,  162,  180 },       /* MCS 10 */
   69         { 104, 116,  216,  240 },       /* MCS 11 */
   70         { 156, 173,  324,  360 },       /* MCS 12 */
   71         { 208, 231,  432,  480 },       /* MCS 13 */
   72         { 234, 260,  486,  540 },       /* MCS 14 */
   73         { 260, 289,  540,  600 },       /* MCS 15 */
   74         {  39,  43,   81,   90 },       /* MCS 16 */
   75         {  78,  87,  162,  180 },       /* MCS 17 */
   76         { 117, 130,  243,  270 },       /* MCS 18 */
   77         { 156, 173,  324,  360 },       /* MCS 19 */
   78         { 234, 260,  486,  540 },       /* MCS 20 */
   79         { 312, 347,  648,  720 },       /* MCS 21 */
   80         { 351, 390,  729,  810 },       /* MCS 22 */
   81         { 390, 433,  810,  900 },       /* MCS 23 */
   82         {  52,  58,  108,  120 },       /* MCS 24 */
   83         { 104, 116,  216,  240 },       /* MCS 25 */
   84         { 156, 173,  324,  360 },       /* MCS 26 */
   85         { 208, 231,  432,  480 },       /* MCS 27 */
   86         { 312, 347,  648,  720 },       /* MCS 28 */
   87         { 416, 462,  864,  960 },       /* MCS 29 */
   88         { 468, 520,  972, 1080 },       /* MCS 30 */
   89         { 520, 578, 1080, 1200 },       /* MCS 31 */
   90         {   0,   0,   12,   13 },       /* MCS 32 */
   91         {  78,  87,  162,  180 },       /* MCS 33 */
   92         { 104, 116,  216,  240 },       /* MCS 34 */
   93         { 130, 144,  270,  300 },       /* MCS 35 */
   94         { 117, 130,  243,  270 },       /* MCS 36 */
   95         { 156, 173,  324,  360 },       /* MCS 37 */
   96         { 195, 217,  405,  450 },       /* MCS 38 */
   97         { 104, 116,  216,  240 },       /* MCS 39 */
   98         { 130, 144,  270,  300 },       /* MCS 40 */
   99         { 130, 144,  270,  300 },       /* MCS 41 */
  100         { 156, 173,  324,  360 },       /* MCS 42 */
  101         { 182, 202,  378,  420 },       /* MCS 43 */
  102         { 182, 202,  378,  420 },       /* MCS 44 */
  103         { 208, 231,  432,  480 },       /* MCS 45 */
  104         { 156, 173,  324,  360 },       /* MCS 46 */
  105         { 195, 217,  405,  450 },       /* MCS 47 */
  106         { 195, 217,  405,  450 },       /* MCS 48 */
  107         { 234, 260,  486,  540 },       /* MCS 49 */
  108         { 273, 303,  567,  630 },       /* MCS 50 */
  109         { 273, 303,  567,  630 },       /* MCS 51 */
  110         { 312, 347,  648,  720 },       /* MCS 52 */
  111         { 130, 144,  270,  300 },       /* MCS 53 */
  112         { 156, 173,  324,  360 },       /* MCS 54 */
  113         { 182, 202,  378,  420 },       /* MCS 55 */
  114         { 156, 173,  324,  360 },       /* MCS 56 */
  115         { 182, 202,  378,  420 },       /* MCS 57 */
  116         { 208, 231,  432,  480 },       /* MCS 58 */
  117         { 234, 260,  486,  540 },       /* MCS 59 */
  118         { 208, 231,  432,  480 },       /* MCS 60 */
  119         { 234, 260,  486,  540 },       /* MCS 61 */
  120         { 260, 289,  540,  600 },       /* MCS 62 */
  121         { 260, 289,  540,  600 },       /* MCS 63 */
  122         { 286, 318,  594,  660 },       /* MCS 64 */
  123         { 195, 217,  405,  450 },       /* MCS 65 */
  124         { 234, 260,  486,  540 },       /* MCS 66 */
  125         { 273, 303,  567,  630 },       /* MCS 67 */
  126         { 234, 260,  486,  540 },       /* MCS 68 */
  127         { 273, 303,  567,  630 },       /* MCS 69 */
  128         { 312, 347,  648,  720 },       /* MCS 70 */
  129         { 351, 390,  729,  810 },       /* MCS 71 */
  130         { 312, 347,  648,  720 },       /* MCS 72 */
  131         { 351, 390,  729,  810 },       /* MCS 73 */
  132         { 390, 433,  810,  900 },       /* MCS 74 */
  133         { 390, 433,  810,  900 },       /* MCS 75 */
  134         { 429, 477,  891,  990 },       /* MCS 76 */
  135 };
  136 
  137 static  int ieee80211_ampdu_age = -1;   /* threshold for ampdu reorder q (ms) */
  138 SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLTYPE_INT | CTLFLAG_RW,
  139         &ieee80211_ampdu_age, 0, ieee80211_sysctl_msecs_ticks, "I",
  140         "AMPDU max reorder age (ms)");
  141 
  142 static  int ieee80211_recv_bar_ena = 1;
  143 SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena,
  144             0, "BAR frame processing (ena/dis)");
  145 
  146 static  int ieee80211_addba_timeout = -1;/* timeout for ADDBA response */
  147 SYSCTL_PROC(_net_wlan, OID_AUTO, addba_timeout, CTLTYPE_INT | CTLFLAG_RW,
  148         &ieee80211_addba_timeout, 0, ieee80211_sysctl_msecs_ticks, "I",
  149         "ADDBA request timeout (ms)");
  150 static  int ieee80211_addba_backoff = -1;/* backoff after max ADDBA requests */
  151 SYSCTL_PROC(_net_wlan, OID_AUTO, addba_backoff, CTLTYPE_INT | CTLFLAG_RW,
  152         &ieee80211_addba_backoff, 0, ieee80211_sysctl_msecs_ticks, "I",
  153         "ADDBA request backoff (ms)");
  154 static  int ieee80211_addba_maxtries = 3;/* max ADDBA requests before backoff */
  155 SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLFLAG_RW,
  156         &ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff");
  157 
  158 static  int ieee80211_bar_timeout = -1; /* timeout waiting for BAR response */
  159 static  int ieee80211_bar_maxtries = 50;/* max BAR requests before DELBA */
  160 
  161 static  ieee80211_recv_action_func ht_recv_action_ba_addba_request;
  162 static  ieee80211_recv_action_func ht_recv_action_ba_addba_response;
  163 static  ieee80211_recv_action_func ht_recv_action_ba_delba;
  164 static  ieee80211_recv_action_func ht_recv_action_ht_mimopwrsave;
  165 static  ieee80211_recv_action_func ht_recv_action_ht_txchwidth;
  166 
  167 static  ieee80211_send_action_func ht_send_action_ba_addba;
  168 static  ieee80211_send_action_func ht_send_action_ba_delba;
  169 static  ieee80211_send_action_func ht_send_action_ht_txchwidth;
  170 
  171 static void
  172 ieee80211_ht_init(void)
  173 {
  174         /*
  175          * Setup HT parameters that depends on the clock frequency.
  176          */
  177         ieee80211_ampdu_age = msecs_to_ticks(500);
  178         ieee80211_addba_timeout = msecs_to_ticks(250);
  179         ieee80211_addba_backoff = msecs_to_ticks(10*1000);
  180         ieee80211_bar_timeout = msecs_to_ticks(250);
  181         /*
  182          * Register action frame handlers.
  183          */
  184         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA, 
  185             IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_recv_action_ba_addba_request);
  186         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA, 
  187             IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_recv_action_ba_addba_response);
  188         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_BA, 
  189             IEEE80211_ACTION_BA_DELBA, ht_recv_action_ba_delba);
  190         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT, 
  191             IEEE80211_ACTION_HT_MIMOPWRSAVE, ht_recv_action_ht_mimopwrsave);
  192         ieee80211_recv_action_register(IEEE80211_ACTION_CAT_HT, 
  193             IEEE80211_ACTION_HT_TXCHWIDTH, ht_recv_action_ht_txchwidth);
  194 
  195         ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA, 
  196             IEEE80211_ACTION_BA_ADDBA_REQUEST, ht_send_action_ba_addba);
  197         ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA, 
  198             IEEE80211_ACTION_BA_ADDBA_RESPONSE, ht_send_action_ba_addba);
  199         ieee80211_send_action_register(IEEE80211_ACTION_CAT_BA, 
  200             IEEE80211_ACTION_BA_DELBA, ht_send_action_ba_delba);
  201         ieee80211_send_action_register(IEEE80211_ACTION_CAT_HT, 
  202             IEEE80211_ACTION_HT_TXCHWIDTH, ht_send_action_ht_txchwidth);
  203 }
  204 SYSINIT(wlan_ht, SI_SUB_DRIVERS, SI_ORDER_FIRST, ieee80211_ht_init, NULL);
  205 
  206 static int ieee80211_ampdu_enable(struct ieee80211_node *ni,
  207         struct ieee80211_tx_ampdu *tap);
  208 static int ieee80211_addba_request(struct ieee80211_node *ni,
  209         struct ieee80211_tx_ampdu *tap,
  210         int dialogtoken, int baparamset, int batimeout);
  211 static int ieee80211_addba_response(struct ieee80211_node *ni,
  212         struct ieee80211_tx_ampdu *tap,
  213         int code, int baparamset, int batimeout);
  214 static void ieee80211_addba_stop(struct ieee80211_node *ni,
  215         struct ieee80211_tx_ampdu *tap);
  216 static void null_addba_response_timeout(struct ieee80211_node *ni,
  217         struct ieee80211_tx_ampdu *tap);
  218 
  219 static void ieee80211_bar_response(struct ieee80211_node *ni,
  220         struct ieee80211_tx_ampdu *tap, int status);
  221 static void ampdu_tx_stop(struct ieee80211_tx_ampdu *tap);
  222 static void bar_stop_timer(struct ieee80211_tx_ampdu *tap);
  223 static int ampdu_rx_start(struct ieee80211_node *, struct ieee80211_rx_ampdu *,
  224         int baparamset, int batimeout, int baseqctl);
  225 static void ampdu_rx_stop(struct ieee80211_node *, struct ieee80211_rx_ampdu *);
  226 
  227 void
  228 ieee80211_ht_attach(struct ieee80211com *ic)
  229 {
  230         /* setup default aggregation policy */
  231         ic->ic_recv_action = ieee80211_recv_action;
  232         ic->ic_send_action = ieee80211_send_action;
  233         ic->ic_ampdu_enable = ieee80211_ampdu_enable;
  234         ic->ic_addba_request = ieee80211_addba_request;
  235         ic->ic_addba_response = ieee80211_addba_response;
  236         ic->ic_addba_response_timeout = null_addba_response_timeout;
  237         ic->ic_addba_stop = ieee80211_addba_stop;
  238         ic->ic_bar_response = ieee80211_bar_response;
  239         ic->ic_ampdu_rx_start = ampdu_rx_start;
  240         ic->ic_ampdu_rx_stop = ampdu_rx_stop;
  241 
  242         ic->ic_htprotmode = IEEE80211_PROT_RTSCTS;
  243         ic->ic_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
  244 }
  245 
  246 void
  247 ieee80211_ht_detach(struct ieee80211com *ic)
  248 {
  249 }
  250 
  251 void
  252 ieee80211_ht_vattach(struct ieee80211vap *vap)
  253 {
  254 
  255         /* driver can override defaults */
  256         vap->iv_ampdu_rxmax = IEEE80211_HTCAP_MAXRXAMPDU_8K;
  257         vap->iv_ampdu_density = IEEE80211_HTCAP_MPDUDENSITY_NA;
  258         vap->iv_ampdu_limit = vap->iv_ampdu_rxmax;
  259         vap->iv_amsdu_limit = vap->iv_htcaps & IEEE80211_HTCAP_MAXAMSDU;
  260         /* tx aggregation traffic thresholds */
  261         vap->iv_ampdu_mintraffic[WME_AC_BK] = 128;
  262         vap->iv_ampdu_mintraffic[WME_AC_BE] = 64;
  263         vap->iv_ampdu_mintraffic[WME_AC_VO] = 32;
  264         vap->iv_ampdu_mintraffic[WME_AC_VI] = 32;
  265 
  266         vap->iv_htprotmode = IEEE80211_PROT_RTSCTS;
  267         vap->iv_curhtprotmode = IEEE80211_HTINFO_OPMODE_PURE;
  268 
  269         if (vap->iv_htcaps & IEEE80211_HTC_HT) {
  270                 /*
  271                  * Device is HT capable; enable all HT-related
  272                  * facilities by default.
  273                  * XXX these choices may be too aggressive.
  274                  */
  275                 vap->iv_flags_ht |= IEEE80211_FHT_HT
  276                                  |  IEEE80211_FHT_HTCOMPAT
  277                                  ;
  278                 if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI20)
  279                         vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI20;
  280                 /* XXX infer from channel list? */
  281                 if (vap->iv_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
  282                         vap->iv_flags_ht |= IEEE80211_FHT_USEHT40;
  283                         if (vap->iv_htcaps & IEEE80211_HTCAP_SHORTGI40)
  284                                 vap->iv_flags_ht |= IEEE80211_FHT_SHORTGI40;
  285                 }
  286                 /* enable RIFS if capable */
  287                 if (vap->iv_htcaps & IEEE80211_HTC_RIFS)
  288                         vap->iv_flags_ht |= IEEE80211_FHT_RIFS;
  289 
  290                 /* NB: A-MPDU and A-MSDU rx are mandated, these are tx only */
  291                 vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_RX;
  292                 if (vap->iv_htcaps & IEEE80211_HTC_AMPDU)
  293                         vap->iv_flags_ht |= IEEE80211_FHT_AMPDU_TX;
  294                 vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_RX;
  295                 if (vap->iv_htcaps & IEEE80211_HTC_AMSDU)
  296                         vap->iv_flags_ht |= IEEE80211_FHT_AMSDU_TX;
  297 
  298                 if (vap->iv_htcaps & IEEE80211_HTCAP_TXSTBC)
  299                         vap->iv_flags_ht |= IEEE80211_FHT_STBC_TX;
  300                 if (vap->iv_htcaps & IEEE80211_HTCAP_RXSTBC)
  301                         vap->iv_flags_ht |= IEEE80211_FHT_STBC_RX;
  302 
  303                 if (vap->iv_htcaps & IEEE80211_HTCAP_LDPC)
  304                         vap->iv_flags_ht |= IEEE80211_FHT_LDPC_RX;
  305                 if (vap->iv_htcaps & IEEE80211_HTC_TXLDPC)
  306                         vap->iv_flags_ht |= IEEE80211_FHT_LDPC_TX;
  307         }
  308         /* NB: disable default legacy WDS, too many issues right now */
  309         if (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY)
  310                 vap->iv_flags_ht &= ~IEEE80211_FHT_HT;
  311 }
  312 
  313 void
  314 ieee80211_ht_vdetach(struct ieee80211vap *vap)
  315 {
  316 }
  317 
  318 static int
  319 ht_getrate(struct ieee80211com *ic, int index, enum ieee80211_phymode mode,
  320     int ratetype)
  321 {
  322         int mword, rate;
  323 
  324         mword = ieee80211_rate2media(ic, index | IEEE80211_RATE_MCS, mode);
  325         if (IFM_SUBTYPE(mword) != IFM_IEEE80211_MCS)
  326                 return (0);
  327         switch (ratetype) {
  328         case 0:
  329                 rate = ieee80211_htrates[index].ht20_rate_800ns;
  330                 break;
  331         case 1:
  332                 rate = ieee80211_htrates[index].ht20_rate_400ns;
  333                 break;
  334         case 2:
  335                 rate = ieee80211_htrates[index].ht40_rate_800ns;
  336                 break;
  337         default:
  338                 rate = ieee80211_htrates[index].ht40_rate_400ns;
  339                 break;
  340         }
  341         return (rate);
  342 }
  343 
  344 static struct printranges {
  345         int     minmcs;
  346         int     maxmcs;
  347         int     txstream;
  348         int     ratetype;
  349         int     htcapflags;
  350 } ranges[] = {
  351         {  0,  7, 1, 0, 0 },
  352         {  8, 15, 2, 0, 0 },
  353         { 16, 23, 3, 0, 0 },
  354         { 24, 31, 4, 0, 0 },
  355         { 32,  0, 1, 2, IEEE80211_HTC_TXMCS32 },
  356         { 33, 38, 2, 0, IEEE80211_HTC_TXUNEQUAL },
  357         { 39, 52, 3, 0, IEEE80211_HTC_TXUNEQUAL },
  358         { 53, 76, 4, 0, IEEE80211_HTC_TXUNEQUAL },
  359         {  0,  0, 0, 0, 0 },
  360 };
  361 
  362 static void
  363 ht_rateprint(struct ieee80211com *ic, enum ieee80211_phymode mode, int ratetype)
  364 {
  365         int minrate, maxrate;
  366         struct printranges *range;
  367 
  368         for (range = ranges; range->txstream != 0; range++) {
  369                 if (ic->ic_txstream < range->txstream)
  370                         continue;
  371                 if (range->htcapflags &&
  372                     (ic->ic_htcaps & range->htcapflags) == 0)
  373                         continue;
  374                 if (ratetype < range->ratetype)
  375                         continue;
  376                 minrate = ht_getrate(ic, range->minmcs, mode, ratetype);
  377                 maxrate = ht_getrate(ic, range->maxmcs, mode, ratetype);
  378                 if (range->maxmcs) {
  379                         ic_printf(ic, "MCS %d-%d: %d%sMbps - %d%sMbps\n",
  380                             range->minmcs, range->maxmcs,
  381                             minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""),
  382                             maxrate/2, ((maxrate & 0x1) != 0 ? ".5" : ""));
  383                 } else {
  384                         ic_printf(ic, "MCS %d: %d%sMbps\n", range->minmcs,
  385                             minrate/2, ((minrate & 0x1) != 0 ? ".5" : ""));
  386                 }
  387         }
  388 }
  389 
  390 static void
  391 ht_announce(struct ieee80211com *ic, enum ieee80211_phymode mode)
  392 {
  393         const char *modestr = ieee80211_phymode_name[mode];
  394 
  395         ic_printf(ic, "%s MCS 20MHz\n", modestr);
  396         ht_rateprint(ic, mode, 0);
  397         if (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI20) {
  398                 ic_printf(ic, "%s MCS 20MHz SGI\n", modestr);
  399                 ht_rateprint(ic, mode, 1);
  400         }
  401         if (ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) {
  402                 ic_printf(ic, "%s MCS 40MHz:\n", modestr);
  403                 ht_rateprint(ic, mode, 2);
  404         }
  405         if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
  406             (ic->ic_htcaps & IEEE80211_HTCAP_SHORTGI40)) {
  407                 ic_printf(ic, "%s MCS 40MHz SGI:\n", modestr);
  408                 ht_rateprint(ic, mode, 3);
  409         }
  410 }
  411 
  412 void
  413 ieee80211_ht_announce(struct ieee80211com *ic)
  414 {
  415 
  416         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA) ||
  417             isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
  418                 ic_printf(ic, "%dT%dR\n", ic->ic_txstream, ic->ic_rxstream);
  419         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NA))
  420                 ht_announce(ic, IEEE80211_MODE_11NA);
  421         if (isset(ic->ic_modecaps, IEEE80211_MODE_11NG))
  422                 ht_announce(ic, IEEE80211_MODE_11NG);
  423 }
  424 
  425 void
  426 ieee80211_init_suphtrates(struct ieee80211com *ic)
  427 {
  428 #define ADDRATE(x)      do {                                            \
  429         htrateset->rs_rates[htrateset->rs_nrates] = x;                  \
  430         htrateset->rs_nrates++;                                         \
  431 } while (0)
  432         struct ieee80211_htrateset *htrateset = &ic->ic_sup_htrates;
  433         int i;
  434 
  435         memset(htrateset, 0, sizeof(struct ieee80211_htrateset));
  436         for (i = 0; i < ic->ic_txstream * 8; i++)
  437                 ADDRATE(i);
  438         if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
  439             (ic->ic_htcaps & IEEE80211_HTC_TXMCS32))
  440                 ADDRATE(32);
  441         if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) {
  442                 if (ic->ic_txstream >= 2) {
  443                          for (i = 33; i <= 38; i++)
  444                                 ADDRATE(i);
  445                 }
  446                 if (ic->ic_txstream >= 3) {
  447                         for (i = 39; i <= 52; i++)
  448                                 ADDRATE(i);
  449                 }
  450                 if (ic->ic_txstream == 4) {
  451                         for (i = 53; i <= 76; i++)
  452                                 ADDRATE(i);
  453                 }
  454         }
  455 #undef  ADDRATE
  456 }
  457 
  458 /*
  459  * Receive processing.
  460  */
  461 
  462 /*
  463  * Decap the encapsulated A-MSDU frames and dispatch all but
  464  * the last for delivery.  The last frame is returned for 
  465  * delivery via the normal path.
  466  */
  467 struct mbuf *
  468 ieee80211_decap_amsdu(struct ieee80211_node *ni, struct mbuf *m)
  469 {
  470         struct ieee80211vap *vap = ni->ni_vap;
  471         int framelen;
  472         struct mbuf *n;
  473 
  474         /* discard 802.3 header inserted by ieee80211_decap */
  475         m_adj(m, sizeof(struct ether_header));
  476 
  477         vap->iv_stats.is_amsdu_decap++;
  478 
  479         for (;;) {
  480                 /*
  481                  * Decap the first frame, bust it apart from the
  482                  * remainder and deliver.  We leave the last frame
  483                  * delivery to the caller (for consistency with other
  484                  * code paths, could also do it here).
  485                  */
  486                 m = ieee80211_decap1(m, &framelen);
  487                 if (m == NULL) {
  488                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
  489                             ni->ni_macaddr, "a-msdu", "%s", "decap failed");
  490                         vap->iv_stats.is_amsdu_tooshort++;
  491                         return NULL;
  492                 }
  493                 if (m->m_pkthdr.len == framelen)
  494                         break;
  495                 n = m_split(m, framelen, M_NOWAIT);
  496                 if (n == NULL) {
  497                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
  498                             ni->ni_macaddr, "a-msdu",
  499                             "%s", "unable to split encapsulated frames");
  500                         vap->iv_stats.is_amsdu_split++;
  501                         m_freem(m);                     /* NB: must reclaim */
  502                         return NULL;
  503                 }
  504                 vap->iv_deliver_data(vap, ni, m);
  505 
  506                 /*
  507                  * Remove frame contents; each intermediate frame
  508                  * is required to be aligned to a 4-byte boundary.
  509                  */
  510                 m = n;
  511                 m_adj(m, roundup2(framelen, 4) - framelen);     /* padding */
  512         }
  513         return m;                               /* last delivered by caller */
  514 }
  515 
  516 static void
  517 ampdu_rx_purge_slot(struct ieee80211_rx_ampdu *rap, int i)
  518 {
  519         struct mbuf *m;
  520 
  521         /* Walk the queue, removing frames as appropriate */
  522         while (mbufq_len(&rap->rxa_mq[i]) != 0) {
  523                 m = mbufq_dequeue(&rap->rxa_mq[i]);
  524                 if (m == NULL)
  525                         break;
  526                 rap->rxa_qbytes -= m->m_pkthdr.len;
  527                 rap->rxa_qframes--;
  528                 m_freem(m);
  529         }
  530 }
  531 
  532 /*
  533  * Add the given frame to the current RX reorder slot.
  534  *
  535  * For future offloaded A-MSDU handling where multiple frames with
  536  * the same sequence number show up here, this routine will append
  537  * those frames as long as they're appropriately tagged.
  538  */
  539 static int
  540 ampdu_rx_add_slot(struct ieee80211_rx_ampdu *rap, int off, int tid,
  541     ieee80211_seq rxseq,
  542     struct ieee80211_node *ni,
  543     struct mbuf *m,
  544     const struct ieee80211_rx_stats *rxs)
  545 {
  546         const struct ieee80211_rx_stats *rxs_final = NULL;
  547         struct ieee80211vap *vap = ni->ni_vap;
  548         int toss_dup;
  549 #define PROCESS         0       /* caller should process frame */
  550 #define CONSUMED        1       /* frame consumed, caller does nothing */
  551 
  552         /*
  553          * Figure out if this is a duplicate frame for the given slot.
  554          *
  555          * We're assuming that the driver will hand us all the frames
  556          * for a given AMSDU decap pass and if we get /a/ frame
  557          * for an AMSDU decap then we'll get all of them.
  558          *
  559          * The tricksy bit is that we don't know when the /end/ of
  560          * the decap pass is, because we aren't tracking state here
  561          * per-slot to know that we've finished receiving the frame list.
  562          *
  563          * The driver sets RX_F_AMSDU and RX_F_AMSDU_MORE to tell us
  564          * what's going on; so ideally we'd just check the frame at the
  565          * end of the reassembly slot to see if its F_AMSDU w/ no F_AMSDU_MORE -
  566          * that means we've received the whole AMSDU decap pass.
  567          */
  568 
  569         /*
  570          * Get the rxs of the final mbuf in the slot, if one exists.
  571          */
  572         if (mbufq_len(&rap->rxa_mq[off]) != 0) {
  573                 rxs_final = ieee80211_get_rx_params_ptr(mbufq_last(&rap->rxa_mq[off]));
  574         }
  575 
  576         /* Default to tossing the duplicate frame */
  577         toss_dup = 1;
  578 
  579         /*
  580          * Check to see if the final frame has F_AMSDU and F_AMSDU set, AND
  581          * this frame has F_AMSDU set (MORE or otherwise.)  That's a sign
  582          * that more can come.
  583          */
  584 
  585         if ((rxs != NULL) && (rxs_final != NULL) &&
  586             ieee80211_check_rxseq_amsdu(rxs) &&
  587             ieee80211_check_rxseq_amsdu(rxs_final)) {
  588                 if (! ieee80211_check_rxseq_amsdu_more(rxs_final)) {
  589                         /*
  590                          * amsdu_more() returning 0 means "it's not the
  591                          * final frame" so we can append more
  592                          * frames here.
  593                          */
  594                         toss_dup = 0;
  595                 }
  596         }
  597 
  598         /*
  599          * If the list is empty OR we have determined we can put more
  600          * driver decap'ed AMSDU frames in here, then insert.
  601          */
  602         if ((mbufq_len(&rap->rxa_mq[off]) == 0) || (toss_dup == 0)) {
  603                 if (mbufq_enqueue(&rap->rxa_mq[off], m) != 0) {
  604                         IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
  605                             ni->ni_macaddr,
  606                             "a-mpdu queue fail",
  607                             "seqno %u tid %u BA win <%u:%u> off=%d, qlen=%d, maxqlen=%d",
  608                             rxseq, tid, rap->rxa_start,
  609                             IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
  610                             off,
  611                             mbufq_len(&rap->rxa_mq[off]),
  612                             rap->rxa_mq[off].mq_maxlen);
  613                         /* XXX error count */
  614                         m_freem(m);
  615                         return CONSUMED;
  616                 }
  617                 rap->rxa_qframes++;
  618                 rap->rxa_qbytes += m->m_pkthdr.len;
  619                 vap->iv_stats.is_ampdu_rx_reorder++;
  620                 /*
  621                  * Statistics for AMSDU decap.
  622                  */
  623                 if (rxs != NULL && ieee80211_check_rxseq_amsdu(rxs)) {
  624                         if (ieee80211_check_rxseq_amsdu_more(rxs)) {
  625                                 /* more=1, AMSDU, end of batch */
  626                                 IEEE80211_NODE_STAT(ni, rx_amsdu_more_end);
  627                         } else {
  628                                 IEEE80211_NODE_STAT(ni, rx_amsdu_more);
  629                         }
  630                 }
  631         } else {
  632                 IEEE80211_DISCARD_MAC(vap,
  633                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
  634                     ni->ni_macaddr, "a-mpdu duplicate",
  635                     "seqno %u tid %u BA win <%u:%u>",
  636                     rxseq, tid, rap->rxa_start,
  637                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1));
  638                 if (rxs != NULL) {
  639                         IEEE80211_DISCARD_MAC(vap,
  640                             IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
  641                             ni->ni_macaddr, "a-mpdu duplicate",
  642                             "seqno %d tid %u pktflags 0x%08x\n",
  643                             rxseq, tid, rxs->c_pktflags);
  644                 }
  645                 if (rxs_final != NULL) {
  646                         IEEE80211_DISCARD_MAC(vap,
  647                             IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
  648                             ni->ni_macaddr, "a-mpdu duplicate",
  649                             "final: pktflags 0x%08x\n",
  650                             rxs_final->c_pktflags);
  651                 }
  652                 vap->iv_stats.is_rx_dup++;
  653                 IEEE80211_NODE_STAT(ni, rx_dup);
  654                 m_freem(m);
  655         }
  656         return CONSUMED;
  657 #undef  CONSUMED
  658 #undef  PROCESS
  659 }
  660 
  661 /*
  662  * Purge all frames in the A-MPDU re-order queue.
  663  */
  664 static void
  665 ampdu_rx_purge(struct ieee80211_rx_ampdu *rap)
  666 {
  667         int i;
  668 
  669         for (i = 0; i < rap->rxa_wnd; i++) {
  670                 ampdu_rx_purge_slot(rap, i);
  671                 if (rap->rxa_qframes == 0)
  672                         break;
  673         }
  674         KASSERT(rap->rxa_qbytes == 0 && rap->rxa_qframes == 0,
  675             ("lost %u data, %u frames on ampdu rx q",
  676             rap->rxa_qbytes, rap->rxa_qframes));
  677 }
  678 
  679 static void
  680 ieee80211_ampdu_rx_init_rap(struct ieee80211_node *ni,
  681     struct ieee80211_rx_ampdu *rap)
  682 {
  683         int i;
  684 
  685         /* XXX TODO: ensure the queues are empty */
  686         memset(rap, 0, sizeof(*rap));
  687         for (i = 0; i < IEEE80211_AGGR_BAWMAX; i++)
  688                 mbufq_init(&rap->rxa_mq[i], 256);
  689 }
  690 
  691 /*
  692  * Start A-MPDU rx/re-order processing for the specified TID.
  693  */
  694 static int
  695 ampdu_rx_start(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap,
  696         int baparamset, int batimeout, int baseqctl)
  697 {
  698         struct ieee80211vap *vap = ni->ni_vap;
  699         int bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
  700 
  701         if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
  702                 /*
  703                  * AMPDU previously setup and not terminated with a DELBA,
  704                  * flush the reorder q's in case anything remains.
  705                  */
  706                 ampdu_rx_purge(rap);
  707         }
  708         ieee80211_ampdu_rx_init_rap(ni, rap);
  709         rap->rxa_wnd = (bufsiz == 0) ?
  710             IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
  711         rap->rxa_start = _IEEE80211_MASKSHIFT(baseqctl, IEEE80211_BASEQ_START);
  712         rap->rxa_flags |=  IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
  713 
  714         /* XXX this should be a configuration flag */
  715         if ((vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU) &&
  716             (_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU)))
  717                 rap->rxa_flags |= IEEE80211_AGGR_AMSDU;
  718         else
  719                 rap->rxa_flags &= ~IEEE80211_AGGR_AMSDU;
  720 
  721         return 0;
  722 }
  723 
  724 /*
  725  * Public function; manually setup the RX ampdu state.
  726  */
  727 int
  728 ieee80211_ampdu_rx_start_ext(struct ieee80211_node *ni, int tid, int seq, int baw)
  729 {
  730         struct ieee80211_rx_ampdu *rap;
  731 
  732         /* XXX TODO: sanity check tid, seq, baw */
  733 
  734         rap = &ni->ni_rx_ampdu[tid];
  735 
  736         if (rap->rxa_flags & IEEE80211_AGGR_RUNNING) {
  737                 /*
  738                  * AMPDU previously setup and not terminated with a DELBA,
  739                  * flush the reorder q's in case anything remains.
  740                  */
  741                 ampdu_rx_purge(rap);
  742         }
  743 
  744         ieee80211_ampdu_rx_init_rap(ni, rap);
  745 
  746         rap->rxa_wnd = (baw== 0) ?
  747             IEEE80211_AGGR_BAWMAX : min(baw, IEEE80211_AGGR_BAWMAX);
  748         if (seq == -1) {
  749                 /* Wait for the first RX frame, use that as BAW */
  750                 rap->rxa_start = 0;
  751                 rap->rxa_flags |= IEEE80211_AGGR_WAITRX;
  752         } else {
  753                 rap->rxa_start = seq;
  754         }
  755         rap->rxa_flags |=  IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_XCHGPEND;
  756 
  757         /* XXX TODO: no amsdu flag */
  758 
  759         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
  760             "%s: tid=%d, start=%d, wnd=%d, flags=0x%08x",
  761             __func__,
  762             tid,
  763             seq,
  764             rap->rxa_wnd,
  765             rap->rxa_flags);
  766 
  767         return 0;
  768 }
  769 
  770 /*
  771  * Public function; manually stop the RX AMPDU state.
  772  */
  773 void
  774 ieee80211_ampdu_rx_stop_ext(struct ieee80211_node *ni, int tid)
  775 {
  776         struct ieee80211_rx_ampdu *rap;
  777 
  778         /* XXX TODO: sanity check tid, seq, baw */
  779         rap = &ni->ni_rx_ampdu[tid];
  780         ampdu_rx_stop(ni, rap);
  781 }
  782 
  783 /*
  784  * Stop A-MPDU rx processing for the specified TID.
  785  */
  786 static void
  787 ampdu_rx_stop(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
  788 {
  789 
  790         ampdu_rx_purge(rap);
  791         rap->rxa_flags &= ~(IEEE80211_AGGR_RUNNING
  792             | IEEE80211_AGGR_XCHGPEND
  793             | IEEE80211_AGGR_WAITRX);
  794 }
  795 
  796 /*
  797  * Dispatch a frame from the A-MPDU reorder queue.  The
  798  * frame is fed back into ieee80211_input marked with an
  799  * M_AMPDU_MPDU flag so it doesn't come back to us (it also
  800  * permits ieee80211_input to optimize re-processing).
  801  */
  802 static __inline void
  803 ampdu_dispatch(struct ieee80211_node *ni, struct mbuf *m)
  804 {
  805         m->m_flags |= M_AMPDU_MPDU;     /* bypass normal processing */
  806         /* NB: rssi and noise are ignored w/ M_AMPDU_MPDU set */
  807         (void) ieee80211_input(ni, m, 0, 0);
  808 }
  809 
  810 static int
  811 ampdu_dispatch_slot(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni,
  812     int i)
  813 {
  814         struct mbuf *m;
  815         int n = 0;
  816 
  817         while (mbufq_len(&rap->rxa_mq[i]) != 0) {
  818                 m = mbufq_dequeue(&rap->rxa_mq[i]);
  819                 if (m == NULL)
  820                         break;
  821                 n++;
  822 
  823                 rap->rxa_qbytes -= m->m_pkthdr.len;
  824                 rap->rxa_qframes--;
  825 
  826                 ampdu_dispatch(ni, m);
  827         }
  828         return (n);
  829 }
  830 
  831 static void
  832 ampdu_rx_moveup(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni,
  833     int i, int winstart)
  834 {
  835         struct ieee80211vap *vap = ni->ni_vap;
  836 
  837         /*
  838          * If frames remain, copy the mbuf pointers down so
  839          * they correspond to the offsets in the new window.
  840          */
  841         if (rap->rxa_qframes != 0) {
  842                 int n = rap->rxa_qframes, j;
  843                 for (j = i+1; j < rap->rxa_wnd; j++) {
  844                         /*
  845                          * Concat the list contents over, which will
  846                          * blank the source list for us.
  847                          */
  848                         if (mbufq_len(&rap->rxa_mq[j]) != 0) {
  849                                 n = n - mbufq_len(&rap->rxa_mq[j]);
  850                                 mbufq_concat(&rap->rxa_mq[j-i], &rap->rxa_mq[j]);
  851                                 KASSERT(n >= 0, ("%s: n < 0 (%d)", __func__, n));
  852                                 if (n == 0)
  853                                         break;
  854                         }
  855                 }
  856                 KASSERT(n == 0, ("%s: lost %d frames, qframes %d off %d "
  857                     "BA win <%d:%d> winstart %d",
  858                     __func__, n, rap->rxa_qframes, i, rap->rxa_start,
  859                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
  860                     winstart));
  861                 vap->iv_stats.is_ampdu_rx_copy += rap->rxa_qframes;
  862         }
  863 }
  864 
  865 /*
  866  * Dispatch as many frames as possible from the re-order queue.
  867  * Frames will always be "at the front"; we process all frames
  868  * up to the first empty slot in the window.  On completion we
  869  * cleanup state if there are still pending frames in the current
  870  * BA window.  We assume the frame at slot 0 is already handled
  871  * by the caller; we always start at slot 1.
  872  */
  873 static void
  874 ampdu_rx_dispatch(struct ieee80211_rx_ampdu *rap, struct ieee80211_node *ni)
  875 {
  876         struct ieee80211vap *vap = ni->ni_vap;
  877         int i, r, r2;
  878 
  879         /* flush run of frames */
  880         r2 = 0;
  881         for (i = 1; i < rap->rxa_wnd; i++) {
  882                 r = ampdu_dispatch_slot(rap, ni, i);
  883                 if (r == 0)
  884                         break;
  885                 r2 += r;
  886         }
  887 
  888         /* move up frames */
  889         ampdu_rx_moveup(rap, ni, i, -1);
  890 
  891         /*
  892          * Adjust the start of the BA window to
  893          * reflect the frames just dispatched.
  894          */
  895         rap->rxa_start = IEEE80211_SEQ_ADD(rap->rxa_start, i);
  896         vap->iv_stats.is_ampdu_rx_oor += r2;
  897 
  898         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
  899             "%s: moved slot up %d slots to start at %d (%d frames)",
  900             __func__,
  901             i,
  902             rap->rxa_start,
  903             r2);
  904 }
  905 
  906 /*
  907  * Dispatch all frames in the A-MPDU re-order queue.
  908  */
  909 static void
  910 ampdu_rx_flush(struct ieee80211_node *ni, struct ieee80211_rx_ampdu *rap)
  911 {
  912         int i, r;
  913 
  914         for (i = 0; i < rap->rxa_wnd; i++) {
  915                 r = ampdu_dispatch_slot(rap, ni, i);
  916                 if (r == 0)
  917                         continue;
  918                 ni->ni_vap->iv_stats.is_ampdu_rx_oor += r;
  919 
  920                 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
  921                     "%s: moved slot up %d slots to start at %d (%d frames)",
  922                     __func__,
  923                     1,
  924                     rap->rxa_start,
  925                     r);
  926 
  927                 if (rap->rxa_qframes == 0)
  928                         break;
  929         }
  930 }
  931 
  932 /*
  933  * Dispatch all frames in the A-MPDU re-order queue
  934  * preceding the specified sequence number.  This logic
  935  * handles window moves due to a received MSDU or BAR.
  936  */
  937 static void
  938 ampdu_rx_flush_upto(struct ieee80211_node *ni,
  939         struct ieee80211_rx_ampdu *rap, ieee80211_seq winstart)
  940 {
  941         struct ieee80211vap *vap = ni->ni_vap;
  942         ieee80211_seq seqno;
  943         int i, r;
  944 
  945         /*
  946          * Flush any complete MSDU's with a sequence number lower
  947          * than winstart.  Gaps may exist.  Note that we may actually
  948          * dispatch frames past winstart if a run continues; this is
  949          * an optimization that avoids having to do a separate pass
  950          * to dispatch frames after moving the BA window start.
  951          */
  952         seqno = rap->rxa_start;
  953         for (i = 0; i < rap->rxa_wnd; i++) {
  954                 if ((r = mbufq_len(&rap->rxa_mq[i])) != 0) {
  955                         (void) ampdu_dispatch_slot(rap, ni, i);
  956                 } else {
  957                         if (!IEEE80211_SEQ_BA_BEFORE(seqno, winstart))
  958                                 break;
  959                 }
  960                 vap->iv_stats.is_ampdu_rx_oor += r;
  961                 seqno = IEEE80211_SEQ_INC(seqno);
  962 
  963                 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N, ni,
  964                     "%s: moved slot up %d slots to start at %d (%d frames)",
  965                     __func__,
  966                     1,
  967                     seqno,
  968                     r);
  969         }
  970 
  971         /*
  972          * If frames remain, copy the mbuf pointers down so
  973          * they correspond to the offsets in the new window.
  974          */
  975         ampdu_rx_moveup(rap, ni, i, winstart);
  976 
  977         /*
  978          * Move the start of the BA window; we use the
  979          * sequence number of the last MSDU that was
  980          * passed up the stack+1 or winstart if stopped on
  981          * a gap in the reorder buffer.
  982          */
  983         rap->rxa_start = seqno;
  984 }
  985 
  986 /*
  987  * Process a received QoS data frame for an HT station.  Handle
  988  * A-MPDU reordering: if this frame is received out of order
  989  * and falls within the BA window hold onto it.  Otherwise if
  990  * this frame completes a run, flush any pending frames.  We
  991  * return 1 if the frame is consumed.  A 0 is returned if
  992  * the frame should be processed normally by the caller.
  993  *
  994  * A-MSDU: handle hardware decap'ed A-MSDU frames that are
  995  * pretending to be MPDU's.  They're dispatched directly if
  996  * able; or attempted to put into the receive reordering slot.
  997  */
  998 int
  999 ieee80211_ampdu_reorder(struct ieee80211_node *ni, struct mbuf *m,
 1000     const struct ieee80211_rx_stats *rxs)
 1001 {
 1002 #define PROCESS         0       /* caller should process frame */
 1003 #define CONSUMED        1       /* frame consumed, caller does nothing */
 1004         struct ieee80211vap *vap = ni->ni_vap;
 1005         struct ieee80211_qosframe *wh;
 1006         struct ieee80211_rx_ampdu *rap;
 1007         ieee80211_seq rxseq;
 1008         uint8_t tid;
 1009         int off;
 1010         int amsdu = ieee80211_check_rxseq_amsdu(rxs);
 1011         int amsdu_end = ieee80211_check_rxseq_amsdu_more(rxs);
 1012 
 1013         KASSERT((m->m_flags & (M_AMPDU | M_AMPDU_MPDU)) == M_AMPDU,
 1014             ("!a-mpdu or already re-ordered, flags 0x%x", m->m_flags));
 1015         KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
 1016 
 1017         /* NB: m_len known to be sufficient */
 1018         wh = mtod(m, struct ieee80211_qosframe *);
 1019         if (wh->i_fc[0] != IEEE80211_FC0_QOSDATA) {
 1020                 /*
 1021                  * Not QoS data, shouldn't get here but just
 1022                  * return it to the caller for processing.
 1023                  */
 1024                 return PROCESS;
 1025         }
 1026 
 1027         /*
 1028          * 802.11-2012 9.3.2.10 - Duplicate detection and recovery.
 1029          *
 1030          * Multicast QoS data frames are checked against a different
 1031          * counter, not the per-TID counter.
 1032          */
 1033         if (IEEE80211_IS_MULTICAST(wh->i_addr1))
 1034                 return PROCESS;
 1035 
 1036         tid = ieee80211_getqos(wh)[0];
 1037         tid &= IEEE80211_QOS_TID;
 1038         rap = &ni->ni_rx_ampdu[tid];
 1039         if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
 1040                 /*
 1041                  * No ADDBA request yet, don't touch.
 1042                  */
 1043                 return PROCESS;
 1044         }
 1045         rxseq = le16toh(*(uint16_t *)wh->i_seq);
 1046         if ((rxseq & IEEE80211_SEQ_FRAG_MASK) != 0) {
 1047                 /*
 1048                  * Fragments are not allowed; toss.
 1049                  */
 1050                 IEEE80211_DISCARD_MAC(vap,
 1051                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
 1052                     "A-MPDU", "fragment, rxseq 0x%x tid %u%s", rxseq, tid,
 1053                     wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
 1054                 vap->iv_stats.is_ampdu_rx_drop++;
 1055                 IEEE80211_NODE_STAT(ni, rx_drop);
 1056                 m_freem(m);
 1057                 return CONSUMED;
 1058         }
 1059         rxseq >>= IEEE80211_SEQ_SEQ_SHIFT;
 1060         rap->rxa_nframes++;
 1061 
 1062         /*
 1063          * Handle waiting for the first frame to define the BAW.
 1064          * Some firmware doesn't provide the RX of the starting point
 1065          * of the BAW and we have to cope.
 1066          */
 1067         if (rap->rxa_flags & IEEE80211_AGGR_WAITRX) {
 1068                 rap->rxa_flags &= ~IEEE80211_AGGR_WAITRX;
 1069                 rap->rxa_start = rxseq;
 1070         }
 1071 again:
 1072         if (rxseq == rap->rxa_start) {
 1073                 /*
 1074                  * First frame in window.
 1075                  */
 1076                 if (rap->rxa_qframes != 0) {
 1077                         /*
 1078                          * Dispatch as many packets as we can.
 1079                          */
 1080                         KASSERT((mbufq_len(&rap->rxa_mq[0]) == 0), ("unexpected dup"));
 1081                         ampdu_dispatch(ni, m);
 1082                         ampdu_rx_dispatch(rap, ni);
 1083                         return CONSUMED;
 1084                 } else {
 1085                         /*
 1086                          * In order; advance window if needed and notify
 1087                          * caller to dispatch directly.
 1088                          */
 1089                         if (amsdu) {
 1090                                 if (amsdu_end) {
 1091                                         rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
 1092                                         IEEE80211_NODE_STAT(ni, rx_amsdu_more_end);
 1093                                 } else {
 1094                                         IEEE80211_NODE_STAT(ni, rx_amsdu_more);
 1095                                 }
 1096                         } else {
 1097                                 rap->rxa_start = IEEE80211_SEQ_INC(rxseq);
 1098                         }
 1099                         return PROCESS;
 1100                 }
 1101         }
 1102         /*
 1103          * Frame is out of order; store if in the BA window.
 1104          */
 1105         /* calculate offset in BA window */
 1106         off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
 1107         if (off < rap->rxa_wnd) {
 1108                 /*
 1109                  * Common case (hopefully): in the BA window.
 1110                  * Sec 9.10.7.6.2 a) (p.137)
 1111                  */
 1112 
 1113                 /* 
 1114                  * Check for frames sitting too long in the reorder queue.
 1115                  * This should only ever happen if frames are not delivered
 1116                  * without the sender otherwise notifying us (e.g. with a
 1117                  * BAR to move the window).  Typically this happens because
 1118                  * of vendor bugs that cause the sequence number to jump.
 1119                  * When this happens we get a gap in the reorder queue that
 1120                  * leaves frame sitting on the queue until they get pushed
 1121                  * out due to window moves.  When the vendor does not send
 1122                  * BAR this move only happens due to explicit packet sends
 1123                  *
 1124                  * NB: we only track the time of the oldest frame in the
 1125                  * reorder q; this means that if we flush we might push
 1126                  * frames that still "new"; if this happens then subsequent
 1127                  * frames will result in BA window moves which cost something
 1128                  * but is still better than a big throughput dip.
 1129                  */
 1130                 if (rap->rxa_qframes != 0) {
 1131                         /* XXX honor batimeout? */
 1132                         if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
 1133                                 /*
 1134                                  * Too long since we received the first
 1135                                  * frame; flush the reorder buffer.
 1136                                  */
 1137                                 if (rap->rxa_qframes != 0) {
 1138                                         vap->iv_stats.is_ampdu_rx_age +=
 1139                                             rap->rxa_qframes;
 1140                                         ampdu_rx_flush(ni, rap);
 1141                                 }
 1142                                 /*
 1143                                  * Advance the window if needed and notify
 1144                                  * the caller to dispatch directly.
 1145                                  */
 1146                                 if (amsdu) {
 1147                                         if (amsdu_end) {
 1148                                                 rap->rxa_start =
 1149                                                     IEEE80211_SEQ_INC(rxseq);
 1150                                                 IEEE80211_NODE_STAT(ni,
 1151                                                     rx_amsdu_more_end);
 1152                                         } else {
 1153                                                 IEEE80211_NODE_STAT(ni,
 1154                                                     rx_amsdu_more);
 1155                                         }
 1156                                 } else {
 1157                                         rap->rxa_start =
 1158                                             IEEE80211_SEQ_INC(rxseq);
 1159                                 }
 1160                                 return PROCESS;
 1161                         }
 1162                 } else {
 1163                         /*
 1164                          * First frame, start aging timer.
 1165                          */
 1166                         rap->rxa_age = ticks;
 1167                 }
 1168 
 1169                 /* save packet - this consumes, no matter what */
 1170                 ampdu_rx_add_slot(rap, off, tid, rxseq, ni, m, rxs);
 1171                 return CONSUMED;
 1172         }
 1173         if (off < IEEE80211_SEQ_BA_RANGE) {
 1174                 /*
 1175                  * Outside the BA window, but within range;
 1176                  * flush the reorder q and move the window.
 1177                  * Sec 9.10.7.6.2 b) (p.138)
 1178                  */
 1179                 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
 1180                     "move BA win <%u:%u> (%u frames) rxseq %u tid %u",
 1181                     rap->rxa_start,
 1182                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
 1183                     rap->rxa_qframes, rxseq, tid);
 1184                 vap->iv_stats.is_ampdu_rx_move++;
 1185 
 1186                 /*
 1187                  * The spec says to flush frames up to but not including:
 1188                  *      WinStart_B = rxseq - rap->rxa_wnd + 1
 1189                  * Then insert the frame or notify the caller to process
 1190                  * it immediately.  We can safely do this by just starting
 1191                  * over again because we know the frame will now be within
 1192                  * the BA window.
 1193                  */
 1194                 /* NB: rxa_wnd known to be >0 */
 1195                 ampdu_rx_flush_upto(ni, rap,
 1196                     IEEE80211_SEQ_SUB(rxseq, rap->rxa_wnd-1));
 1197                 goto again;
 1198         } else {
 1199                 /*
 1200                  * Outside the BA window and out of range; toss.
 1201                  * Sec 9.10.7.6.2 c) (p.138)
 1202                  */
 1203                 IEEE80211_DISCARD_MAC(vap,
 1204                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
 1205                     "MPDU", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
 1206                     rap->rxa_start,
 1207                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
 1208                     rap->rxa_qframes, rxseq, tid,
 1209                     wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
 1210                 vap->iv_stats.is_ampdu_rx_drop++;
 1211                 IEEE80211_NODE_STAT(ni, rx_drop);
 1212                 m_freem(m);
 1213                 return CONSUMED;
 1214         }
 1215 #undef CONSUMED
 1216 #undef PROCESS
 1217 }
 1218 
 1219 /*
 1220  * Process a BAR ctl frame.  Dispatch all frames up to
 1221  * the sequence number of the frame.  If this frame is
 1222  * out of range it's discarded.
 1223  */
 1224 void
 1225 ieee80211_recv_bar(struct ieee80211_node *ni, struct mbuf *m0)
 1226 {
 1227         struct ieee80211vap *vap = ni->ni_vap;
 1228         struct ieee80211_frame_bar *wh;
 1229         struct ieee80211_rx_ampdu *rap;
 1230         ieee80211_seq rxseq;
 1231         int tid, off;
 1232 
 1233         if (!ieee80211_recv_bar_ena) {
 1234 #if 0
 1235                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_11N,
 1236                     ni->ni_macaddr, "BAR", "%s", "processing disabled");
 1237 #endif
 1238                 vap->iv_stats.is_ampdu_bar_bad++;
 1239                 return;
 1240         }
 1241         wh = mtod(m0, struct ieee80211_frame_bar *);
 1242         /* XXX check basic BAR */
 1243         tid = _IEEE80211_MASKSHIFT(le16toh(wh->i_ctl), IEEE80211_BAR_TID);
 1244         rap = &ni->ni_rx_ampdu[tid];
 1245         if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
 1246                 /*
 1247                  * No ADDBA request yet, don't touch.
 1248                  */
 1249                 IEEE80211_DISCARD_MAC(vap,
 1250                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N,
 1251                     ni->ni_macaddr, "BAR", "no BA stream, tid %u", tid);
 1252                 vap->iv_stats.is_ampdu_bar_bad++;
 1253                 return;
 1254         }
 1255         vap->iv_stats.is_ampdu_bar_rx++;
 1256         rxseq = le16toh(wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
 1257         if (rxseq == rap->rxa_start)
 1258                 return;
 1259         /* calculate offset in BA window */
 1260         off = IEEE80211_SEQ_SUB(rxseq, rap->rxa_start);
 1261         if (off < IEEE80211_SEQ_BA_RANGE) {
 1262                 /*
 1263                  * Flush the reorder q up to rxseq and move the window.
 1264                  * Sec 9.10.7.6.3 a) (p.138)
 1265                  */
 1266                 IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
 1267                     "BAR moves BA win <%u:%u> (%u frames) rxseq %u tid %u",
 1268                     rap->rxa_start,
 1269                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
 1270                     rap->rxa_qframes, rxseq, tid);
 1271                 vap->iv_stats.is_ampdu_bar_move++;
 1272 
 1273                 ampdu_rx_flush_upto(ni, rap, rxseq);
 1274                 if (off >= rap->rxa_wnd) {
 1275                         /*
 1276                          * BAR specifies a window start to the right of BA
 1277                          * window; we must move it explicitly since
 1278                          * ampdu_rx_flush_upto will not.
 1279                          */
 1280                         rap->rxa_start = rxseq;
 1281                 }
 1282         } else {
 1283                 /*
 1284                  * Out of range; toss.
 1285                  * Sec 9.10.7.6.3 b) (p.138)
 1286                  */
 1287                 IEEE80211_DISCARD_MAC(vap,
 1288                     IEEE80211_MSG_INPUT | IEEE80211_MSG_11N, ni->ni_macaddr,
 1289                     "BAR", "BA win <%u:%u> (%u frames) rxseq %u tid %u%s",
 1290                     rap->rxa_start,
 1291                     IEEE80211_SEQ_ADD(rap->rxa_start, rap->rxa_wnd-1),
 1292                     rap->rxa_qframes, rxseq, tid,
 1293                     wh->i_fc[1] & IEEE80211_FC1_RETRY ? " (retransmit)" : "");
 1294                 vap->iv_stats.is_ampdu_bar_oow++;
 1295                 IEEE80211_NODE_STAT(ni, rx_drop);
 1296         }
 1297 }
 1298 
 1299 /*
 1300  * Setup HT-specific state in a node.  Called only
 1301  * when HT use is negotiated so we don't do extra
 1302  * work for temporary and/or legacy sta's.
 1303  */
 1304 void
 1305 ieee80211_ht_node_init(struct ieee80211_node *ni)
 1306 {
 1307         struct ieee80211_tx_ampdu *tap;
 1308         int tid;
 1309 
 1310         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
 1311             ni,
 1312             "%s: called (%p)",
 1313             __func__,
 1314             ni);
 1315 
 1316         if (ni->ni_flags & IEEE80211_NODE_HT) {
 1317                 /*
 1318                  * Clean AMPDU state on re-associate.  This handles the case
 1319                  * where a station leaves w/o notifying us and then returns
 1320                  * before node is reaped for inactivity.
 1321                  */
 1322                 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
 1323                     ni,
 1324                     "%s: calling cleanup (%p)",
 1325                     __func__, ni);
 1326                 ieee80211_ht_node_cleanup(ni);
 1327         }
 1328         for (tid = 0; tid < WME_NUM_TID; tid++) {
 1329                 tap = &ni->ni_tx_ampdu[tid];
 1330                 tap->txa_tid = tid;
 1331                 tap->txa_ni = ni;
 1332                 ieee80211_txampdu_init_pps(tap);
 1333                 /* NB: further initialization deferred */
 1334                 ieee80211_ampdu_rx_init_rap(ni, &ni->ni_rx_ampdu[tid]);
 1335         }
 1336         ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU |
 1337             IEEE80211_NODE_AMSDU;
 1338 }
 1339 
 1340 /*
 1341  * Cleanup HT-specific state in a node.  Called only
 1342  * when HT use has been marked.
 1343  */
 1344 void
 1345 ieee80211_ht_node_cleanup(struct ieee80211_node *ni)
 1346 {
 1347         struct ieee80211com *ic = ni->ni_ic;
 1348         int i;
 1349 
 1350         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
 1351             ni,
 1352             "%s: called (%p)",
 1353             __func__, ni);
 1354 
 1355         KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT node"));
 1356 
 1357         /* XXX optimize this */
 1358         for (i = 0; i < WME_NUM_TID; i++) {
 1359                 struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[i];
 1360                 if (tap->txa_flags & IEEE80211_AGGR_SETUP)
 1361                         ampdu_tx_stop(tap);
 1362         }
 1363         for (i = 0; i < WME_NUM_TID; i++)
 1364                 ic->ic_ampdu_rx_stop(ni, &ni->ni_rx_ampdu[i]);
 1365 
 1366         ni->ni_htcap = 0;
 1367         ni->ni_flags &= ~IEEE80211_NODE_HT_ALL;
 1368 }
 1369 
 1370 /*
 1371  * Age out HT resources for a station.
 1372  */
 1373 void
 1374 ieee80211_ht_node_age(struct ieee80211_node *ni)
 1375 {
 1376         struct ieee80211vap *vap = ni->ni_vap;
 1377         uint8_t tid;
 1378 
 1379         KASSERT(ni->ni_flags & IEEE80211_NODE_HT, ("not an HT sta"));
 1380 
 1381         for (tid = 0; tid < WME_NUM_TID; tid++) {
 1382                 struct ieee80211_rx_ampdu *rap;
 1383 
 1384                 rap = &ni->ni_rx_ampdu[tid];
 1385                 if ((rap->rxa_flags & IEEE80211_AGGR_XCHGPEND) == 0)
 1386                         continue;
 1387                 if (rap->rxa_qframes == 0)
 1388                         continue;
 1389                 /* 
 1390                  * Check for frames sitting too long in the reorder queue.
 1391                  * See above for more details on what's happening here.
 1392                  */
 1393                 /* XXX honor batimeout? */
 1394                 if (ticks - rap->rxa_age > ieee80211_ampdu_age) {
 1395                         /*
 1396                          * Too long since we received the first
 1397                          * frame; flush the reorder buffer.
 1398                          */
 1399                         vap->iv_stats.is_ampdu_rx_age += rap->rxa_qframes;
 1400                         ampdu_rx_flush(ni, rap);
 1401                 }
 1402         }
 1403 }
 1404 
 1405 static struct ieee80211_channel *
 1406 findhtchan(struct ieee80211com *ic, struct ieee80211_channel *c, int htflags)
 1407 {
 1408         return ieee80211_find_channel(ic, c->ic_freq,
 1409             (c->ic_flags &~ IEEE80211_CHAN_HT) | htflags);
 1410 }
 1411 
 1412 /*
 1413  * Adjust a channel to be HT/non-HT according to the vap's configuration.
 1414  */
 1415 struct ieee80211_channel *
 1416 ieee80211_ht_adjust_channel(struct ieee80211com *ic,
 1417         struct ieee80211_channel *chan, int flags)
 1418 {
 1419         struct ieee80211_channel *c;
 1420 
 1421         if (flags & IEEE80211_FHT_HT) {
 1422                 /* promote to HT if possible */
 1423                 if (flags & IEEE80211_FHT_USEHT40) {
 1424                         if (!IEEE80211_IS_CHAN_HT40(chan)) {
 1425                                 /* NB: arbitrarily pick ht40+ over ht40- */
 1426                                 c = findhtchan(ic, chan, IEEE80211_CHAN_HT40U);
 1427                                 if (c == NULL)
 1428                                         c = findhtchan(ic, chan,
 1429                                                 IEEE80211_CHAN_HT40D);
 1430                                 if (c == NULL)
 1431                                         c = findhtchan(ic, chan,
 1432                                                 IEEE80211_CHAN_HT20);
 1433                                 if (c != NULL)
 1434                                         chan = c;
 1435                         }
 1436                 } else if (!IEEE80211_IS_CHAN_HT20(chan)) {
 1437                         c = findhtchan(ic, chan, IEEE80211_CHAN_HT20);
 1438                         if (c != NULL)
 1439                                 chan = c;
 1440                 }
 1441         } else if (IEEE80211_IS_CHAN_HT(chan)) {
 1442                 /* demote to legacy, HT use is disabled */
 1443                 c = ieee80211_find_channel(ic, chan->ic_freq,
 1444                     chan->ic_flags &~ IEEE80211_CHAN_HT);
 1445                 if (c != NULL)
 1446                         chan = c;
 1447         }
 1448         return chan;
 1449 }
 1450 
 1451 /*
 1452  * Setup HT-specific state for a legacy WDS peer.
 1453  */
 1454 void
 1455 ieee80211_ht_wds_init(struct ieee80211_node *ni)
 1456 {
 1457         struct ieee80211vap *vap = ni->ni_vap;
 1458         struct ieee80211_tx_ampdu *tap;
 1459         int tid;
 1460 
 1461         KASSERT(vap->iv_flags_ht & IEEE80211_FHT_HT, ("no HT requested"));
 1462 
 1463         /* XXX check scan cache in case peer has an ap and we have info */
 1464         /*
 1465          * If setup with a legacy channel; locate an HT channel.
 1466          * Otherwise if the inherited channel (from a companion
 1467          * AP) is suitable use it so we use the same location
 1468          * for the extension channel).
 1469          */
 1470         ni->ni_chan = ieee80211_ht_adjust_channel(ni->ni_ic,
 1471             ni->ni_chan, ieee80211_htchanflags(ni->ni_chan));
 1472 
 1473         ni->ni_htcap = 0;
 1474         if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20)
 1475                 ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI20;
 1476         if (IEEE80211_IS_CHAN_HT40(ni->ni_chan)) {
 1477                 ni->ni_htcap |= IEEE80211_HTCAP_CHWIDTH40;
 1478                 ni->ni_chw = 40;
 1479                 if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
 1480                         ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_ABOVE;
 1481                 else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
 1482                         ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_BELOW;
 1483                 if (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40)
 1484                         ni->ni_htcap |= IEEE80211_HTCAP_SHORTGI40;
 1485         } else {
 1486                 ni->ni_chw = 20;
 1487                 ni->ni_ht2ndchan = IEEE80211_HTINFO_2NDCHAN_NONE;
 1488         }
 1489         ni->ni_htctlchan = ni->ni_chan->ic_ieee;
 1490         if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
 1491                 ni->ni_flags |= IEEE80211_NODE_RIFS;
 1492         /* XXX does it make sense to enable SMPS? */
 1493 
 1494         ni->ni_htopmode = 0;            /* XXX need protection state */
 1495         ni->ni_htstbc = 0;              /* XXX need info */
 1496 
 1497         for (tid = 0; tid < WME_NUM_TID; tid++) {
 1498                 tap = &ni->ni_tx_ampdu[tid];
 1499                 tap->txa_tid = tid;
 1500                 ieee80211_txampdu_init_pps(tap);
 1501         }
 1502         /* NB: AMPDU tx/rx governed by IEEE80211_FHT_AMPDU_{TX,RX} */
 1503         ni->ni_flags |= IEEE80211_NODE_HT | IEEE80211_NODE_AMPDU |
 1504             IEEE80211_NODE_AMSDU;
 1505 }
 1506 
 1507 /*
 1508  * Notify a VAP of a change in the HTINFO ie if it's a hostap VAP.
 1509  *
 1510  * This is to be called from the deferred HT protection update
 1511  * task once the flags are updated.
 1512  */
 1513 void
 1514 ieee80211_htinfo_notify(struct ieee80211vap *vap)
 1515 {
 1516 
 1517         IEEE80211_LOCK_ASSERT(vap->iv_ic);
 1518 
 1519         if (vap->iv_opmode != IEEE80211_M_HOSTAP)
 1520                 return;
 1521         if (vap->iv_state != IEEE80211_S_RUN ||
 1522             !IEEE80211_IS_CHAN_HT(vap->iv_bss->ni_chan))
 1523                 return;
 1524 
 1525         IEEE80211_NOTE(vap,
 1526             IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
 1527             vap->iv_bss,
 1528             "HT bss occupancy change: %d sta, %d ht, "
 1529             "%d ht40%s, HT protmode now 0x%x"
 1530             , vap->iv_sta_assoc
 1531             , vap->iv_ht_sta_assoc
 1532             , vap->iv_ht40_sta_assoc
 1533             , (vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) ?
 1534                  ", non-HT sta present" : ""
 1535             , vap->iv_curhtprotmode);
 1536 
 1537         ieee80211_beacon_notify(vap, IEEE80211_BEACON_HTINFO);
 1538 }
 1539 
 1540 /*
 1541  * Calculate HT protection mode from current
 1542  * state and handle updates.
 1543  */
 1544 static void
 1545 htinfo_update(struct ieee80211vap *vap)
 1546 {
 1547         struct ieee80211com *ic = vap->iv_ic;
 1548         uint8_t protmode;
 1549 
 1550         if (vap->iv_sta_assoc != vap->iv_ht_sta_assoc) {
 1551                 protmode = IEEE80211_HTINFO_OPMODE_MIXED
 1552                          | IEEE80211_HTINFO_NONHT_PRESENT;
 1553         } else if (vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) {
 1554                 protmode = IEEE80211_HTINFO_OPMODE_PROTOPT
 1555                          | IEEE80211_HTINFO_NONHT_PRESENT;
 1556         } else if (ic->ic_bsschan != IEEE80211_CHAN_ANYC &&
 1557             IEEE80211_IS_CHAN_HT40(ic->ic_bsschan) && 
 1558             vap->iv_sta_assoc != vap->iv_ht40_sta_assoc) {
 1559                 protmode = IEEE80211_HTINFO_OPMODE_HT20PR;
 1560         } else {
 1561                 protmode = IEEE80211_HTINFO_OPMODE_PURE;
 1562         }
 1563         if (protmode != vap->iv_curhtprotmode) {
 1564                 vap->iv_curhtprotmode = protmode;
 1565                 /* Update VAP with new protection mode */
 1566                 ieee80211_vap_update_ht_protmode(vap);
 1567         }
 1568 }
 1569 
 1570 /*
 1571  * Handle an HT station joining a BSS.
 1572  */
 1573 void
 1574 ieee80211_ht_node_join(struct ieee80211_node *ni)
 1575 {
 1576         struct ieee80211vap *vap = ni->ni_vap;
 1577 
 1578         IEEE80211_LOCK_ASSERT(vap->iv_ic);
 1579 
 1580         if (ni->ni_flags & IEEE80211_NODE_HT) {
 1581                 vap->iv_ht_sta_assoc++;
 1582                 if (ni->ni_chw == 40)
 1583                         vap->iv_ht40_sta_assoc++;
 1584         }
 1585         htinfo_update(vap);
 1586 }
 1587 
 1588 /*
 1589  * Handle an HT station leaving a BSS.
 1590  */
 1591 void
 1592 ieee80211_ht_node_leave(struct ieee80211_node *ni)
 1593 {
 1594         struct ieee80211vap *vap = ni->ni_vap;
 1595 
 1596         IEEE80211_LOCK_ASSERT(vap->iv_ic);
 1597 
 1598         if (ni->ni_flags & IEEE80211_NODE_HT) {
 1599                 vap->iv_ht_sta_assoc--;
 1600                 if (ni->ni_chw == 40)
 1601                         vap->iv_ht40_sta_assoc--;
 1602         }
 1603         htinfo_update(vap);
 1604 }
 1605 
 1606 /*
 1607  * Public version of htinfo_update; used for processing
 1608  * beacon frames from overlapping bss.
 1609  *
 1610  * Caller can specify either IEEE80211_HTINFO_OPMODE_MIXED
 1611  * (on receipt of a beacon that advertises MIXED) or
 1612  * IEEE80211_HTINFO_OPMODE_PROTOPT (on receipt of a beacon
 1613  * from an overlapping legacy bss).  We treat MIXED with
 1614  * a higher precedence than PROTOPT (i.e. we will not change
 1615  * change PROTOPT -> MIXED; only MIXED -> PROTOPT).  This
 1616  * corresponds to how we handle things in htinfo_update.
 1617  *
 1618  */
 1619 void
 1620 ieee80211_htprot_update(struct ieee80211vap *vap, int protmode)
 1621 {
 1622         struct ieee80211com *ic = vap->iv_ic;
 1623 #define OPMODE(x)       _IEEE80211_SHIFTMASK(x, IEEE80211_HTINFO_OPMODE)
 1624         IEEE80211_LOCK(ic);
 1625 
 1626         /* track non-HT station presence */
 1627         KASSERT(protmode & IEEE80211_HTINFO_NONHT_PRESENT,
 1628             ("protmode 0x%x", protmode));
 1629         vap->iv_flags_ht |= IEEE80211_FHT_NONHT_PR;
 1630         vap->iv_lastnonht = ticks;
 1631 
 1632         if (protmode != vap->iv_curhtprotmode &&
 1633             (OPMODE(vap->iv_curhtprotmode) != IEEE80211_HTINFO_OPMODE_MIXED ||
 1634              OPMODE(protmode) == IEEE80211_HTINFO_OPMODE_PROTOPT)) {
 1635                 vap->iv_curhtprotmode = protmode;
 1636                 /* Update VAP with new protection mode */
 1637                 ieee80211_vap_update_ht_protmode(vap);
 1638         }
 1639         IEEE80211_UNLOCK(ic);
 1640 #undef OPMODE
 1641 }
 1642 
 1643 /*
 1644  * Time out presence of an overlapping bss with non-HT
 1645  * stations.  When operating in hostap mode we listen for
 1646  * beacons from other stations and if we identify a non-HT
 1647  * station is present we update the opmode field of the
 1648  * HTINFO ie.  To identify when all non-HT stations are
 1649  * gone we time out this condition.
 1650  */
 1651 void
 1652 ieee80211_ht_timeout(struct ieee80211vap *vap)
 1653 {
 1654 
 1655         IEEE80211_LOCK_ASSERT(vap->iv_ic);
 1656 
 1657         if ((vap->iv_flags_ht & IEEE80211_FHT_NONHT_PR) &&
 1658             ieee80211_time_after(ticks, vap->iv_lastnonht + IEEE80211_NONHT_PRESENT_AGE)) {
 1659                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
 1660                     "%s", "time out non-HT STA present on channel");
 1661                 vap->iv_flags_ht &= ~IEEE80211_FHT_NONHT_PR;
 1662                 htinfo_update(vap);
 1663         }
 1664 }
 1665 
 1666 /*
 1667  * Process an 802.11n HT capabilities ie.
 1668  */
 1669 void
 1670 ieee80211_parse_htcap(struct ieee80211_node *ni, const uint8_t *ie)
 1671 {
 1672         if (ie[0] == IEEE80211_ELEMID_VENDOR) {
 1673                 /*
 1674                  * Station used Vendor OUI ie to associate;
 1675                  * mark the node so when we respond we'll use
 1676                  * the Vendor OUI's and not the standard ie's.
 1677                  */
 1678                 ni->ni_flags |= IEEE80211_NODE_HTCOMPAT;
 1679                 ie += 4;
 1680         } else
 1681                 ni->ni_flags &= ~IEEE80211_NODE_HTCOMPAT;
 1682 
 1683         ni->ni_htcap = le16dec(ie +
 1684                 __offsetof(struct ieee80211_ie_htcap, hc_cap));
 1685         ni->ni_htparam = ie[__offsetof(struct ieee80211_ie_htcap, hc_param)];
 1686 }
 1687 
 1688 static void
 1689 htinfo_parse(struct ieee80211_node *ni,
 1690         const struct ieee80211_ie_htinfo *htinfo)
 1691 {
 1692         uint16_t w;
 1693 
 1694         ni->ni_htctlchan = htinfo->hi_ctrlchannel;
 1695         ni->ni_ht2ndchan = _IEEE80211_SHIFTMASK(htinfo->hi_byte1,
 1696             IEEE80211_HTINFO_2NDCHAN);
 1697         w = le16dec(&htinfo->hi_byte2);
 1698         ni->ni_htopmode = _IEEE80211_SHIFTMASK(w, IEEE80211_HTINFO_OPMODE);
 1699         w = le16dec(&htinfo->hi_byte45);
 1700         ni->ni_htstbc = _IEEE80211_SHIFTMASK(w, IEEE80211_HTINFO_BASIC_STBCMCS);
 1701 }
 1702 
 1703 /*
 1704  * Parse an 802.11n HT info ie and save useful information
 1705  * to the node state.  Note this does not effect any state
 1706  * changes such as for channel width change.
 1707  */
 1708 void
 1709 ieee80211_parse_htinfo(struct ieee80211_node *ni, const uint8_t *ie)
 1710 {
 1711         if (ie[0] == IEEE80211_ELEMID_VENDOR)
 1712                 ie += 4;
 1713         htinfo_parse(ni, (const struct ieee80211_ie_htinfo *) ie);
 1714 }
 1715 
 1716 /*
 1717  * Handle 11n/11ac channel switch.
 1718  *
 1719  * Use the received HT/VHT ie's to identify the right channel to use.
 1720  * If we cannot locate it in the channel table then fallback to
 1721  * legacy operation.
 1722  *
 1723  * Note that we use this information to identify the node's
 1724  * channel only; the caller is responsible for insuring any
 1725  * required channel change is done (e.g. in sta mode when
 1726  * parsing the contents of a beacon frame).
 1727  */
 1728 static int
 1729 htinfo_update_chw(struct ieee80211_node *ni, int htflags, int vhtflags)
 1730 {
 1731         struct ieee80211com *ic = ni->ni_ic;
 1732         struct ieee80211_channel *c;
 1733         int chanflags;
 1734         int ret = 0;
 1735 
 1736         /*
 1737          * First step - do HT/VHT only channel lookup based on operating mode
 1738          * flags.  This involves masking out the VHT flags as well.
 1739          * Otherwise we end up doing the full channel walk each time
 1740          * we trigger this, which is expensive.
 1741          */
 1742         chanflags = (ni->ni_chan->ic_flags &~
 1743             (IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT)) | htflags | vhtflags;
 1744 
 1745         if (chanflags == ni->ni_chan->ic_flags)
 1746                 goto done;
 1747 
 1748         /*
 1749          * If HT /or/ VHT flags have changed then check both.
 1750          * We need to start by picking a HT channel anyway.
 1751          */
 1752 
 1753         c = NULL;
 1754         chanflags = (ni->ni_chan->ic_flags &~
 1755             (IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT)) | htflags;
 1756         /* XXX not right for ht40- */
 1757         c = ieee80211_find_channel(ic, ni->ni_chan->ic_freq, chanflags);
 1758         if (c == NULL && (htflags & IEEE80211_CHAN_HT40)) {
 1759                 /*
 1760                  * No HT40 channel entry in our table; fall back
 1761                  * to HT20 operation.  This should not happen.
 1762                  */
 1763                 c = findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT20);
 1764 #if 0
 1765                 IEEE80211_NOTE(ni->ni_vap,
 1766                     IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
 1767                     "no HT40 channel (freq %u), falling back to HT20",
 1768                     ni->ni_chan->ic_freq);
 1769 #endif
 1770                 /* XXX stat */
 1771         }
 1772 
 1773         /* Nothing found - leave it alone; move onto VHT */
 1774         if (c == NULL)
 1775                 c = ni->ni_chan;
 1776 
 1777         /*
 1778          * If it's non-HT, then bail out now.
 1779          */
 1780         if (! IEEE80211_IS_CHAN_HT(c)) {
 1781                 IEEE80211_NOTE(ni->ni_vap,
 1782                     IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
 1783                     "not HT; skipping VHT check (%u/0x%x)",
 1784                     c->ic_freq, c->ic_flags);
 1785                 goto done;
 1786         }
 1787 
 1788         /*
 1789          * Next step - look at the current VHT flags and determine
 1790          * if we need to upgrade.  Mask out the VHT and HT flags since
 1791          * the vhtflags field will already have the correct HT
 1792          * flags to use.
 1793          */
 1794         if (IEEE80211_CONF_VHT(ic) && ni->ni_vhtcap != 0 && vhtflags != 0) {
 1795                 chanflags = (c->ic_flags
 1796                     &~ (IEEE80211_CHAN_HT | IEEE80211_CHAN_VHT))
 1797                     | vhtflags;
 1798                 IEEE80211_NOTE(ni->ni_vap,
 1799                     IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
 1800                     ni,
 1801                     "%s: VHT; chanwidth=0x%02x; vhtflags=0x%08x",
 1802                     __func__, ni->ni_vht_chanwidth, vhtflags);
 1803 
 1804                 IEEE80211_NOTE(ni->ni_vap,
 1805                     IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N,
 1806                     ni,
 1807                     "%s: VHT; trying lookup for %d/0x%08x",
 1808                     __func__, c->ic_freq, chanflags);
 1809                 c = ieee80211_find_channel(ic, c->ic_freq, chanflags);
 1810         }
 1811 
 1812         /* Finally, if it's changed */
 1813         if (c != NULL && c != ni->ni_chan) {
 1814                 IEEE80211_NOTE(ni->ni_vap,
 1815                     IEEE80211_MSG_ASSOC | IEEE80211_MSG_11N, ni,
 1816                     "switch station to %s%d channel %u/0x%x",
 1817                     IEEE80211_IS_CHAN_VHT(c) ? "VHT" : "HT",
 1818                     IEEE80211_IS_CHAN_VHT80(c) ? 80 :
 1819                       (IEEE80211_IS_CHAN_HT40(c) ? 40 : 20),
 1820                     c->ic_freq, c->ic_flags);
 1821                 ni->ni_chan = c;
 1822                 ret = 1;
 1823         }
 1824         /* NB: caller responsible for forcing any channel change */
 1825 
 1826 done:
 1827         /* update node's (11n) tx channel width */
 1828         ni->ni_chw = IEEE80211_IS_CHAN_HT40(ni->ni_chan)? 40 : 20;
 1829         return (ret);
 1830 }
 1831 
 1832 /*
 1833  * Update 11n MIMO PS state according to received htcap.
 1834  */
 1835 static __inline int
 1836 htcap_update_mimo_ps(struct ieee80211_node *ni)
 1837 {
 1838         uint16_t oflags = ni->ni_flags;
 1839 
 1840         switch (ni->ni_htcap & IEEE80211_HTCAP_SMPS) {
 1841         case IEEE80211_HTCAP_SMPS_DYNAMIC:
 1842                 ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
 1843                 ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
 1844                 break;
 1845         case IEEE80211_HTCAP_SMPS_ENA:
 1846                 ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
 1847                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
 1848                 break;
 1849         case IEEE80211_HTCAP_SMPS_OFF:
 1850         default:                /* disable on rx of reserved value */
 1851                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
 1852                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
 1853                 break;
 1854         }
 1855         return (oflags ^ ni->ni_flags);
 1856 }
 1857 
 1858 /*
 1859  * Update short GI state according to received htcap
 1860  * and local settings.
 1861  */
 1862 static __inline void
 1863 htcap_update_shortgi(struct ieee80211_node *ni)
 1864 {
 1865         struct ieee80211vap *vap = ni->ni_vap;
 1866 
 1867         ni->ni_flags &= ~(IEEE80211_NODE_SGI20|IEEE80211_NODE_SGI40);
 1868         if ((ni->ni_htcap & IEEE80211_HTCAP_SHORTGI20) &&
 1869             (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20))
 1870                 ni->ni_flags |= IEEE80211_NODE_SGI20;
 1871         if ((ni->ni_htcap & IEEE80211_HTCAP_SHORTGI40) &&
 1872             (vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40))
 1873                 ni->ni_flags |= IEEE80211_NODE_SGI40;
 1874 }
 1875 
 1876 /*
 1877  * Update LDPC state according to received htcap
 1878  * and local settings.
 1879  */
 1880 static __inline void
 1881 htcap_update_ldpc(struct ieee80211_node *ni)
 1882 {
 1883         struct ieee80211vap *vap = ni->ni_vap;
 1884 
 1885         if ((ni->ni_htcap & IEEE80211_HTCAP_LDPC) &&
 1886             (vap->iv_flags_ht & IEEE80211_FHT_LDPC_TX))
 1887                 ni->ni_flags |= IEEE80211_NODE_LDPC;
 1888 }
 1889 
 1890 /*
 1891  * Parse and update HT-related state extracted from
 1892  * the HT cap and info ie's.
 1893  *
 1894  * This is called from the STA management path and
 1895  * the ieee80211_node_join() path.  It will take into
 1896  * account the IEs discovered during scanning and
 1897  * adjust things accordingly.
 1898  */
 1899 void
 1900 ieee80211_ht_updateparams(struct ieee80211_node *ni,
 1901         const uint8_t *htcapie, const uint8_t *htinfoie)
 1902 {
 1903         struct ieee80211vap *vap = ni->ni_vap;
 1904         const struct ieee80211_ie_htinfo *htinfo;
 1905 
 1906         ieee80211_parse_htcap(ni, htcapie);
 1907         if (vap->iv_htcaps & IEEE80211_HTC_SMPS)
 1908                 htcap_update_mimo_ps(ni);
 1909         htcap_update_shortgi(ni);
 1910         htcap_update_ldpc(ni);
 1911 
 1912         if (htinfoie[0] == IEEE80211_ELEMID_VENDOR)
 1913                 htinfoie += 4;
 1914         htinfo = (const struct ieee80211_ie_htinfo *) htinfoie;
 1915         htinfo_parse(ni, htinfo);
 1916 
 1917         /*
 1918          * Defer the node channel change; we need to now
 1919          * update VHT parameters before we do it.
 1920          */
 1921 
 1922         if ((htinfo->hi_byte1 & IEEE80211_HTINFO_RIFSMODE_PERM) &&
 1923             (vap->iv_flags_ht & IEEE80211_FHT_RIFS))
 1924                 ni->ni_flags |= IEEE80211_NODE_RIFS;
 1925         else
 1926                 ni->ni_flags &= ~IEEE80211_NODE_RIFS;
 1927 }
 1928 
 1929 static uint32_t
 1930 ieee80211_vht_get_vhtflags(struct ieee80211_node *ni, uint32_t htflags)
 1931 {
 1932         struct ieee80211vap *vap = ni->ni_vap;
 1933         uint32_t vhtflags = 0;
 1934 
 1935         vhtflags = 0;
 1936         if (ni->ni_flags & IEEE80211_NODE_VHT && vap->iv_flags_vht & IEEE80211_FVHT_VHT) {
 1937                 if ((ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_160MHZ) &&
 1938                     /* XXX 2 means "160MHz and 80+80MHz", 1 means "160MHz" */
 1939                     (_IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
 1940                      IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) >= 1) &&
 1941                     (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT160)) {
 1942                         vhtflags = IEEE80211_CHAN_VHT160;
 1943                         /* Mirror the HT40 flags */
 1944                         if (htflags == IEEE80211_CHAN_HT40U) {
 1945                                 vhtflags |= IEEE80211_CHAN_HT40U;
 1946                         } else if (htflags == IEEE80211_CHAN_HT40D) {
 1947                                 vhtflags |= IEEE80211_CHAN_HT40D;
 1948                         }
 1949                 } else if ((ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_80P80MHZ) &&
 1950                     /* XXX 2 means "160MHz and 80+80MHz" */
 1951                     (_IEEE80211_MASKSHIFT(vap->iv_vhtcaps,
 1952                      IEEE80211_VHTCAP_SUPP_CHAN_WIDTH_MASK) == 2) &&
 1953                     (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT80P80)) {
 1954                         vhtflags = IEEE80211_CHAN_VHT80P80;
 1955                         /* Mirror the HT40 flags */
 1956                         if (htflags == IEEE80211_CHAN_HT40U) {
 1957                                 vhtflags |= IEEE80211_CHAN_HT40U;
 1958                         } else if (htflags == IEEE80211_CHAN_HT40D) {
 1959                                 vhtflags |= IEEE80211_CHAN_HT40D;
 1960                         }
 1961                 } else if ((ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_80MHZ) &&
 1962                     (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT80)) {
 1963                         vhtflags = IEEE80211_CHAN_VHT80;
 1964                         /* Mirror the HT40 flags */
 1965                         if (htflags == IEEE80211_CHAN_HT40U) {
 1966                                 vhtflags |= IEEE80211_CHAN_HT40U;
 1967                         } else if (htflags == IEEE80211_CHAN_HT40D) {
 1968                                 vhtflags |= IEEE80211_CHAN_HT40D;
 1969                         }
 1970                 } else if (ni->ni_vht_chanwidth == IEEE80211_VHT_CHANWIDTH_USE_HT) {
 1971                         /* Mirror the HT40 flags */
 1972                         /*
 1973                          * XXX TODO: if ht40 is disabled, but vht40 isn't
 1974                          * disabled then this logic will get very, very sad.
 1975                          * It's quite possible the only sane thing to do is
 1976                          * to not have vht40 as an option, and just obey
 1977                          * 'ht40' as that flag.
 1978                          */
 1979                         if ((htflags == IEEE80211_CHAN_HT40U) &&
 1980                             (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT40)) {
 1981                                 vhtflags = IEEE80211_CHAN_VHT40U
 1982                                     | IEEE80211_CHAN_HT40U;
 1983                         } else if (htflags == IEEE80211_CHAN_HT40D &&
 1984                             (vap->iv_flags_vht & IEEE80211_FVHT_USEVHT40)) {
 1985                                 vhtflags = IEEE80211_CHAN_VHT40D
 1986                                     | IEEE80211_CHAN_HT40D;
 1987                         } else if (htflags == IEEE80211_CHAN_HT20) {
 1988                                 vhtflags = IEEE80211_CHAN_VHT20
 1989                                     | IEEE80211_CHAN_HT20;
 1990                         }
 1991                 } else {
 1992                         vhtflags = IEEE80211_CHAN_VHT20;
 1993                 }
 1994         }
 1995         return (vhtflags);
 1996 }
 1997 
 1998 /*
 1999  * Final part of updating the HT parameters.
 2000  *
 2001  * This is called from the STA management path and
 2002  * the ieee80211_node_join() path.  It will take into
 2003  * account the IEs discovered during scanning and
 2004  * adjust things accordingly.
 2005  *
 2006  * This is done after a call to ieee80211_ht_updateparams()
 2007  * because it (and the upcoming VHT version of updateparams)
 2008  * needs to ensure everything is parsed before htinfo_update_chw()
 2009  * is called - which will change the channel config for the
 2010  * node for us.
 2011  */
 2012 int
 2013 ieee80211_ht_updateparams_final(struct ieee80211_node *ni,
 2014         const uint8_t *htcapie, const uint8_t *htinfoie)
 2015 {
 2016         struct ieee80211vap *vap = ni->ni_vap;
 2017         const struct ieee80211_ie_htinfo *htinfo;
 2018         int htflags, vhtflags;
 2019         int ret = 0;
 2020 
 2021         htinfo = (const struct ieee80211_ie_htinfo *) htinfoie;
 2022 
 2023         htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ?
 2024             IEEE80211_CHAN_HT20 : 0;
 2025 
 2026         /* NB: honor operating mode constraint */
 2027         if ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH_2040) &&
 2028             (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)) {
 2029                 if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_ABOVE)
 2030                         htflags = IEEE80211_CHAN_HT40U;
 2031                 else if (ni->ni_ht2ndchan == IEEE80211_HTINFO_2NDCHAN_BELOW)
 2032                         htflags = IEEE80211_CHAN_HT40D;
 2033         }
 2034 
 2035         /*
 2036          * VHT flags - do much the same; check whether VHT is available
 2037          * and if so, what our ideal channel use would be based on our
 2038          * capabilities and the (pre-parsed) VHT info IE.
 2039          */
 2040         vhtflags = ieee80211_vht_get_vhtflags(ni, htflags);
 2041 
 2042         if (htinfo_update_chw(ni, htflags, vhtflags))
 2043                 ret = 1;
 2044 
 2045         return (ret);
 2046 }
 2047 
 2048 /*
 2049  * Parse and update HT-related state extracted from the HT cap ie
 2050  * for a station joining an HT BSS.
 2051  *
 2052  * This is called from the hostap path for each station.
 2053  */
 2054 void
 2055 ieee80211_ht_updatehtcap(struct ieee80211_node *ni, const uint8_t *htcapie)
 2056 {
 2057         struct ieee80211vap *vap = ni->ni_vap;
 2058 
 2059         ieee80211_parse_htcap(ni, htcapie);
 2060         if (vap->iv_htcaps & IEEE80211_HTC_SMPS)
 2061                 htcap_update_mimo_ps(ni);
 2062         htcap_update_shortgi(ni);
 2063         htcap_update_ldpc(ni);
 2064 }
 2065 
 2066 /*
 2067  * Called once HT and VHT capabilities are parsed in hostap mode -
 2068  * this will adjust the channel configuration of the given node
 2069  * based on the configuration and capabilities.
 2070  */
 2071 void
 2072 ieee80211_ht_updatehtcap_final(struct ieee80211_node *ni)
 2073 {
 2074         struct ieee80211vap *vap = ni->ni_vap;
 2075         int htflags;
 2076         int vhtflags;
 2077 
 2078         /* NB: honor operating mode constraint */
 2079         /* XXX 40 MHz intolerant */
 2080         htflags = (vap->iv_flags_ht & IEEE80211_FHT_HT) ?
 2081             IEEE80211_CHAN_HT20 : 0;
 2082         if ((ni->ni_htcap & IEEE80211_HTCAP_CHWIDTH40) &&
 2083             (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)) {
 2084                 if (IEEE80211_IS_CHAN_HT40U(vap->iv_bss->ni_chan))
 2085                         htflags = IEEE80211_CHAN_HT40U;
 2086                 else if (IEEE80211_IS_CHAN_HT40D(vap->iv_bss->ni_chan))
 2087                         htflags = IEEE80211_CHAN_HT40D;
 2088         }
 2089         /*
 2090          * VHT flags - do much the same; check whether VHT is available
 2091          * and if so, what our ideal channel use would be based on our
 2092          * capabilities and the (pre-parsed) VHT info IE.
 2093          */
 2094         vhtflags = ieee80211_vht_get_vhtflags(ni, htflags);
 2095 
 2096         (void) htinfo_update_chw(ni, htflags, vhtflags);
 2097 }
 2098 
 2099 /*
 2100  * Install received HT rate set by parsing the HT cap ie.
 2101  */
 2102 int
 2103 ieee80211_setup_htrates(struct ieee80211_node *ni, const uint8_t *ie, int flags)
 2104 {
 2105         struct ieee80211com *ic = ni->ni_ic;
 2106         struct ieee80211vap *vap = ni->ni_vap;
 2107         const struct ieee80211_ie_htcap *htcap;
 2108         struct ieee80211_htrateset *rs;
 2109         int i, maxequalmcs, maxunequalmcs;
 2110 
 2111         maxequalmcs = ic->ic_txstream * 8 - 1;
 2112         maxunequalmcs = 0;
 2113         if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) {
 2114                 if (ic->ic_txstream >= 2)
 2115                         maxunequalmcs = 38;
 2116                 if (ic->ic_txstream >= 3)
 2117                         maxunequalmcs = 52;
 2118                 if (ic->ic_txstream >= 4)
 2119                         maxunequalmcs = 76;
 2120         }
 2121 
 2122         rs = &ni->ni_htrates;
 2123         memset(rs, 0, sizeof(*rs));
 2124         if (ie != NULL) {
 2125                 if (ie[0] == IEEE80211_ELEMID_VENDOR)
 2126                         ie += 4;
 2127                 htcap = (const struct ieee80211_ie_htcap *) ie;
 2128                 for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
 2129                         if (isclr(htcap->hc_mcsset, i))
 2130                                 continue;
 2131                         if (rs->rs_nrates == IEEE80211_HTRATE_MAXSIZE) {
 2132                                 IEEE80211_NOTE(vap,
 2133                                     IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
 2134                                     "WARNING, HT rate set too large; only "
 2135                                     "using %u rates", IEEE80211_HTRATE_MAXSIZE);
 2136                                 vap->iv_stats.is_rx_rstoobig++;
 2137                                 break;
 2138                         }
 2139                         if (i <= 31 && i > maxequalmcs)
 2140                                 continue;
 2141                         if (i == 32 &&
 2142                             (ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0)
 2143                                 continue;
 2144                         if (i > 32 && i > maxunequalmcs)
 2145                                 continue;
 2146                         rs->rs_rates[rs->rs_nrates++] = i;
 2147                 }
 2148         }
 2149         return ieee80211_fix_rate(ni, (struct ieee80211_rateset *) rs, flags);
 2150 }
 2151 
 2152 /*
 2153  * Mark rates in a node's HT rate set as basic according
 2154  * to the information in the supplied HT info ie.
 2155  */
 2156 void
 2157 ieee80211_setup_basic_htrates(struct ieee80211_node *ni, const uint8_t *ie)
 2158 {
 2159         const struct ieee80211_ie_htinfo *htinfo;
 2160         struct ieee80211_htrateset *rs;
 2161         int i, j;
 2162 
 2163         if (ie[0] == IEEE80211_ELEMID_VENDOR)
 2164                 ie += 4;
 2165         htinfo = (const struct ieee80211_ie_htinfo *) ie;
 2166         rs = &ni->ni_htrates;
 2167         if (rs->rs_nrates == 0) {
 2168                 IEEE80211_NOTE(ni->ni_vap,
 2169                     IEEE80211_MSG_XRATE | IEEE80211_MSG_11N, ni,
 2170                     "%s", "WARNING, empty HT rate set");
 2171                 return;
 2172         }
 2173         for (i = 0; i < IEEE80211_HTRATE_MAXSIZE; i++) {
 2174                 if (isclr(htinfo->hi_basicmcsset, i))
 2175                         continue;
 2176                 for (j = 0; j < rs->rs_nrates; j++)
 2177                         if ((rs->rs_rates[j] & IEEE80211_RATE_VAL) == i)
 2178                                 rs->rs_rates[j] |= IEEE80211_RATE_BASIC;
 2179         }
 2180 }
 2181 
 2182 static void
 2183 ampdu_tx_setup(struct ieee80211_tx_ampdu *tap)
 2184 {
 2185         callout_init(&tap->txa_timer, 1);
 2186         tap->txa_flags |= IEEE80211_AGGR_SETUP;
 2187         tap->txa_lastsample = ticks;
 2188 }
 2189 
 2190 static void
 2191 ampdu_tx_stop(struct ieee80211_tx_ampdu *tap)
 2192 {
 2193         struct ieee80211_node *ni = tap->txa_ni;
 2194         struct ieee80211com *ic = ni->ni_ic;
 2195 
 2196         IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
 2197             tap->txa_ni,
 2198             "%s: called",
 2199             __func__);
 2200 
 2201         KASSERT(tap->txa_flags & IEEE80211_AGGR_SETUP,
 2202             ("txa_flags 0x%x tid %d ac %d", tap->txa_flags, tap->txa_tid,
 2203             TID_TO_WME_AC(tap->txa_tid)));
 2204 
 2205         /*
 2206          * Stop BA stream if setup so driver has a chance
 2207          * to reclaim any resources it might have allocated.
 2208          */
 2209         ic->ic_addba_stop(ni, tap);
 2210         /*
 2211          * Stop any pending BAR transmit.
 2212          */
 2213         bar_stop_timer(tap);
 2214 
 2215         /*
 2216          * Reset packet estimate.
 2217          */
 2218         ieee80211_txampdu_init_pps(tap);
 2219 
 2220         /* NB: clearing NAK means we may re-send ADDBA */ 
 2221         tap->txa_flags &= ~(IEEE80211_AGGR_SETUP | IEEE80211_AGGR_NAK);
 2222 }
 2223 
 2224 /*
 2225  * ADDBA response timeout.
 2226  *
 2227  * If software aggregation and per-TID queue management was done here,
 2228  * that queue would be unpaused after the ADDBA timeout occurs.
 2229  */
 2230 static void
 2231 addba_timeout(void *arg)
 2232 {
 2233         struct ieee80211_tx_ampdu *tap = arg;
 2234         struct ieee80211_node *ni = tap->txa_ni;
 2235         struct ieee80211com *ic = ni->ni_ic;
 2236 
 2237         /* XXX ? */
 2238         tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
 2239         tap->txa_attempts++;
 2240         ic->ic_addba_response_timeout(ni, tap);
 2241 }
 2242 
 2243 static void
 2244 addba_start_timeout(struct ieee80211_tx_ampdu *tap)
 2245 {
 2246         /* XXX use CALLOUT_PENDING instead? */
 2247         callout_reset(&tap->txa_timer, ieee80211_addba_timeout,
 2248             addba_timeout, tap);
 2249         tap->txa_flags |= IEEE80211_AGGR_XCHGPEND;
 2250         tap->txa_nextrequest = ticks + ieee80211_addba_timeout;
 2251 }
 2252 
 2253 static void
 2254 addba_stop_timeout(struct ieee80211_tx_ampdu *tap)
 2255 {
 2256         /* XXX use CALLOUT_PENDING instead? */
 2257         if (tap->txa_flags & IEEE80211_AGGR_XCHGPEND) {
 2258                 callout_stop(&tap->txa_timer);
 2259                 tap->txa_flags &= ~IEEE80211_AGGR_XCHGPEND;
 2260         }
 2261 }
 2262 
 2263 static void
 2264 null_addba_response_timeout(struct ieee80211_node *ni,
 2265     struct ieee80211_tx_ampdu *tap)
 2266 {
 2267 }
 2268 
 2269 /*
 2270  * Default method for requesting A-MPDU tx aggregation.
 2271  * We setup the specified state block and start a timer
 2272  * to wait for an ADDBA response frame.
 2273  */
 2274 static int
 2275 ieee80211_addba_request(struct ieee80211_node *ni,
 2276         struct ieee80211_tx_ampdu *tap,
 2277         int dialogtoken, int baparamset, int batimeout)
 2278 {
 2279         int bufsiz;
 2280 
 2281         /* XXX locking */
 2282         tap->txa_token = dialogtoken;
 2283         tap->txa_flags |= IEEE80211_AGGR_IMMEDIATE;
 2284         bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
 2285         tap->txa_wnd = (bufsiz == 0) ?
 2286             IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
 2287         addba_start_timeout(tap);
 2288         return 1;
 2289 }
 2290 
 2291 /*
 2292  * Called by drivers that wish to request an ADDBA session be
 2293  * setup.  This brings it up and starts the request timer.
 2294  */
 2295 int
 2296 ieee80211_ampdu_tx_request_ext(struct ieee80211_node *ni, int tid)
 2297 {
 2298         struct ieee80211_tx_ampdu *tap;
 2299 
 2300         if (tid < 0 || tid > 15)
 2301                 return (0);
 2302         tap = &ni->ni_tx_ampdu[tid];
 2303 
 2304         /* XXX locking */
 2305         if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
 2306                 /* do deferred setup of state */
 2307                 ampdu_tx_setup(tap);
 2308         }
 2309         /* XXX hack for not doing proper locking */
 2310         tap->txa_flags &= ~IEEE80211_AGGR_NAK;
 2311         addba_start_timeout(tap);
 2312         return (1);
 2313 }
 2314 
 2315 /*
 2316  * Called by drivers that have marked a session as active.
 2317  */
 2318 int
 2319 ieee80211_ampdu_tx_request_active_ext(struct ieee80211_node *ni, int tid,
 2320     int status)
 2321 {
 2322         struct ieee80211_tx_ampdu *tap;
 2323 
 2324         if (tid < 0 || tid > 15)
 2325                 return (0);
 2326         tap = &ni->ni_tx_ampdu[tid];
 2327 
 2328         /* XXX locking */
 2329         addba_stop_timeout(tap);
 2330         if (status == 1) {
 2331                 tap->txa_flags |= IEEE80211_AGGR_RUNNING;
 2332                 tap->txa_attempts = 0;
 2333         } else {
 2334                 /* mark tid so we don't try again */
 2335                 tap->txa_flags |= IEEE80211_AGGR_NAK;
 2336         }
 2337         return (1);
 2338 }
 2339 
 2340 /*
 2341  * Default method for processing an A-MPDU tx aggregation
 2342  * response.  We shutdown any pending timer and update the
 2343  * state block according to the reply.
 2344  */
 2345 static int
 2346 ieee80211_addba_response(struct ieee80211_node *ni,
 2347         struct ieee80211_tx_ampdu *tap,
 2348         int status, int baparamset, int batimeout)
 2349 {
 2350         struct ieee80211vap *vap = ni->ni_vap;
 2351         int bufsiz, tid;
 2352 
 2353         /* XXX locking */
 2354         addba_stop_timeout(tap);
 2355         if (status == IEEE80211_STATUS_SUCCESS) {
 2356                 bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
 2357                 /* XXX override our request? */
 2358                 tap->txa_wnd = (bufsiz == 0) ?
 2359                     IEEE80211_AGGR_BAWMAX : min(bufsiz, IEEE80211_AGGR_BAWMAX);
 2360                 tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
 2361                 tap->txa_flags |= IEEE80211_AGGR_RUNNING;
 2362                 tap->txa_attempts = 0;
 2363                 /* TODO: this should be a vap flag */
 2364                 if ((vap->iv_htcaps & IEEE80211_HTC_TX_AMSDU_AMPDU) &&
 2365                     (ni->ni_flags & IEEE80211_NODE_AMSDU_TX) &&
 2366                     (_IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU)))
 2367                         tap->txa_flags |= IEEE80211_AGGR_AMSDU;
 2368                 else
 2369                         tap->txa_flags &= ~IEEE80211_AGGR_AMSDU;
 2370         } else {
 2371                 /* mark tid so we don't try again */
 2372                 tap->txa_flags |= IEEE80211_AGGR_NAK;
 2373         }
 2374         return 1;
 2375 }
 2376 
 2377 /*
 2378  * Default method for stopping A-MPDU tx aggregation.
 2379  * Any timer is cleared and we drain any pending frames.
 2380  */
 2381 static void
 2382 ieee80211_addba_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap)
 2383 {
 2384         /* XXX locking */
 2385         addba_stop_timeout(tap);
 2386         if (tap->txa_flags & IEEE80211_AGGR_RUNNING) {
 2387                 /* XXX clear aggregation queue */
 2388                 tap->txa_flags &= ~(IEEE80211_AGGR_RUNNING | IEEE80211_AGGR_AMSDU);
 2389         }
 2390         tap->txa_attempts = 0;
 2391 }
 2392 
 2393 /*
 2394  * Process a received action frame using the default aggregation
 2395  * policy.  We intercept ADDBA-related frames and use them to
 2396  * update our aggregation state.  All other frames are passed up
 2397  * for processing by ieee80211_recv_action.
 2398  */
 2399 static int
 2400 ht_recv_action_ba_addba_request(struct ieee80211_node *ni,
 2401         const struct ieee80211_frame *wh,
 2402         const uint8_t *frm, const uint8_t *efrm)
 2403 {
 2404         struct ieee80211com *ic = ni->ni_ic;
 2405         struct ieee80211vap *vap = ni->ni_vap;
 2406         struct ieee80211_rx_ampdu *rap;
 2407         uint8_t dialogtoken;
 2408         uint16_t baparamset, batimeout, baseqctl;
 2409         uint16_t args[5];
 2410         int tid;
 2411 
 2412         dialogtoken = frm[2];
 2413         baparamset = le16dec(frm+3);
 2414         batimeout = le16dec(frm+5);
 2415         baseqctl = le16dec(frm+7);
 2416 
 2417         tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
 2418 
 2419         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 2420             "recv ADDBA request: dialogtoken %u baparamset 0x%x "
 2421             "(tid %d bufsiz %d) batimeout %d baseqctl %d:%d amsdu %d",
 2422             dialogtoken, baparamset,
 2423             tid, _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ),
 2424             batimeout,
 2425             _IEEE80211_MASKSHIFT(baseqctl, IEEE80211_BASEQ_START),
 2426             _IEEE80211_MASKSHIFT(baseqctl, IEEE80211_BASEQ_FRAG),
 2427             _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU));
 2428 
 2429         rap = &ni->ni_rx_ampdu[tid];
 2430 
 2431         /* Send ADDBA response */
 2432         args[0] = dialogtoken;
 2433         /*
 2434          * NB: We ack only if the sta associated with HT and
 2435          * the ap is configured to do AMPDU rx (the latter
 2436          * violates the 11n spec and is mostly for testing).
 2437          */
 2438         if ((ni->ni_flags & IEEE80211_NODE_AMPDU_RX) &&
 2439             (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_RX)) {
 2440                 /* XXX TODO: handle ampdu_rx_start failure */
 2441                 ic->ic_ampdu_rx_start(ni, rap,
 2442                     baparamset, batimeout, baseqctl);
 2443 
 2444                 args[1] = IEEE80211_STATUS_SUCCESS;
 2445         } else {
 2446                 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
 2447                     ni, "reject ADDBA request: %s",
 2448                     ni->ni_flags & IEEE80211_NODE_AMPDU_RX ?
 2449                        "administratively disabled" :
 2450                        "not negotiated for station");
 2451                 vap->iv_stats.is_addba_reject++;
 2452                 args[1] = IEEE80211_STATUS_UNSPECIFIED;
 2453         }
 2454         /* XXX honor rap flags? */
 2455         args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
 2456                 | _IEEE80211_SHIFTMASK(tid, IEEE80211_BAPS_TID)
 2457                 | _IEEE80211_SHIFTMASK(rap->rxa_wnd, IEEE80211_BAPS_BUFSIZ)
 2458                 ;
 2459 
 2460         /*
 2461          * TODO: we're out of iv_flags_ht fields; once
 2462          * this is extended we should make this configurable.
 2463          */
 2464         if ((baparamset & IEEE80211_BAPS_AMSDU) &&
 2465             (ni->ni_flags & IEEE80211_NODE_AMSDU_RX) &&
 2466             (vap->iv_htcaps & IEEE80211_HTC_RX_AMSDU_AMPDU))
 2467                 args[2] |= IEEE80211_BAPS_AMSDU;
 2468 
 2469         args[3] = 0;
 2470         args[4] = 0;
 2471         ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
 2472                 IEEE80211_ACTION_BA_ADDBA_RESPONSE, args);
 2473         return 0;
 2474 }
 2475 
 2476 static int
 2477 ht_recv_action_ba_addba_response(struct ieee80211_node *ni,
 2478         const struct ieee80211_frame *wh,
 2479         const uint8_t *frm, const uint8_t *efrm)
 2480 {
 2481         struct ieee80211com *ic = ni->ni_ic;
 2482         struct ieee80211vap *vap = ni->ni_vap;
 2483         struct ieee80211_tx_ampdu *tap;
 2484         uint8_t dialogtoken, policy;
 2485         uint16_t baparamset, batimeout, code;
 2486         int tid, bufsiz;
 2487         int amsdu;
 2488 
 2489         dialogtoken = frm[2];
 2490         code = le16dec(frm+3);
 2491         baparamset = le16dec(frm+5);
 2492         tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_TID);
 2493         bufsiz = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_BUFSIZ);
 2494         policy = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_POLICY);
 2495         amsdu = !! _IEEE80211_MASKSHIFT(baparamset, IEEE80211_BAPS_AMSDU);
 2496         batimeout = le16dec(frm+7);
 2497 
 2498         tap = &ni->ni_tx_ampdu[tid];
 2499         if ((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0) {
 2500                 IEEE80211_DISCARD_MAC(vap,
 2501                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
 2502                     ni->ni_macaddr, "ADDBA response",
 2503                     "no pending ADDBA, tid %d dialogtoken %u "
 2504                     "code %d", tid, dialogtoken, code);
 2505                 vap->iv_stats.is_addba_norequest++;
 2506                 return 0;
 2507         }
 2508         if (dialogtoken != tap->txa_token) {
 2509                 IEEE80211_DISCARD_MAC(vap,
 2510                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
 2511                     ni->ni_macaddr, "ADDBA response",
 2512                     "dialogtoken mismatch: waiting for %d, "
 2513                     "received %d, tid %d code %d",
 2514                     tap->txa_token, dialogtoken, tid, code);
 2515                 vap->iv_stats.is_addba_badtoken++;
 2516                 return 0;
 2517         }
 2518         /* NB: assumes IEEE80211_AGGR_IMMEDIATE is 1 */
 2519         if (policy != (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE)) {
 2520                 IEEE80211_DISCARD_MAC(vap,
 2521                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
 2522                     ni->ni_macaddr, "ADDBA response",
 2523                     "policy mismatch: expecting %s, "
 2524                     "received %s, tid %d code %d",
 2525                     tap->txa_flags & IEEE80211_AGGR_IMMEDIATE,
 2526                     policy, tid, code);
 2527                 vap->iv_stats.is_addba_badpolicy++;
 2528                 return 0;
 2529         }
 2530 #if 0
 2531         /* XXX we take MIN in ieee80211_addba_response */
 2532         if (bufsiz > IEEE80211_AGGR_BAWMAX) {
 2533                 IEEE80211_DISCARD_MAC(vap,
 2534                     IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
 2535                     ni->ni_macaddr, "ADDBA response",
 2536                     "BA window too large: max %d, "
 2537                     "received %d, tid %d code %d",
 2538                     bufsiz, IEEE80211_AGGR_BAWMAX, tid, code);
 2539                 vap->iv_stats.is_addba_badbawinsize++;
 2540                 return 0;
 2541         }
 2542 #endif
 2543 
 2544         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 2545             "recv ADDBA response: dialogtoken %u code %d "
 2546             "baparamset 0x%x (tid %d bufsiz %d amsdu %d) batimeout %d",
 2547             dialogtoken, code, baparamset, tid,
 2548             bufsiz,
 2549             amsdu,
 2550             batimeout);
 2551         ic->ic_addba_response(ni, tap, code, baparamset, batimeout);
 2552         return 0;
 2553 }
 2554 
 2555 static int
 2556 ht_recv_action_ba_delba(struct ieee80211_node *ni,
 2557         const struct ieee80211_frame *wh,
 2558         const uint8_t *frm, const uint8_t *efrm)
 2559 {
 2560         struct ieee80211com *ic = ni->ni_ic;
 2561         struct ieee80211_rx_ampdu *rap;
 2562         struct ieee80211_tx_ampdu *tap;
 2563         uint16_t baparamset, code;
 2564         int tid;
 2565 
 2566         baparamset = le16dec(frm+2);
 2567         code = le16dec(frm+4);
 2568 
 2569         tid = _IEEE80211_MASKSHIFT(baparamset, IEEE80211_DELBAPS_TID);
 2570 
 2571         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 2572             "recv DELBA: baparamset 0x%x (tid %d initiator %d) "
 2573             "code %d", baparamset, tid,
 2574             _IEEE80211_MASKSHIFT(baparamset, IEEE80211_DELBAPS_INIT), code);
 2575 
 2576         if ((baparamset & IEEE80211_DELBAPS_INIT) == 0) {
 2577                 tap = &ni->ni_tx_ampdu[tid];
 2578                 ic->ic_addba_stop(ni, tap);
 2579         } else {
 2580                 rap = &ni->ni_rx_ampdu[tid];
 2581                 ic->ic_ampdu_rx_stop(ni, rap);
 2582         }
 2583         return 0;
 2584 }
 2585 
 2586 static int
 2587 ht_recv_action_ht_txchwidth(struct ieee80211_node *ni,
 2588         const struct ieee80211_frame *wh,
 2589         const uint8_t *frm, const uint8_t *efrm)
 2590 {
 2591         int chw;
 2592 
 2593         chw = (frm[2] == IEEE80211_A_HT_TXCHWIDTH_2040) ? 40 : 20;
 2594 
 2595         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 2596             "%s: HT txchwidth, width %d%s",
 2597             __func__, chw, ni->ni_chw != chw ? "*" : "");
 2598         if (chw != ni->ni_chw) {
 2599                 /* XXX does this need to change the ht40 station count? */
 2600                 ni->ni_chw = chw;
 2601                 /* XXX notify on change */
 2602         }
 2603         return 0;
 2604 }
 2605 
 2606 static int
 2607 ht_recv_action_ht_mimopwrsave(struct ieee80211_node *ni,
 2608         const struct ieee80211_frame *wh,
 2609         const uint8_t *frm, const uint8_t *efrm)
 2610 {
 2611         const struct ieee80211_action_ht_mimopowersave *mps =
 2612             (const struct ieee80211_action_ht_mimopowersave *) frm;
 2613 
 2614         /* XXX check iv_htcaps */
 2615         if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_ENA)
 2616                 ni->ni_flags |= IEEE80211_NODE_MIMO_PS;
 2617         else
 2618                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_PS;
 2619         if (mps->am_control & IEEE80211_A_HT_MIMOPWRSAVE_MODE)
 2620                 ni->ni_flags |= IEEE80211_NODE_MIMO_RTS;
 2621         else
 2622                 ni->ni_flags &= ~IEEE80211_NODE_MIMO_RTS;
 2623         /* XXX notify on change */
 2624         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 2625             "%s: HT MIMO PS (%s%s)", __func__,
 2626             (ni->ni_flags & IEEE80211_NODE_MIMO_PS) ?  "on" : "off",
 2627             (ni->ni_flags & IEEE80211_NODE_MIMO_RTS) ?  "+rts" : ""
 2628         );
 2629         return 0;
 2630 }
 2631 
 2632 /*
 2633  * Transmit processing.
 2634  */
 2635 
 2636 /*
 2637  * Check if A-MPDU should be requested/enabled for a stream.
 2638  * We require a traffic rate above a per-AC threshold and we
 2639  * also handle backoff from previous failed attempts.
 2640  *
 2641  * Drivers may override this method to bring in information
 2642  * such as link state conditions in making the decision.
 2643  */
 2644 static int
 2645 ieee80211_ampdu_enable(struct ieee80211_node *ni,
 2646         struct ieee80211_tx_ampdu *tap)
 2647 {
 2648         struct ieee80211vap *vap = ni->ni_vap;
 2649 
 2650         if (tap->txa_avgpps <
 2651             vap->iv_ampdu_mintraffic[TID_TO_WME_AC(tap->txa_tid)])
 2652                 return 0;
 2653         /* XXX check rssi? */
 2654         if (tap->txa_attempts >= ieee80211_addba_maxtries &&
 2655             ieee80211_time_after(ticks, tap->txa_nextrequest)) {
 2656                 /*
 2657                  * Don't retry too often; txa_nextrequest is set
 2658                  * to the minimum interval we'll retry after
 2659                  * ieee80211_addba_maxtries failed attempts are made.
 2660                  */
 2661                 return 0;
 2662         }
 2663         IEEE80211_NOTE(vap, IEEE80211_MSG_11N, ni,
 2664             "enable AMPDU on tid %d (%s), avgpps %d pkts %d attempt %d",
 2665             tap->txa_tid, ieee80211_wme_acnames[TID_TO_WME_AC(tap->txa_tid)],
 2666             tap->txa_avgpps, tap->txa_pkts, tap->txa_attempts);
 2667         return 1;
 2668 }
 2669 
 2670 /*
 2671  * Request A-MPDU tx aggregation.  Setup local state and
 2672  * issue an ADDBA request.  BA use will only happen after
 2673  * the other end replies with ADDBA response.
 2674  */
 2675 int
 2676 ieee80211_ampdu_request(struct ieee80211_node *ni,
 2677         struct ieee80211_tx_ampdu *tap)
 2678 {
 2679         struct ieee80211com *ic = ni->ni_ic;
 2680         uint16_t args[5];
 2681         int tid, dialogtoken;
 2682         static int tokens = 0;  /* XXX */
 2683 
 2684         /* XXX locking */
 2685         if ((tap->txa_flags & IEEE80211_AGGR_SETUP) == 0) {
 2686                 /* do deferred setup of state */
 2687                 ampdu_tx_setup(tap);
 2688         }
 2689         /* XXX hack for not doing proper locking */
 2690         tap->txa_flags &= ~IEEE80211_AGGR_NAK;
 2691 
 2692         dialogtoken = (tokens+1) % 63;          /* XXX */
 2693         tid = tap->txa_tid;
 2694 
 2695         /*
 2696          * XXX TODO: This is racy with any other parallel TX going on. :(
 2697          */
 2698         tap->txa_start = ni->ni_txseqs[tid];
 2699 
 2700         args[0] = dialogtoken;
 2701         args[1] = 0;    /* NB: status code not used */
 2702         args[2] = IEEE80211_BAPS_POLICY_IMMEDIATE
 2703                 | _IEEE80211_SHIFTMASK(tid, IEEE80211_BAPS_TID)
 2704                 | _IEEE80211_SHIFTMASK(IEEE80211_AGGR_BAWMAX,
 2705                     IEEE80211_BAPS_BUFSIZ)
 2706                 ;
 2707 
 2708         /* XXX TODO: this should be a flag, not iv_htcaps */
 2709         if ((ni->ni_flags & IEEE80211_NODE_AMSDU_TX) &&
 2710             (ni->ni_vap->iv_htcaps & IEEE80211_HTC_TX_AMSDU_AMPDU))
 2711                 args[2] |= IEEE80211_BAPS_AMSDU;
 2712 
 2713         args[3] = 0;    /* batimeout */
 2714         /* NB: do first so there's no race against reply */
 2715         if (!ic->ic_addba_request(ni, tap, dialogtoken, args[2], args[3])) {
 2716                 /* unable to setup state, don't make request */
 2717                 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
 2718                     ni, "%s: could not setup BA stream for TID %d AC %d",
 2719                     __func__, tap->txa_tid, TID_TO_WME_AC(tap->txa_tid));
 2720                 /* defer next try so we don't slam the driver with requests */
 2721                 tap->txa_attempts = ieee80211_addba_maxtries;
 2722                 /* NB: check in case driver wants to override */
 2723                 if (tap->txa_nextrequest <= ticks)
 2724                         tap->txa_nextrequest = ticks + ieee80211_addba_backoff;
 2725                 return 0;
 2726         }
 2727         tokens = dialogtoken;                   /* allocate token */
 2728         /* NB: after calling ic_addba_request so driver can set txa_start */
 2729         args[4] = _IEEE80211_SHIFTMASK(tap->txa_start, IEEE80211_BASEQ_START)
 2730                 | _IEEE80211_SHIFTMASK(0, IEEE80211_BASEQ_FRAG)
 2731                 ;
 2732         return ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
 2733                 IEEE80211_ACTION_BA_ADDBA_REQUEST, args);
 2734 }
 2735 
 2736 /*
 2737  * Terminate an AMPDU tx stream.  State is reclaimed
 2738  * and the peer notified with a DelBA Action frame.
 2739  */
 2740 void
 2741 ieee80211_ampdu_stop(struct ieee80211_node *ni, struct ieee80211_tx_ampdu *tap,
 2742         int reason)
 2743 {
 2744         struct ieee80211com *ic = ni->ni_ic;
 2745         struct ieee80211vap *vap = ni->ni_vap;
 2746         uint16_t args[4];
 2747 
 2748         /* XXX locking */
 2749         tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
 2750         if (IEEE80211_AMPDU_RUNNING(tap)) {
 2751                 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
 2752                     ni, "%s: stop BA stream for TID %d (reason: %d (%s))",
 2753                     __func__, tap->txa_tid, reason,
 2754                     ieee80211_reason_to_string(reason));
 2755                 vap->iv_stats.is_ampdu_stop++;
 2756 
 2757                 ic->ic_addba_stop(ni, tap);
 2758                 args[0] = tap->txa_tid;
 2759                 args[1] = IEEE80211_DELBAPS_INIT;
 2760                 args[2] = reason;                       /* XXX reason code */
 2761                 ic->ic_send_action(ni, IEEE80211_ACTION_CAT_BA,
 2762                         IEEE80211_ACTION_BA_DELBA, args);
 2763         } else {
 2764                 IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N,
 2765                     ni, "%s: BA stream for TID %d not running "
 2766                     "(reason: %d (%s))", __func__, tap->txa_tid, reason,
 2767                     ieee80211_reason_to_string(reason));
 2768                 vap->iv_stats.is_ampdu_stop_failed++;
 2769         }
 2770 }
 2771 
 2772 /* XXX */
 2773 static void bar_start_timer(struct ieee80211_tx_ampdu *tap);
 2774 
 2775 static void
 2776 bar_timeout(void *arg)
 2777 {
 2778         struct ieee80211_tx_ampdu *tap = arg;
 2779         struct ieee80211_node *ni = tap->txa_ni;
 2780 
 2781         KASSERT((tap->txa_flags & IEEE80211_AGGR_XCHGPEND) == 0,
 2782             ("bar/addba collision, flags 0x%x", tap->txa_flags));
 2783 
 2784         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
 2785             ni, "%s: tid %u flags 0x%x attempts %d", __func__,
 2786             tap->txa_tid, tap->txa_flags, tap->txa_attempts);
 2787 
 2788         /* guard against race with bar_tx_complete */
 2789         if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
 2790                 return;
 2791         /* XXX ? */
 2792         if (tap->txa_attempts >= ieee80211_bar_maxtries) {
 2793                 struct ieee80211com *ic = ni->ni_ic;
 2794 
 2795                 ni->ni_vap->iv_stats.is_ampdu_bar_tx_fail++;
 2796                 /*
 2797                  * If (at least) the last BAR TX timeout was due to
 2798                  * an ieee80211_send_bar() failures, then we need
 2799                  * to make sure we notify the driver that a BAR
 2800                  * TX did occur and fail.  This gives the driver
 2801                  * a chance to undo any queue pause that may
 2802                  * have occurred.
 2803                  */
 2804                 ic->ic_bar_response(ni, tap, 1);
 2805                 ieee80211_ampdu_stop(ni, tap, IEEE80211_REASON_TIMEOUT);
 2806         } else {
 2807                 ni->ni_vap->iv_stats.is_ampdu_bar_tx_retry++;
 2808                 if (ieee80211_send_bar(ni, tap, tap->txa_seqpending) != 0) {
 2809                         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
 2810                             ni, "%s: failed to TX, starting timer\n",
 2811                             __func__);
 2812                         /*
 2813                          * If ieee80211_send_bar() fails here, the
 2814                          * timer may have stopped and/or the pending
 2815                          * flag may be clear.  Because of this,
 2816                          * fake the BARPEND and reset the timer.
 2817                          * A retransmission attempt will then occur
 2818                          * during the next timeout.
 2819                          */
 2820                         /* XXX locking */
 2821                         tap->txa_flags |= IEEE80211_AGGR_BARPEND;
 2822                         bar_start_timer(tap);
 2823                 }
 2824         }
 2825 }
 2826 
 2827 static void
 2828 bar_start_timer(struct ieee80211_tx_ampdu *tap)
 2829 {
 2830         IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
 2831             tap->txa_ni,
 2832             "%s: called",
 2833             __func__);
 2834         callout_reset(&tap->txa_timer, ieee80211_bar_timeout, bar_timeout, tap);
 2835 }
 2836 
 2837 static void
 2838 bar_stop_timer(struct ieee80211_tx_ampdu *tap)
 2839 {
 2840         IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
 2841             tap->txa_ni,
 2842             "%s: called",
 2843             __func__);
 2844         callout_stop(&tap->txa_timer);
 2845 }
 2846 
 2847 static void
 2848 bar_tx_complete(struct ieee80211_node *ni, void *arg, int status)
 2849 {
 2850         struct ieee80211_tx_ampdu *tap = arg;
 2851 
 2852         IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
 2853             ni, "%s: tid %u flags 0x%x pending %d status %d",
 2854             __func__, tap->txa_tid, tap->txa_flags,
 2855             callout_pending(&tap->txa_timer), status);
 2856 
 2857         ni->ni_vap->iv_stats.is_ampdu_bar_tx++;
 2858         /* XXX locking */
 2859         if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) &&
 2860             callout_pending(&tap->txa_timer)) {
 2861                 struct ieee80211com *ic = ni->ni_ic;
 2862 
 2863                 if (status == 0)                /* ACK'd */
 2864                         bar_stop_timer(tap);
 2865                 ic->ic_bar_response(ni, tap, status);
 2866                 /* NB: just let timer expire so we pace requests */
 2867         }
 2868 }
 2869 
 2870 static void
 2871 ieee80211_bar_response(struct ieee80211_node *ni,
 2872         struct ieee80211_tx_ampdu *tap, int status)
 2873 {
 2874 
 2875         IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
 2876             tap->txa_ni,
 2877             "%s: called",
 2878             __func__);
 2879         if (status == 0) {              /* got ACK */
 2880                 IEEE80211_NOTE(ni->ni_vap, IEEE80211_MSG_11N,
 2881                     ni, "BAR moves BA win <%u:%u> (%u frames) txseq %u tid %u",
 2882                     tap->txa_start,
 2883                     IEEE80211_SEQ_ADD(tap->txa_start, tap->txa_wnd-1),
 2884                     tap->txa_qframes, tap->txa_seqpending,
 2885                     tap->txa_tid);
 2886 
 2887                 /* NB: timer already stopped in bar_tx_complete */
 2888                 tap->txa_start = tap->txa_seqpending;
 2889                 tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
 2890         }
 2891 }
 2892 
 2893 /*
 2894  * Transmit a BAR frame to the specified node.  The
 2895  * BAR contents are drawn from the supplied aggregation
 2896  * state associated with the node.
 2897  *
 2898  * NB: we only handle immediate ACK w/ compressed bitmap.
 2899  */
 2900 int
 2901 ieee80211_send_bar(struct ieee80211_node *ni,
 2902         struct ieee80211_tx_ampdu *tap, ieee80211_seq seq)
 2903 {
 2904 #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0)
 2905         struct ieee80211vap *vap = ni->ni_vap;
 2906         struct ieee80211com *ic = ni->ni_ic;
 2907         struct ieee80211_frame_bar *bar;
 2908         struct mbuf *m;
 2909         uint16_t barctl, barseqctl;
 2910         uint8_t *frm;
 2911         int tid, ret;
 2912 
 2913 
 2914         IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
 2915             tap->txa_ni,
 2916             "%s: called",
 2917             __func__);
 2918 
 2919         if ((tap->txa_flags & IEEE80211_AGGR_RUNNING) == 0) {
 2920                 /* no ADDBA response, should not happen */
 2921                 /* XXX stat+msg */
 2922                 return EINVAL;
 2923         }
 2924         /* XXX locking */
 2925         bar_stop_timer(tap);
 2926 
 2927         ieee80211_ref_node(ni);
 2928 
 2929         m = ieee80211_getmgtframe(&frm, ic->ic_headroom, sizeof(*bar));
 2930         if (m == NULL)
 2931                 senderr(ENOMEM, is_tx_nobuf);
 2932 
 2933         if (!ieee80211_add_callback(m, bar_tx_complete, tap)) {
 2934                 m_freem(m);
 2935                 senderr(ENOMEM, is_tx_nobuf);   /* XXX */
 2936                 /* NOTREACHED */
 2937         }
 2938 
 2939         bar = mtod(m, struct ieee80211_frame_bar *);
 2940         bar->i_fc[0] = IEEE80211_FC0_VERSION_0 |
 2941                 IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_BAR;
 2942         bar->i_fc[1] = 0;
 2943         IEEE80211_ADDR_COPY(bar->i_ra, ni->ni_macaddr);
 2944         IEEE80211_ADDR_COPY(bar->i_ta, vap->iv_myaddr);
 2945 
 2946         tid = tap->txa_tid;
 2947         barctl  = (tap->txa_flags & IEEE80211_AGGR_IMMEDIATE ?
 2948                         0 : IEEE80211_BAR_NOACK)
 2949                 | IEEE80211_BAR_COMP
 2950                 | _IEEE80211_SHIFTMASK(tid, IEEE80211_BAR_TID)
 2951                 ;
 2952         barseqctl = _IEEE80211_SHIFTMASK(seq, IEEE80211_BAR_SEQ_START);
 2953         /* NB: known to have proper alignment */
 2954         bar->i_ctl = htole16(barctl);
 2955         bar->i_seq = htole16(barseqctl);
 2956         m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_bar);
 2957 
 2958         M_WME_SETAC(m, WME_AC_VO);
 2959 
 2960         IEEE80211_NODE_STAT(ni, tx_mgmt);       /* XXX tx_ctl? */
 2961 
 2962         /* XXX locking */
 2963         /* init/bump attempts counter */
 2964         if ((tap->txa_flags & IEEE80211_AGGR_BARPEND) == 0)
 2965                 tap->txa_attempts = 1;
 2966         else
 2967                 tap->txa_attempts++;
 2968         tap->txa_seqpending = seq;
 2969         tap->txa_flags |= IEEE80211_AGGR_BARPEND;
 2970 
 2971         IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
 2972             ni, "send BAR: tid %u ctl 0x%x start %u (attempt %d)",
 2973             tid, barctl, seq, tap->txa_attempts);
 2974 
 2975         /*
 2976          * ic_raw_xmit will free the node reference
 2977          * regardless of queue/TX success or failure.
 2978          */
 2979         IEEE80211_TX_LOCK(ic);
 2980         ret = ieee80211_raw_output(vap, ni, m, NULL);
 2981         IEEE80211_TX_UNLOCK(ic);
 2982         if (ret != 0) {
 2983                 IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_11N,
 2984                     ni, "send BAR: failed: (ret = %d)\n",
 2985                     ret);
 2986                 /* xmit failed, clear state flag */
 2987                 tap->txa_flags &= ~IEEE80211_AGGR_BARPEND;
 2988                 vap->iv_stats.is_ampdu_bar_tx_fail++;
 2989                 return ret;
 2990         }
 2991         /* XXX hack against tx complete happening before timer is started */
 2992         if (tap->txa_flags & IEEE80211_AGGR_BARPEND)
 2993                 bar_start_timer(tap);
 2994         return 0;
 2995 bad:
 2996         IEEE80211_NOTE(tap->txa_ni->ni_vap, IEEE80211_MSG_11N,
 2997             tap->txa_ni,
 2998             "%s: bad! ret=%d",
 2999             __func__, ret);
 3000         vap->iv_stats.is_ampdu_bar_tx_fail++;
 3001         ieee80211_free_node(ni);
 3002         return ret;
 3003 #undef senderr
 3004 }
 3005 
 3006 static int
 3007 ht_action_output(struct ieee80211_node *ni, struct mbuf *m)
 3008 {
 3009         struct ieee80211_bpf_params params;
 3010 
 3011         memset(&params, 0, sizeof(params));
 3012         params.ibp_pri = WME_AC_VO;
 3013         params.ibp_rate0 = ni->ni_txparms->mgmtrate;
 3014         /* NB: we know all frames are unicast */
 3015         params.ibp_try0 = ni->ni_txparms->maxretry;
 3016         params.ibp_power = ni->ni_txpower;
 3017         return ieee80211_mgmt_output(ni, m, IEEE80211_FC0_SUBTYPE_ACTION,
 3018              &params);
 3019 }
 3020 
 3021 #define ADDSHORT(frm, v) do {                   \
 3022         frm[0] = (v) & 0xff;                    \
 3023         frm[1] = (v) >> 8;                      \
 3024         frm += 2;                               \
 3025 } while (0)
 3026 
 3027 /*
 3028  * Send an action management frame.  The arguments are stuff
 3029  * into a frame without inspection; the caller is assumed to
 3030  * prepare them carefully (e.g. based on the aggregation state).
 3031  */
 3032 static int
 3033 ht_send_action_ba_addba(struct ieee80211_node *ni,
 3034         int category, int action, void *arg0)
 3035 {
 3036         struct ieee80211vap *vap = ni->ni_vap;
 3037         struct ieee80211com *ic = ni->ni_ic;
 3038         uint16_t *args = arg0;
 3039         struct mbuf *m;
 3040         uint8_t *frm;
 3041 
 3042         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 3043             "send ADDBA %s: dialogtoken %d status %d "
 3044             "baparamset 0x%x (tid %d amsdu %d) batimeout 0x%x baseqctl 0x%x",
 3045             (action == IEEE80211_ACTION_BA_ADDBA_REQUEST) ?
 3046                 "request" : "response", args[0], args[1], args[2],
 3047             _IEEE80211_MASKSHIFT(args[2], IEEE80211_BAPS_TID),
 3048             _IEEE80211_MASKSHIFT(args[2], IEEE80211_BAPS_AMSDU),
 3049             args[3], args[4]);
 3050 
 3051         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
 3052             "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
 3053             ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
 3054         ieee80211_ref_node(ni);
 3055 
 3056         m = ieee80211_getmgtframe(&frm,
 3057             ic->ic_headroom + sizeof(struct ieee80211_frame),
 3058             sizeof(uint16_t)    /* action+category */
 3059             /* XXX may action payload */
 3060             + sizeof(struct ieee80211_action_ba_addbaresponse)
 3061         );
 3062         if (m != NULL) {
 3063                 *frm++ = category;
 3064                 *frm++ = action;
 3065                 *frm++ = args[0];               /* dialog token */
 3066                 if (action == IEEE80211_ACTION_BA_ADDBA_RESPONSE)
 3067                         ADDSHORT(frm, args[1]); /* status code */
 3068                 ADDSHORT(frm, args[2]);         /* baparamset */
 3069                 ADDSHORT(frm, args[3]);         /* batimeout */
 3070                 if (action == IEEE80211_ACTION_BA_ADDBA_REQUEST)
 3071                         ADDSHORT(frm, args[4]); /* baseqctl */
 3072                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
 3073                 return ht_action_output(ni, m);
 3074         } else {
 3075                 vap->iv_stats.is_tx_nobuf++;
 3076                 ieee80211_free_node(ni);
 3077                 return ENOMEM;
 3078         }
 3079 }
 3080 
 3081 static int
 3082 ht_send_action_ba_delba(struct ieee80211_node *ni,
 3083         int category, int action, void *arg0)
 3084 {
 3085         struct ieee80211vap *vap = ni->ni_vap;
 3086         struct ieee80211com *ic = ni->ni_ic;
 3087         uint16_t *args = arg0;
 3088         struct mbuf *m;
 3089         uint16_t baparamset;
 3090         uint8_t *frm;
 3091 
 3092         baparamset = _IEEE80211_SHIFTMASK(args[0], IEEE80211_DELBAPS_TID)
 3093                    | args[1]
 3094                    ;
 3095         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 3096             "send DELBA action: tid %d, initiator %d reason %d (%s)",
 3097             args[0], args[1], args[2], ieee80211_reason_to_string(args[2]));
 3098 
 3099         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
 3100             "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
 3101             ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
 3102         ieee80211_ref_node(ni);
 3103 
 3104         m = ieee80211_getmgtframe(&frm,
 3105             ic->ic_headroom + sizeof(struct ieee80211_frame),
 3106             sizeof(uint16_t)    /* action+category */
 3107             /* XXX may action payload */
 3108             + sizeof(struct ieee80211_action_ba_addbaresponse)
 3109         );
 3110         if (m != NULL) {
 3111                 *frm++ = category;
 3112                 *frm++ = action;
 3113                 ADDSHORT(frm, baparamset);
 3114                 ADDSHORT(frm, args[2]);         /* reason code */
 3115                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
 3116                 return ht_action_output(ni, m);
 3117         } else {
 3118                 vap->iv_stats.is_tx_nobuf++;
 3119                 ieee80211_free_node(ni);
 3120                 return ENOMEM;
 3121         }
 3122 }
 3123 
 3124 static int
 3125 ht_send_action_ht_txchwidth(struct ieee80211_node *ni,
 3126         int category, int action, void *arg0)
 3127 {
 3128         struct ieee80211vap *vap = ni->ni_vap;
 3129         struct ieee80211com *ic = ni->ni_ic;
 3130         struct mbuf *m;
 3131         uint8_t *frm;
 3132 
 3133         IEEE80211_NOTE(vap, IEEE80211_MSG_ACTION | IEEE80211_MSG_11N, ni,
 3134             "send HT txchwidth: width %d",
 3135             IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 40 : 20);
 3136 
 3137         IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE,
 3138             "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", __func__, __LINE__,
 3139             ni, ether_sprintf(ni->ni_macaddr), ieee80211_node_refcnt(ni)+1);
 3140         ieee80211_ref_node(ni);
 3141 
 3142         m = ieee80211_getmgtframe(&frm,
 3143             ic->ic_headroom + sizeof(struct ieee80211_frame),
 3144             sizeof(uint16_t)    /* action+category */
 3145             /* XXX may action payload */
 3146             + sizeof(struct ieee80211_action_ba_addbaresponse)
 3147         );
 3148         if (m != NULL) {
 3149                 *frm++ = category;
 3150                 *frm++ = action;
 3151                 *frm++ = IEEE80211_IS_CHAN_HT40(ni->ni_chan) ? 
 3152                         IEEE80211_A_HT_TXCHWIDTH_2040 :
 3153                         IEEE80211_A_HT_TXCHWIDTH_20;
 3154                 m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *);
 3155                 return ht_action_output(ni, m);
 3156         } else {
 3157                 vap->iv_stats.is_tx_nobuf++;
 3158                 ieee80211_free_node(ni);
 3159                 return ENOMEM;
 3160         }
 3161 }
 3162 #undef ADDSHORT
 3163 
 3164 /*
 3165  * Construct the MCS bit mask for inclusion in an HT capabilities
 3166  * information element.
 3167  */
 3168 static void
 3169 ieee80211_set_mcsset(struct ieee80211com *ic, uint8_t *frm)
 3170 {
 3171         int i;
 3172         uint8_t txparams;
 3173 
 3174         KASSERT((ic->ic_rxstream > 0 && ic->ic_rxstream <= 4),
 3175             ("ic_rxstream %d out of range", ic->ic_rxstream));
 3176         KASSERT((ic->ic_txstream > 0 && ic->ic_txstream <= 4),
 3177             ("ic_txstream %d out of range", ic->ic_txstream));
 3178 
 3179         for (i = 0; i < ic->ic_rxstream * 8; i++)
 3180                 setbit(frm, i);
 3181         if ((ic->ic_htcaps & IEEE80211_HTCAP_CHWIDTH40) &&
 3182             (ic->ic_htcaps & IEEE80211_HTC_RXMCS32))
 3183                 setbit(frm, 32);
 3184         if (ic->ic_htcaps & IEEE80211_HTC_RXUNEQUAL) {
 3185                 if (ic->ic_rxstream >= 2) {
 3186                         for (i = 33; i <= 38; i++)
 3187                                 setbit(frm, i);
 3188                 }
 3189                 if (ic->ic_rxstream >= 3) {
 3190                         for (i = 39; i <= 52; i++)
 3191                                 setbit(frm, i);
 3192                 }
 3193                 if (ic->ic_txstream >= 4) {
 3194                         for (i = 53; i <= 76; i++)
 3195                                 setbit(frm, i);
 3196                 }
 3197         }
 3198 
 3199         if (ic->ic_rxstream != ic->ic_txstream) {
 3200                 txparams = 0x1;                 /* TX MCS set defined */
 3201                 txparams |= 0x2;                /* TX RX MCS not equal */
 3202                 txparams |= (ic->ic_txstream - 1) << 2; /* num TX streams */
 3203                 if (ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL)
 3204                         txparams |= 0x16;       /* TX unequal modulation sup */
 3205         } else
 3206                 txparams = 0;
 3207         frm[12] = txparams;
 3208 }
 3209 
 3210 /*
 3211  * Add body of an HTCAP information element.
 3212  */
 3213 static uint8_t *
 3214 ieee80211_add_htcap_body(uint8_t *frm, struct ieee80211_node *ni)
 3215 {
 3216 #define ADDSHORT(frm, v) do {                   \
 3217         frm[0] = (v) & 0xff;                    \
 3218         frm[1] = (v) >> 8;                      \
 3219         frm += 2;                               \
 3220 } while (0)
 3221         struct ieee80211com *ic = ni->ni_ic;
 3222         struct ieee80211vap *vap = ni->ni_vap;
 3223         uint16_t caps, extcaps;
 3224         int rxmax, density;
 3225 
 3226         /* HT capabilities */
 3227         caps = vap->iv_htcaps & 0xffff;
 3228         /*
 3229          * Note channel width depends on whether we are operating as
 3230          * a sta or not.  When operating as a sta we are generating
 3231          * a request based on our desired configuration.  Otherwise
 3232          * we are operational and the channel attributes identify
 3233          * how we've been setup (which might be different if a fixed
 3234          * channel is specified).
 3235          */
 3236         if (vap->iv_opmode == IEEE80211_M_STA) {
 3237                 /* override 20/40 use based on config */
 3238                 if (vap->iv_flags_ht & IEEE80211_FHT_USEHT40)
 3239                         caps |= IEEE80211_HTCAP_CHWIDTH40;
 3240                 else
 3241                         caps &= ~IEEE80211_HTCAP_CHWIDTH40;
 3242 
 3243                 /* Start by using the advertised settings */
 3244                 rxmax = _IEEE80211_MASKSHIFT(ni->ni_htparam,
 3245                     IEEE80211_HTCAP_MAXRXAMPDU);
 3246                 density = _IEEE80211_MASKSHIFT(ni->ni_htparam,
 3247                     IEEE80211_HTCAP_MPDUDENSITY);
 3248 
 3249                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_11N,
 3250                     "%s: advertised rxmax=%d, density=%d, vap rxmax=%d, density=%d\n",
 3251                     __func__,
 3252                     rxmax,
 3253                     density,
 3254                     vap->iv_ampdu_rxmax,
 3255                     vap->iv_ampdu_density);
 3256 
 3257                 /* Cap at VAP rxmax */
 3258                 if (rxmax > vap->iv_ampdu_rxmax)
 3259                         rxmax = vap->iv_ampdu_rxmax;
 3260 
 3261                 /*
 3262                  * If the VAP ampdu density value greater, use that.
 3263                  *
 3264                  * (Larger density value == larger minimum gap between A-MPDU
 3265                  * subframes.)
 3266                  */
 3267                 if (vap->iv_ampdu_density > density)
 3268                         density = vap->iv_ampdu_density;
 3269 
 3270                 /*
 3271                  * NB: Hardware might support HT40 on some but not all
 3272                  * channels. We can't determine this earlier because only
 3273                  * after association the channel is upgraded to HT based
 3274                  * on the negotiated capabilities.
 3275                  */
 3276                 if (ni->ni_chan != IEEE80211_CHAN_ANYC &&
 3277                     findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40U) == NULL &&
 3278                     findhtchan(ic, ni->ni_chan, IEEE80211_CHAN_HT40D) == NULL)
 3279                         caps &= ~IEEE80211_HTCAP_CHWIDTH40;
 3280         } else {
 3281                 /* override 20/40 use based on current channel */
 3282                 if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
 3283                         caps |= IEEE80211_HTCAP_CHWIDTH40;
 3284                 else
 3285                         caps &= ~IEEE80211_HTCAP_CHWIDTH40;
 3286 
 3287                 /* XXX TODO should it start by using advertised settings? */
 3288                 rxmax = vap->iv_ampdu_rxmax;
 3289                 density = vap->iv_ampdu_density;
 3290         }
 3291 
 3292         /* adjust short GI based on channel and config */
 3293         if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
 3294                 caps &= ~IEEE80211_HTCAP_SHORTGI20;
 3295         if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) == 0 ||
 3296             (caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
 3297                 caps &= ~IEEE80211_HTCAP_SHORTGI40;
 3298 
 3299         /* adjust STBC based on receive capabilities */
 3300         if ((vap->iv_flags_ht & IEEE80211_FHT_STBC_RX) == 0)
 3301                 caps &= ~IEEE80211_HTCAP_RXSTBC;
 3302 
 3303         /* adjust LDPC based on receive capabilites */
 3304         if ((vap->iv_flags_ht & IEEE80211_FHT_LDPC_RX) == 0)
 3305                 caps &= ~IEEE80211_HTCAP_LDPC;
 3306 
 3307         ADDSHORT(frm, caps);
 3308 
 3309         /* HT parameters */
 3310         *frm = _IEEE80211_SHIFTMASK(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
 3311              | _IEEE80211_SHIFTMASK(density, IEEE80211_HTCAP_MPDUDENSITY)
 3312              ;
 3313         frm++;
 3314 
 3315         /* pre-zero remainder of ie */
 3316         memset(frm, 0, sizeof(struct ieee80211_ie_htcap) - 
 3317                 __offsetof(struct ieee80211_ie_htcap, hc_mcsset));
 3318 
 3319         /* supported MCS set */
 3320         /*
 3321          * XXX: For sta mode the rate set should be restricted based
 3322          * on the AP's capabilities, but ni_htrates isn't setup when
 3323          * we're called to form an AssocReq frame so for now we're
 3324          * restricted to the device capabilities.
 3325          */
 3326         ieee80211_set_mcsset(ni->ni_ic, frm);
 3327 
 3328         frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) -
 3329                 __offsetof(struct ieee80211_ie_htcap, hc_mcsset);
 3330 
 3331         /* HT extended capabilities */
 3332         extcaps = vap->iv_htextcaps & 0xffff;
 3333 
 3334         ADDSHORT(frm, extcaps);
 3335 
 3336         frm += sizeof(struct ieee80211_ie_htcap) -
 3337                 __offsetof(struct ieee80211_ie_htcap, hc_txbf);
 3338 
 3339         return frm;
 3340 #undef ADDSHORT
 3341 }
 3342 
 3343 /*
 3344  * Add 802.11n HT capabilities information element
 3345  */
 3346 uint8_t *
 3347 ieee80211_add_htcap(uint8_t *frm, struct ieee80211_node *ni)
 3348 {
 3349         frm[0] = IEEE80211_ELEMID_HTCAP;
 3350         frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
 3351         return ieee80211_add_htcap_body(frm + 2, ni);
 3352 }
 3353 
 3354 /*
 3355  * Non-associated probe request - add HT capabilities based on
 3356  * the current channel configuration.
 3357  */
 3358 static uint8_t *
 3359 ieee80211_add_htcap_body_ch(uint8_t *frm, struct ieee80211vap *vap,
 3360     struct ieee80211_channel *c)
 3361 {
 3362 #define ADDSHORT(frm, v) do {                   \
 3363         frm[0] = (v) & 0xff;                    \
 3364         frm[1] = (v) >> 8;                      \
 3365         frm += 2;                               \
 3366 } while (0)
 3367         struct ieee80211com *ic = vap->iv_ic;
 3368         uint16_t caps, extcaps;
 3369         int rxmax, density;
 3370 
 3371         /* HT capabilities */
 3372         caps = vap->iv_htcaps & 0xffff;
 3373 
 3374         /*
 3375          * We don't use this in STA mode; only in IBSS mode.
 3376          * So in IBSS mode we base our HTCAP flags on the
 3377          * given channel.
 3378          */
 3379 
 3380         /* override 20/40 use based on current channel */
 3381         if (IEEE80211_IS_CHAN_HT40(c))
 3382                 caps |= IEEE80211_HTCAP_CHWIDTH40;
 3383         else
 3384                 caps &= ~IEEE80211_HTCAP_CHWIDTH40;
 3385 
 3386         /* Use the currently configured values */
 3387         rxmax = vap->iv_ampdu_rxmax;
 3388         density = vap->iv_ampdu_density;
 3389 
 3390         /* adjust short GI based on channel and config */
 3391         if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI20) == 0)
 3392                 caps &= ~IEEE80211_HTCAP_SHORTGI20;
 3393         if ((vap->iv_flags_ht & IEEE80211_FHT_SHORTGI40) == 0 ||
 3394             (caps & IEEE80211_HTCAP_CHWIDTH40) == 0)
 3395                 caps &= ~IEEE80211_HTCAP_SHORTGI40;
 3396         ADDSHORT(frm, caps);
 3397 
 3398         /* HT parameters */
 3399         *frm = _IEEE80211_SHIFTMASK(rxmax, IEEE80211_HTCAP_MAXRXAMPDU)
 3400              | _IEEE80211_SHIFTMASK(density, IEEE80211_HTCAP_MPDUDENSITY)
 3401              ;
 3402         frm++;
 3403 
 3404         /* pre-zero remainder of ie */
 3405         memset(frm, 0, sizeof(struct ieee80211_ie_htcap) - 
 3406                 __offsetof(struct ieee80211_ie_htcap, hc_mcsset));
 3407 
 3408         /* supported MCS set */
 3409         /*
 3410          * XXX: For sta mode the rate set should be restricted based
 3411          * on the AP's capabilities, but ni_htrates isn't setup when
 3412          * we're called to form an AssocReq frame so for now we're
 3413          * restricted to the device capabilities.
 3414          */
 3415         ieee80211_set_mcsset(ic, frm);
 3416 
 3417         frm += __offsetof(struct ieee80211_ie_htcap, hc_extcap) -
 3418                 __offsetof(struct ieee80211_ie_htcap, hc_mcsset);
 3419 
 3420         /* HT extended capabilities */
 3421         extcaps = vap->iv_htextcaps & 0xffff;
 3422 
 3423         ADDSHORT(frm, extcaps);
 3424 
 3425         frm += sizeof(struct ieee80211_ie_htcap) -
 3426                 __offsetof(struct ieee80211_ie_htcap, hc_txbf);
 3427 
 3428         return frm;
 3429 #undef ADDSHORT
 3430 }
 3431 
 3432 /*
 3433  * Add 802.11n HT capabilities information element
 3434  */
 3435 uint8_t *
 3436 ieee80211_add_htcap_ch(uint8_t *frm, struct ieee80211vap *vap,
 3437     struct ieee80211_channel *c)
 3438 {
 3439         frm[0] = IEEE80211_ELEMID_HTCAP;
 3440         frm[1] = sizeof(struct ieee80211_ie_htcap) - 2;
 3441         return ieee80211_add_htcap_body_ch(frm + 2, vap, c);
 3442 }
 3443 
 3444 /*
 3445  * Add Broadcom OUI wrapped standard HTCAP ie; this is
 3446  * used for compatibility w/ pre-draft implementations.
 3447  */
 3448 uint8_t *
 3449 ieee80211_add_htcap_vendor(uint8_t *frm, struct ieee80211_node *ni)
 3450 {
 3451         frm[0] = IEEE80211_ELEMID_VENDOR;
 3452         frm[1] = 4 + sizeof(struct ieee80211_ie_htcap) - 2;
 3453         frm[2] = (BCM_OUI >> 0) & 0xff;
 3454         frm[3] = (BCM_OUI >> 8) & 0xff;
 3455         frm[4] = (BCM_OUI >> 16) & 0xff;
 3456         frm[5] = BCM_OUI_HTCAP;
 3457         return ieee80211_add_htcap_body(frm + 6, ni);
 3458 }
 3459 
 3460 /*
 3461  * Construct the MCS bit mask of basic rates
 3462  * for inclusion in an HT information element.
 3463  */
 3464 static void
 3465 ieee80211_set_basic_htrates(uint8_t *frm, const struct ieee80211_htrateset *rs)
 3466 {
 3467         int i;
 3468 
 3469         for (i = 0; i < rs->rs_nrates; i++) {
 3470                 int r = rs->rs_rates[i] & IEEE80211_RATE_VAL;
 3471                 if ((rs->rs_rates[i] & IEEE80211_RATE_BASIC) &&
 3472                     r < IEEE80211_HTRATE_MAXSIZE) {
 3473                         /* NB: this assumes a particular implementation */
 3474                         setbit(frm, r);
 3475                 }
 3476         }
 3477 }
 3478 
 3479 /*
 3480  * Update the HTINFO ie for a beacon frame.
 3481  */
 3482 void
 3483 ieee80211_ht_update_beacon(struct ieee80211vap *vap,
 3484         struct ieee80211_beacon_offsets *bo)
 3485 {
 3486 #define PROTMODE        (IEEE80211_HTINFO_OPMODE|IEEE80211_HTINFO_NONHT_PRESENT)
 3487         struct ieee80211_node *ni;
 3488         const struct ieee80211_channel *bsschan;
 3489         struct ieee80211com *ic = vap->iv_ic;
 3490         struct ieee80211_ie_htinfo *ht =
 3491            (struct ieee80211_ie_htinfo *) bo->bo_htinfo;
 3492 
 3493         ni = ieee80211_ref_node(vap->iv_bss);
 3494         bsschan = ni->ni_chan;
 3495 
 3496         /* XXX only update on channel change */
 3497         ht->hi_ctrlchannel = ieee80211_chan2ieee(ic, bsschan);
 3498         if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
 3499                 ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PERM;
 3500         else
 3501                 ht->hi_byte1 = IEEE80211_HTINFO_RIFSMODE_PROH;
 3502         if (IEEE80211_IS_CHAN_HT40U(bsschan))
 3503                 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
 3504         else if (IEEE80211_IS_CHAN_HT40D(bsschan))
 3505                 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_BELOW;
 3506         else
 3507                 ht->hi_byte1 |= IEEE80211_HTINFO_2NDCHAN_NONE;
 3508         if (IEEE80211_IS_CHAN_HT40(bsschan))
 3509                 ht->hi_byte1 |= IEEE80211_HTINFO_TXWIDTH_2040;
 3510 
 3511         /* protection mode */
 3512         /*
 3513          * XXX TODO: this uses the global flag, not the per-VAP flag.
 3514          * Eventually (once the protection modes are done per-channel
 3515          * rather than per-VAP) we can flip this over to be per-VAP but
 3516          * using the channel protection mode.
 3517          */
 3518         ht->hi_byte2 = (ht->hi_byte2 &~ PROTMODE) | ic->ic_curhtprotmode;
 3519 
 3520         ieee80211_free_node(ni);
 3521 
 3522         /* XXX propagate to vendor ie's */
 3523 #undef PROTMODE
 3524 }
 3525 
 3526 /*
 3527  * Add body of an HTINFO information element.
 3528  *
 3529  * NB: We don't use struct ieee80211_ie_htinfo because we can
 3530  * be called to fillin both a standard ie and a compat ie that
 3531  * has a vendor OUI at the front.
 3532  */
 3533 static uint8_t *
 3534 ieee80211_add_htinfo_body(uint8_t *frm, struct ieee80211_node *ni)
 3535 {
 3536         struct ieee80211vap *vap = ni->ni_vap;
 3537         struct ieee80211com *ic = ni->ni_ic;
 3538 
 3539         /* pre-zero remainder of ie */
 3540         memset(frm, 0, sizeof(struct ieee80211_ie_htinfo) - 2);
 3541 
 3542         /* primary/control channel center */
 3543         *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
 3544 
 3545         if (vap->iv_flags_ht & IEEE80211_FHT_RIFS)
 3546                 frm[0] = IEEE80211_HTINFO_RIFSMODE_PERM;
 3547         else
 3548                 frm[0] = IEEE80211_HTINFO_RIFSMODE_PROH;
 3549         if (IEEE80211_IS_CHAN_HT40U(ni->ni_chan))
 3550                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_ABOVE;
 3551         else if (IEEE80211_IS_CHAN_HT40D(ni->ni_chan))
 3552                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_BELOW;
 3553         else
 3554                 frm[0] |= IEEE80211_HTINFO_2NDCHAN_NONE;
 3555         if (IEEE80211_IS_CHAN_HT40(ni->ni_chan))
 3556                 frm[0] |= IEEE80211_HTINFO_TXWIDTH_2040;
 3557 
 3558         /*
 3559          * Add current protection mode.  Unlike for beacons,
 3560          * this will respect the per-VAP flags.
 3561          */
 3562         frm[1] = vap->iv_curhtprotmode;
 3563 
 3564         frm += 5;
 3565 
 3566         /* basic MCS set */
 3567         ieee80211_set_basic_htrates(frm, &ni->ni_htrates);
 3568         frm += sizeof(struct ieee80211_ie_htinfo) -
 3569                 __offsetof(struct ieee80211_ie_htinfo, hi_basicmcsset);
 3570         return frm;
 3571 }
 3572 
 3573 /*
 3574  * Add 802.11n HT information element.
 3575  */
 3576 uint8_t *
 3577 ieee80211_add_htinfo(uint8_t *frm, struct ieee80211_node *ni)
 3578 {
 3579         frm[0] = IEEE80211_ELEMID_HTINFO;
 3580         frm[1] = sizeof(struct ieee80211_ie_htinfo) - 2;
 3581         return ieee80211_add_htinfo_body(frm + 2, ni);
 3582 }
 3583 
 3584 /*
 3585  * Add Broadcom OUI wrapped standard HTINFO ie; this is
 3586  * used for compatibility w/ pre-draft implementations.
 3587  */
 3588 uint8_t *
 3589 ieee80211_add_htinfo_vendor(uint8_t *frm, struct ieee80211_node *ni)
 3590 {
 3591         frm[0] = IEEE80211_ELEMID_VENDOR;
 3592         frm[1] = 4 + sizeof(struct ieee80211_ie_htinfo) - 2;
 3593         frm[2] = (BCM_OUI >> 0) & 0xff;
 3594         frm[3] = (BCM_OUI >> 8) & 0xff;
 3595         frm[4] = (BCM_OUI >> 16) & 0xff;
 3596         frm[5] = BCM_OUI_HTINFO;
 3597         return ieee80211_add_htinfo_body(frm + 6, ni);
 3598 }

Cache object: a1b0d98ad1eb2ba41f3f18a45a379342


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.