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_input.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_input.c,v 1.21.2.1 2004/08/03 16:54:42 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_input.c,v 1.12 2003/10/17 23:59:11 sam Exp $");
   37 #else
   38 __KERNEL_RCSID(0, "$NetBSD: ieee80211_input.c,v 1.21.2.1 2004/08/03 16:54:42 jmc Exp $");
   39 #endif
   40 
   41 #include "opt_inet.h"
   42 
   43 #ifdef __NetBSD__
   44 #include "bpfilter.h"
   45 #endif /* __NetBSD__ */
   46 
   47 #include <sys/param.h>
   48 #include <sys/systm.h> 
   49 #include <sys/mbuf.h>   
   50 #include <sys/malloc.h>
   51 #include <sys/kernel.h>
   52 #include <sys/socket.h>
   53 #include <sys/sockio.h>
   54 #include <sys/endian.h>
   55 #include <sys/errno.h>
   56 #ifdef __FreeBSD__
   57 #include <sys/bus.h>
   58 #endif
   59 #include <sys/proc.h>
   60 #include <sys/sysctl.h>
   61 
   62 #ifdef __FreeBSD__
   63 #include <machine/atomic.h>
   64 #endif
   65  
   66 #include <net/if.h>
   67 #include <net/if_dl.h>
   68 #include <net/if_media.h>
   69 #include <net/if_arp.h>
   70 #ifdef __FreeBSD__
   71 #include <net/ethernet.h>
   72 #else
   73 #include <net/if_ether.h>
   74 #endif
   75 #include <net/if_llc.h>
   76 
   77 #include <net80211/ieee80211_var.h>
   78 #include <net80211/ieee80211_compat.h>
   79 
   80 #if NBPFILTER > 0
   81 #include <net/bpf.h>
   82 #endif
   83 
   84 #ifdef INET
   85 #include <netinet/in.h> 
   86 #ifdef __FreeBSD__
   87 #include <netinet/if_ether.h>
   88 #else
   89 #include <net/if_ether.h>
   90 #endif
   91 #endif
   92 
   93 static void ieee80211_recv_pspoll(struct ieee80211com *,
   94     struct mbuf *, int, u_int32_t);
   95 
   96 /*
   97  * Process a received frame.  The node associated with the sender
   98  * should be supplied.  If nothing was found in the node table then
   99  * the caller is assumed to supply a reference to ic_bss instead.
  100  * The RSSI and a timestamp are also supplied.  The RSSI data is used
  101  * during AP scanning to select a AP to associate with; it can have
  102  * any units so long as values have consistent units and higher values
  103  * mean ``better signal''.  The receive timestamp is currently not used
  104  * by the 802.11 layer.
  105  */
  106 void
  107 ieee80211_input(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni,
  108         int rssi, u_int32_t rstamp)
  109 {
  110         struct ieee80211com *ic = (void *)ifp;
  111         struct ieee80211_frame *wh;
  112         struct ether_header *eh;
  113         struct mbuf *m1;
  114         int len;
  115         u_int8_t dir, type, subtype;
  116         u_int8_t *bssid;
  117         u_int16_t rxseq;
  118         ALTQ_DECL(struct altq_pktattr pktattr;)
  119 
  120         IASSERT(ni != NULL, ("null node"));
  121 
  122         /* trim CRC here so WEP can find its own CRC at the end of packet. */
  123         if (m->m_flags & M_HASFCS) {
  124                 m_adj(m, -IEEE80211_CRC_LEN);
  125                 m->m_flags &= ~M_HASFCS;
  126         }
  127 
  128         /*
  129          * In monitor mode, send everything directly to bpf.
  130          * Also do not process frames w/o i_addr2 any further.
  131          * XXX may want to include the CRC
  132          */
  133         if (ic->ic_opmode == IEEE80211_M_MONITOR || 
  134             m->m_pkthdr.len < sizeof(struct ieee80211_frame_min))
  135                 goto out;
  136 
  137         wh = mtod(m, struct ieee80211_frame *);
  138         if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
  139             IEEE80211_FC0_VERSION_0) {
  140                 if (ifp->if_flags & IFF_DEBUG)
  141                         if_printf(ifp, "receive packet with wrong version: %x\n",
  142                             wh->i_fc[0]);
  143                 ieee80211_unref_node(&ni);
  144                 ic->ic_stats.is_rx_badversion++;
  145                 goto err;
  146         }
  147 
  148         dir = wh->i_fc[1] & IEEE80211_FC1_DIR_MASK;
  149         type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
  150         /*
  151          * NB: We are not yet prepared to handle control frames,
  152          *     but permitting drivers to send them to us allows
  153          *     them to go through bpf tapping at the 802.11 layer.
  154          */
  155         if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) {
  156                 /* XXX statistic */
  157                 IEEE80211_DPRINTF2(("%s: frame too short, len %u\n",
  158                         __func__, m->m_pkthdr.len));
  159                 ic->ic_stats.is_rx_tooshort++;
  160                 goto out;               /* XXX */
  161         }
  162         if (ic->ic_state != IEEE80211_S_SCAN) {
  163                 switch (ic->ic_opmode) {
  164                 case IEEE80211_M_STA:
  165                         if (!IEEE80211_ADDR_EQ(wh->i_addr2, ni->ni_bssid)) {
  166                                 /* not interested in */
  167                                 IEEE80211_DPRINTF2(("%s: discard frame from "
  168                                         "bss %s\n", __func__,
  169                                         ether_sprintf(wh->i_addr2)));
  170                                 ic->ic_stats.is_rx_wrongbss++;
  171                                 goto out;
  172                         }
  173                         break;
  174                 case IEEE80211_M_IBSS:
  175                 case IEEE80211_M_AHDEMO:
  176                 case IEEE80211_M_HOSTAP:
  177                         if (dir == IEEE80211_FC1_DIR_NODS)
  178                                 bssid = wh->i_addr3;
  179                         else
  180                                 bssid = wh->i_addr1;
  181                         if (!IEEE80211_ADDR_EQ(bssid, ic->ic_bss->ni_bssid) &&
  182                             !IEEE80211_ADDR_EQ(bssid, ifp->if_broadcastaddr) &&
  183                             (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
  184                             IEEE80211_FC0_TYPE_DATA) {
  185                                 /* not interested in */
  186                                 IEEE80211_DPRINTF2(("%s: discard frame from "
  187                                         "bss %s\n", __func__,
  188                                         ether_sprintf(bssid)));
  189                                 ic->ic_stats.is_rx_wrongbss++;
  190                                 goto out;
  191                         }
  192                         break;
  193                 case IEEE80211_M_MONITOR:
  194                         goto out;
  195                 default:
  196                         /* XXX catch bad values */
  197                         break;
  198                 }
  199                 ni->ni_rssi = rssi;
  200                 ni->ni_rstamp = rstamp;
  201                 rxseq = ni->ni_rxseq;
  202                 ni->ni_rxseq =
  203                     le16toh(*(u_int16_t *)wh->i_seq) >> IEEE80211_SEQ_SEQ_SHIFT;
  204                 /* TODO: fragment */
  205                 if ((wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
  206                     rxseq == ni->ni_rxseq) {
  207                         /* duplicate, silently discarded */
  208                         ic->ic_stats.is_rx_dup++; /* XXX per-station stat */
  209                         goto out;
  210                 }
  211                 ni->ni_inact = 0;
  212         }
  213 
  214         if (ic->ic_set_tim != NULL &&
  215             (wh->i_fc[1] & IEEE80211_FC1_PWR_MGT)
  216             && ni->ni_pwrsave == 0) {
  217                 /* turn on power save mode */
  218 
  219                 if (ifp->if_flags & IFF_DEBUG)
  220                         printf("%s: power save mode on for %s\n",
  221                             ifp->if_xname, ether_sprintf(wh->i_addr2));
  222 
  223                 ni->ni_pwrsave = IEEE80211_PS_SLEEP;
  224         }
  225         if (ic->ic_set_tim != NULL &&
  226             (wh->i_fc[1] & IEEE80211_FC1_PWR_MGT) == 0 &&
  227             ni->ni_pwrsave != 0) {
  228                 /* turn off power save mode, dequeue stored packets */
  229 
  230                 ni->ni_pwrsave = 0;
  231                 if (ic->ic_set_tim) 
  232                         ic->ic_set_tim(ic, ni->ni_associd, 0);
  233 
  234                 if (ifp->if_flags & IFF_DEBUG)
  235                         printf("%s: power save mode off for %s\n",
  236                             ifp->if_xname, ether_sprintf(wh->i_addr2));
  237 
  238                 while (!IF_IS_EMPTY(&ni->ni_savedq)) {
  239                         struct mbuf *m;
  240                         IF_DEQUEUE(&ni->ni_savedq, m);
  241                         IF_ENQUEUE(&ic->ic_pwrsaveq, m);
  242                         (*ifp->if_start)(ifp);
  243                 }
  244         }
  245 
  246         switch (type) {
  247         case IEEE80211_FC0_TYPE_DATA:
  248                 switch (ic->ic_opmode) {
  249                 case IEEE80211_M_STA:
  250                         if (dir != IEEE80211_FC1_DIR_FROMDS) {
  251                                 ic->ic_stats.is_rx_wrongdir++;
  252                                 goto out;
  253                         }
  254                         if ((ifp->if_flags & IFF_SIMPLEX) &&
  255                             IEEE80211_IS_MULTICAST(wh->i_addr1) &&
  256                             IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_myaddr)) {
  257                                 /*
  258                                  * In IEEE802.11 network, multicast packet
  259                                  * sent from me is broadcasted from AP.
  260                                  * It should be silently discarded for
  261                                  * SIMPLEX interface.
  262                                  */
  263                                 ic->ic_stats.is_rx_mcastecho++;
  264                                 goto out;
  265                         }
  266                         break;
  267                 case IEEE80211_M_IBSS:
  268                 case IEEE80211_M_AHDEMO:
  269                         if (dir != IEEE80211_FC1_DIR_NODS) {
  270                                 ic->ic_stats.is_rx_wrongdir++;
  271                                 goto out;
  272                         }
  273                         break;
  274                 case IEEE80211_M_HOSTAP:
  275                         if (dir != IEEE80211_FC1_DIR_TODS) {
  276                                 ic->ic_stats.is_rx_wrongdir++;
  277                                 goto out;
  278                         }
  279                         /* check if source STA is associated */
  280                         if (ni == ic->ic_bss) {
  281                                 IEEE80211_DPRINTF(("%s: data from unknown src "
  282                                         "%s\n", __func__,
  283                                         ether_sprintf(wh->i_addr2)));
  284                                 /* NB: caller deals with reference */
  285                                 ni = ieee80211_dup_bss(ic, wh->i_addr2);
  286                                 if (ni != NULL) {
  287                                         IEEE80211_SEND_MGMT(ic, ni,
  288                                             IEEE80211_FC0_SUBTYPE_DEAUTH,
  289                                             IEEE80211_REASON_NOT_AUTHED);
  290                                         ieee80211_free_node(ic, ni);
  291                                 }
  292                                 ic->ic_stats.is_rx_notassoc++;
  293                                 goto err;
  294                         }
  295                         if (ni->ni_associd == 0) {
  296                                 IEEE80211_DPRINTF(("ieee80211_input: "
  297                                     "data from unassoc src %s\n",
  298                                     ether_sprintf(wh->i_addr2)));
  299                                 IEEE80211_SEND_MGMT(ic, ni,
  300                                     IEEE80211_FC0_SUBTYPE_DISASSOC,
  301                                     IEEE80211_REASON_NOT_ASSOCED);
  302                                 ieee80211_unref_node(&ni);
  303                                 ic->ic_stats.is_rx_notassoc++;
  304                                 goto err;
  305                         }
  306                         break;
  307                 case IEEE80211_M_MONITOR:
  308                         break;
  309                 }
  310                 if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
  311                         if (ic->ic_flags & IEEE80211_F_WEPON) {
  312                                 m = ieee80211_wep_crypt(ifp, m, 0);
  313                                 if (m == NULL) {
  314                                         ic->ic_stats.is_rx_wepfail++;
  315                                         goto err;
  316                                 }
  317                                 wh = mtod(m, struct ieee80211_frame *);
  318                         } else {
  319                                 ic->ic_stats.is_rx_nowep++;
  320                                 goto out;
  321                         }
  322                 }
  323 #if NBPFILTER > 0
  324                 /* copy to listener after decrypt */
  325                 if (ic->ic_rawbpf)
  326                         bpf_mtap(ic->ic_rawbpf, m);
  327 #endif
  328                 m = ieee80211_decap(ifp, m);
  329                 if (m == NULL) {
  330                         IEEE80211_DPRINTF(("ieee80211_input: "
  331                             "decapsulation error for src %s\n",
  332                             ether_sprintf(wh->i_addr2)));
  333                         ic->ic_stats.is_rx_decap++;
  334                         goto err;
  335                 }
  336                 ifp->if_ipackets++;
  337 
  338                 /* perform as a bridge within the AP */
  339                 m1 = NULL;
  340                 if (ic->ic_opmode == IEEE80211_M_HOSTAP) {
  341                         eh = mtod(m, struct ether_header *);
  342                         if (ETHER_IS_MULTICAST(eh->ether_dhost)) {
  343                                 m1 = m_copypacket(m, M_DONTWAIT);
  344                                 if (m1 == NULL)
  345                                         ifp->if_oerrors++;
  346                                 else
  347                                         m1->m_flags |= M_MCAST;
  348                         } else {
  349                                 ni = ieee80211_find_node(ic, eh->ether_dhost);
  350                                 if (ni != NULL) {
  351                                         if (ni->ni_associd != 0) {
  352                                                 m1 = m;
  353                                                 m = NULL;
  354                                         }
  355                                         ieee80211_unref_node(&ni);
  356                                 }
  357                         }
  358                         if (m1 != NULL) {
  359 #ifdef ALTQ
  360                                 if (ALTQ_IS_ENABLED(&ifp->if_snd))
  361                                         altq_etherclassify(&ifp->if_snd, m1,
  362                                             &pktattr);
  363 #endif
  364                                 len = m1->m_pkthdr.len;
  365                                 IF_ENQUEUE(&ifp->if_snd, m1);
  366                                 if (m != NULL)
  367                                         ifp->if_omcasts++;
  368                                 ifp->if_obytes += len;
  369                         }
  370                 }
  371                 if (m != NULL) {
  372 #if NBPFILTER > 0
  373                         /*
  374                          * If we forward packet into transmitter of the AP,
  375                          * we don't need to duplicate for DLT_EN10MB.
  376                          */
  377                         if (ifp->if_bpf && m1 == NULL)
  378                                 bpf_mtap(ifp->if_bpf, m);
  379 #endif
  380                         (*ifp->if_input)(ifp, m);
  381                 }
  382                 return;
  383 
  384         case IEEE80211_FC0_TYPE_MGT:
  385                 if (dir != IEEE80211_FC1_DIR_NODS) {
  386                         ic->ic_stats.is_rx_wrongdir++;
  387                         goto err;
  388                 }
  389                 if (ic->ic_opmode == IEEE80211_M_AHDEMO) {
  390                         ic->ic_stats.is_rx_ahdemo_mgt++;
  391                         goto out;
  392                 }
  393                 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
  394 
  395                 /* drop frames without interest */
  396                 if (ic->ic_state == IEEE80211_S_SCAN) {
  397                         if (subtype != IEEE80211_FC0_SUBTYPE_BEACON &&
  398                             subtype != IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
  399                                 ic->ic_stats.is_rx_mgtdiscard++;
  400                                 goto out;
  401                         }
  402                 } else {
  403                         if (ic->ic_opmode != IEEE80211_M_IBSS &&
  404                             subtype == IEEE80211_FC0_SUBTYPE_BEACON) {
  405                                 ic->ic_stats.is_rx_mgtdiscard++;
  406                                 goto out;
  407                         }
  408                 }
  409 
  410                 if (ifp->if_flags & IFF_DEBUG) {
  411                         /* avoid to print too many frames */
  412                         int doprint = 0;
  413 
  414                         switch (subtype) {
  415                         case IEEE80211_FC0_SUBTYPE_BEACON:
  416                                 if (ic->ic_state == IEEE80211_S_SCAN)
  417                                         doprint = 1;
  418                                 break;
  419                         case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
  420                                 if (ic->ic_opmode == IEEE80211_M_IBSS)
  421                                         doprint = 1;
  422                                 break;
  423                         default:
  424                                 doprint = 1;
  425                                 break;
  426                         }
  427 #ifdef IEEE80211_DEBUG
  428                         doprint += ieee80211_debug;
  429 #endif
  430                         if (doprint)
  431                                 if_printf(ifp, "received %s from %s rssi %d\n",
  432                                     ieee80211_mgt_subtype_name[subtype
  433                                     >> IEEE80211_FC0_SUBTYPE_SHIFT],
  434                                     ether_sprintf(wh->i_addr2), rssi);
  435                 }
  436 #if NBPFILTER > 0
  437                 if (ic->ic_rawbpf)
  438                         bpf_mtap(ic->ic_rawbpf, m);
  439 #endif
  440                 (*ic->ic_recv_mgmt)(ic, m, ni, subtype, rssi, rstamp);
  441                 m_freem(m);
  442                 return;
  443 
  444         case IEEE80211_FC0_TYPE_CTL:
  445                 ic->ic_stats.is_rx_ctl++;
  446                 if (ic->ic_opmode != IEEE80211_M_HOSTAP)
  447                         goto out;
  448                 subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
  449                 if (subtype == IEEE80211_FC0_SUBTYPE_PS_POLL) {
  450                         /* XXX statistic */
  451                         /* Dump out a single packet from the host */
  452                         if (ifp->if_flags & IFF_DEBUG)
  453                                 printf("%s: got power save probe from %s\n",
  454                                     ifp->if_xname,
  455                                     ether_sprintf(wh->i_addr2));
  456                         ieee80211_recv_pspoll(ic, m, rssi, rstamp);
  457                 }
  458                 goto out;
  459 
  460         default:
  461                 IEEE80211_DPRINTF(("%s: bad type %x\n", __func__, type));
  462                 /* should not come here */
  463                 break;
  464         }
  465   err:
  466         ifp->if_ierrors++;
  467   out:
  468         if (m != NULL) {
  469 #if NBPFILTER > 0
  470                 if (ic->ic_rawbpf)
  471                         bpf_mtap(ic->ic_rawbpf, m);
  472 #endif
  473                 m_freem(m);
  474         }
  475 }
  476 
  477 struct mbuf *
  478 ieee80211_decap(struct ifnet *ifp, struct mbuf *m)
  479 {
  480         struct ether_header *eh;
  481         struct ieee80211_frame wh;
  482         struct llc *llc;
  483 
  484         if (m->m_len < sizeof(wh) + sizeof(*llc)) {
  485                 m = m_pullup(m, sizeof(wh) + sizeof(*llc));
  486                 if (m == NULL)
  487                         return NULL;
  488         }
  489         memcpy(&wh, mtod(m, caddr_t), sizeof(wh));
  490         llc = (struct llc *)(mtod(m, caddr_t) + sizeof(wh));
  491         if (llc->llc_dsap == LLC_SNAP_LSAP && llc->llc_ssap == LLC_SNAP_LSAP &&
  492             llc->llc_control == LLC_UI && llc->llc_snap.org_code[0] == 0 &&
  493             llc->llc_snap.org_code[1] == 0 && llc->llc_snap.org_code[2] == 0) {
  494                 m_adj(m, sizeof(wh) + sizeof(struct llc) - sizeof(*eh));
  495                 llc = NULL;
  496         } else {
  497                 m_adj(m, sizeof(wh) - sizeof(*eh));
  498         }
  499         eh = mtod(m, struct ether_header *);
  500         switch (wh.i_fc[1] & IEEE80211_FC1_DIR_MASK) {
  501         case IEEE80211_FC1_DIR_NODS:
  502                 IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1);
  503                 IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2);
  504                 break;
  505         case IEEE80211_FC1_DIR_TODS:
  506                 IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr3);
  507                 IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr2);
  508                 break;
  509         case IEEE80211_FC1_DIR_FROMDS:
  510                 IEEE80211_ADDR_COPY(eh->ether_dhost, wh.i_addr1);
  511                 IEEE80211_ADDR_COPY(eh->ether_shost, wh.i_addr3);
  512                 break;
  513         case IEEE80211_FC1_DIR_DSTODS:
  514                 /* not yet supported */
  515                 IEEE80211_DPRINTF(("%s: DS to DS\n", __func__));
  516                 m_freem(m);
  517                 return NULL;
  518         }
  519 #ifdef ALIGNED_POINTER
  520         if (!ALIGNED_POINTER(mtod(m, caddr_t) + sizeof(*eh), u_int32_t)) {
  521                 struct mbuf *n, *n0, **np;
  522                 caddr_t newdata;
  523                 int off, pktlen;
  524 
  525                 n0 = NULL;
  526                 np = &n0;
  527                 off = 0;
  528                 pktlen = m->m_pkthdr.len;
  529                 while (pktlen > off) {
  530                         if (n0 == NULL) {
  531                                 MGETHDR(n, M_DONTWAIT, MT_DATA);
  532                                 if (n == NULL) {
  533                                         m_freem(m);
  534                                         return NULL;
  535                                 }
  536 #ifdef __FreeBSD__
  537                                 M_MOVE_PKTHDR(n, m);
  538 #else
  539                                 M_COPY_PKTHDR(n, m);
  540 #endif
  541                                 n->m_len = MHLEN;
  542                         } else {
  543                                 MGET(n, M_DONTWAIT, MT_DATA);
  544                                 if (n == NULL) {
  545                                         m_freem(m);
  546                                         m_freem(n0);
  547                                         return NULL;
  548                                 }
  549                                 n->m_len = MLEN;
  550                         }
  551                         if (pktlen - off >= MINCLSIZE) {
  552                                 MCLGET(n, M_DONTWAIT);
  553                                 if (n->m_flags & M_EXT)
  554                                         n->m_len = n->m_ext.ext_size;
  555                         }
  556                         if (n0 == NULL) {
  557                                 newdata =
  558                                     (caddr_t)ALIGN(n->m_data + sizeof(*eh)) -
  559                                     sizeof(*eh);
  560                                 n->m_len -= newdata - n->m_data;
  561                                 n->m_data = newdata;
  562                         }
  563                         if (n->m_len > pktlen - off)
  564                                 n->m_len = pktlen - off;
  565                         m_copydata(m, off, n->m_len, mtod(n, caddr_t));
  566                         off += n->m_len;
  567                         *np = n;
  568                         np = &n->m_next;
  569                 }
  570                 m_freem(m);
  571                 m = n0;
  572         }
  573 #endif /* ALIGNED_POINTER */
  574         if (llc != NULL) {
  575                 eh = mtod(m, struct ether_header *);
  576                 eh->ether_type = htons(m->m_pkthdr.len - sizeof(*eh));
  577         }
  578         return m;
  579 }
  580 
  581 /*
  582  * Install received rate set information in the node's state block.
  583  */
  584 static int
  585 ieee80211_setup_rates(struct ieee80211com *ic, struct ieee80211_node *ni,
  586         u_int8_t *rates, u_int8_t *xrates, int flags)
  587 {
  588         struct ieee80211_rateset *rs = &ni->ni_rates;
  589 
  590         memset(rs, 0, sizeof(*rs));
  591         rs->rs_nrates = rates[1];
  592         memcpy(rs->rs_rates, rates + 2, rs->rs_nrates);
  593         if (xrates != NULL) {
  594                 u_int8_t nxrates;
  595                 /*
  596                  * Tack on 11g extended supported rate element.
  597                  */
  598                 nxrates = xrates[1];
  599                 if (rs->rs_nrates + nxrates > IEEE80211_RATE_MAXSIZE) {
  600                         nxrates = IEEE80211_RATE_MAXSIZE - rs->rs_nrates;
  601                         IEEE80211_DPRINTF(("%s: extended rate set too large;"
  602                                 " only using %u of %u rates\n",
  603                                 __func__, nxrates, xrates[1]));
  604                         ic->ic_stats.is_rx_rstoobig++;
  605                 }
  606                 memcpy(rs->rs_rates + rs->rs_nrates, xrates+2, nxrates);
  607                 rs->rs_nrates += nxrates;
  608         }
  609         return ieee80211_fix_rate(ic, ni, flags);
  610 }
  611 
  612 /* Verify the existence and length of __elem or get out. */
  613 #define IEEE80211_VERIFY_ELEMENT(__elem, __maxlen) do {                 \
  614         if ((__elem) == NULL) {                                         \
  615                 IEEE80211_DPRINTF(("%s: no " #__elem "in %s frame\n",   \
  616                         __func__, ieee80211_mgt_subtype_name[subtype >> \
  617                                 IEEE80211_FC0_SUBTYPE_SHIFT]));         \
  618                 ic->ic_stats.is_rx_elem_missing++;                      \
  619                 return;                                                 \
  620         }                                                               \
  621         if ((__elem)[1] > (__maxlen)) {                                 \
  622                 IEEE80211_DPRINTF(("%s: bad " #__elem " len %d in %s "  \
  623                         "frame from %s\n", __func__, (__elem)[1],       \
  624                         ieee80211_mgt_subtype_name[subtype >>           \
  625                                 IEEE80211_FC0_SUBTYPE_SHIFT],           \
  626                         ether_sprintf(wh->i_addr2)));                   \
  627                 ic->ic_stats.is_rx_elem_toobig++;                       \
  628                 return;                                                 \
  629         }                                                               \
  630 } while (0)
  631 
  632 #define IEEE80211_VERIFY_LENGTH(_len, _minlen) do {                     \
  633         if ((_len) < (_minlen)) {                                       \
  634                 IEEE80211_DPRINTF(("%s: %s frame too short from %s\n",  \
  635                         __func__,                                       \
  636                         ieee80211_mgt_subtype_name[subtype >>           \
  637                                 IEEE80211_FC0_SUBTYPE_SHIFT],           \
  638                         ether_sprintf(wh->i_addr2)));                   \
  639                 ic->ic_stats.is_rx_elem_toosmall++;                     \
  640                 return;                                                 \
  641         }                                                               \
  642 } while (0)
  643 
  644 static void
  645 ieee80211_auth_open(struct ieee80211com *ic, struct ieee80211_frame *wh,
  646     struct ieee80211_node *ni, int rssi, u_int32_t rstamp, u_int16_t seq,
  647     u_int16_t status)
  648 {
  649         struct ifnet *ifp = &ic->ic_if;
  650         int allocbs;
  651         switch (ic->ic_opmode) {
  652         case IEEE80211_M_IBSS:
  653                 if (ic->ic_state != IEEE80211_S_RUN ||
  654                     seq != IEEE80211_AUTH_OPEN_REQUEST) {
  655                         ic->ic_stats.is_rx_bad_auth++;
  656                         return;
  657                 }
  658                 ieee80211_new_state(ic, IEEE80211_S_AUTH,
  659                     wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
  660                 break;
  661 
  662         case IEEE80211_M_AHDEMO:
  663                 /* should not come here */
  664                 break;
  665 
  666         case IEEE80211_M_HOSTAP:
  667                 if (ic->ic_state != IEEE80211_S_RUN ||
  668                     seq != IEEE80211_AUTH_OPEN_REQUEST) {
  669                         ic->ic_stats.is_rx_bad_auth++;
  670                         return;
  671                 }
  672                 if (ni == ic->ic_bss) {
  673                         ni = ieee80211_alloc_node(ic, wh->i_addr2);
  674                         if (ni == NULL) {
  675                                 ic->ic_stats.is_rx_nodealloc++;
  676                                 return;
  677                         }
  678                         IEEE80211_ADDR_COPY(ni->ni_bssid, ic->ic_bss->ni_bssid);
  679                         ni->ni_rssi = rssi;
  680                         ni->ni_rstamp = rstamp;
  681                         ni->ni_chan = ic->ic_bss->ni_chan;
  682                         allocbs = 1;
  683                 } else
  684                         allocbs = 0;
  685                 IEEE80211_SEND_MGMT(ic, ni,
  686                         IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
  687                 if (ifp->if_flags & IFF_DEBUG)
  688                         if_printf(ifp, "station %s %s authenticated (open)\n",
  689                             ether_sprintf(ni->ni_macaddr),
  690                             (allocbs ? "newly" : "already"));
  691                 break;
  692 
  693         case IEEE80211_M_STA:
  694                 if (ic->ic_state != IEEE80211_S_AUTH ||
  695                     seq != IEEE80211_AUTH_OPEN_RESPONSE) {
  696                         ic->ic_stats.is_rx_bad_auth++;
  697                         return;
  698                 }
  699                 if (status != 0) {
  700                         if_printf(&ic->ic_if,
  701                             "open authentication failed (reason %d) for %s\n",
  702                             status,
  703                             ether_sprintf(wh->i_addr3));
  704                         if (ni != ic->ic_bss)
  705                                 ni->ni_fails++;
  706                         ic->ic_stats.is_rx_auth_fail++;
  707                         return;
  708                 }
  709                 ieee80211_new_state(ic, IEEE80211_S_ASSOC,
  710                     wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
  711                 break;
  712         case IEEE80211_M_MONITOR:
  713                 break;
  714         }
  715 }
  716 
  717 /* TBD send appropriate responses on error? */
  718 static void
  719 ieee80211_auth_shared(struct ieee80211com *ic, struct ieee80211_frame *wh,
  720     u_int8_t *frm, u_int8_t *efrm, struct ieee80211_node *ni, int rssi,
  721     u_int32_t rstamp, u_int16_t seq, u_int16_t status)
  722 {
  723         struct ifnet *ifp = &ic->ic_if;
  724         u_int8_t *challenge = NULL;
  725         int allocbs, i;
  726 
  727         if ((ic->ic_flags & IEEE80211_F_WEPON) == 0) {
  728                 IEEE80211_DPRINTF(("%s: WEP is off\n", __func__));
  729                 return;
  730         }
  731 
  732         if (frm + 1 < efrm) {
  733                 if (frm[1] + 2 > efrm - frm) {
  734                         IEEE80211_DPRINTF(("elt %d %d bytes too long\n",
  735                             frm[0], (frm[1] + 2) - (int)(efrm - frm)));
  736                         ic->ic_stats.is_rx_bad_auth++;
  737                         return;
  738                 }
  739                 if (*frm == IEEE80211_ELEMID_CHALLENGE)
  740                         challenge = frm;
  741                 frm += frm[1] + 2;
  742         }
  743         switch (seq) {
  744         case IEEE80211_AUTH_SHARED_CHALLENGE:
  745         case IEEE80211_AUTH_SHARED_RESPONSE:
  746                 if (challenge == NULL) {
  747                         IEEE80211_DPRINTF(("%s: no challenge sent\n",
  748                             __func__));
  749                         ic->ic_stats.is_rx_bad_auth++;
  750                         return;
  751                 }
  752                 if (challenge[1] != IEEE80211_CHALLENGE_LEN) {
  753                         IEEE80211_DPRINTF(("%s: bad challenge len %d\n",
  754                             __func__, challenge[1]));
  755                         ic->ic_stats.is_rx_bad_auth++;
  756                         return;
  757                 }
  758         default:
  759                 break;
  760         }
  761         switch (ic->ic_opmode) {
  762         case IEEE80211_M_MONITOR:
  763         case IEEE80211_M_AHDEMO:
  764         case IEEE80211_M_IBSS:
  765                 IEEE80211_DPRINTF(("%s: unexpected operating mode\n",
  766                     __func__));
  767                 return;
  768         case IEEE80211_M_HOSTAP:
  769                 if (ic->ic_state != IEEE80211_S_RUN) {
  770                         IEEE80211_DPRINTF(("%s: not running\n", __func__));
  771                         return;
  772                 }
  773                 switch (seq) {
  774                 case IEEE80211_AUTH_SHARED_REQUEST:
  775                         if (ni == ic->ic_bss) {
  776                                 ni = ieee80211_alloc_node(ic, wh->i_addr2);
  777                                 if (ni == NULL) {
  778                                         ic->ic_stats.is_rx_nodealloc++;
  779                                         return;
  780                                 }
  781                                 IEEE80211_ADDR_COPY(ni->ni_bssid,
  782                                     ic->ic_bss->ni_bssid);
  783                                 ni->ni_rssi = rssi;
  784                                 ni->ni_rstamp = rstamp;
  785                                 ni->ni_chan = ic->ic_bss->ni_chan;
  786                                 allocbs = 1;
  787                         } else
  788                                 allocbs = 0;
  789                         if (ni->ni_challenge == NULL)
  790                                 ni->ni_challenge = (u_int32_t*)malloc(
  791                                     IEEE80211_CHALLENGE_LEN, M_DEVBUF,
  792                                     M_NOWAIT);
  793                         if (ni->ni_challenge == NULL) {
  794                                 IEEE80211_DPRINTF(("challenge alloc failed\n"));
  795                                 /* XXX statistic */
  796                                 return;
  797                         }
  798                         for (i = IEEE80211_CHALLENGE_LEN / sizeof(u_int32_t);
  799                              --i >= 0; )
  800                                 ni->ni_challenge[i] = arc4random();
  801                         if (ifp->if_flags & IFF_DEBUG)
  802                                 if_printf(ifp, "station %s shared key "
  803                                         "%sauthentication\n",
  804                                         ether_sprintf(ni->ni_macaddr),
  805                                         allocbs ? "" : "re");
  806                         break;
  807                 case IEEE80211_AUTH_SHARED_RESPONSE:
  808                         if (ni == ic->ic_bss) {
  809                                 IEEE80211_DPRINTF(("%s: unknown STA\n",
  810                                     __func__));
  811                                 return;
  812                         }
  813                         if (ni->ni_challenge == NULL) {
  814                                 IEEE80211_DPRINTF((
  815                                     "%s: no challenge recorded\n", __func__));
  816                                 ic->ic_stats.is_rx_bad_auth++;
  817                                 return;
  818                         }
  819                         if (memcmp(ni->ni_challenge, &challenge[2],
  820                                    challenge[1]) != 0) {
  821                                 IEEE80211_DPRINTF(("%s: challenge mismatch\n",
  822                                     __func__));
  823                                 ic->ic_stats.is_rx_auth_fail++;
  824                                 return;
  825                         }
  826                         if (ifp->if_flags & IFF_DEBUG)
  827                                 if_printf(ifp, "station %s authenticated "
  828                                         "(shared key)\n",
  829                                         ether_sprintf(ni->ni_macaddr));
  830                         break;
  831                 default:
  832                         IEEE80211_DPRINTF(("%s: bad seq %d from %s\n",
  833                             __func__, seq, ether_sprintf(wh->i_addr2)));
  834                         ic->ic_stats.is_rx_bad_auth++;
  835                         return;
  836                 }
  837                 IEEE80211_SEND_MGMT(ic, ni,
  838                         IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
  839                 break;
  840 
  841         case IEEE80211_M_STA:
  842                 if (ic->ic_state != IEEE80211_S_AUTH)
  843                         return;
  844                 switch (seq) {
  845                 case IEEE80211_AUTH_SHARED_PASS:
  846                         if (ni->ni_challenge != NULL) {
  847                                 FREE(ni->ni_challenge, M_DEVBUF);
  848                                 ni->ni_challenge = NULL;
  849                         }
  850                         if (status != 0) {
  851                                 if_printf(&ic->ic_if,
  852                                     "%s: shared authentication failed "
  853                                     "(reason %d) for %s\n",
  854                                     __func__, status,
  855                                     ether_sprintf(wh->i_addr3));
  856                                 if (ni != ic->ic_bss)
  857                                         ni->ni_fails++;
  858                                 ic->ic_stats.is_rx_auth_fail++;
  859                                 return;
  860                         }
  861                         ieee80211_new_state(ic, IEEE80211_S_ASSOC,
  862                             wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
  863                         break;
  864                 case IEEE80211_AUTH_SHARED_CHALLENGE:
  865                         if (ni->ni_challenge == NULL)
  866                                 ni->ni_challenge = (u_int32_t*)malloc(
  867                                     challenge[1], M_DEVBUF, M_NOWAIT);
  868                         if (ni->ni_challenge == NULL) {
  869                                 IEEE80211_DPRINTF((
  870                                     "%s: challenge alloc failed\n", __func__));
  871                                 /* XXX statistic */
  872                                 return;
  873                         }
  874                         memcpy(ni->ni_challenge, &challenge[2], challenge[1]);
  875                         IEEE80211_SEND_MGMT(ic, ni,
  876                                 IEEE80211_FC0_SUBTYPE_AUTH, seq + 1);
  877                         break;
  878                 default:
  879                         IEEE80211_DPRINTF(("%s: bad seq %d from %s\n",
  880                             __func__, seq, ether_sprintf(wh->i_addr2)));
  881                         ic->ic_stats.is_rx_bad_auth++;
  882                         return;
  883                 }
  884                 break;
  885         }
  886 }
  887 
  888 void
  889 ieee80211_recv_mgmt(struct ieee80211com *ic, struct mbuf *m0,
  890         struct ieee80211_node *ni,
  891         int subtype, int rssi, u_int32_t rstamp)
  892 {
  893 #define ISPROBE(_st)    ((_st) == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
  894         struct ifnet *ifp = &ic->ic_if;
  895         struct ieee80211_frame *wh;
  896         u_int8_t *frm, *efrm;
  897         u_int8_t *ssid, *rates, *xrates;
  898         int reassoc, resp, newassoc, allocbs;
  899 
  900         wh = mtod(m0, struct ieee80211_frame *);
  901         frm = (u_int8_t *)&wh[1];
  902         efrm = mtod(m0, u_int8_t *) + m0->m_len;
  903         switch (subtype) {
  904         case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
  905         case IEEE80211_FC0_SUBTYPE_BEACON: {
  906                 u_int8_t *tstamp, *bintval, *capinfo, *country;
  907                 u_int8_t chan, bchan, fhindex, erp;
  908                 u_int16_t fhdwell;
  909 
  910                 if (ic->ic_opmode != IEEE80211_M_IBSS &&
  911                     ic->ic_state != IEEE80211_S_SCAN) {
  912                         /* XXX: may be useful for background scan */
  913                         return;
  914                 }
  915 
  916                 /*
  917                  * beacon/probe response frame format
  918                  *      [8] time stamp
  919                  *      [2] beacon interval
  920                  *      [2] capability information
  921                  *      [tlv] ssid
  922                  *      [tlv] supported rates
  923                  *      [tlv] country information
  924                  *      [tlv] parameter set (FH/DS)
  925                  *      [tlv] erp information
  926                  *      [tlv] extended supported rates
  927                  */
  928                 IEEE80211_VERIFY_LENGTH(efrm - frm, 12);
  929                 tstamp  = frm;  frm += 8;
  930                 bintval = frm;  frm += 2;
  931                 capinfo = frm;  frm += 2;
  932                 ssid = rates = xrates = country = NULL;
  933                 bchan = ieee80211_chan2ieee(ic, ic->ic_bss->ni_chan);
  934                 chan = bchan;
  935                 fhdwell = 0;
  936                 fhindex = 0;
  937                 erp = 0;
  938                 while (frm < efrm) {
  939                         switch (*frm) {
  940                         case IEEE80211_ELEMID_SSID:
  941                                 ssid = frm;
  942                                 break;
  943                         case IEEE80211_ELEMID_RATES:
  944                                 rates = frm;
  945                                 break;
  946                         case IEEE80211_ELEMID_COUNTRY:
  947                                 country = frm;
  948                                 break;
  949                         case IEEE80211_ELEMID_FHPARMS:
  950                                 if (ic->ic_phytype == IEEE80211_T_FH) {
  951                                         fhdwell = (frm[3] << 8) | frm[2];
  952                                         chan = IEEE80211_FH_CHAN(frm[4], frm[5]);
  953                                         fhindex = frm[6];
  954                                 }
  955                                 break;
  956                         case IEEE80211_ELEMID_DSPARMS:
  957                                 /*
  958                                  * XXX hack this since depending on phytype
  959                                  * is problematic for multi-mode devices.
  960                                  */
  961                                 if (ic->ic_phytype != IEEE80211_T_FH)
  962                                         chan = frm[2];
  963                                 break;
  964                         case IEEE80211_ELEMID_TIM:
  965                                 break;
  966                         case IEEE80211_ELEMID_XRATES:
  967                                 xrates = frm;
  968                                 break;
  969                         case IEEE80211_ELEMID_ERP:
  970                                 if (frm[1] != 1) {
  971                                         IEEE80211_DPRINTF(("%s: invalid ERP "
  972                                                 "element; length %u, expecting "
  973                                                 "1\n", __func__, frm[1]));
  974                                         ic->ic_stats.is_rx_elem_toobig++;
  975                                         break;
  976                                 }
  977                                 erp = frm[2];
  978                                 break;
  979                         default:
  980                                 IEEE80211_DPRINTF2(("%s: element id %u/len %u "
  981                                         "ignored\n", __func__, *frm, frm[1]));
  982                                 ic->ic_stats.is_rx_elem_unknown++;
  983                                 break;
  984                         }
  985                         frm += frm[1] + 2;
  986                 }
  987                 IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
  988                 IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
  989                 if (
  990 #if IEEE80211_CHAN_MAX < 255
  991                     chan > IEEE80211_CHAN_MAX ||
  992 #endif
  993                     isclr(ic->ic_chan_active, chan)) {
  994                         IEEE80211_DPRINTF(("%s: ignore %s with invalid channel "
  995                                 "%u\n", __func__,
  996                                 ISPROBE(subtype) ? "probe response" : "beacon",
  997                                 chan));
  998                         ic->ic_stats.is_rx_badchan++;
  999                         return;
 1000                 }
 1001                 if (chan != bchan && ic->ic_phytype != IEEE80211_T_FH) {
 1002                         /*
 1003                          * Frame was received on a channel different from the
 1004                          * one indicated in the DS params element id;
 1005                          * silently discard it.
 1006                          *
 1007                          * NB: this can happen due to signal leakage.
 1008                          *     But we should take it for FH phy because
 1009                          *     the rssi value should be correct even for
 1010                          *     different hop pattern in FH.
 1011                          */
 1012                         IEEE80211_DPRINTF(("%s: ignore %s on channel %u marked "
 1013                                 "for channel %u\n", __func__,
 1014                                 ISPROBE(subtype) ? "probe response" : "beacon",
 1015                                 bchan, chan));
 1016                         ic->ic_stats.is_rx_chanmismatch++;
 1017                         return;
 1018                 }
 1019 
 1020                 /*
 1021                  * Use mac and channel for lookup so we collect all
 1022                  * potential AP's when scanning.  Otherwise we may
 1023                  * see the same AP on multiple channels and will only
 1024                  * record the last one.  We could filter APs here based
 1025                  * on rssi, etc. but leave that to the end of the scan
 1026                  * so we can keep the selection criteria in one spot.
 1027                  * This may result in a bloat of the scanned AP list but
 1028                  * it shouldn't be too much.
 1029                  */
 1030                 ni = ieee80211_lookup_node_for_beacon(ic, wh->i_addr2,
 1031                                 &ic->ic_channels[chan], ssid);
 1032 #ifdef IEEE80211_DEBUG
 1033                 if (ieee80211_debug &&
 1034                     (ni == NULL || ic->ic_state == IEEE80211_S_SCAN)) {
 1035                         printf("%s: %s%s on chan %u (bss chan %u) ",
 1036                             __func__, (ni == NULL ? "new " : ""),
 1037                             ISPROBE(subtype) ? "probe response" : "beacon",
 1038                             chan, bchan);
 1039                         ieee80211_print_essid(ssid + 2, ssid[1]);
 1040                         printf(" from %s\n", ether_sprintf(wh->i_addr2));
 1041                         printf("%s: caps 0x%x bintval %u erp 0x%x\n",
 1042                                 __func__, le16toh(*(u_int16_t *)capinfo),
 1043                                 le16toh(*(u_int16_t *)bintval), erp);
 1044                         if (country) {
 1045                                 int i;
 1046                                 printf("%s: country info", __func__);
 1047                                 for (i = 0; i < country[1]; i++)
 1048                                         printf(" %02x", country[i+2]);
 1049                                 printf("\n");
 1050                         }
 1051                 }
 1052 #endif
 1053                 if (ni == NULL) {
 1054                         ni = ieee80211_alloc_node(ic, wh->i_addr2);
 1055                         if (ni == NULL) {
 1056                                 ic->ic_stats.is_rx_nodealloc++;
 1057                                 return;
 1058                         }
 1059                         ni->ni_esslen = ssid[1];
 1060                         memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
 1061                         memcpy(ni->ni_essid, ssid + 2, ssid[1]);
 1062                 } else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
 1063                         /*
 1064                          * Update ESSID at probe response to adopt hidden AP by
 1065                          * Lucent/Cisco, which announces null ESSID in beacon.
 1066                          */
 1067                         ni->ni_esslen = ssid[1];
 1068                         memset(ni->ni_essid, 0, sizeof(ni->ni_essid));
 1069                         memcpy(ni->ni_essid, ssid + 2, ssid[1]);
 1070                 }
 1071                 IEEE80211_ADDR_COPY(ni->ni_bssid, wh->i_addr3);
 1072                 ni->ni_rssi = rssi;
 1073                 ni->ni_rstamp = rstamp;
 1074                 memcpy(ni->ni_tstamp, tstamp, sizeof(ni->ni_tstamp));
 1075                 ni->ni_intval = le16toh(*(u_int16_t *)bintval);
 1076                 ni->ni_capinfo = le16toh(*(u_int16_t *)capinfo);
 1077                 /* XXX validate channel # */
 1078                 ni->ni_chan = &ic->ic_channels[chan];
 1079                 ni->ni_fhdwell = fhdwell;
 1080                 ni->ni_fhindex = fhindex;
 1081                 ni->ni_erp = erp;
 1082                 /* NB: must be after ni_chan is setup */
 1083                 ieee80211_setup_rates(ic, ni, rates, xrates, IEEE80211_F_DOSORT);
 1084                 ieee80211_unref_node(&ni);
 1085                 break;
 1086         }
 1087 
 1088         case IEEE80211_FC0_SUBTYPE_PROBE_REQ: {
 1089                 u_int8_t rate;
 1090 
 1091                 if (ic->ic_opmode == IEEE80211_M_STA)
 1092                         return;
 1093                 if (ic->ic_state != IEEE80211_S_RUN)
 1094                         return;
 1095 
 1096                 /*
 1097                  * prreq frame format
 1098                  *      [tlv] ssid
 1099                  *      [tlv] supported rates
 1100                  *      [tlv] extended supported rates
 1101                  */
 1102                 ssid = rates = xrates = NULL;
 1103                 while (frm < efrm) {
 1104                         switch (*frm) {
 1105                         case IEEE80211_ELEMID_SSID:
 1106                                 ssid = frm;
 1107                                 break;
 1108                         case IEEE80211_ELEMID_RATES:
 1109                                 rates = frm;
 1110                                 break;
 1111                         case IEEE80211_ELEMID_XRATES:
 1112                                 xrates = frm;
 1113                                 break;
 1114                         }
 1115                         frm += frm[1] + 2;
 1116                 }
 1117                 IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
 1118                 IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
 1119                 if (ssid[1] != 0 &&
 1120                     (ssid[1] != ic->ic_bss->ni_esslen ||
 1121                     memcmp(ssid + 2, ic->ic_bss->ni_essid, ic->ic_bss->ni_esslen) != 0)) {
 1122 #ifdef IEEE80211_DEBUG
 1123                         if (ieee80211_debug) {
 1124                                 printf("%s: ssid mismatch ", __func__);
 1125                                 ieee80211_print_essid(ssid + 2, ssid[1]);
 1126                                 printf(" from %s\n", ether_sprintf(wh->i_addr2));
 1127                         }
 1128 #endif
 1129                         ic->ic_stats.is_rx_ssidmismatch++;
 1130                         return;
 1131                 }
 1132 
 1133                 if (ni == ic->ic_bss) {
 1134                         ni = ieee80211_dup_bss(ic, wh->i_addr2);
 1135                         if (ni == NULL) {
 1136                                 ic->ic_stats.is_rx_nodealloc++;
 1137                                 return;
 1138                         }
 1139                         IEEE80211_DPRINTF(("%s: new req from %s\n",
 1140                                 __func__, ether_sprintf(wh->i_addr2)));
 1141                         allocbs = 1;
 1142                 } else
 1143                         allocbs = 0;
 1144                 ni->ni_rssi = rssi;
 1145                 ni->ni_rstamp = rstamp;
 1146                 rate = ieee80211_setup_rates(ic, ni, rates, xrates,
 1147                                 IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE
 1148                                 | IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
 1149                 if (rate & IEEE80211_RATE_BASIC) {
 1150                         IEEE80211_DPRINTF(("%s: rate negotiation failed: %s\n",
 1151                                 __func__,ether_sprintf(wh->i_addr2)));
 1152                 } else {
 1153                         IEEE80211_SEND_MGMT(ic, ni,
 1154                                 IEEE80211_FC0_SUBTYPE_PROBE_RESP, 0);
 1155                 }
 1156                 if (allocbs) {
 1157                         /* XXX just use free? */
 1158                         if (ic->ic_opmode == IEEE80211_M_HOSTAP)
 1159                                 ieee80211_free_node(ic, ni);
 1160                         else
 1161                                 ieee80211_unref_node(&ni);
 1162                 }
 1163                 break;
 1164         }
 1165 
 1166         case IEEE80211_FC0_SUBTYPE_AUTH: {
 1167                 u_int16_t algo, seq, status;
 1168                 /*
 1169                  * auth frame format
 1170                  *      [2] algorithm
 1171                  *      [2] sequence
 1172                  *      [2] status
 1173                  *      [tlv*] challenge
 1174                  */
 1175                 IEEE80211_VERIFY_LENGTH(efrm - frm, 6);
 1176                 algo   = le16toh(*(u_int16_t *)frm);
 1177                 seq    = le16toh(*(u_int16_t *)(frm + 2));
 1178                 status = le16toh(*(u_int16_t *)(frm + 4));
 1179                 IEEE80211_DPRINTF(("%s: auth %d seq %d from %s\n",
 1180                     __func__, algo, seq, ether_sprintf(wh->i_addr2)));
 1181 
 1182                 if (algo == IEEE80211_AUTH_ALG_SHARED)
 1183                         ieee80211_auth_shared(ic, wh, frm + 6, efrm, ni, rssi,
 1184                             rstamp, seq, status);
 1185                 else if (algo == IEEE80211_AUTH_ALG_OPEN)
 1186                         ieee80211_auth_open(ic, wh, ni, rssi, rstamp, seq,
 1187                             status);
 1188                 else {
 1189                         IEEE80211_DPRINTF(("%s: unsupported authentication "
 1190                                 "algorithm %d from %s\n",
 1191                                 __func__, algo, ether_sprintf(wh->i_addr2)));
 1192                         ic->ic_stats.is_rx_auth_unsupported++;
 1193                         return;
 1194                 } 
 1195                 break;
 1196         }
 1197 
 1198         case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
 1199         case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: {
 1200                 u_int16_t capinfo, bintval;
 1201 
 1202                 if (ic->ic_opmode != IEEE80211_M_HOSTAP ||
 1203                     (ic->ic_state != IEEE80211_S_RUN))
 1204                         return;
 1205 
 1206                 if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
 1207                         reassoc = 1;
 1208                         resp = IEEE80211_FC0_SUBTYPE_REASSOC_RESP;
 1209                 } else {
 1210                         reassoc = 0;
 1211                         resp = IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
 1212                 }
 1213                 /*
 1214                  * asreq frame format
 1215                  *      [2] capability information
 1216                  *      [2] listen interval
 1217                  *      [6*] current AP address (reassoc only)
 1218                  *      [tlv] ssid
 1219                  *      [tlv] supported rates
 1220                  *      [tlv] extended supported rates
 1221                  */
 1222                 IEEE80211_VERIFY_LENGTH(efrm - frm, (reassoc ? 10 : 4));
 1223                 if (!IEEE80211_ADDR_EQ(wh->i_addr3, ic->ic_bss->ni_bssid)) {
 1224                         IEEE80211_DPRINTF(("%s: ignore other bss from %s\n",
 1225                                 __func__, ether_sprintf(wh->i_addr2)));
 1226                         ic->ic_stats.is_rx_assoc_bss++;
 1227                         return;
 1228                 }
 1229                 capinfo = le16toh(*(u_int16_t *)frm);   frm += 2;
 1230                 bintval = le16toh(*(u_int16_t *)frm);   frm += 2;
 1231                 if (reassoc)
 1232                         frm += 6;       /* ignore current AP info */
 1233                 ssid = rates = xrates = NULL;
 1234                 while (frm < efrm) {
 1235                         switch (*frm) {
 1236                         case IEEE80211_ELEMID_SSID:
 1237                                 ssid = frm;
 1238                                 break;
 1239                         case IEEE80211_ELEMID_RATES:
 1240                                 rates = frm;
 1241                                 break;
 1242                         case IEEE80211_ELEMID_XRATES:
 1243                                 xrates = frm;
 1244                                 break;
 1245                         }
 1246                         frm += frm[1] + 2;
 1247                 }
 1248                 IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
 1249                 IEEE80211_VERIFY_ELEMENT(ssid, IEEE80211_NWID_LEN);
 1250                 if (ssid[1] != ic->ic_bss->ni_esslen ||
 1251                     memcmp(ssid + 2, ic->ic_bss->ni_essid, ssid[1]) != 0) {
 1252 #ifdef IEEE80211_DEBUG
 1253                         if (ieee80211_debug) {
 1254                                 printf("%s: ssid mismatch ", __func__);
 1255                                 ieee80211_print_essid(ssid + 2, ssid[1]);
 1256                                 printf(" from %s\n", ether_sprintf(wh->i_addr2));
 1257                         }
 1258 #endif
 1259                         ic->ic_stats.is_rx_ssidmismatch++;
 1260                         return;
 1261                 }
 1262                 if (ni == ic->ic_bss) {
 1263                         IEEE80211_DPRINTF(("%s: not authenticated for %s\n",
 1264                                 __func__, ether_sprintf(wh->i_addr2)));
 1265                         ni = ieee80211_dup_bss(ic, wh->i_addr2);
 1266                         if (ni != NULL) {
 1267                                 IEEE80211_SEND_MGMT(ic, ni,
 1268                                     IEEE80211_FC0_SUBTYPE_DEAUTH,
 1269                                     IEEE80211_REASON_ASSOC_NOT_AUTHED);
 1270                                 ieee80211_free_node(ic, ni);
 1271                         }
 1272                         ic->ic_stats.is_rx_assoc_notauth++;
 1273                         return;
 1274                 }
 1275                 /* discard challenge after association */
 1276                 if (ni->ni_challenge != NULL) {
 1277                         FREE(ni->ni_challenge, M_DEVBUF);
 1278                         ni->ni_challenge = NULL;
 1279                 }
 1280                 /* XXX per-node cipher suite */
 1281                 /* XXX some stations use the privacy bit for handling APs
 1282                        that suport both encrypted and unencrypted traffic */
 1283                 if ((capinfo & IEEE80211_CAPINFO_ESS) == 0 ||
 1284                     (capinfo & IEEE80211_CAPINFO_PRIVACY) !=
 1285                     ((ic->ic_flags & IEEE80211_F_WEPON) ?
 1286                      IEEE80211_CAPINFO_PRIVACY : 0)) {
 1287                         IEEE80211_DPRINTF(("%s: capability mismatch %x for %s\n",
 1288                                 __func__, capinfo, ether_sprintf(wh->i_addr2)));
 1289                         IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
 1290                         ni->ni_associd = 0;
 1291                         IEEE80211_SEND_MGMT(ic, ni, resp,
 1292                                 IEEE80211_STATUS_CAPINFO);
 1293                         ic->ic_stats.is_rx_assoc_capmismatch++;
 1294                         return;
 1295                 }
 1296                 ieee80211_setup_rates(ic, ni, rates, xrates,
 1297                                 IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
 1298                                 IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
 1299                 if (ni->ni_rates.rs_nrates == 0) {
 1300                         IEEE80211_DPRINTF(("%s: rate mismatch for %s\n",
 1301                                 __func__, ether_sprintf(wh->i_addr2)));
 1302                         IEEE80211_AID_CLR(ni->ni_associd, ic->ic_aid_bitmap);
 1303                         ni->ni_associd = 0;
 1304                         IEEE80211_SEND_MGMT(ic, ni, resp,
 1305                                 IEEE80211_STATUS_BASIC_RATE);
 1306                         ic->ic_stats.is_rx_assoc_norate++;
 1307                         return;
 1308                 }
 1309                 ni->ni_rssi = rssi;
 1310                 ni->ni_rstamp = rstamp;
 1311                 ni->ni_intval = bintval;
 1312                 ni->ni_capinfo = capinfo;
 1313                 ni->ni_chan = ic->ic_bss->ni_chan;
 1314                 ni->ni_fhdwell = ic->ic_bss->ni_fhdwell;
 1315                 ni->ni_fhindex = ic->ic_bss->ni_fhindex;
 1316                 if (ni->ni_associd == 0) {
 1317                         u_int16_t aid;
 1318 
 1319                         /*
 1320                          * It would be clever to search the bitmap
 1321                          * more efficiently, but this will do for now.
 1322                          */
 1323                         for (aid = 1; aid < ic->ic_max_aid; aid++) {
 1324                                 if (!IEEE80211_AID_ISSET(aid,
 1325                                     ic->ic_aid_bitmap))
 1326                                         break;
 1327                         }
 1328 
 1329                         if (ic->ic_bss->ni_associd >= ic->ic_max_aid) {
 1330                                 IEEE80211_SEND_MGMT(ic, ni, resp,
 1331                                     IEEE80211_REASON_ASSOC_TOOMANY);
 1332                                 return;
 1333                         } else {
 1334                                 ni->ni_associd = aid | 0xc000;
 1335                                 IEEE80211_AID_SET(ni->ni_associd,
 1336                                     ic->ic_aid_bitmap);
 1337                                 newassoc = 1;
 1338                         }
 1339                 } else
 1340                         newassoc = 0;
 1341                 /* XXX for 11g must turn off short slot time if long
 1342                    slot time sta associates */
 1343                 IEEE80211_SEND_MGMT(ic, ni, resp, IEEE80211_STATUS_SUCCESS);
 1344                 if (ifp->if_flags & IFF_DEBUG)
 1345                         if_printf(ifp, "station %s %s associated at aid %d\n",
 1346                             (newassoc ? "newly" : "already"),
 1347                             ether_sprintf(ni->ni_macaddr),
 1348                             ni->ni_associd & ~0xc000);
 1349                 /* give driver a chance to setup state like ni_txrate */
 1350                 if (ic->ic_newassoc)
 1351                         (*ic->ic_newassoc)(ic, ni, newassoc);
 1352                 break;
 1353         }
 1354 
 1355         case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
 1356         case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: {
 1357                 u_int16_t status;
 1358 
 1359                 if (ic->ic_opmode != IEEE80211_M_STA ||
 1360                     ic->ic_state != IEEE80211_S_ASSOC)
 1361                         return;
 1362 
 1363                 /*
 1364                  * asresp frame format
 1365                  *      [2] capability information
 1366                  *      [2] status
 1367                  *      [2] association ID
 1368                  *      [tlv] supported rates
 1369                  *      [tlv] extended supported rates
 1370                  */
 1371                 IEEE80211_VERIFY_LENGTH(efrm - frm, 6);
 1372                 ni = ic->ic_bss;
 1373                 ni->ni_capinfo = le16toh(*(u_int16_t *)frm);
 1374                 frm += 2;
 1375 
 1376                 status = le16toh(*(u_int16_t *)frm);
 1377                 frm += 2;
 1378                 if (status != 0) {
 1379                         if (ifp->if_flags & IFF_DEBUG)
 1380                                 if_printf(ifp,
 1381                                     "association failed (reason %d) for %s\n",
 1382                                     status, ether_sprintf(wh->i_addr3));
 1383                         if (ni != ic->ic_bss)
 1384                                 ni->ni_fails++;
 1385                         ic->ic_stats.is_rx_auth_fail++;
 1386                         return;
 1387                 }
 1388                 ni->ni_associd = le16toh(*(u_int16_t *)frm);
 1389                 frm += 2;
 1390 
 1391                 rates = xrates = NULL;
 1392                 while (frm < efrm) {
 1393                         switch (*frm) {
 1394                         case IEEE80211_ELEMID_RATES:
 1395                                 rates = frm;
 1396                                 break;
 1397                         case IEEE80211_ELEMID_XRATES:
 1398                                 xrates = frm;
 1399                                 break;
 1400                         }
 1401                         frm += frm[1] + 2;
 1402                 }
 1403 
 1404                 IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE);
 1405                 ieee80211_setup_rates(ic, ni, rates, xrates,
 1406                                 IEEE80211_F_DOSORT | IEEE80211_F_DOFRATE |
 1407                                 IEEE80211_F_DONEGO | IEEE80211_F_DODEL);
 1408                 if (ni->ni_rates.rs_nrates != 0)
 1409                         ieee80211_new_state(ic, IEEE80211_S_RUN,
 1410                                 wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
 1411                 break;
 1412         }
 1413 
 1414         case IEEE80211_FC0_SUBTYPE_DEAUTH: {
 1415                 u_int16_t reason;
 1416                 /*
 1417                  * deauth frame format
 1418                  *      [2] reason
 1419                  */
 1420                 IEEE80211_VERIFY_LENGTH(efrm - frm, 2);
 1421                 reason = le16toh(*(u_int16_t *)frm);
 1422                 ic->ic_stats.is_rx_deauth++;
 1423                 switch (ic->ic_opmode) {
 1424                 case IEEE80211_M_STA:
 1425                         ieee80211_new_state(ic, IEEE80211_S_AUTH,
 1426                             wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
 1427                         break;
 1428                 case IEEE80211_M_HOSTAP:
 1429                         if (ni != ic->ic_bss) {
 1430                                 if (ifp->if_flags & IFF_DEBUG)
 1431                                         if_printf(ifp, "station %s deauthenticated"
 1432                                             " by peer (reason %d)\n",
 1433                                             ether_sprintf(ni->ni_macaddr), reason);
 1434                                 /* node will be free'd on return */
 1435                                 ieee80211_unref_node(&ni);
 1436                         }
 1437                         break;
 1438                 default:
 1439                         break;
 1440                 }
 1441                 break;
 1442         }
 1443 
 1444         case IEEE80211_FC0_SUBTYPE_DISASSOC: {
 1445                 u_int16_t reason;
 1446                 /*
 1447                  * disassoc frame format
 1448                  *      [2] reason
 1449                  */
 1450                 IEEE80211_VERIFY_LENGTH(efrm - frm, 2);
 1451                 reason = le16toh(*(u_int16_t *)frm);
 1452                 ic->ic_stats.is_rx_disassoc++;
 1453                 switch (ic->ic_opmode) {
 1454                 case IEEE80211_M_STA:
 1455                         ieee80211_new_state(ic, IEEE80211_S_ASSOC,
 1456                             wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
 1457                         break;
 1458                 case IEEE80211_M_HOSTAP:
 1459                         if (ni != ic->ic_bss) {
 1460                                 if (ifp->if_flags & IFF_DEBUG)
 1461                                         if_printf(ifp, "station %s disassociated"
 1462                                             " by peer (reason %d)\n",
 1463                                             ether_sprintf(ni->ni_macaddr), reason);
 1464                                 IEEE80211_AID_CLR(ni->ni_associd,
 1465                                     ic->ic_aid_bitmap);
 1466                                 ni->ni_associd = 0;
 1467                                 /* XXX node reclaimed how? */
 1468                         }
 1469                         break;
 1470                 default:
 1471                         break;
 1472                 }
 1473                 break;
 1474         }
 1475         default:
 1476                 IEEE80211_DPRINTF(("%s: mgmt frame with subtype 0x%x not "
 1477                         "handled\n", __func__, subtype));
 1478                 ic->ic_stats.is_rx_badsubtype++;
 1479                 break;
 1480         }
 1481 #undef ISPROBE
 1482 }
 1483 
 1484 static void
 1485 ieee80211_recv_pspoll(struct ieee80211com *ic, struct mbuf *m0, int rssi,
 1486                       u_int32_t rstamp)
 1487 {
 1488         struct ifnet *ifp = &ic->ic_if;
 1489         struct ieee80211_frame *wh;
 1490         struct ieee80211_node *ni;
 1491         struct mbuf *m;
 1492         u_int16_t aid;
 1493 
 1494         if (ic->ic_set_tim == NULL)  /* No powersaving functionality */
 1495                 return;
 1496 
 1497         wh = mtod(m0, struct ieee80211_frame *);
 1498 
 1499         if ((ni = ieee80211_find_node(ic, wh->i_addr2)) == NULL) {
 1500                 if (ifp->if_flags & IFF_DEBUG)
 1501                         printf("%s: station %s sent bogus power save poll\n",
 1502                                ifp->if_xname, ether_sprintf(wh->i_addr2));
 1503                 return;
 1504         }
 1505 
 1506         memcpy(&aid, wh->i_dur, sizeof(wh->i_dur));
 1507         if ((aid & 0xc000) != 0xc000) {
 1508                 if (ifp->if_flags & IFF_DEBUG)
 1509                         printf("%s: station %s sent bogus aid %x\n",
 1510                                ifp->if_xname, ether_sprintf(wh->i_addr2), aid);
 1511                 return;
 1512         }
 1513 
 1514         if (aid != ni->ni_associd) {
 1515                 if (ifp->if_flags & IFF_DEBUG)
 1516                         printf("%s: station %s aid %x doesn't match pspoll "
 1517                                "aid %x\n",
 1518                                ifp->if_xname, ether_sprintf(wh->i_addr2),
 1519                                ni->ni_associd, aid);
 1520                 return;
 1521         }
 1522 
 1523         /* Okay, take the first queued packet and put it out... */
 1524 
 1525         IF_DEQUEUE(&ni->ni_savedq, m);
 1526         if (m == NULL) {
 1527                 if (ifp->if_flags & IFF_DEBUG)
 1528                         printf("%s: station %s sent pspoll, "
 1529                                "but no packets are saved\n",
 1530                                ifp->if_xname, ether_sprintf(wh->i_addr2));
 1531                 return;
 1532         }
 1533         wh = mtod(m, struct ieee80211_frame *);
 1534 
 1535         /* 
 1536          * If this is the last packet, turn off the TIM fields.
 1537          * If there are more packets, set the more packets bit.
 1538          */
 1539 
 1540         if (IF_IS_EMPTY(&ni->ni_savedq)) {
 1541                 if (ic->ic_set_tim) 
 1542                         ic->ic_set_tim(ic, ni->ni_associd, 0);
 1543         } else {
 1544                 wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
 1545         }
 1546 
 1547         if (ifp->if_flags & IFF_DEBUG)
 1548                 printf("%s: enqueued power saving packet for station %s\n",
 1549                        ifp->if_xname, ether_sprintf(ni->ni_macaddr));
 1550 
 1551         IF_ENQUEUE(&ic->ic_pwrsaveq, m);
 1552         (*ifp->if_start)(ifp);
 1553 }
 1554 #undef IEEE80211_VERIFY_LENGTH
 1555 #undef IEEE80211_VERIFY_ELEMENT

Cache object: 5164d425cdf0d9ada54da4c0069725ca


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