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

Cache object: 6d946cf20343e56dcdc801a880a3abe1


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