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_freebsd.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) 2003-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$");
   28 
   29 /*
   30  * IEEE 802.11 support (FreeBSD-specific code)
   31  */
   32 #include "opt_wlan.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h> 
   36 #include <sys/eventhandler.h>
   37 #include <sys/kernel.h>
   38 #include <sys/linker.h>
   39 #include <sys/malloc.h>
   40 #include <sys/mbuf.h>   
   41 #include <sys/module.h>
   42 #include <sys/proc.h>
   43 #include <sys/sysctl.h>
   44 
   45 #include <sys/socket.h>
   46 
   47 #include <net/bpf.h>
   48 #include <net/if.h>
   49 #include <net/if_var.h>
   50 #include <net/if_dl.h>
   51 #include <net/if_clone.h>
   52 #include <net/if_media.h>
   53 #include <net/if_types.h>
   54 #include <net/ethernet.h>
   55 #include <net/route.h>
   56 #include <net/vnet.h>
   57 
   58 #include <net80211/ieee80211_var.h>
   59 #include <net80211/ieee80211_input.h>
   60 
   61 SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters");
   62 
   63 #ifdef IEEE80211_DEBUG
   64 static int      ieee80211_debug = 0;
   65 SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug,
   66             0, "debugging printfs");
   67 #endif
   68 
   69 static const char wlanname[] = "wlan";
   70 static struct if_clone *wlan_cloner;
   71 
   72 static int
   73 wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params)
   74 {
   75         struct ieee80211_clone_params cp;
   76         struct ieee80211vap *vap;
   77         struct ieee80211com *ic;
   78         int error;
   79 
   80         error = copyin(params, &cp, sizeof(cp));
   81         if (error)
   82                 return error;
   83         ic = ieee80211_find_com(cp.icp_parent);
   84         if (ic == NULL)
   85                 return ENXIO;
   86         if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) {
   87                 ic_printf(ic, "%s: invalid opmode %d\n", __func__,
   88                     cp.icp_opmode);
   89                 return EINVAL;
   90         }
   91         if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) {
   92                 ic_printf(ic, "%s mode not supported\n",
   93                     ieee80211_opmode_name[cp.icp_opmode]);
   94                 return EOPNOTSUPP;
   95         }
   96         if ((cp.icp_flags & IEEE80211_CLONE_TDMA) &&
   97 #ifdef IEEE80211_SUPPORT_TDMA
   98             (ic->ic_caps & IEEE80211_C_TDMA) == 0
   99 #else
  100             (1)
  101 #endif
  102         ) {
  103                 ic_printf(ic, "TDMA not supported\n");
  104                 return EOPNOTSUPP;
  105         }
  106         vap = ic->ic_vap_create(ic, wlanname, unit,
  107                         cp.icp_opmode, cp.icp_flags, cp.icp_bssid,
  108                         cp.icp_flags & IEEE80211_CLONE_MACADDR ?
  109                             cp.icp_macaddr : ic->ic_macaddr);
  110 
  111         return (vap == NULL ? EIO : 0);
  112 }
  113 
  114 static void
  115 wlan_clone_destroy(struct ifnet *ifp)
  116 {
  117         struct ieee80211vap *vap = ifp->if_softc;
  118         struct ieee80211com *ic = vap->iv_ic;
  119 
  120         ic->ic_vap_delete(vap);
  121 }
  122 
  123 void
  124 ieee80211_vap_destroy(struct ieee80211vap *vap)
  125 {
  126         CURVNET_SET(vap->iv_ifp->if_vnet);
  127         if_clone_destroyif(wlan_cloner, vap->iv_ifp);
  128         CURVNET_RESTORE();
  129 }
  130 
  131 int
  132 ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS)
  133 {
  134         int msecs = ticks_to_msecs(*(int *)arg1);
  135         int error, t;
  136 
  137         error = sysctl_handle_int(oidp, &msecs, 0, req);
  138         if (error || !req->newptr)
  139                 return error;
  140         t = msecs_to_ticks(msecs);
  141         *(int *)arg1 = (t < 1) ? 1 : t;
  142         return 0;
  143 }
  144 
  145 static int
  146 ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS)
  147 {
  148         int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT;
  149         int error;
  150 
  151         error = sysctl_handle_int(oidp, &inact, 0, req);
  152         if (error || !req->newptr)
  153                 return error;
  154         *(int *)arg1 = inact / IEEE80211_INACT_WAIT;
  155         return 0;
  156 }
  157 
  158 static int
  159 ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS)
  160 {
  161         struct ieee80211com *ic = arg1;
  162 
  163         return SYSCTL_OUT_STR(req, ic->ic_name);
  164 }
  165 
  166 static int
  167 ieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS)
  168 {
  169         struct ieee80211com *ic = arg1;
  170         int t = 0, error;
  171 
  172         error = sysctl_handle_int(oidp, &t, 0, req);
  173         if (error || !req->newptr)
  174                 return error;
  175         IEEE80211_LOCK(ic);
  176         ieee80211_dfs_notify_radar(ic, ic->ic_curchan);
  177         IEEE80211_UNLOCK(ic);
  178         return 0;
  179 }
  180 
  181 /*
  182  * For now, just restart everything.
  183  *
  184  * Later on, it'd be nice to have a separate VAP restart to
  185  * full-device restart.
  186  */
  187 static int
  188 ieee80211_sysctl_vap_restart(SYSCTL_HANDLER_ARGS)
  189 {
  190         struct ieee80211vap *vap = arg1;
  191         int t = 0, error;
  192 
  193         error = sysctl_handle_int(oidp, &t, 0, req);
  194         if (error || !req->newptr)
  195                 return error;
  196 
  197         ieee80211_restart_all(vap->iv_ic);
  198         return 0;
  199 }
  200 
  201 void
  202 ieee80211_sysctl_attach(struct ieee80211com *ic)
  203 {
  204 }
  205 
  206 void
  207 ieee80211_sysctl_detach(struct ieee80211com *ic)
  208 {
  209 }
  210 
  211 void
  212 ieee80211_sysctl_vattach(struct ieee80211vap *vap)
  213 {
  214         struct ifnet *ifp = vap->iv_ifp;
  215         struct sysctl_ctx_list *ctx;
  216         struct sysctl_oid *oid;
  217         char num[14];                   /* sufficient for 32 bits */
  218 
  219         ctx = (struct sysctl_ctx_list *) IEEE80211_MALLOC(sizeof(struct sysctl_ctx_list),
  220                 M_DEVBUF, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
  221         if (ctx == NULL) {
  222                 if_printf(ifp, "%s: cannot allocate sysctl context!\n",
  223                         __func__);
  224                 return;
  225         }
  226         sysctl_ctx_init(ctx);
  227         snprintf(num, sizeof(num), "%u", ifp->if_dunit);
  228         oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan),
  229                 OID_AUTO, num, CTLFLAG_RD, NULL, "");
  230         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  231                 "%parent", CTLTYPE_STRING | CTLFLAG_RD, vap->iv_ic, 0,
  232                 ieee80211_sysctl_parent, "A", "parent device");
  233         SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  234                 "driver_caps", CTLFLAG_RW, &vap->iv_caps, 0,
  235                 "driver capabilities");
  236 #ifdef IEEE80211_DEBUG
  237         vap->iv_debug = ieee80211_debug;
  238         SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  239                 "debug", CTLFLAG_RW, &vap->iv_debug, 0,
  240                 "control debugging printfs");
  241 #endif
  242         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  243                 "bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0,
  244                 "consecutive beacon misses before scanning");
  245         /* XXX inherit from tunables */
  246         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  247                 "inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0,
  248                 ieee80211_sysctl_inact, "I",
  249                 "station inactivity timeout (sec)");
  250         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  251                 "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0,
  252                 ieee80211_sysctl_inact, "I",
  253                 "station inactivity probe timeout (sec)");
  254         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  255                 "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0,
  256                 ieee80211_sysctl_inact, "I",
  257                 "station authentication timeout (sec)");
  258         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  259                 "inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0,
  260                 ieee80211_sysctl_inact, "I",
  261                 "station initial state timeout (sec)");
  262         if (vap->iv_htcaps & IEEE80211_HTC_HT) {
  263                 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  264                         "ampdu_mintraffic_bk", CTLFLAG_RW,
  265                         &vap->iv_ampdu_mintraffic[WME_AC_BK], 0,
  266                         "BK traffic tx aggr threshold (pps)");
  267                 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  268                         "ampdu_mintraffic_be", CTLFLAG_RW,
  269                         &vap->iv_ampdu_mintraffic[WME_AC_BE], 0,
  270                         "BE traffic tx aggr threshold (pps)");
  271                 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  272                         "ampdu_mintraffic_vo", CTLFLAG_RW,
  273                         &vap->iv_ampdu_mintraffic[WME_AC_VO], 0,
  274                         "VO traffic tx aggr threshold (pps)");
  275                 SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  276                         "ampdu_mintraffic_vi", CTLFLAG_RW,
  277                         &vap->iv_ampdu_mintraffic[WME_AC_VI], 0,
  278                         "VI traffic tx aggr threshold (pps)");
  279         }
  280 
  281         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  282                 "force_restart", CTLTYPE_INT | CTLFLAG_RW, vap, 0,
  283                 ieee80211_sysctl_vap_restart, "I",
  284                 "force a VAP restart");
  285 
  286         if (vap->iv_caps & IEEE80211_C_DFS) {
  287                 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  288                         "radar", CTLTYPE_INT | CTLFLAG_RW, vap->iv_ic, 0,
  289                         ieee80211_sysctl_radar, "I", "simulate radar event");
  290         }
  291         vap->iv_sysctl = ctx;
  292         vap->iv_oid = oid;
  293 }
  294 
  295 void
  296 ieee80211_sysctl_vdetach(struct ieee80211vap *vap)
  297 {
  298 
  299         if (vap->iv_sysctl != NULL) {
  300                 sysctl_ctx_free(vap->iv_sysctl);
  301                 IEEE80211_FREE(vap->iv_sysctl, M_DEVBUF);
  302                 vap->iv_sysctl = NULL;
  303         }
  304 }
  305 
  306 #define MS(_v, _f)      (((_v) & _f##_M) >> _f##_S)
  307 int
  308 ieee80211_com_vincref(struct ieee80211vap *vap)
  309 {
  310         uint32_t ostate;
  311 
  312         ostate = atomic_fetchadd_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
  313 
  314         if (ostate & IEEE80211_COM_DETACHED) {
  315                 atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
  316                 return (ENETDOWN);
  317         }
  318 
  319         if (MS(ostate, IEEE80211_COM_REF) == IEEE80211_COM_REF_MAX) {
  320                 atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD);
  321                 return (EOVERFLOW);
  322         }
  323 
  324         return (0);
  325 }
  326 
  327 void
  328 ieee80211_com_vdecref(struct ieee80211vap *vap)
  329 {
  330         uint32_t ostate;
  331 
  332         ostate = atomic_fetchadd_32(&vap->iv_com_state, -IEEE80211_COM_REF_ADD);
  333 
  334         KASSERT(MS(ostate, IEEE80211_COM_REF) != 0,
  335             ("com reference counter underflow"));
  336 
  337         (void) ostate;
  338 }
  339 
  340 void
  341 ieee80211_com_vdetach(struct ieee80211vap *vap)
  342 {
  343         int sleep_time;
  344 
  345         sleep_time = msecs_to_ticks(250);
  346         if (sleep_time == 0)
  347                 sleep_time = 1;
  348 
  349         atomic_set_32(&vap->iv_com_state, IEEE80211_COM_DETACHED);
  350         while (MS(atomic_load_32(&vap->iv_com_state), IEEE80211_COM_REF) != 0)
  351                 pause("comref", sleep_time);
  352 }
  353 #undef  MS
  354 
  355 int
  356 ieee80211_node_dectestref(struct ieee80211_node *ni)
  357 {
  358         /* XXX need equivalent of atomic_dec_and_test */
  359         atomic_subtract_int(&ni->ni_refcnt, 1);
  360         return atomic_cmpset_int(&ni->ni_refcnt, 0, 1);
  361 }
  362 
  363 void
  364 ieee80211_drain_ifq(struct ifqueue *ifq)
  365 {
  366         struct ieee80211_node *ni;
  367         struct mbuf *m;
  368 
  369         for (;;) {
  370                 IF_DEQUEUE(ifq, m);
  371                 if (m == NULL)
  372                         break;
  373 
  374                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
  375                 KASSERT(ni != NULL, ("frame w/o node"));
  376                 ieee80211_free_node(ni);
  377                 m->m_pkthdr.rcvif = NULL;
  378 
  379                 m_freem(m);
  380         }
  381 }
  382 
  383 void
  384 ieee80211_flush_ifq(struct ifqueue *ifq, struct ieee80211vap *vap)
  385 {
  386         struct ieee80211_node *ni;
  387         struct mbuf *m, **mprev;
  388 
  389         IF_LOCK(ifq);
  390         mprev = &ifq->ifq_head;
  391         while ((m = *mprev) != NULL) {
  392                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
  393                 if (ni != NULL && ni->ni_vap == vap) {
  394                         *mprev = m->m_nextpkt;          /* remove from list */
  395                         ifq->ifq_len--;
  396 
  397                         m_freem(m);
  398                         ieee80211_free_node(ni);        /* reclaim ref */
  399                 } else
  400                         mprev = &m->m_nextpkt;
  401         }
  402         /* recalculate tail ptr */
  403         m = ifq->ifq_head;
  404         for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt)
  405                 ;
  406         ifq->ifq_tail = m;
  407         IF_UNLOCK(ifq);
  408 }
  409 
  410 /*
  411  * As above, for mbufs allocated with m_gethdr/MGETHDR
  412  * or initialized by M_COPY_PKTHDR.
  413  */
  414 #define MC_ALIGN(m, len)                                                \
  415 do {                                                                    \
  416         (m)->m_data += rounddown2(MCLBYTES - (len), sizeof(long));      \
  417 } while (/* CONSTCOND */ 0)
  418 
  419 /*
  420  * Allocate and setup a management frame of the specified
  421  * size.  We return the mbuf and a pointer to the start
  422  * of the contiguous data area that's been reserved based
  423  * on the packet length.  The data area is forced to 32-bit
  424  * alignment and the buffer length to a multiple of 4 bytes.
  425  * This is done mainly so beacon frames (that require this)
  426  * can use this interface too.
  427  */
  428 struct mbuf *
  429 ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
  430 {
  431         struct mbuf *m;
  432         u_int len;
  433 
  434         /*
  435          * NB: we know the mbuf routines will align the data area
  436          *     so we don't need to do anything special.
  437          */
  438         len = roundup2(headroom + pktlen, 4);
  439         KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
  440         if (len < MINCLSIZE) {
  441                 m = m_gethdr(M_NOWAIT, MT_DATA);
  442                 /*
  443                  * Align the data in case additional headers are added.
  444                  * This should only happen when a WEP header is added
  445                  * which only happens for shared key authentication mgt
  446                  * frames which all fit in MHLEN.
  447                  */
  448                 if (m != NULL)
  449                         M_ALIGN(m, len);
  450         } else {
  451                 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
  452                 if (m != NULL)
  453                         MC_ALIGN(m, len);
  454         }
  455         if (m != NULL) {
  456                 m->m_data += headroom;
  457                 *frm = m->m_data;
  458         }
  459         return m;
  460 }
  461 
  462 #ifndef __NO_STRICT_ALIGNMENT
  463 /*
  464  * Re-align the payload in the mbuf.  This is mainly used (right now)
  465  * to handle IP header alignment requirements on certain architectures.
  466  */
  467 struct mbuf *
  468 ieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align)
  469 {
  470         int pktlen, space;
  471         struct mbuf *n;
  472 
  473         pktlen = m->m_pkthdr.len;
  474         space = pktlen + align;
  475         if (space < MINCLSIZE)
  476                 n = m_gethdr(M_NOWAIT, MT_DATA);
  477         else {
  478                 n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR,
  479                     space <= MCLBYTES ?     MCLBYTES :
  480 #if MJUMPAGESIZE != MCLBYTES
  481                     space <= MJUMPAGESIZE ? MJUMPAGESIZE :
  482 #endif
  483                     space <= MJUM9BYTES ?   MJUM9BYTES : MJUM16BYTES);
  484         }
  485         if (__predict_true(n != NULL)) {
  486                 m_move_pkthdr(n, m);
  487                 n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align);
  488                 m_copydata(m, 0, pktlen, mtod(n, caddr_t));
  489                 n->m_len = pktlen;
  490         } else {
  491                 IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY,
  492                     mtod(m, const struct ieee80211_frame *), NULL,
  493                     "%s", "no mbuf to realign");
  494                 vap->iv_stats.is_rx_badalign++;
  495         }
  496         m_freem(m);
  497         return n;
  498 }
  499 #endif /* !__NO_STRICT_ALIGNMENT */
  500 
  501 int
  502 ieee80211_add_callback(struct mbuf *m,
  503         void (*func)(struct ieee80211_node *, void *, int), void *arg)
  504 {
  505         struct m_tag *mtag;
  506         struct ieee80211_cb *cb;
  507 
  508         mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK,
  509                         sizeof(struct ieee80211_cb), M_NOWAIT);
  510         if (mtag == NULL)
  511                 return 0;
  512 
  513         cb = (struct ieee80211_cb *)(mtag+1);
  514         cb->func = func;
  515         cb->arg = arg;
  516         m_tag_prepend(m, mtag);
  517         m->m_flags |= M_TXCB;
  518         return 1;
  519 }
  520 
  521 int
  522 ieee80211_add_xmit_params(struct mbuf *m,
  523     const struct ieee80211_bpf_params *params)
  524 {
  525         struct m_tag *mtag;
  526         struct ieee80211_tx_params *tx;
  527 
  528         mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
  529             sizeof(struct ieee80211_tx_params), M_NOWAIT);
  530         if (mtag == NULL)
  531                 return (0);
  532 
  533         tx = (struct ieee80211_tx_params *)(mtag+1);
  534         memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params));
  535         m_tag_prepend(m, mtag);
  536         return (1);
  537 }
  538 
  539 int
  540 ieee80211_get_xmit_params(struct mbuf *m,
  541     struct ieee80211_bpf_params *params)
  542 {
  543         struct m_tag *mtag;
  544         struct ieee80211_tx_params *tx;
  545 
  546         mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS,
  547             NULL);
  548         if (mtag == NULL)
  549                 return (-1);
  550         tx = (struct ieee80211_tx_params *)(mtag + 1);
  551         memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params));
  552         return (0);
  553 }
  554 
  555 void
  556 ieee80211_process_callback(struct ieee80211_node *ni,
  557         struct mbuf *m, int status)
  558 {
  559         struct m_tag *mtag;
  560 
  561         mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL);
  562         if (mtag != NULL) {
  563                 struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1);
  564                 cb->func(ni, cb->arg, status);
  565         }
  566 }
  567 
  568 /*
  569  * Add RX parameters to the given mbuf.
  570  *
  571  * Returns 1 if OK, 0 on error.
  572  */
  573 int
  574 ieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs)
  575 {
  576         struct m_tag *mtag;
  577         struct ieee80211_rx_params *rx;
  578 
  579         mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
  580             sizeof(struct ieee80211_rx_stats), M_NOWAIT);
  581         if (mtag == NULL)
  582                 return (0);
  583 
  584         rx = (struct ieee80211_rx_params *)(mtag + 1);
  585         memcpy(&rx->params, rxs, sizeof(*rxs));
  586         m_tag_prepend(m, mtag);
  587         return (1);
  588 }
  589 
  590 int
  591 ieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs)
  592 {
  593         struct m_tag *mtag;
  594         struct ieee80211_rx_params *rx;
  595 
  596         mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS,
  597             NULL);
  598         if (mtag == NULL)
  599                 return (-1);
  600         rx = (struct ieee80211_rx_params *)(mtag + 1);
  601         memcpy(rxs, &rx->params, sizeof(*rxs));
  602         return (0);
  603 }
  604 
  605 /*
  606  * Transmit a frame to the parent interface.
  607  */
  608 int
  609 ieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m)
  610 {
  611         int error;
  612 
  613         /*
  614          * Assert the IC TX lock is held - this enforces the
  615          * processing -> queuing order is maintained
  616          */
  617         IEEE80211_TX_LOCK_ASSERT(ic);
  618         error = ic->ic_transmit(ic, m);
  619         if (error) {
  620                 struct ieee80211_node *ni;
  621 
  622                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
  623 
  624                 /* XXX number of fragments */
  625                 if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1);
  626                 ieee80211_free_node(ni);
  627                 ieee80211_free_mbuf(m);
  628         }
  629         return (error);
  630 }
  631 
  632 /*
  633  * Transmit a frame to the VAP interface.
  634  */
  635 int
  636 ieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m)
  637 {
  638         struct ifnet *ifp = vap->iv_ifp;
  639 
  640         /*
  641          * When transmitting via the VAP, we shouldn't hold
  642          * any IC TX lock as the VAP TX path will acquire it.
  643          */
  644         IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic);
  645 
  646         return (ifp->if_transmit(ifp, m));
  647 
  648 }
  649 
  650 #include <sys/libkern.h>
  651 
  652 void
  653 get_random_bytes(void *p, size_t n)
  654 {
  655         uint8_t *dp = p;
  656 
  657         while (n > 0) {
  658                 uint32_t v = arc4random();
  659                 size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
  660                 bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
  661                 dp += sizeof(uint32_t), n -= nb;
  662         }
  663 }
  664 
  665 /*
  666  * Helper function for events that pass just a single mac address.
  667  */
  668 static void
  669 notify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN])
  670 {
  671         struct ieee80211_join_event iev;
  672 
  673         CURVNET_SET(ifp->if_vnet);
  674         memset(&iev, 0, sizeof(iev));
  675         IEEE80211_ADDR_COPY(iev.iev_addr, mac);
  676         rt_ieee80211msg(ifp, op, &iev, sizeof(iev));
  677         CURVNET_RESTORE();
  678 }
  679 
  680 void
  681 ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc)
  682 {
  683         struct ieee80211vap *vap = ni->ni_vap;
  684         struct ifnet *ifp = vap->iv_ifp;
  685 
  686         CURVNET_SET_QUIET(ifp->if_vnet);
  687         IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join",
  688             (ni == vap->iv_bss) ? "bss " : "");
  689 
  690         if (ni == vap->iv_bss) {
  691                 notify_macaddr(ifp, newassoc ?
  692                     RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid);
  693                 if_link_state_change(ifp, LINK_STATE_UP);
  694         } else {
  695                 notify_macaddr(ifp, newassoc ?
  696                     RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr);
  697         }
  698         CURVNET_RESTORE();
  699 }
  700 
  701 void
  702 ieee80211_notify_node_leave(struct ieee80211_node *ni)
  703 {
  704         struct ieee80211vap *vap = ni->ni_vap;
  705         struct ifnet *ifp = vap->iv_ifp;
  706 
  707         CURVNET_SET_QUIET(ifp->if_vnet);
  708         IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave",
  709             (ni == vap->iv_bss) ? "bss " : "");
  710 
  711         if (ni == vap->iv_bss) {
  712                 rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
  713                 if_link_state_change(ifp, LINK_STATE_DOWN);
  714         } else {
  715                 /* fire off wireless event station leaving */
  716                 notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr);
  717         }
  718         CURVNET_RESTORE();
  719 }
  720 
  721 void
  722 ieee80211_notify_scan_done(struct ieee80211vap *vap)
  723 {
  724         struct ifnet *ifp = vap->iv_ifp;
  725 
  726         IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done");
  727 
  728         /* dispatch wireless event indicating scan completed */
  729         CURVNET_SET(ifp->if_vnet);
  730         rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
  731         CURVNET_RESTORE();
  732 }
  733 
  734 void
  735 ieee80211_notify_replay_failure(struct ieee80211vap *vap,
  736         const struct ieee80211_frame *wh, const struct ieee80211_key *k,
  737         u_int64_t rsc, int tid)
  738 {
  739         struct ifnet *ifp = vap->iv_ifp;
  740 
  741         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
  742             "%s replay detected tid %d <rsc %ju, csc %ju, keyix %u rxkeyix %u>",
  743             k->wk_cipher->ic_name, tid, (intmax_t) rsc,
  744             (intmax_t) k->wk_keyrsc[tid],
  745             k->wk_keyix, k->wk_rxkeyix);
  746 
  747         if (ifp != NULL) {              /* NB: for cipher test modules */
  748                 struct ieee80211_replay_event iev;
  749 
  750                 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
  751                 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
  752                 iev.iev_cipher = k->wk_cipher->ic_cipher;
  753                 if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
  754                         iev.iev_keyix = k->wk_rxkeyix;
  755                 else
  756                         iev.iev_keyix = k->wk_keyix;
  757                 iev.iev_keyrsc = k->wk_keyrsc[tid];
  758                 iev.iev_rsc = rsc;
  759                 CURVNET_SET(ifp->if_vnet);
  760                 rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
  761                 CURVNET_RESTORE();
  762         }
  763 }
  764 
  765 void
  766 ieee80211_notify_michael_failure(struct ieee80211vap *vap,
  767         const struct ieee80211_frame *wh, u_int keyix)
  768 {
  769         struct ifnet *ifp = vap->iv_ifp;
  770 
  771         IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2,
  772             "michael MIC verification failed <keyix %u>", keyix);
  773         vap->iv_stats.is_rx_tkipmic++;
  774 
  775         if (ifp != NULL) {              /* NB: for cipher test modules */
  776                 struct ieee80211_michael_event iev;
  777 
  778                 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
  779                 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
  780                 iev.iev_cipher = IEEE80211_CIPHER_TKIP;
  781                 iev.iev_keyix = keyix;
  782                 CURVNET_SET(ifp->if_vnet);
  783                 rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
  784                 CURVNET_RESTORE();
  785         }
  786 }
  787 
  788 void
  789 ieee80211_notify_wds_discover(struct ieee80211_node *ni)
  790 {
  791         struct ieee80211vap *vap = ni->ni_vap;
  792         struct ifnet *ifp = vap->iv_ifp;
  793 
  794         notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr);
  795 }
  796 
  797 void
  798 ieee80211_notify_csa(struct ieee80211com *ic,
  799         const struct ieee80211_channel *c, int mode, int count)
  800 {
  801         struct ieee80211_csa_event iev;
  802         struct ieee80211vap *vap;
  803         struct ifnet *ifp;
  804 
  805         memset(&iev, 0, sizeof(iev));
  806         iev.iev_flags = c->ic_flags;
  807         iev.iev_freq = c->ic_freq;
  808         iev.iev_ieee = c->ic_ieee;
  809         iev.iev_mode = mode;
  810         iev.iev_count = count;
  811         TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
  812                 ifp = vap->iv_ifp;
  813                 CURVNET_SET(ifp->if_vnet);
  814                 rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev));
  815                 CURVNET_RESTORE();
  816         }
  817 }
  818 
  819 void
  820 ieee80211_notify_radar(struct ieee80211com *ic,
  821         const struct ieee80211_channel *c)
  822 {
  823         struct ieee80211_radar_event iev;
  824         struct ieee80211vap *vap;
  825         struct ifnet *ifp;
  826 
  827         memset(&iev, 0, sizeof(iev));
  828         iev.iev_flags = c->ic_flags;
  829         iev.iev_freq = c->ic_freq;
  830         iev.iev_ieee = c->ic_ieee;
  831         TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
  832                 ifp = vap->iv_ifp;
  833                 CURVNET_SET(ifp->if_vnet);
  834                 rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev));
  835                 CURVNET_RESTORE();
  836         }
  837 }
  838 
  839 void
  840 ieee80211_notify_cac(struct ieee80211com *ic,
  841         const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type)
  842 {
  843         struct ieee80211_cac_event iev;
  844         struct ieee80211vap *vap;
  845         struct ifnet *ifp;
  846 
  847         memset(&iev, 0, sizeof(iev));
  848         iev.iev_flags = c->ic_flags;
  849         iev.iev_freq = c->ic_freq;
  850         iev.iev_ieee = c->ic_ieee;
  851         iev.iev_type = type;
  852         TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
  853                 ifp = vap->iv_ifp;
  854                 CURVNET_SET(ifp->if_vnet);
  855                 rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev));
  856                 CURVNET_RESTORE();
  857         }
  858 }
  859 
  860 void
  861 ieee80211_notify_node_deauth(struct ieee80211_node *ni)
  862 {
  863         struct ieee80211vap *vap = ni->ni_vap;
  864         struct ifnet *ifp = vap->iv_ifp;
  865 
  866         IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth");
  867 
  868         notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr);
  869 }
  870 
  871 void
  872 ieee80211_notify_node_auth(struct ieee80211_node *ni)
  873 {
  874         struct ieee80211vap *vap = ni->ni_vap;
  875         struct ifnet *ifp = vap->iv_ifp;
  876 
  877         IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth");
  878 
  879         notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr);
  880 }
  881 
  882 void
  883 ieee80211_notify_country(struct ieee80211vap *vap,
  884         const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2])
  885 {
  886         struct ifnet *ifp = vap->iv_ifp;
  887         struct ieee80211_country_event iev;
  888 
  889         memset(&iev, 0, sizeof(iev));
  890         IEEE80211_ADDR_COPY(iev.iev_addr, bssid);
  891         iev.iev_cc[0] = cc[0];
  892         iev.iev_cc[1] = cc[1];
  893         CURVNET_SET(ifp->if_vnet);
  894         rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev));
  895         CURVNET_RESTORE();
  896 }
  897 
  898 void
  899 ieee80211_notify_radio(struct ieee80211com *ic, int state)
  900 {
  901         struct ieee80211_radio_event iev;
  902         struct ieee80211vap *vap;
  903         struct ifnet *ifp;
  904 
  905         memset(&iev, 0, sizeof(iev));
  906         iev.iev_state = state;
  907         TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) {
  908                 ifp = vap->iv_ifp;
  909                 CURVNET_SET(ifp->if_vnet);
  910                 rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev));
  911                 CURVNET_RESTORE();
  912         }
  913 }
  914 
  915 void
  916 ieee80211_load_module(const char *modname)
  917 {
  918 
  919 #ifdef notyet
  920         (void)kern_kldload(curthread, modname, NULL);
  921 #else
  922         printf("%s: load the %s module by hand for now.\n", __func__, modname);
  923 #endif
  924 }
  925 
  926 static eventhandler_tag wlan_bpfevent;
  927 static eventhandler_tag wlan_ifllevent;
  928 
  929 static void
  930 bpf_track(void *arg, struct ifnet *ifp, int dlt, int attach)
  931 {
  932         /* NB: identify vap's by if_init */
  933         if (dlt == DLT_IEEE802_11_RADIO &&
  934             ifp->if_init == ieee80211_init) {
  935                 struct ieee80211vap *vap = ifp->if_softc;
  936                 /*
  937                  * Track bpf radiotap listener state.  We mark the vap
  938                  * to indicate if any listener is present and the com
  939                  * to indicate if any listener exists on any associated
  940                  * vap.  This flag is used by drivers to prepare radiotap
  941                  * state only when needed.
  942                  */
  943                 if (attach) {
  944                         ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF);
  945                         if (vap->iv_opmode == IEEE80211_M_MONITOR)
  946                                 atomic_add_int(&vap->iv_ic->ic_montaps, 1);
  947                 } else if (!bpf_peers_present(vap->iv_rawbpf)) {
  948                         ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF);
  949                         if (vap->iv_opmode == IEEE80211_M_MONITOR)
  950                                 atomic_subtract_int(&vap->iv_ic->ic_montaps, 1);
  951                 }
  952         }
  953 }
  954 
  955 /*
  956  * Change MAC address on the vap (if was not started).
  957  */
  958 static void
  959 wlan_iflladdr(void *arg __unused, struct ifnet *ifp)
  960 {
  961         /* NB: identify vap's by if_init */
  962         if (ifp->if_init == ieee80211_init &&
  963             (ifp->if_flags & IFF_UP) == 0) {
  964                 struct ieee80211vap *vap = ifp->if_softc;
  965 
  966                 IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp));
  967         }
  968 }
  969 
  970 /*
  971  * Module glue.
  972  *
  973  * NB: the module name is "wlan" for compatibility with NetBSD.
  974  */
  975 static int
  976 wlan_modevent(module_t mod, int type, void *unused)
  977 {
  978         switch (type) {
  979         case MOD_LOAD:
  980                 if (bootverbose)
  981                         printf("wlan: <802.11 Link Layer>\n");
  982                 wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track,
  983                     bpf_track, 0, EVENTHANDLER_PRI_ANY);
  984                 wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event,
  985                     wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY);
  986                 wlan_cloner = if_clone_simple(wlanname, wlan_clone_create,
  987                     wlan_clone_destroy, 0);
  988                 return 0;
  989         case MOD_UNLOAD:
  990                 if_clone_detach(wlan_cloner);
  991                 EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent);
  992                 EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent);
  993                 return 0;
  994         }
  995         return EINVAL;
  996 }
  997 
  998 static moduledata_t wlan_mod = {
  999         wlanname,
 1000         wlan_modevent,
 1001         0
 1002 };
 1003 DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
 1004 MODULE_VERSION(wlan, 1);
 1005 MODULE_DEPEND(wlan, ether, 1, 1, 1);
 1006 #ifdef  IEEE80211_ALQ
 1007 MODULE_DEPEND(wlan, alq, 1, 1, 1);
 1008 #endif  /* IEEE80211_ALQ */
 1009 

Cache object: e7b01928fb10d0eda51a2c62ba0513a9


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