The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/net80211/ieee80211_freebsd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2003-2007 Sam Leffler, Errno Consulting
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   24  */
   25 
   26 #include <sys/cdefs.h>
   27 __FBSDID("$FreeBSD: releng/7.3/sys/net80211/ieee80211_freebsd.c 173553 2007-11-11 17:44:36Z sam $");
   28 
   29 /*
   30  * IEEE 802.11 support (FreeBSD-specific code)
   31  */
   32 #include <sys/param.h>
   33 #include <sys/kernel.h>
   34 #include <sys/systm.h> 
   35 #include <sys/linker.h>
   36 #include <sys/mbuf.h>   
   37 #include <sys/module.h>
   38 #include <sys/proc.h>
   39 #include <sys/sysctl.h>
   40 
   41 #include <sys/socket.h>
   42 
   43 #include <net/if.h>
   44 #include <net/if_media.h>
   45 #include <net/ethernet.h>
   46 #include <net/route.h>
   47 
   48 #include <net80211/ieee80211_var.h>
   49 
   50 SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters");
   51 
   52 #ifdef IEEE80211_DEBUG
   53 int     ieee80211_debug = 0;
   54 SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug,
   55             0, "debugging printfs");
   56 #endif
   57 extern int ieee80211_recv_bar_ena;
   58 SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena,
   59             0, "BAR frame processing (ena/dis)");
   60 
   61 #ifdef IEEE80211_AMPDU_AGE
   62 static int
   63 ieee80211_sysctl_ampdu_age(SYSCTL_HANDLER_ARGS)
   64 {
   65         extern int ieee80211_ampdu_age;
   66         int ampdu_age = ticks_to_msecs(ieee80211_ampdu_age);
   67         int error;
   68 
   69         error = sysctl_handle_int(oidp, &ampdu_age, 0, req);
   70         if (error || !req->newptr)
   71                 return error;
   72         ieee80211_ampdu_age = msecs_to_ticks(ampdu_age);
   73         return 0;
   74 }
   75 SYSCTL_PROC(_net_wlan, OID_AUTO, "ampdu_age", CTLFLAG_RW, NULL, 0,
   76         ieee80211_sysctl_ampdu_age, "A", "AMPDU max reorder age (ms)");
   77 #endif
   78 
   79 static int
   80 ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS)
   81 {
   82         int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT;
   83         int error;
   84 
   85         error = sysctl_handle_int(oidp, &inact, 0, req);
   86         if (error || !req->newptr)
   87                 return error;
   88         *(int *)arg1 = inact / IEEE80211_INACT_WAIT;
   89         return 0;
   90 }
   91 
   92 static int
   93 ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS)
   94 {
   95         struct ieee80211com *ic = arg1;
   96         const char *name = ic->ic_ifp->if_xname;
   97 
   98         return SYSCTL_OUT(req, name, strlen(name));
   99 }
  100 
  101 void
  102 ieee80211_sysctl_attach(struct ieee80211com *ic)
  103 {
  104         struct sysctl_ctx_list *ctx;
  105         struct sysctl_oid *oid;
  106         char num[14];                   /* sufficient for 32 bits */
  107 
  108         MALLOC(ctx, struct sysctl_ctx_list *, sizeof(struct sysctl_ctx_list),
  109                 M_DEVBUF, M_NOWAIT | M_ZERO);
  110         if (ctx == NULL) {
  111                 if_printf(ic->ic_ifp, "%s: cannot allocate sysctl context!\n",
  112                         __func__);
  113                 return;
  114         }
  115         sysctl_ctx_init(ctx);
  116         snprintf(num, sizeof(num), "%u", ic->ic_vap);
  117         oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan),
  118                 OID_AUTO, num, CTLFLAG_RD, NULL, "");
  119         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  120                 "%parent", CTLFLAG_RD, ic, 0, ieee80211_sysctl_parent, "A",
  121                 "parent device");
  122 #ifdef IEEE80211_DEBUG
  123         ic->ic_debug = ieee80211_debug;
  124         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  125                 "debug", CTLFLAG_RW, &ic->ic_debug, 0,
  126                 "control debugging printfs");
  127 #endif
  128         /* XXX inherit from tunables */
  129         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  130                 "inact_run", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_run, 0,
  131                 ieee80211_sysctl_inact, "I",
  132                 "station inactivity timeout (sec)");
  133         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  134                 "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_probe, 0,
  135                 ieee80211_sysctl_inact, "I",
  136                 "station inactivity probe timeout (sec)");
  137         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  138                 "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_auth, 0,
  139                 ieee80211_sysctl_inact, "I",
  140                 "station authentication timeout (sec)");
  141         SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  142                 "inact_init", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_init, 0,
  143                 ieee80211_sysctl_inact, "I",
  144                 "station initial state timeout (sec)");
  145         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  146                 "driver_caps", CTLFLAG_RW, &ic->ic_caps, 0,
  147                 "driver capabilities");
  148         SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO,
  149                 "bmiss_max", CTLFLAG_RW, &ic->ic_bmiss_max, 0,
  150                 "consecutive beacon misses before scanning");
  151         ic->ic_sysctl = ctx;
  152 }
  153 
  154 void
  155 ieee80211_sysctl_detach(struct ieee80211com *ic)
  156 {
  157 
  158         if (ic->ic_sysctl != NULL) {
  159                 sysctl_ctx_free(ic->ic_sysctl);
  160                 FREE(ic->ic_sysctl, M_DEVBUF);
  161                 ic->ic_sysctl = NULL;
  162         }
  163 }
  164 
  165 int
  166 ieee80211_node_dectestref(struct ieee80211_node *ni)
  167 {
  168         /* XXX need equivalent of atomic_dec_and_test */
  169         atomic_subtract_int(&ni->ni_refcnt, 1);
  170         return atomic_cmpset_int(&ni->ni_refcnt, 0, 1);
  171 }
  172 
  173 void
  174 ieee80211_drain_ifq(struct ifqueue *ifq)
  175 {
  176         struct ieee80211_node *ni;
  177         struct mbuf *m;
  178 
  179         for (;;) {
  180                 IF_DEQUEUE(ifq, m);
  181                 if (m == NULL)
  182                         break;
  183 
  184                 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif;
  185                 KASSERT(ni != NULL, ("frame w/o node"));
  186                 ieee80211_free_node(ni);
  187                 m->m_pkthdr.rcvif = NULL;
  188 
  189                 m_freem(m);
  190         }
  191 }
  192 
  193 /*
  194  * As above, for mbufs allocated with m_gethdr/MGETHDR
  195  * or initialized by M_COPY_PKTHDR.
  196  */
  197 #define MC_ALIGN(m, len)                                                \
  198 do {                                                                    \
  199         (m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1);        \
  200 } while (/* CONSTCOND */ 0)
  201 
  202 /*
  203  * Allocate and setup a management frame of the specified
  204  * size.  We return the mbuf and a pointer to the start
  205  * of the contiguous data area that's been reserved based
  206  * on the packet length.  The data area is forced to 32-bit
  207  * alignment and the buffer length to a multiple of 4 bytes.
  208  * This is done mainly so beacon frames (that require this)
  209  * can use this interface too.
  210  */
  211 struct mbuf *
  212 ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen)
  213 {
  214         struct mbuf *m;
  215         u_int len;
  216 
  217         /*
  218          * NB: we know the mbuf routines will align the data area
  219          *     so we don't need to do anything special.
  220          */
  221         len = roundup2(headroom + pktlen, 4);
  222         KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len));
  223         if (len < MINCLSIZE) {
  224                 m = m_gethdr(M_NOWAIT, MT_DATA);
  225                 /*
  226                  * Align the data in case additional headers are added.
  227                  * This should only happen when a WEP header is added
  228                  * which only happens for shared key authentication mgt
  229                  * frames which all fit in MHLEN.
  230                  */
  231                 if (m != NULL)
  232                         MH_ALIGN(m, len);
  233         } else {
  234                 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
  235                 if (m != NULL)
  236                         MC_ALIGN(m, len);
  237         }
  238         if (m != NULL) {
  239                 m->m_data += headroom;
  240                 *frm = m->m_data;
  241         }
  242         return m;
  243 }
  244 
  245 int
  246 ieee80211_add_callback(struct mbuf *m,
  247         void (*func)(struct ieee80211_node *, void *, int), void *arg)
  248 {
  249         struct m_tag *mtag;
  250         struct ieee80211_cb *cb;
  251 
  252         mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK,
  253                         sizeof(struct ieee80211_cb), M_NOWAIT);
  254         if (mtag == NULL)
  255                 return 0;
  256 
  257         cb = (struct ieee80211_cb *)(mtag+1);
  258         cb->func = func;
  259         cb->arg = arg;
  260         m_tag_prepend(m, mtag);
  261         m->m_flags |= M_TXCB;
  262         return 1;
  263 }
  264 
  265 void
  266 ieee80211_process_callback(struct ieee80211_node *ni,
  267         struct mbuf *m, int status)
  268 {
  269         struct m_tag *mtag;
  270 
  271         mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL);
  272         if (mtag != NULL) {
  273                 struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1);
  274                 cb->func(ni, cb->arg, status);
  275         }
  276 }
  277 
  278 #include <sys/libkern.h>
  279 
  280 void
  281 get_random_bytes(void *p, size_t n)
  282 {
  283         uint8_t *dp = p;
  284 
  285         while (n > 0) {
  286                 uint32_t v = arc4random();
  287                 size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n;
  288                 bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n);
  289                 dp += sizeof(uint32_t), n -= nb;
  290         }
  291 }
  292 
  293 void
  294 ieee80211_notify_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int newassoc)
  295 {
  296         struct ifnet *ifp = ic->ic_ifp;
  297         struct ieee80211_join_event iev;
  298 
  299         memset(&iev, 0, sizeof(iev));
  300         if (ni == ic->ic_bss) {
  301                 IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_bssid);
  302                 rt_ieee80211msg(ifp, newassoc ?
  303                         RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC,
  304                         &iev, sizeof(iev));
  305                 if_link_state_change(ifp, LINK_STATE_UP);
  306         } else {
  307                 IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr);
  308                 rt_ieee80211msg(ifp, newassoc ?
  309                         RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN,
  310                         &iev, sizeof(iev));
  311         }
  312 }
  313 
  314 void
  315 ieee80211_notify_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni)
  316 {
  317         struct ifnet *ifp = ic->ic_ifp;
  318         struct ieee80211_leave_event iev;
  319 
  320         if (ni == ic->ic_bss) {
  321                 rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0);
  322                 if_link_state_change(ifp, LINK_STATE_DOWN);
  323         } else {
  324                 /* fire off wireless event station leaving */
  325                 memset(&iev, 0, sizeof(iev));
  326                 IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr);
  327                 rt_ieee80211msg(ifp, RTM_IEEE80211_LEAVE, &iev, sizeof(iev));
  328         }
  329 }
  330 
  331 void
  332 ieee80211_notify_scan_done(struct ieee80211com *ic)
  333 {
  334         struct ifnet *ifp = ic->ic_ifp;
  335 
  336         IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "%s\n", "notify scan done");
  337 
  338         /* dispatch wireless event indicating scan completed */
  339         rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0);
  340 }
  341 
  342 void
  343 ieee80211_notify_replay_failure(struct ieee80211com *ic,
  344         const struct ieee80211_frame *wh, const struct ieee80211_key *k,
  345         u_int64_t rsc)
  346 {
  347         struct ifnet *ifp = ic->ic_ifp;
  348 
  349         IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
  350             "[%s] %s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>\n",
  351             ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name,
  352             (intmax_t) rsc, (intmax_t) k->wk_keyrsc,
  353             k->wk_keyix, k->wk_rxkeyix);
  354 
  355         if (ifp != NULL) {              /* NB: for cipher test modules */
  356                 struct ieee80211_replay_event iev;
  357 
  358                 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
  359                 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
  360                 iev.iev_cipher = k->wk_cipher->ic_cipher;
  361                 if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE)
  362                         iev.iev_keyix = k->wk_rxkeyix;
  363                 else
  364                         iev.iev_keyix = k->wk_keyix;
  365                 iev.iev_keyrsc = k->wk_keyrsc;
  366                 iev.iev_rsc = rsc;
  367                 rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev));
  368         }
  369 }
  370 
  371 void
  372 ieee80211_notify_michael_failure(struct ieee80211com *ic,
  373         const struct ieee80211_frame *wh, u_int keyix)
  374 {
  375         struct ifnet *ifp = ic->ic_ifp;
  376 
  377         IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO,
  378                 "[%s] michael MIC verification failed <keyix %u>\n",
  379                ether_sprintf(wh->i_addr2), keyix);
  380         ic->ic_stats.is_rx_tkipmic++;
  381 
  382         if (ifp != NULL) {              /* NB: for cipher test modules */
  383                 struct ieee80211_michael_event iev;
  384 
  385                 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1);
  386                 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2);
  387                 iev.iev_cipher = IEEE80211_CIPHER_TKIP;
  388                 iev.iev_keyix = keyix;
  389                 rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev));
  390         }
  391 }
  392 
  393 void
  394 ieee80211_load_module(const char *modname)
  395 {
  396 
  397 #ifdef notyet
  398         (void)kern_kldload(curthread, modname, NULL);
  399 #else
  400         printf("%s: load the %s module by hand for now.\n", __func__, modname);
  401 #endif
  402 }
  403 
  404 /*
  405  * Module glue.
  406  *
  407  * NB: the module name is "wlan" for compatibility with NetBSD.
  408  */
  409 static int
  410 wlan_modevent(module_t mod, int type, void *unused)
  411 {
  412         switch (type) {
  413         case MOD_LOAD:
  414                 if (bootverbose)
  415                         printf("wlan: <802.11 Link Layer>\n");
  416                 return 0;
  417         case MOD_UNLOAD:
  418                 return 0;
  419         }
  420         return EINVAL;
  421 }
  422 
  423 static moduledata_t wlan_mod = {
  424         "wlan",
  425         wlan_modevent,
  426         0
  427 };
  428 DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
  429 MODULE_VERSION(wlan, 1);
  430 MODULE_DEPEND(wlan, ether, 1, 1, 1);

Cache object: a189332e09c16f735afe6dc5244adb7d


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