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

Cache object: 0927eb03ec5068d61574de7e4923e7ed


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