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_node.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 /*      $NetBSD: ieee80211_node.c,v 1.10.2.1 2004/08/03 16:54:45 jmc Exp $      */
    2 /*-
    3  * Copyright (c) 2001 Atsushi Onoe
    4  * Copyright (c) 2002, 2003 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  * 3. The name of the author may not be used to endorse or promote products
   16  *    derived from this software without specific prior written permission.
   17  *
   18  * Alternatively, this software may be distributed under the terms of the
   19  * GNU General Public License ("GPL") version 2 as published by the Free
   20  * Software Foundation.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 #ifdef __FreeBSD__
   36 __FBSDID("$FreeBSD: src/sys/net80211/ieee80211_node.c,v 1.13 2003/11/09 23:36:46 sam Exp $");
   37 #else
   38 __KERNEL_RCSID(0, "$NetBSD: ieee80211_node.c,v 1.10.2.1 2004/08/03 16:54:45 jmc Exp $");
   39 #endif
   40 
   41 #include "opt_inet.h"
   42 
   43 #include <sys/param.h>
   44 #include <sys/systm.h> 
   45 #include <sys/mbuf.h>   
   46 #include <sys/malloc.h>
   47 #include <sys/kernel.h>
   48 #include <sys/socket.h>
   49 #include <sys/sockio.h>
   50 #include <sys/endian.h>
   51 #include <sys/errno.h>
   52 #ifdef __FreeBSD__
   53 #include <sys/bus.h>
   54 #endif
   55 #include <sys/proc.h>
   56 #include <sys/sysctl.h>
   57 
   58 #ifdef __FreeBSD__
   59 #include <machine/atomic.h>
   60 #endif
   61  
   62 #include <net/if.h>
   63 #include <net/if_dl.h>
   64 #include <net/if_media.h>
   65 #include <net/if_arp.h>
   66 #ifdef __FreeBSD__
   67 #include <net/ethernet.h>
   68 #else
   69 #include <net/if_ether.h>
   70 #endif
   71 #include <net/if_llc.h>
   72 
   73 #include <net80211/ieee80211_var.h>
   74 #include <net80211/ieee80211_compat.h>
   75 
   76 #include <net/bpf.h>
   77 
   78 #ifdef INET
   79 #include <netinet/in.h> 
   80 #ifdef __FreeBSD__
   81 #include <netinet/if_ether.h>
   82 #else
   83 #include <net/if_ether.h>
   84 #endif
   85 #endif
   86 
   87 static struct ieee80211_node *ieee80211_node_alloc(struct ieee80211com *);
   88 static void ieee80211_node_free(struct ieee80211com *, struct ieee80211_node *);
   89 static void ieee80211_node_copy(struct ieee80211com *,
   90                 struct ieee80211_node *, const struct ieee80211_node *);
   91 static u_int8_t ieee80211_node_getrssi(struct ieee80211com *,
   92                 struct ieee80211_node *);
   93 
   94 static void ieee80211_setup_node(struct ieee80211com *ic,
   95                 struct ieee80211_node *ni, u_int8_t *macaddr);
   96 static void _ieee80211_free_node(struct ieee80211com *,
   97                 struct ieee80211_node *);
   98 
   99 MALLOC_DEFINE(M_80211_NODE, "node", "802.11 node state");
  100 
  101 void
  102 ieee80211_node_attach(struct ifnet *ifp)
  103 {
  104         struct ieee80211com *ic = (void *)ifp;
  105 
  106 #ifdef __FreeBSD__
  107         /* XXX need unit */
  108         IEEE80211_NODE_LOCK_INIT(ic, ifp->if_xname);
  109 #endif
  110         TAILQ_INIT(&ic->ic_node);
  111         ic->ic_node_alloc = ieee80211_node_alloc;
  112         ic->ic_node_free = ieee80211_node_free;
  113         ic->ic_node_copy = ieee80211_node_copy;
  114         ic->ic_node_getrssi = ieee80211_node_getrssi;
  115         ic->ic_scangen = 1;
  116 }
  117 
  118 void
  119 ieee80211_node_lateattach(struct ifnet *ifp)
  120 {
  121         struct ieee80211com *ic = (void *)ifp;
  122 
  123         ic->ic_bss = (*ic->ic_node_alloc)(ic);
  124         IASSERT(ic->ic_bss != NULL, ("unable to setup inital BSS node"));
  125         ic->ic_bss->ni_chan = IEEE80211_CHAN_ANYC;
  126 }
  127 
  128 void
  129 ieee80211_node_detach(struct ifnet *ifp)
  130 {
  131         struct ieee80211com *ic = (void *)ifp;
  132 
  133         if (ic->ic_bss != NULL)
  134                 (*ic->ic_node_free)(ic, ic->ic_bss);
  135         ieee80211_free_allnodes(ic);
  136 #ifdef __FreeBSD__
  137         IEEE80211_NODE_LOCK_DESTROY(ic);
  138 #endif
  139 }
  140 
  141 /*
  142  * AP scanning support.
  143  */
  144 
  145 /*
  146  * Initialize the active channel set based on the set
  147  * of available channels and the current PHY mode.
  148  */
  149 static void
  150 ieee80211_reset_scan(struct ifnet *ifp)
  151 {
  152         struct ieee80211com *ic = (void *)ifp;
  153 
  154         memcpy(ic->ic_chan_scan, ic->ic_chan_active,
  155                 sizeof(ic->ic_chan_active));
  156         /* NB: hack, setup so next_scan starts with the first channel */
  157         if (ic->ic_bss->ni_chan == IEEE80211_CHAN_ANYC)
  158                 ic->ic_bss->ni_chan = &ic->ic_channels[IEEE80211_CHAN_MAX];
  159 }
  160 
  161 /*
  162  * Begin an active scan.
  163  */
  164 void
  165 ieee80211_begin_scan(struct ifnet *ifp)
  166 {
  167         struct ieee80211com *ic = (void *)ifp;
  168 
  169         /*
  170          * In all but hostap mode scanning starts off in
  171          * an active mode before switching to passive.
  172          */
  173         if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
  174                 ic->ic_flags |= IEEE80211_F_ASCAN;
  175                 ic->ic_stats.is_scan_active++;
  176         } else
  177                 ic->ic_stats.is_scan_passive++;
  178         if (ifp->if_flags & IFF_DEBUG)
  179                 if_printf(ifp, "begin %s scan\n",
  180                         (ic->ic_flags & IEEE80211_F_ASCAN) ?
  181                                 "active" : "passive");
  182         /*
  183          * Clear scan state and flush any previously seen
  184          * AP's.  Note that the latter assumes we don't act
  185          * as both an AP and a station, otherwise we'll
  186          * potentially flush state of stations associated
  187          * with us.
  188          */
  189         ieee80211_reset_scan(ifp);
  190         ieee80211_free_allnodes(ic);
  191 
  192         /* Scan the next channel. */
  193         ieee80211_next_scan(ifp);
  194 }
  195 
  196 /*
  197  * Switch to the next channel marked for scanning.
  198  */
  199 void
  200 ieee80211_next_scan(struct ifnet *ifp)
  201 {
  202         struct ieee80211com *ic = (void *)ifp;
  203         struct ieee80211_channel *chan;
  204 
  205         chan = ic->ic_bss->ni_chan;
  206         for (;;) {
  207                 if (++chan > &ic->ic_channels[IEEE80211_CHAN_MAX])
  208                         chan = &ic->ic_channels[0];
  209                 if (isset(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan))) {
  210                         /*
  211                          * Honor channels marked passive-only
  212                          * during an active scan.
  213                          */
  214                         if ((ic->ic_flags & IEEE80211_F_ASCAN) == 0 ||
  215                             (chan->ic_flags & IEEE80211_CHAN_PASSIVE) == 0)
  216                                 break;
  217                 }
  218                 if (chan == ic->ic_bss->ni_chan) {
  219                         ieee80211_end_scan(ifp);
  220                         return;
  221                 }
  222         }
  223         clrbit(ic->ic_chan_scan, ieee80211_chan2ieee(ic, chan));
  224         IEEE80211_DPRINTF(("ieee80211_next_scan: chan %d->%d\n",
  225             ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan),
  226             ieee80211_chan2ieee(ic, chan)));
  227         ic->ic_bss->ni_chan = chan;
  228         ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
  229 }
  230 
  231 void
  232 ieee80211_create_ibss(struct ieee80211com* ic, struct ieee80211_channel *chan)
  233 {
  234         struct ieee80211_node *ni;
  235         struct ifnet *ifp = &ic->ic_if;
  236 
  237         ni = ic->ic_bss;
  238         if (ifp->if_flags & IFF_DEBUG)
  239                 if_printf(ifp, "creating ibss\n");
  240         ic->ic_flags |= IEEE80211_F_SIBSS;
  241         ni->ni_chan = chan;
  242         ni->ni_rates = ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
  243         IEEE80211_ADDR_COPY(ni->ni_macaddr, ic->ic_myaddr);
  244         IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_myaddr);
  245         if (ic->ic_opmode == IEEE80211_M_IBSS)
  246                 ni->ni_bssid[0] |= 0x02;        /* local bit for IBSS */
  247         ni->ni_esslen = ic->ic_des_esslen;
  248         memcpy(ni->ni_essid, ic->ic_des_essid, ni->ni_esslen);
  249         ni->ni_rssi = 0;
  250         ni->ni_rstamp = 0;
  251         memset(ni->ni_tstamp, 0, sizeof(ni->ni_tstamp));
  252         ni->ni_intval = ic->ic_lintval;
  253         ni->ni_capinfo = IEEE80211_CAPINFO_IBSS;
  254         if (ic->ic_flags & IEEE80211_F_WEPON)
  255                 ni->ni_capinfo |= IEEE80211_CAPINFO_PRIVACY;
  256         if (ic->ic_phytype == IEEE80211_T_FH) {
  257                 ni->ni_fhdwell = 200;   /* XXX */
  258                 ni->ni_fhindex = 1;
  259         }
  260         ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
  261 }
  262 
  263 int
  264 ieee80211_match_bss(struct ieee80211com *ic, struct ieee80211_node *ni)
  265 {
  266         struct ifnet *ifp = &ic->ic_if;
  267         u_int8_t rate;
  268         int fail;
  269 
  270         fail = 0;
  271         if (isclr(ic->ic_chan_active, ieee80211_chan2ieee(ic, ni->ni_chan)))
  272                 fail |= 0x01;
  273         if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
  274             ni->ni_chan != ic->ic_des_chan)
  275                 fail |= 0x01;
  276         if (ic->ic_opmode == IEEE80211_M_IBSS) {
  277                 if ((ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) == 0)
  278                         fail |= 0x02;
  279         } else {
  280                 if ((ni->ni_capinfo & IEEE80211_CAPINFO_ESS) == 0)
  281                         fail |= 0x02;
  282         }
  283         if (ic->ic_flags & IEEE80211_F_WEPON) {
  284                 if ((ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) == 0)
  285                         fail |= 0x04;
  286         } else {
  287                 if (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY)
  288                         fail |= 0x04;
  289         }
  290         rate = ieee80211_fix_rate(ic, ni, IEEE80211_F_DONEGO);
  291         if (rate & IEEE80211_RATE_BASIC)
  292                 fail |= 0x08;
  293         if (ic->ic_des_esslen != 0 &&
  294             (ni->ni_esslen != ic->ic_des_esslen ||
  295              memcmp(ni->ni_essid, ic->ic_des_essid,
  296              ic->ic_des_esslen != 0)))
  297                 fail |= 0x10;
  298         if ((ic->ic_flags & IEEE80211_F_DESBSSID) &&
  299             !IEEE80211_ADDR_EQ(ic->ic_des_bssid, ni->ni_bssid))
  300                 fail |= 0x20;
  301         if (ifp->if_flags & IFF_DEBUG) {
  302                 printf(" %c %s", fail ? '-' : '+',
  303                     ether_sprintf(ni->ni_macaddr));
  304                 printf(" %s%c", ether_sprintf(ni->ni_bssid),
  305                     fail & 0x20 ? '!' : ' ');
  306                 printf(" %3d%c", ieee80211_chan2ieee(ic, ni->ni_chan),
  307                         fail & 0x01 ? '!' : ' ');
  308                 printf(" %+4d", ni->ni_rssi);
  309                 printf(" %2dM%c", (rate & IEEE80211_RATE_VAL) / 2,
  310                     fail & 0x08 ? '!' : ' ');
  311                 printf(" %4s%c",
  312                     (ni->ni_capinfo & IEEE80211_CAPINFO_ESS) ? "ess" :
  313                     (ni->ni_capinfo & IEEE80211_CAPINFO_IBSS) ? "ibss" :
  314                     "????",
  315                     fail & 0x02 ? '!' : ' ');
  316                 printf(" %3s%c ",
  317                     (ni->ni_capinfo & IEEE80211_CAPINFO_PRIVACY) ?
  318                     "wep" : "no",
  319                     fail & 0x04 ? '!' : ' ');
  320                 ieee80211_print_essid(ni->ni_essid, ni->ni_esslen);
  321                 printf("%s\n", fail & 0x10 ? "!" : "");
  322         }
  323         return fail;
  324 }
  325 
  326 /*
  327  * Complete a scan of potential channels.
  328  */
  329 void
  330 ieee80211_end_scan(struct ifnet *ifp)
  331 {
  332         struct ieee80211com *ic = (void *)ifp;
  333         struct ieee80211_node *ni, *nextbs, *selbs;
  334         int i, fail;
  335 
  336         ic->ic_flags &= ~IEEE80211_F_ASCAN;
  337         ni = TAILQ_FIRST(&ic->ic_node);
  338 
  339         if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
  340                 /* XXX off stack? */
  341                 u_char occupied[roundup(IEEE80211_CHAN_MAX, NBBY)];
  342                 /*
  343                  * The passive scan to look for existing AP's completed,
  344                  * select a channel to camp on.  Identify the channels
  345                  * that already have one or more AP's and try to locate
  346                  * an unnoccupied one.  If that fails, pick a random
  347                  * channel from the active set.
  348                  */
  349                 for (; ni != NULL; ni = nextbs) {
  350                         ieee80211_ref_node(ni);
  351                         nextbs = TAILQ_NEXT(ni, ni_list);
  352                         setbit(occupied, ieee80211_chan2ieee(ic, ni->ni_chan));
  353                         ieee80211_free_node(ic, ni);
  354                 }
  355                 for (i = 0; i < IEEE80211_CHAN_MAX; i++)
  356                         if (isset(ic->ic_chan_active, i) && isclr(occupied, i))
  357                                 break;
  358                 if (i == IEEE80211_CHAN_MAX) {
  359                         fail = arc4random() & 3;        /* random 0-3 */
  360                         for (i = 0; i < IEEE80211_CHAN_MAX; i++)
  361                                 if (isset(ic->ic_chan_active, i) && fail-- == 0)
  362                                         break;
  363                 }
  364                 ieee80211_create_ibss(ic, &ic->ic_channels[i]);
  365                 return;
  366         }
  367         if (ni == NULL) {
  368                 IEEE80211_DPRINTF(("%s: no scan candidate\n", __func__));
  369   notfound:
  370                 if (ic->ic_opmode == IEEE80211_M_IBSS &&
  371                     (ic->ic_flags & IEEE80211_F_IBSSON) &&
  372                     ic->ic_des_esslen != 0) {
  373                         ieee80211_create_ibss(ic, ic->ic_ibss_chan);
  374                         return;
  375                 }
  376                 /*
  377                  * Reset the list of channels to scan and start again.
  378                  */
  379                 ieee80211_reset_scan(ifp);
  380                 ieee80211_next_scan(ifp);
  381                 return;
  382         }
  383         selbs = NULL;
  384         if (ifp->if_flags & IFF_DEBUG)
  385                 if_printf(ifp, "\tmacaddr          bssid         chan  rssi rate flag  wep  essid\n");
  386         for (; ni != NULL; ni = nextbs) {
  387                 ieee80211_ref_node(ni);
  388                 nextbs = TAILQ_NEXT(ni, ni_list);
  389                 if (ni->ni_fails) {
  390                         /*
  391                          * The configuration of the access points may change
  392                          * during my scan.  So delete the entry for the AP
  393                          * and retry to associate if there is another beacon.
  394                          */
  395                         if (ni->ni_fails++ > 2)
  396                                 ieee80211_free_node(ic, ni);
  397                         continue;
  398                 }
  399                 if (ieee80211_match_bss(ic, ni) == 0) {
  400                         if (selbs == NULL)
  401                                 selbs = ni;
  402                         else if (ni->ni_rssi > selbs->ni_rssi) {
  403                                 ieee80211_unref_node(&selbs);
  404                                 selbs = ni;
  405                         } else
  406                                 ieee80211_unref_node(&ni);
  407                 } else {
  408                         ieee80211_unref_node(&ni);
  409                 }
  410         }
  411         if (selbs == NULL)
  412                 goto notfound;
  413         (*ic->ic_node_copy)(ic, ic->ic_bss, selbs);
  414         if (ic->ic_opmode == IEEE80211_M_IBSS) {
  415                 ieee80211_fix_rate(ic, ic->ic_bss, IEEE80211_F_DOFRATE |
  416                     IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
  417                 if (ic->ic_bss->ni_rates.rs_nrates == 0) {
  418                         selbs->ni_fails++;
  419                         ieee80211_unref_node(&selbs);
  420                         goto notfound;
  421                 }
  422                 ieee80211_unref_node(&selbs);
  423                 ieee80211_new_state(ic, IEEE80211_S_RUN, -1);
  424         } else {
  425                 ieee80211_unref_node(&selbs);
  426                 ieee80211_new_state(ic, IEEE80211_S_AUTH, -1);
  427         }
  428 }
  429 
  430 int
  431 ieee80211_get_rate(struct ieee80211com *ic)
  432 {
  433         u_int8_t (*rates)[IEEE80211_RATE_MAXSIZE];
  434         int rate;
  435 
  436         rates = &ic->ic_bss->ni_rates.rs_rates;
  437 
  438         if (ic->ic_fixed_rate != -1)
  439                 rate = (*rates)[ic->ic_fixed_rate];
  440         else if (ic->ic_state == IEEE80211_S_RUN)
  441                 rate = (*rates)[ic->ic_bss->ni_txrate];
  442         else
  443                 rate = 0;
  444 
  445         return rate & IEEE80211_RATE_VAL;
  446 }
  447 
  448 static struct ieee80211_node *
  449 ieee80211_node_alloc(struct ieee80211com *ic)
  450 {
  451         return malloc(sizeof(struct ieee80211_node), M_80211_NODE,
  452                 M_NOWAIT | M_ZERO);
  453 }
  454 
  455 static void
  456 ieee80211_node_free(struct ieee80211com *ic, struct ieee80211_node *ni)
  457 {
  458         if (ni->ni_challenge != NULL) {
  459                 free(ni->ni_challenge, M_DEVBUF);
  460                 ni->ni_challenge = NULL;
  461         }
  462         free(ni, M_80211_NODE);
  463 }
  464 
  465 static void
  466 ieee80211_node_copy(struct ieee80211com *ic,
  467         struct ieee80211_node *dst, const struct ieee80211_node *src)
  468 {
  469         *dst = *src;
  470         dst->ni_challenge = NULL;
  471 }
  472 
  473 static u_int8_t
  474 ieee80211_node_getrssi(struct ieee80211com *ic, struct ieee80211_node *ni)
  475 {
  476         return ni->ni_rssi;
  477 }
  478 
  479 static void
  480 ieee80211_setup_node(struct ieee80211com *ic,
  481         struct ieee80211_node *ni, u_int8_t *macaddr)
  482 {
  483         int hash;
  484         ieee80211_node_critsec_decl(s);
  485 
  486         IEEE80211_ADDR_COPY(ni->ni_macaddr, macaddr);
  487         hash = IEEE80211_NODE_HASH(macaddr);
  488         ni->ni_refcnt = 1;              /* mark referenced */
  489         ieee80211_node_critsec_begin(ic, s);
  490         TAILQ_INSERT_TAIL(&ic->ic_node, ni, ni_list);
  491         LIST_INSERT_HEAD(&ic->ic_hash[hash], ni, ni_hash);
  492         /* 
  493          * Note we don't enable the inactive timer when acting
  494          * as a station.  Nodes created in this mode represent
  495          * AP's identified while scanning.  If we time them out
  496          * then several things happen: we can't return the data
  497          * to users to show the list of AP's we encountered, and
  498          * more importantly, we'll incorrectly deauthenticate
  499          * ourself because the inactivity timer will kick us off. 
  500          */
  501         if (ic->ic_opmode != IEEE80211_M_STA)
  502                 ic->ic_inact_timer = IEEE80211_INACT_WAIT;
  503         ieee80211_node_critsec_end(ic, s);
  504 }
  505 
  506 struct ieee80211_node *
  507 ieee80211_alloc_node(struct ieee80211com *ic, u_int8_t *macaddr)
  508 {
  509         struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic);
  510         if (ni != NULL)
  511                 ieee80211_setup_node(ic, ni, macaddr);
  512         return ni;
  513 }
  514 
  515 struct ieee80211_node *
  516 ieee80211_dup_bss(struct ieee80211com *ic, u_int8_t *macaddr)
  517 {
  518         struct ieee80211_node *ni = (*ic->ic_node_alloc)(ic);
  519         if (ni != NULL) {
  520                 memcpy(ni, ic->ic_bss, sizeof(struct ieee80211_node));
  521                 ieee80211_setup_node(ic, ni, macaddr);
  522         }
  523         return ni;
  524 }
  525 
  526 struct ieee80211_node *
  527 ieee80211_find_node(struct ieee80211com *ic, u_int8_t *macaddr)
  528 {
  529         struct ieee80211_node *ni;
  530         int hash;
  531         ieee80211_node_critsec_decl(s);
  532 
  533         hash = IEEE80211_NODE_HASH(macaddr);
  534         ieee80211_node_critsec_begin(ic, s);
  535         LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
  536                 if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) {
  537                         ieee80211_node_incref(ni); /* mark referenced */
  538                         break;
  539                 }
  540         }
  541         ieee80211_node_critsec_end(ic, s);
  542         return ni;
  543 }
  544 
  545 struct ieee80211_node *
  546 ieee80211_find_txnode(struct ieee80211com *ic, u_int8_t *macaddr)
  547 {
  548         struct ieee80211_node *ni;
  549         ieee80211_node_critsec_decl(s);
  550 
  551         /*
  552          * The destination address should be in the node table
  553          * unless this is a multicast/broadcast frames or we are
  554          * in station mode.
  555          */
  556         if (IEEE80211_IS_MULTICAST(macaddr) || ic->ic_opmode == IEEE80211_M_STA)
  557                 return ic->ic_bss;
  558 
  559         ieee80211_node_critsec_begin(ic, s);
  560         ni = ieee80211_find_node(ic, macaddr);
  561         if (ni == NULL) {
  562                 if (ic->ic_opmode != IEEE80211_M_MONITOR)
  563                         ni = ieee80211_dup_bss(ic, macaddr);
  564                 IEEE80211_DPRINTF(("%s: faked-up node %p for %s\n",
  565                     __func__, ni, ether_sprintf(macaddr)));
  566                 if (ni == NULL) {
  567                         ieee80211_node_critsec_end(ic, s);
  568                         /* ic->ic_stats.st_tx_nonode++; XXX statistic */
  569                         return NULL;
  570                 }
  571                 (void)ieee80211_ref_node(ni);
  572         }
  573         ieee80211_node_critsec_end(ic, s);
  574         return ni;
  575 }
  576 
  577 /*
  578  * For some types of packet and for some operating modes, it is
  579  * desirable to process a Rx packet using its sender's node-record
  580  * instead of the BSS record, when that is possible.
  581  *
  582  * - AP mode: it is desirable to keep a node-record for every
  583  *   authenticated/associated station *in the BSS*. For future use,
  584  *   we also track neighboring APs, since they might belong to the
  585  *   same ESSID.
  586  *
  587  * - IBSS mode: it is desirable to keep a node-record for every
  588  *   station *in the BSS*.
  589  *
  590  * - monitor mode: it is desirable to keep a node-record for every
  591  *   sender, regardless of BSS.
  592  *
  593  * - STA mode: the only available node-record is the BSS record,
  594  *   ic->ic_bss.
  595  *
  596  * Of all the 802.11 Control packets, only the node-records for
  597  * RTS packets node-record can be looked up.
  598  *
  599  * Return non-zero if the packet's node-record is kept, zero
  600  * otherwise.
  601  */
  602 static __inline int
  603 ieee80211_needs_rxnode(struct ieee80211com *ic, struct ieee80211_frame *wh,
  604     u_int8_t **bssid)
  605 {
  606         struct ieee80211_node *bss = ic->ic_bss;
  607         int needsnode, rc = 0;
  608 
  609         if (ic->ic_opmode == IEEE80211_M_STA)
  610                 return 0;
  611 
  612         needsnode = (ic->ic_opmode == IEEE80211_M_MONITOR);
  613 
  614         *bssid = NULL;
  615 
  616         switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
  617         case IEEE80211_FC0_TYPE_CTL:
  618                 return (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
  619                     IEEE80211_FC0_SUBTYPE_RTS;
  620 
  621         case IEEE80211_FC0_TYPE_MGT:
  622                 *bssid = wh->i_addr3;
  623                 rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid);
  624                 break;
  625         case IEEE80211_FC0_TYPE_DATA:
  626                 switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
  627                 case IEEE80211_FC1_DIR_NODS:
  628                         *bssid = wh->i_addr3;
  629                         if (ic->ic_opmode == IEEE80211_M_IBSS ||
  630                             ic->ic_opmode == IEEE80211_M_AHDEMO)
  631                                 rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid);
  632                         break;
  633                 case IEEE80211_FC1_DIR_TODS:
  634                         *bssid = wh->i_addr1;
  635                         if (ic->ic_opmode == IEEE80211_M_HOSTAP)
  636                                 rc = IEEE80211_ADDR_EQ(*bssid, bss->ni_bssid);
  637                         break;
  638                 case IEEE80211_FC1_DIR_FROMDS:
  639                 case IEEE80211_FC1_DIR_DSTODS:
  640                         *bssid = wh->i_addr2;
  641                         rc = (ic->ic_opmode == IEEE80211_M_HOSTAP);
  642                         break;
  643                 }
  644                 break;
  645         }
  646         return needsnode || rc;
  647 }
  648 
  649 struct ieee80211_node *
  650 ieee80211_find_rxnode(struct ieee80211com *ic, struct ieee80211_frame *wh)
  651 {
  652         struct ieee80211_node *ni;
  653         const static u_int8_t zero[IEEE80211_ADDR_LEN];
  654         u_int8_t *bssid;
  655         ieee80211_node_critsec_decl(s);
  656 
  657         ieee80211_node_critsec_begin(ic, s);
  658 
  659         if (!ieee80211_needs_rxnode(ic, wh, &bssid))
  660                 return ieee80211_ref_node(ic->ic_bss);
  661 
  662         ni = ieee80211_find_node(ic, wh->i_addr2);
  663 
  664         if (ni == NULL) {
  665                 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
  666                         if ((ni = ieee80211_dup_bss(ic, wh->i_addr2)) != NULL)
  667                                 IEEE80211_ADDR_COPY(ni->ni_bssid,
  668                                     (bssid != NULL) ? bssid : zero);
  669 
  670                         IEEE80211_DPRINTF(("%s: faked-up node %p for %s\n",
  671                             __func__, ni, ether_sprintf(wh->i_addr2)));
  672                 }
  673                 ni = ieee80211_ref_node((ni == NULL) ? ic->ic_bss : ni);
  674         }
  675         ieee80211_node_critsec_end(ic, s);
  676         IASSERT(ni != NULL, ("%s: null node", __func__));
  677         return ni;
  678 }
  679 
  680 /*
  681  * Like find but search based on the channel too.
  682  */
  683 struct ieee80211_node *
  684 ieee80211_lookup_node(struct ieee80211com *ic,
  685         u_int8_t *macaddr, struct ieee80211_channel *chan)
  686 {
  687         struct ieee80211_node *ni;
  688         int hash;
  689         ieee80211_node_critsec_decl(s);
  690 
  691         hash = IEEE80211_NODE_HASH(macaddr);
  692         ieee80211_node_critsec_begin(ic, s);
  693         LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
  694                 if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 
  695                     ni->ni_chan == chan) {
  696                         ieee80211_node_incref(ni);/* mark referenced */
  697                         break;
  698                 }
  699         }
  700         ieee80211_node_critsec_end(ic, s);
  701         return ni;
  702 }
  703 
  704 /*
  705  * Like find but search based on the channel and ssid too.
  706  */
  707 struct ieee80211_node *
  708 ieee80211_lookup_node_for_beacon(struct ieee80211com *ic,
  709         u_int8_t *macaddr, struct ieee80211_channel *chan, char *ssid)
  710 {
  711         struct ieee80211_node *ni;
  712         int hash;
  713         ieee80211_node_critsec_decl(s);
  714 
  715         hash = IEEE80211_NODE_HASH(macaddr);
  716         ieee80211_node_critsec_begin(ic, s);
  717         LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) {
  718                 if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr) && 
  719                     ni->ni_chan == chan &&
  720                     (ssid[1] == 0 || (ssid[1] == ni->ni_esslen &&
  721                      !memcmp(ssid + 2, ni->ni_essid, ssid[1])))) {
  722                         ieee80211_node_incref(ni);/* mark referenced */
  723                         break;
  724                 }
  725         }
  726         ieee80211_node_critsec_end(ic, s);
  727         return ni;
  728 }
  729 
  730 static void
  731 _ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
  732 {
  733         IASSERT(ni != ic->ic_bss, ("freeing bss node"));
  734 
  735         IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
  736         TAILQ_REMOVE(&ic->ic_node, ni, ni_list);
  737         LIST_REMOVE(ni, ni_hash);
  738         if (!IF_IS_EMPTY(&ni->ni_savedq)) {
  739                 IF_PURGE(&ni->ni_savedq); 
  740                 if (ic->ic_set_tim)
  741                         ic->ic_set_tim(ic, ni->ni_associd, 0);
  742         }
  743         if (TAILQ_EMPTY(&ic->ic_node))
  744                 ic->ic_inact_timer = 0;
  745         (*ic->ic_node_free)(ic, ni);
  746 }
  747 
  748 void
  749 ieee80211_free_node(struct ieee80211com *ic, struct ieee80211_node *ni)
  750 {
  751         ieee80211_node_critsec_decl(s);
  752 
  753         IASSERT(ni != ic->ic_bss, ("freeing ic_bss"));
  754 
  755         if (ieee80211_node_decref(ni) == 0) {
  756                 ieee80211_node_critsec_begin(ic, s);
  757                 _ieee80211_free_node(ic, ni);
  758                 ieee80211_node_critsec_end(ic, s);
  759         }
  760 }
  761 
  762 void
  763 ieee80211_free_allnodes(struct ieee80211com *ic)
  764 {
  765         struct ieee80211_node *ni;
  766         ieee80211_node_critsec_decl(s);
  767 
  768         ieee80211_node_critsec_begin(ic, s);
  769         while ((ni = TAILQ_FIRST(&ic->ic_node)) != NULL)
  770                 _ieee80211_free_node(ic, ni);  
  771         ieee80211_node_critsec_end(ic, s);
  772 }
  773 
  774 /*
  775  * Timeout inactive nodes.  Note that we cannot hold the node
  776  * lock while sending a frame as this would lead to a LOR.
  777  * Instead we use a generation number to mark nodes that we've
  778  * scanned and drop the lock and restart a scan if we have to
  779  * time out a node.  Since we are single-threaded by virtue of
  780  * controlling the inactivity timer we can be sure this will
  781  * process each node only once.
  782  */
  783 void
  784 ieee80211_timeout_nodes(struct ieee80211com *ic)
  785 {
  786         struct ieee80211_node *ni;
  787         ieee80211_node_critsec_decl(s);
  788         u_int gen = ic->ic_scangen++;           /* NB: ok 'cuz single-threaded*/
  789 
  790 restart:
  791         ieee80211_node_critsec_begin(ic, s);
  792         TAILQ_FOREACH(ni, &ic->ic_node, ni_list) {
  793                 if (ni->ni_scangen == gen)      /* previously handled */
  794                         continue;
  795                 ni->ni_scangen = gen;
  796                 if (++ni->ni_inact > IEEE80211_INACT_MAX) {
  797                         IEEE80211_DPRINTF(("station %s timed out "
  798                             "due to inactivity (%u secs)\n",
  799                             ether_sprintf(ni->ni_macaddr),
  800                             ni->ni_inact));
  801                         /*
  802                          * Send a deauthenticate frame.
  803                          *
  804                          * Drop the node lock before sending the
  805                          * deauthentication frame in case the driver takes     
  806                          * a lock, as this will result in a LOR between the     
  807                          * node lock and the driver lock.
  808                          */
  809                         ieee80211_node_critsec_end(ic, s);
  810                         IEEE80211_SEND_MGMT(ic, ni,
  811                             IEEE80211_FC0_SUBTYPE_DEAUTH,
  812                             IEEE80211_REASON_AUTH_EXPIRE);
  813                         ieee80211_free_node(ic, ni);
  814                         ic->ic_stats.is_node_timeout++;
  815                         goto restart;
  816                 }
  817         }
  818         if (!TAILQ_EMPTY(&ic->ic_node))
  819                 ic->ic_inact_timer = IEEE80211_INACT_WAIT;
  820         ieee80211_node_critsec_end(ic, s);
  821 }
  822 
  823 void
  824 ieee80211_iterate_nodes(struct ieee80211com *ic, ieee80211_iter_func *f, void *arg)
  825 {
  826         struct ieee80211_node *ni;
  827         ieee80211_node_critsec_decl(s);
  828 
  829         ieee80211_node_critsec_begin(ic, s);
  830         TAILQ_FOREACH(ni, &ic->ic_node, ni_list)
  831                 (*f)(arg, ni);
  832         ieee80211_node_critsec_end(ic, s);
  833 }

Cache object: 234ce92a18691507e4b51a4f250b5aa8


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