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_vht.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: ca9ad3c9e76817862b0082c09cf396d0


[ 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.