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_superg.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) 2002-2009 Sam Leffler, Errno Consulting
    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 __FBSDID("$FreeBSD: releng/11.1/sys/net80211/ieee80211_superg.c 302283 2016-06-29 17:25:46Z avos $");
   28 
   29 #include "opt_wlan.h"
   30 
   31 #ifdef  IEEE80211_SUPPORT_SUPERG
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h> 
   35 #include <sys/mbuf.h>   
   36 #include <sys/kernel.h>
   37 #include <sys/endian.h>
   38 
   39 #include <sys/socket.h>
   40  
   41 #include <net/if.h>
   42 #include <net/if_var.h>
   43 #include <net/if_llc.h>
   44 #include <net/if_media.h>
   45 #include <net/bpf.h>
   46 #include <net/ethernet.h>
   47 
   48 #include <net80211/ieee80211_var.h>
   49 #include <net80211/ieee80211_input.h>
   50 #include <net80211/ieee80211_phy.h>
   51 #include <net80211/ieee80211_superg.h>
   52 
   53 /*
   54  * Atheros fast-frame encapsulation format.
   55  * FF max payload:
   56  * 802.2 + FFHDR + HPAD + 802.3 + 802.2 + 1500 + SPAD + 802.3 + 802.2 + 1500:
   57  *   8   +   4   +  4   +   14  +   8   + 1500 +  6   +   14  +   8   + 1500
   58  * = 3066
   59  */
   60 /* fast frame header is 32-bits */
   61 #define ATH_FF_PROTO    0x0000003f      /* protocol */
   62 #define ATH_FF_PROTO_S  0
   63 #define ATH_FF_FTYPE    0x000000c0      /* frame type */
   64 #define ATH_FF_FTYPE_S  6
   65 #define ATH_FF_HLEN32   0x00000300      /* optional hdr length */
   66 #define ATH_FF_HLEN32_S 8
   67 #define ATH_FF_SEQNUM   0x001ffc00      /* sequence number */
   68 #define ATH_FF_SEQNUM_S 10
   69 #define ATH_FF_OFFSET   0xffe00000      /* offset to 2nd payload */
   70 #define ATH_FF_OFFSET_S 21
   71 
   72 #define ATH_FF_MAX_HDR_PAD      4
   73 #define ATH_FF_MAX_SEP_PAD      6
   74 #define ATH_FF_MAX_HDR          30
   75 
   76 #define ATH_FF_PROTO_L2TUNNEL   0       /* L2 tunnel protocol */
   77 #define ATH_FF_ETH_TYPE         0x88bd  /* Ether type for encapsulated frames */
   78 #define ATH_FF_SNAP_ORGCODE_0   0x00
   79 #define ATH_FF_SNAP_ORGCODE_1   0x03
   80 #define ATH_FF_SNAP_ORGCODE_2   0x7f
   81 
   82 #define ATH_FF_TXQMIN   2               /* min txq depth for staging */
   83 #define ATH_FF_TXQMAX   50              /* maximum # of queued frames allowed */
   84 #define ATH_FF_STAGEMAX 5               /* max waiting period for staged frame*/
   85 
   86 #define ETHER_HEADER_COPY(dst, src) \
   87         memcpy(dst, src, sizeof(struct ether_header))
   88 
   89 static  int ieee80211_ffppsmin = 2;     /* pps threshold for ff aggregation */
   90 SYSCTL_INT(_net_wlan, OID_AUTO, ffppsmin, CTLFLAG_RW,
   91         &ieee80211_ffppsmin, 0, "min packet rate before fast-frame staging");
   92 static  int ieee80211_ffagemax = -1;    /* max time frames held on stage q */
   93 SYSCTL_PROC(_net_wlan, OID_AUTO, ffagemax, CTLTYPE_INT | CTLFLAG_RW,
   94         &ieee80211_ffagemax, 0, ieee80211_sysctl_msecs_ticks, "I",
   95         "max hold time for fast-frame staging (ms)");
   96 
   97 void
   98 ieee80211_superg_attach(struct ieee80211com *ic)
   99 {
  100         struct ieee80211_superg *sg;
  101 
  102         IEEE80211_FF_LOCK_INIT(ic, ic->ic_name);
  103 
  104         sg = (struct ieee80211_superg *) IEEE80211_MALLOC(
  105              sizeof(struct ieee80211_superg), M_80211_VAP,
  106              IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
  107         if (sg == NULL) {
  108                 printf("%s: cannot allocate SuperG state block\n",
  109                     __func__);
  110                 return;
  111         }
  112         ic->ic_superg = sg;
  113 
  114         /*
  115          * Default to not being so aggressive for FF/AMSDU
  116          * aging, otherwise we may hold a frame around
  117          * for way too long before we expire it out.
  118          */
  119         ieee80211_ffagemax = msecs_to_ticks(2);
  120 }
  121 
  122 void
  123 ieee80211_superg_detach(struct ieee80211com *ic)
  124 {
  125         IEEE80211_FF_LOCK_DESTROY(ic);
  126 
  127         if (ic->ic_superg != NULL) {
  128                 IEEE80211_FREE(ic->ic_superg, M_80211_VAP);
  129                 ic->ic_superg = NULL;
  130         }
  131 }
  132 
  133 void
  134 ieee80211_superg_vattach(struct ieee80211vap *vap)
  135 {
  136         struct ieee80211com *ic = vap->iv_ic;
  137 
  138         if (ic->ic_superg == NULL)      /* NB: can't do fast-frames w/o state */
  139                 vap->iv_caps &= ~IEEE80211_C_FF;
  140         if (vap->iv_caps & IEEE80211_C_FF)
  141                 vap->iv_flags |= IEEE80211_F_FF;
  142         /* NB: we only implement sta mode */
  143         if (vap->iv_opmode == IEEE80211_M_STA &&
  144             (vap->iv_caps & IEEE80211_C_TURBOP))
  145                 vap->iv_flags |= IEEE80211_F_TURBOP;
  146 }
  147 
  148 void
  149 ieee80211_superg_vdetach(struct ieee80211vap *vap)
  150 {
  151 }
  152 
  153 #define ATH_OUI_BYTES           0x00, 0x03, 0x7f
  154 /*
  155  * Add a WME information element to a frame.
  156  */
  157 uint8_t *
  158 ieee80211_add_ath(uint8_t *frm, uint8_t caps, ieee80211_keyix defkeyix)
  159 {
  160         static const struct ieee80211_ath_ie info = {
  161                 .ath_id         = IEEE80211_ELEMID_VENDOR,
  162                 .ath_len        = sizeof(struct ieee80211_ath_ie) - 2,
  163                 .ath_oui        = { ATH_OUI_BYTES },
  164                 .ath_oui_type   = ATH_OUI_TYPE,
  165                 .ath_oui_subtype= ATH_OUI_SUBTYPE,
  166                 .ath_version    = ATH_OUI_VERSION,
  167         };
  168         struct ieee80211_ath_ie *ath = (struct ieee80211_ath_ie *) frm;
  169 
  170         memcpy(frm, &info, sizeof(info));
  171         ath->ath_capability = caps;
  172         if (defkeyix != IEEE80211_KEYIX_NONE) {
  173                 ath->ath_defkeyix[0] = (defkeyix & 0xff);
  174                 ath->ath_defkeyix[1] = ((defkeyix >> 8) & 0xff);
  175         } else {
  176                 ath->ath_defkeyix[0] = 0xff;
  177                 ath->ath_defkeyix[1] = 0x7f;
  178         }
  179         return frm + sizeof(info); 
  180 }
  181 #undef ATH_OUI_BYTES
  182 
  183 uint8_t *
  184 ieee80211_add_athcaps(uint8_t *frm, const struct ieee80211_node *bss)
  185 {
  186         const struct ieee80211vap *vap = bss->ni_vap;
  187 
  188         return ieee80211_add_ath(frm,
  189             vap->iv_flags & IEEE80211_F_ATHEROS,
  190             ((vap->iv_flags & IEEE80211_F_WPA) == 0 &&
  191             bss->ni_authmode != IEEE80211_AUTH_8021X) ?
  192             vap->iv_def_txkey : IEEE80211_KEYIX_NONE);
  193 }
  194 
  195 void
  196 ieee80211_parse_ath(struct ieee80211_node *ni, uint8_t *ie)
  197 {
  198         const struct ieee80211_ath_ie *ath =
  199                 (const struct ieee80211_ath_ie *) ie;
  200 
  201         ni->ni_ath_flags = ath->ath_capability;
  202         ni->ni_ath_defkeyix = le16dec(&ath->ath_defkeyix);
  203 }
  204 
  205 int
  206 ieee80211_parse_athparams(struct ieee80211_node *ni, uint8_t *frm,
  207         const struct ieee80211_frame *wh)
  208 {
  209         struct ieee80211vap *vap = ni->ni_vap;
  210         const struct ieee80211_ath_ie *ath;
  211         u_int len = frm[1];
  212         int capschanged;
  213         uint16_t defkeyix;
  214 
  215         if (len < sizeof(struct ieee80211_ath_ie)-2) {
  216                 IEEE80211_DISCARD_IE(vap,
  217                     IEEE80211_MSG_ELEMID | IEEE80211_MSG_SUPERG,
  218                     wh, "Atheros", "too short, len %u", len);
  219                 return -1;
  220         }
  221         ath = (const struct ieee80211_ath_ie *)frm;
  222         capschanged = (ni->ni_ath_flags != ath->ath_capability);
  223         defkeyix = le16dec(ath->ath_defkeyix);
  224         if (capschanged || defkeyix != ni->ni_ath_defkeyix) {
  225                 ni->ni_ath_flags = ath->ath_capability;
  226                 ni->ni_ath_defkeyix = defkeyix;
  227                 IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
  228                     "ath ie change: new caps 0x%x defkeyix 0x%x",
  229                     ni->ni_ath_flags, ni->ni_ath_defkeyix);
  230         }
  231         if (IEEE80211_ATH_CAP(vap, ni, ATHEROS_CAP_TURBO_PRIME)) {
  232                 uint16_t curflags, newflags;
  233 
  234                 /*
  235                  * Check for turbo mode switch.  Calculate flags
  236                  * for the new mode and effect the switch.
  237                  */
  238                 newflags = curflags = vap->iv_ic->ic_bsschan->ic_flags;
  239                 /* NB: BOOST is not in ic_flags, so get it from the ie */
  240                 if (ath->ath_capability & ATHEROS_CAP_BOOST) 
  241                         newflags |= IEEE80211_CHAN_TURBO;
  242                 else
  243                         newflags &= ~IEEE80211_CHAN_TURBO;
  244                 if (newflags != curflags)
  245                         ieee80211_dturbo_switch(vap, newflags);
  246         }
  247         return capschanged;
  248 }
  249 
  250 /*
  251  * Decap the encapsulated frame pair and dispatch the first
  252  * for delivery.  The second frame is returned for delivery
  253  * via the normal path.
  254  */
  255 struct mbuf *
  256 ieee80211_ff_decap(struct ieee80211_node *ni, struct mbuf *m)
  257 {
  258 #define FF_LLC_SIZE     (sizeof(struct ether_header) + sizeof(struct llc))
  259 #define MS(x,f) (((x) & f) >> f##_S)
  260         struct ieee80211vap *vap = ni->ni_vap;
  261         struct llc *llc;
  262         uint32_t ath;
  263         struct mbuf *n;
  264         int framelen;
  265 
  266         /* NB: we assume caller does this check for us */
  267         KASSERT(IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF),
  268             ("ff not negotiated"));
  269         /*
  270          * Check for fast-frame tunnel encapsulation.
  271          */
  272         if (m->m_pkthdr.len < 3*FF_LLC_SIZE)
  273                 return m;
  274         if (m->m_len < FF_LLC_SIZE &&
  275             (m = m_pullup(m, FF_LLC_SIZE)) == NULL) {
  276                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
  277                     ni->ni_macaddr, "fast-frame",
  278                     "%s", "m_pullup(llc) failed");
  279                 vap->iv_stats.is_rx_tooshort++;
  280                 return NULL;
  281         }
  282         llc = (struct llc *)(mtod(m, uint8_t *) +
  283             sizeof(struct ether_header));
  284         if (llc->llc_snap.ether_type != htons(ATH_FF_ETH_TYPE))
  285                 return m;
  286         m_adj(m, FF_LLC_SIZE);
  287         m_copydata(m, 0, sizeof(uint32_t), (caddr_t) &ath);
  288         if (MS(ath, ATH_FF_PROTO) != ATH_FF_PROTO_L2TUNNEL) {
  289                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
  290                     ni->ni_macaddr, "fast-frame",
  291                     "unsupport tunnel protocol, header 0x%x", ath);
  292                 vap->iv_stats.is_ff_badhdr++;
  293                 m_freem(m);
  294                 return NULL;
  295         }
  296         /* NB: skip header and alignment padding */
  297         m_adj(m, roundup(sizeof(uint32_t) - 2, 4) + 2);
  298 
  299         vap->iv_stats.is_ff_decap++;
  300 
  301         /*
  302          * Decap the first frame, bust it apart from the
  303          * second and deliver; then decap the second frame
  304          * and return it to the caller for normal delivery.
  305          */
  306         m = ieee80211_decap1(m, &framelen);
  307         if (m == NULL) {
  308                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
  309                     ni->ni_macaddr, "fast-frame", "%s", "first decap failed");
  310                 vap->iv_stats.is_ff_tooshort++;
  311                 return NULL;
  312         }
  313         n = m_split(m, framelen, M_NOWAIT);
  314         if (n == NULL) {
  315                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
  316                     ni->ni_macaddr, "fast-frame",
  317                     "%s", "unable to split encapsulated frames");
  318                 vap->iv_stats.is_ff_split++;
  319                 m_freem(m);                     /* NB: must reclaim */
  320                 return NULL;
  321         }
  322         /* XXX not right for WDS */
  323         vap->iv_deliver_data(vap, ni, m);       /* 1st of pair */
  324 
  325         /*
  326          * Decap second frame.
  327          */
  328         m_adj(n, roundup2(framelen, 4) - framelen);     /* padding */
  329         n = ieee80211_decap1(n, &framelen);
  330         if (n == NULL) {
  331                 IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_ANY,
  332                     ni->ni_macaddr, "fast-frame", "%s", "second decap failed");
  333                 vap->iv_stats.is_ff_tooshort++;
  334         }
  335         /* XXX verify framelen against mbuf contents */
  336         return n;                               /* 2nd delivered by caller */
  337 #undef MS
  338 #undef FF_LLC_SIZE
  339 }
  340 
  341 /*
  342  * Fast frame encapsulation.  There must be two packets
  343  * chained with m_nextpkt.  We do header adjustment for
  344  * each, add the tunnel encapsulation, and then concatenate
  345  * the mbuf chains to form a single frame for transmission.
  346  */
  347 struct mbuf *
  348 ieee80211_ff_encap(struct ieee80211vap *vap, struct mbuf *m1, int hdrspace,
  349         struct ieee80211_key *key)
  350 {
  351         struct mbuf *m2;
  352         struct ether_header eh1, eh2;
  353         struct llc *llc;
  354         struct mbuf *m;
  355         int pad;
  356 
  357         m2 = m1->m_nextpkt;
  358         if (m2 == NULL) {
  359                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
  360                     "%s: only one frame\n", __func__);
  361                 goto bad;
  362         }
  363         m1->m_nextpkt = NULL;
  364 
  365         /*
  366          * Adjust to include 802.11 header requirement.
  367          */
  368         KASSERT(m1->m_len >= sizeof(eh1), ("no ethernet header!"));
  369         ETHER_HEADER_COPY(&eh1, mtod(m1, caddr_t));
  370         m1 = ieee80211_mbuf_adjust(vap, hdrspace, key, m1);
  371         if (m1 == NULL) {
  372                 printf("%s: failed initial mbuf_adjust\n", __func__);
  373                 /* NB: ieee80211_mbuf_adjust handles msgs+statistics */
  374                 m_freem(m2);
  375                 goto bad;
  376         }
  377 
  378         /*
  379          * Copy second frame's Ethernet header out of line
  380          * and adjust for possible padding in case there isn't room
  381          * at the end of first frame.
  382          */
  383         KASSERT(m2->m_len >= sizeof(eh2), ("no ethernet header!"));
  384         ETHER_HEADER_COPY(&eh2, mtod(m2, caddr_t));
  385         m2 = ieee80211_mbuf_adjust(vap, 4, NULL, m2);
  386         if (m2 == NULL) {
  387                 /* NB: ieee80211_mbuf_adjust handles msgs+statistics */
  388                 printf("%s: failed second \n", __func__);
  389                 goto bad;
  390         }
  391 
  392         /*
  393          * Now do tunnel encapsulation.  First, each
  394          * frame gets a standard encapsulation.
  395          */
  396         m1 = ieee80211_ff_encap1(vap, m1, &eh1);
  397         if (m1 == NULL)
  398                 goto bad;
  399         m2 = ieee80211_ff_encap1(vap, m2, &eh2);
  400         if (m2 == NULL)
  401                 goto bad;
  402 
  403         /*
  404          * Pad leading frame to a 4-byte boundary.  If there
  405          * is space at the end of the first frame, put it
  406          * there; otherwise prepend to the front of the second
  407          * frame.  We know doing the second will always work
  408          * because we reserve space above.  We prefer appending
  409          * as this typically has better DMA alignment properties.
  410          */
  411         for (m = m1; m->m_next != NULL; m = m->m_next)
  412                 ;
  413         pad = roundup2(m1->m_pkthdr.len, 4) - m1->m_pkthdr.len;
  414         if (pad) {
  415                 if (M_TRAILINGSPACE(m) < pad) {         /* prepend to second */
  416                         m2->m_data -= pad;
  417                         m2->m_len += pad;
  418                         m2->m_pkthdr.len += pad;
  419                 } else {                                /* append to first */
  420                         m->m_len += pad;
  421                         m1->m_pkthdr.len += pad;
  422                 }
  423         }
  424 
  425         /*
  426          * A-MSDU's are just appended; the "I'm A-MSDU!" bit is in the
  427          * QoS header.
  428          *
  429          * XXX optimize by prepending together
  430          */
  431         m->m_next = m2;                 /* NB: last mbuf from above */
  432         m1->m_pkthdr.len += m2->m_pkthdr.len;
  433         M_PREPEND(m1, sizeof(uint32_t)+2, M_NOWAIT);
  434         if (m1 == NULL) {               /* XXX cannot happen */
  435                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
  436                     "%s: no space for tunnel header\n", __func__);
  437                 vap->iv_stats.is_tx_nobuf++;
  438                 return NULL;
  439         }
  440         memset(mtod(m1, void *), 0, sizeof(uint32_t)+2);
  441 
  442         M_PREPEND(m1, sizeof(struct llc), M_NOWAIT);
  443         if (m1 == NULL) {               /* XXX cannot happen */
  444                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
  445                     "%s: no space for llc header\n", __func__);
  446                 vap->iv_stats.is_tx_nobuf++;
  447                 return NULL;
  448         }
  449         llc = mtod(m1, struct llc *);
  450         llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
  451         llc->llc_control = LLC_UI;
  452         llc->llc_snap.org_code[0] = ATH_FF_SNAP_ORGCODE_0;
  453         llc->llc_snap.org_code[1] = ATH_FF_SNAP_ORGCODE_1;
  454         llc->llc_snap.org_code[2] = ATH_FF_SNAP_ORGCODE_2;
  455         llc->llc_snap.ether_type = htons(ATH_FF_ETH_TYPE);
  456 
  457         vap->iv_stats.is_ff_encap++;
  458 
  459         return m1;
  460 bad:
  461         vap->iv_stats.is_ff_encapfail++;
  462         if (m1 != NULL)
  463                 m_freem(m1);
  464         if (m2 != NULL)
  465                 m_freem(m2);
  466         return NULL;
  467 }
  468 
  469 /*
  470  * A-MSDU encapsulation.
  471  *
  472  * This assumes just two frames for now, since we're borrowing the
  473  * same queuing code and infrastructure as fast-frames.
  474  *
  475  * There must be two packets chained with m_nextpkt.
  476  * We do header adjustment for each, and then concatenate the mbuf chains
  477  * to form a single frame for transmission.
  478  */
  479 struct mbuf *
  480 ieee80211_amsdu_encap(struct ieee80211vap *vap, struct mbuf *m1, int hdrspace,
  481         struct ieee80211_key *key)
  482 {
  483         struct mbuf *m2;
  484         struct ether_header eh1, eh2;
  485         struct mbuf *m;
  486         int pad;
  487 
  488         m2 = m1->m_nextpkt;
  489         if (m2 == NULL) {
  490                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
  491                     "%s: only one frame\n", __func__);
  492                 goto bad;
  493         }
  494         m1->m_nextpkt = NULL;
  495 
  496         /*
  497          * Include A-MSDU header in adjusting header layout.
  498          */
  499         KASSERT(m1->m_len >= sizeof(eh1), ("no ethernet header!"));
  500         ETHER_HEADER_COPY(&eh1, mtod(m1, caddr_t));
  501         m1 = ieee80211_mbuf_adjust(vap,
  502                 hdrspace + sizeof(struct llc) + sizeof(uint32_t) +
  503                     sizeof(struct ether_header),
  504                 key, m1);
  505         if (m1 == NULL) {
  506                 /* NB: ieee80211_mbuf_adjust handles msgs+statistics */
  507                 m_freem(m2);
  508                 goto bad;
  509         }
  510 
  511         /*
  512          * Copy second frame's Ethernet header out of line
  513          * and adjust for encapsulation headers.  Note that
  514          * we make room for padding in case there isn't room
  515          * at the end of first frame.
  516          */
  517         KASSERT(m2->m_len >= sizeof(eh2), ("no ethernet header!"));
  518         ETHER_HEADER_COPY(&eh2, mtod(m2, caddr_t));
  519         m2 = ieee80211_mbuf_adjust(vap, 4, NULL, m2);
  520         if (m2 == NULL) {
  521                 /* NB: ieee80211_mbuf_adjust handles msgs+statistics */
  522                 goto bad;
  523         }
  524 
  525         /*
  526          * Now do tunnel encapsulation.  First, each
  527          * frame gets a standard encapsulation.
  528          */
  529         m1 = ieee80211_ff_encap1(vap, m1, &eh1);
  530         if (m1 == NULL)
  531                 goto bad;
  532         m2 = ieee80211_ff_encap1(vap, m2, &eh2);
  533         if (m2 == NULL)
  534                 goto bad;
  535 
  536         /*
  537          * Pad leading frame to a 4-byte boundary.  If there
  538          * is space at the end of the first frame, put it
  539          * there; otherwise prepend to the front of the second
  540          * frame.  We know doing the second will always work
  541          * because we reserve space above.  We prefer appending
  542          * as this typically has better DMA alignment properties.
  543          */
  544         for (m = m1; m->m_next != NULL; m = m->m_next)
  545                 ;
  546         pad = roundup2(m1->m_pkthdr.len, 4) - m1->m_pkthdr.len;
  547         if (pad) {
  548                 if (M_TRAILINGSPACE(m) < pad) {         /* prepend to second */
  549                         m2->m_data -= pad;
  550                         m2->m_len += pad;
  551                         m2->m_pkthdr.len += pad;
  552                 } else {                                /* append to first */
  553                         m->m_len += pad;
  554                         m1->m_pkthdr.len += pad;
  555                 }
  556         }
  557 
  558         /*
  559          * Now, stick 'em together.
  560          */
  561         m->m_next = m2;                 /* NB: last mbuf from above */
  562         m1->m_pkthdr.len += m2->m_pkthdr.len;
  563 
  564         vap->iv_stats.is_amsdu_encap++;
  565 
  566         return m1;
  567 bad:
  568         vap->iv_stats.is_amsdu_encapfail++;
  569         if (m1 != NULL)
  570                 m_freem(m1);
  571         if (m2 != NULL)
  572                 m_freem(m2);
  573         return NULL;
  574 }
  575 
  576 
  577 static void
  578 ff_transmit(struct ieee80211_node *ni, struct mbuf *m)
  579 {
  580         struct ieee80211vap *vap = ni->ni_vap;
  581         struct ieee80211com *ic = ni->ni_ic;
  582 
  583         IEEE80211_TX_LOCK_ASSERT(ic);
  584 
  585         /* encap and xmit */
  586         m = ieee80211_encap(vap, ni, m);
  587         if (m != NULL)
  588                 (void) ieee80211_parent_xmitpkt(ic, m);
  589         else
  590                 ieee80211_free_node(ni);
  591 }
  592 
  593 /*
  594  * Flush frames to device; note we re-use the linked list
  595  * the frames were stored on and use the sentinel (unchanged)
  596  * which may be non-NULL.
  597  */
  598 static void
  599 ff_flush(struct mbuf *head, struct mbuf *last)
  600 {
  601         struct mbuf *m, *next;
  602         struct ieee80211_node *ni;
  603         struct ieee80211vap *vap;
  604 
  605         for (m = head; m != last; m = next) {
  606                 next = m->m_nextpkt;
  607                 m->m_nextpkt = NULL;
  608 
  609                 ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
  610                 vap = ni->ni_vap;
  611 
  612                 IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
  613                     "%s: flush frame, age %u", __func__, M_AGE_GET(m));
  614                 vap->iv_stats.is_ff_flush++;
  615 
  616                 ff_transmit(ni, m);
  617         }
  618 }
  619 
  620 /*
  621  * Age frames on the staging queue.
  622  */
  623 void
  624 ieee80211_ff_age(struct ieee80211com *ic, struct ieee80211_stageq *sq,
  625     int quanta)
  626 {
  627         struct mbuf *m, *head;
  628         struct ieee80211_node *ni;
  629 
  630         IEEE80211_FF_LOCK(ic);
  631         if (sq->depth == 0) {
  632                 IEEE80211_FF_UNLOCK(ic);
  633                 return;         /* nothing to do */
  634         }
  635 
  636         KASSERT(sq->head != NULL, ("stageq empty"));
  637 
  638         head = sq->head;
  639         while ((m = sq->head) != NULL && M_AGE_GET(m) < quanta) {
  640                 int tid = WME_AC_TO_TID(M_WME_GETAC(m));
  641 
  642                 /* clear staging ref to frame */
  643                 ni = (struct ieee80211_node *) m->m_pkthdr.rcvif;
  644                 KASSERT(ni->ni_tx_superg[tid] == m, ("staging queue empty"));
  645                 ni->ni_tx_superg[tid] = NULL;
  646 
  647                 sq->head = m->m_nextpkt;
  648                 sq->depth--;
  649         }
  650         if (m == NULL)
  651                 sq->tail = NULL;
  652         else
  653                 M_AGE_SUB(m, quanta);
  654         IEEE80211_FF_UNLOCK(ic);
  655 
  656         IEEE80211_TX_LOCK(ic);
  657         ff_flush(head, m);
  658         IEEE80211_TX_UNLOCK(ic);
  659 }
  660 
  661 static void
  662 stageq_add(struct ieee80211com *ic, struct ieee80211_stageq *sq, struct mbuf *m)
  663 {
  664         int age = ieee80211_ffagemax;
  665 
  666         IEEE80211_FF_LOCK_ASSERT(ic);
  667 
  668         if (sq->tail != NULL) {
  669                 sq->tail->m_nextpkt = m;
  670                 age -= M_AGE_GET(sq->head);
  671         } else
  672                 sq->head = m;
  673         KASSERT(age >= 0, ("age %d", age));
  674         M_AGE_SET(m, age);
  675         m->m_nextpkt = NULL;
  676         sq->tail = m;
  677         sq->depth++;
  678 }
  679 
  680 static void
  681 stageq_remove(struct ieee80211com *ic, struct ieee80211_stageq *sq, struct mbuf *mstaged)
  682 {
  683         struct mbuf *m, *mprev;
  684 
  685         IEEE80211_FF_LOCK_ASSERT(ic);
  686 
  687         mprev = NULL;
  688         for (m = sq->head; m != NULL; m = m->m_nextpkt) {
  689                 if (m == mstaged) {
  690                         if (mprev == NULL)
  691                                 sq->head = m->m_nextpkt;
  692                         else
  693                                 mprev->m_nextpkt = m->m_nextpkt;
  694                         if (sq->tail == m)
  695                                 sq->tail = mprev;
  696                         sq->depth--;
  697                         return;
  698                 }
  699                 mprev = m;
  700         }
  701         printf("%s: packet not found\n", __func__);
  702 }
  703 
  704 static uint32_t
  705 ff_approx_txtime(struct ieee80211_node *ni,
  706         const struct mbuf *m1, const struct mbuf *m2)
  707 {
  708         struct ieee80211com *ic = ni->ni_ic;
  709         struct ieee80211vap *vap = ni->ni_vap;
  710         uint32_t framelen;
  711         uint32_t frame_time;
  712 
  713         /*
  714          * Approximate the frame length to be transmitted. A swag to add
  715          * the following maximal values to the skb payload:
  716          *   - 32: 802.11 encap + CRC
  717          *   - 24: encryption overhead (if wep bit)
  718          *   - 4 + 6: fast-frame header and padding
  719          *   - 16: 2 LLC FF tunnel headers
  720          *   - 14: 1 802.3 FF tunnel header (mbuf already accounts for 2nd)
  721          */
  722         framelen = m1->m_pkthdr.len + 32 +
  723             ATH_FF_MAX_HDR_PAD + ATH_FF_MAX_SEP_PAD + ATH_FF_MAX_HDR;
  724         if (vap->iv_flags & IEEE80211_F_PRIVACY)
  725                 framelen += 24;
  726         if (m2 != NULL)
  727                 framelen += m2->m_pkthdr.len;
  728 
  729         /*
  730          * For now, we assume non-shortgi, 20MHz, just because I want to
  731          * at least test 802.11n.
  732          */
  733         if (ni->ni_txrate & IEEE80211_RATE_MCS)
  734                 frame_time = ieee80211_compute_duration_ht(framelen,
  735                     ni->ni_txrate,
  736                     IEEE80211_HT_RC_2_STREAMS(ni->ni_txrate),
  737                     0, /* isht40 */
  738                     0); /* isshortgi */
  739         else
  740                 frame_time = ieee80211_compute_duration(ic->ic_rt, framelen,
  741                             ni->ni_txrate, 0);
  742         return (frame_time);
  743 }
  744 
  745 /*
  746  * Check if the supplied frame can be partnered with an existing
  747  * or pending frame.  Return a reference to any frame that should be
  748  * sent on return; otherwise return NULL.
  749  */
  750 struct mbuf *
  751 ieee80211_ff_check(struct ieee80211_node *ni, struct mbuf *m)
  752 {
  753         struct ieee80211vap *vap = ni->ni_vap;
  754         struct ieee80211com *ic = ni->ni_ic;
  755         struct ieee80211_superg *sg = ic->ic_superg;
  756         const int pri = M_WME_GETAC(m);
  757         struct ieee80211_stageq *sq;
  758         struct ieee80211_tx_ampdu *tap;
  759         struct mbuf *mstaged;
  760         uint32_t txtime, limit;
  761 
  762         IEEE80211_TX_UNLOCK_ASSERT(ic);
  763 
  764         IEEE80211_LOCK(ic);
  765         limit = IEEE80211_TXOP_TO_US(
  766             ic->ic_wme.wme_chanParams.cap_wmeParams[pri].wmep_txopLimit);
  767         IEEE80211_UNLOCK(ic);
  768 
  769         /*
  770          * Check if the supplied frame can be aggregated.
  771          *
  772          * NB: we allow EAPOL frames to be aggregated with other ucast traffic.
  773          *     Do 802.1x EAPOL frames proceed in the clear? Then they couldn't
  774          *     be aggregated with other types of frames when encryption is on?
  775          */
  776         IEEE80211_FF_LOCK(ic);
  777         tap = &ni->ni_tx_ampdu[WME_AC_TO_TID(pri)];
  778         mstaged = ni->ni_tx_superg[WME_AC_TO_TID(pri)];
  779         /* XXX NOTE: reusing packet counter state from A-MPDU */
  780         /*
  781          * XXX NOTE: this means we're double-counting; it should just
  782          * be done in ieee80211_output.c once for both superg and A-MPDU.
  783          */
  784         ieee80211_txampdu_count_packet(tap);
  785 
  786         /*
  787          * When not in station mode never aggregate a multicast
  788          * frame; this insures, for example, that a combined frame
  789          * does not require multiple encryption keys.
  790          */
  791         if (vap->iv_opmode != IEEE80211_M_STA &&
  792             ETHER_IS_MULTICAST(mtod(m, struct ether_header *)->ether_dhost)) {
  793                 /* XXX flush staged frame? */
  794                 IEEE80211_FF_UNLOCK(ic);
  795                 return m;
  796         }
  797         /*
  798          * If there is no frame to combine with and the pps is
  799          * too low; then do not attempt to aggregate this frame.
  800          */
  801         if (mstaged == NULL &&
  802             ieee80211_txampdu_getpps(tap) < ieee80211_ffppsmin) {
  803                 IEEE80211_FF_UNLOCK(ic);
  804                 return m;
  805         }
  806         sq = &sg->ff_stageq[pri];
  807         /*
  808          * Check the txop limit to insure the aggregate fits.
  809          */
  810         if (limit != 0 &&
  811             (txtime = ff_approx_txtime(ni, m, mstaged)) > limit) {
  812                 /*
  813                  * Aggregate too long, return to the caller for direct
  814                  * transmission.  In addition, flush any pending frame
  815                  * before sending this one.
  816                  */
  817                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
  818                     "%s: txtime %u exceeds txop limit %u\n",
  819                     __func__, txtime, limit);
  820 
  821                 ni->ni_tx_superg[WME_AC_TO_TID(pri)] = NULL;
  822                 if (mstaged != NULL)
  823                         stageq_remove(ic, sq, mstaged);
  824                 IEEE80211_FF_UNLOCK(ic);
  825 
  826                 if (mstaged != NULL) {
  827                         IEEE80211_TX_LOCK(ic);
  828                         IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
  829                             "%s: flush staged frame", __func__);
  830                         /* encap and xmit */
  831                         ff_transmit(ni, mstaged);
  832                         IEEE80211_TX_UNLOCK(ic);
  833                 }
  834                 return m;               /* NB: original frame */
  835         }
  836         /*
  837          * An aggregation candidate.  If there's a frame to partner
  838          * with then combine and return for processing.  Otherwise
  839          * save this frame and wait for a partner to show up (or
  840          * the frame to be flushed).  Note that staged frames also
  841          * hold their node reference.
  842          */
  843         if (mstaged != NULL) {
  844                 ni->ni_tx_superg[WME_AC_TO_TID(pri)] = NULL;
  845                 stageq_remove(ic, sq, mstaged);
  846                 IEEE80211_FF_UNLOCK(ic);
  847 
  848                 IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
  849                     "%s: aggregate fast-frame", __func__);
  850                 /*
  851                  * Release the node reference; we only need
  852                  * the one already in mstaged.
  853                  */
  854                 KASSERT(mstaged->m_pkthdr.rcvif == (void *)ni,
  855                     ("rcvif %p ni %p", mstaged->m_pkthdr.rcvif, ni));
  856                 ieee80211_free_node(ni);
  857 
  858                 m->m_nextpkt = NULL;
  859                 mstaged->m_nextpkt = m;
  860                 mstaged->m_flags |= M_FF; /* NB: mark for encap work */
  861         } else {
  862                 KASSERT(ni->ni_tx_superg[WME_AC_TO_TID(pri)] == NULL,
  863                     ("ni_tx_superg[]: %p",
  864                     ni->ni_tx_superg[WME_AC_TO_TID(pri)]));
  865                 ni->ni_tx_superg[WME_AC_TO_TID(pri)] = m;
  866 
  867                 stageq_add(ic, sq, m);
  868                 IEEE80211_FF_UNLOCK(ic);
  869 
  870                 IEEE80211_NOTE(vap, IEEE80211_MSG_SUPERG, ni,
  871                     "%s: stage frame, %u queued", __func__, sq->depth);
  872                 /* NB: mstaged is NULL */
  873         }
  874         return mstaged;
  875 }
  876 
  877 struct mbuf *
  878 ieee80211_amsdu_check(struct ieee80211_node *ni, struct mbuf *m)
  879 {
  880         /*
  881          * XXX TODO: actually enforce the node support
  882          * and HTCAP requirements for the maximum A-MSDU
  883          * size.
  884          */
  885 
  886         /* First: software A-MSDU transmit? */
  887         if (! ieee80211_amsdu_tx_ok(ni))
  888                 return (m);
  889 
  890         /* Next - EAPOL? Nope, don't aggregate; we don't QoS encap them */
  891         if (m->m_flags & (M_EAPOL | M_MCAST | M_BCAST))
  892                 return (m);
  893 
  894         /* Next - needs to be a data frame, non-broadcast, etc */
  895         if (ETHER_IS_MULTICAST(mtod(m, struct ether_header *)->ether_dhost))
  896                 return (m);
  897 
  898         return (ieee80211_ff_check(ni, m));
  899 }
  900 
  901 void
  902 ieee80211_ff_node_init(struct ieee80211_node *ni)
  903 {
  904         /*
  905          * Clean FF state on re-associate.  This handles the case
  906          * where a station leaves w/o notifying us and then returns
  907          * before node is reaped for inactivity.
  908          */
  909         ieee80211_ff_node_cleanup(ni);
  910 }
  911 
  912 /*
  913  * Note: this comlock acquisition LORs with the node lock:
  914  *
  915  * 1: sta_join1 -> NODE_LOCK -> node_free -> node_cleanup -> ff_node_cleanup -> COM_LOCK
  916  * 2: TBD
  917  */
  918 void
  919 ieee80211_ff_node_cleanup(struct ieee80211_node *ni)
  920 {
  921         struct ieee80211com *ic = ni->ni_ic;
  922         struct ieee80211_superg *sg = ic->ic_superg;
  923         struct mbuf *m, *next_m, *head;
  924         int tid;
  925 
  926         IEEE80211_FF_LOCK(ic);
  927         head = NULL;
  928         for (tid = 0; tid < WME_NUM_TID; tid++) {
  929                 int ac = TID_TO_WME_AC(tid);
  930                 /*
  931                  * XXX Initialise the packet counter.
  932                  *
  933                  * This may be double-work for 11n stations;
  934                  * but without it we never setup things.
  935                  */
  936                 ieee80211_txampdu_init_pps(&ni->ni_tx_ampdu[tid]);
  937                 m = ni->ni_tx_superg[tid];
  938                 if (m != NULL) {
  939                         ni->ni_tx_superg[tid] = NULL;
  940                         stageq_remove(ic, &sg->ff_stageq[ac], m);
  941                         m->m_nextpkt = head;
  942                         head = m;
  943                 }
  944         }
  945         IEEE80211_FF_UNLOCK(ic);
  946 
  947         /*
  948          * Free mbufs, taking care to not dereference the mbuf after
  949          * we free it (hence grabbing m_nextpkt before we free it.)
  950          */
  951         m = head;
  952         while (m != NULL) {
  953                 next_m = m->m_nextpkt;
  954                 m_freem(m);
  955                 ieee80211_free_node(ni);
  956                 m = next_m;
  957         }
  958 }
  959 
  960 /*
  961  * Switch between turbo and non-turbo operating modes.
  962  * Use the specified channel flags to locate the new
  963  * channel, update 802.11 state, and then call back into
  964  * the driver to effect the change.
  965  */
  966 void
  967 ieee80211_dturbo_switch(struct ieee80211vap *vap, int newflags)
  968 {
  969         struct ieee80211com *ic = vap->iv_ic;
  970         struct ieee80211_channel *chan;
  971 
  972         chan = ieee80211_find_channel(ic, ic->ic_bsschan->ic_freq, newflags);
  973         if (chan == NULL) {             /* XXX should not happen */
  974                 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
  975                     "%s: no channel with freq %u flags 0x%x\n",
  976                     __func__, ic->ic_bsschan->ic_freq, newflags);
  977                 return;
  978         }
  979 
  980         IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG,
  981             "%s: %s -> %s (freq %u flags 0x%x)\n", __func__,
  982             ieee80211_phymode_name[ieee80211_chan2mode(ic->ic_bsschan)],
  983             ieee80211_phymode_name[ieee80211_chan2mode(chan)],
  984             chan->ic_freq, chan->ic_flags);
  985 
  986         ic->ic_bsschan = chan;
  987         ic->ic_prevchan = ic->ic_curchan;
  988         ic->ic_curchan = chan;
  989         ic->ic_rt = ieee80211_get_ratetable(chan);
  990         ic->ic_set_channel(ic);
  991         ieee80211_radiotap_chan_change(ic);
  992         /* NB: do not need to reset ERP state 'cuz we're in sta mode */
  993 }
  994 
  995 /*
  996  * Return the current ``state'' of an Atheros capbility.
  997  * If associated in station mode report the negotiated
  998  * setting. Otherwise report the current setting.
  999  */
 1000 static int
 1001 getathcap(struct ieee80211vap *vap, int cap)
 1002 {
 1003         if (vap->iv_opmode == IEEE80211_M_STA &&
 1004             vap->iv_state == IEEE80211_S_RUN)
 1005                 return IEEE80211_ATH_CAP(vap, vap->iv_bss, cap) != 0;
 1006         else
 1007                 return (vap->iv_flags & cap) != 0;
 1008 }
 1009 
 1010 static int
 1011 superg_ioctl_get80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
 1012 {
 1013         switch (ireq->i_type) {
 1014         case IEEE80211_IOC_FF:
 1015                 ireq->i_val = getathcap(vap, IEEE80211_F_FF);
 1016                 break;
 1017         case IEEE80211_IOC_TURBOP:
 1018                 ireq->i_val = getathcap(vap, IEEE80211_F_TURBOP);
 1019                 break;
 1020         default:
 1021                 return ENOSYS;
 1022         }
 1023         return 0;
 1024 }
 1025 IEEE80211_IOCTL_GET(superg, superg_ioctl_get80211);
 1026 
 1027 static int
 1028 superg_ioctl_set80211(struct ieee80211vap *vap, struct ieee80211req *ireq)
 1029 {
 1030         switch (ireq->i_type) {
 1031         case IEEE80211_IOC_FF:
 1032                 if (ireq->i_val) {
 1033                         if ((vap->iv_caps & IEEE80211_C_FF) == 0)
 1034                                 return EOPNOTSUPP;
 1035                         vap->iv_flags |= IEEE80211_F_FF;
 1036                 } else
 1037                         vap->iv_flags &= ~IEEE80211_F_FF;
 1038                 return ENETRESET;
 1039         case IEEE80211_IOC_TURBOP:
 1040                 if (ireq->i_val) {
 1041                         if ((vap->iv_caps & IEEE80211_C_TURBOP) == 0)
 1042                                 return EOPNOTSUPP;
 1043                         vap->iv_flags |= IEEE80211_F_TURBOP;
 1044                 } else
 1045                         vap->iv_flags &= ~IEEE80211_F_TURBOP;
 1046                 return ENETRESET;
 1047         default:
 1048                 return ENOSYS;
 1049         }
 1050 }
 1051 IEEE80211_IOCTL_SET(superg, superg_ioctl_set80211);
 1052 
 1053 #endif  /* IEEE80211_SUPPORT_SUPERG */

Cache object: d726d13f08d85fcda2dfc1b9012e44a4


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