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

Cache object: bd1edfdb11f3f5f1aa23b051b0437286


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