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_output.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_output.c,v 1.28 2005/02/26 22:45:09 perry 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_output.c,v 1.10 2004/04/02 23:25:39 sam Exp $");
   37 #else
   38 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.28 2005/02/26 22:45:09 perry 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 #ifdef IEEE80211_DEBUG
   94 /*
   95  * Decide if an outbound management frame should be
   96  * printed when debugging is enabled.  This filters some
   97  * of the less interesting frames that come frequently
   98  * (e.g. beacons).
   99  */
  100 static __inline int
  101 doprint(struct ieee80211com *ic, int subtype)
  102 {
  103         switch (subtype) {
  104         case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
  105                 return (ic->ic_opmode == IEEE80211_M_IBSS);
  106         }
  107         return 1;
  108 }
  109 #endif
  110 
  111 /*
  112  * Send a management frame to the specified node.  The node pointer
  113  * must have a reference as the pointer will be passed to the driver
  114  * and potentially held for a long time.  If the frame is successfully
  115  * dispatched to the driver, then it is responsible for freeing the
  116  * reference (and potentially free'ing up any associated storage).
  117  */
  118 static int
  119 ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
  120     struct mbuf *m, int type)
  121 {
  122         struct ieee80211com *ic = (void *)ifp;
  123         struct ieee80211_frame *wh;
  124 
  125         IASSERT(ni != NULL, ("null node"));
  126         ni->ni_inact = 0;
  127 
  128         /*
  129          * Yech, hack alert!  We want to pass the node down to the
  130          * driver's start routine.  If we don't do so then the start
  131          * routine must immediately look it up again and that can
  132          * cause a lock order reversal if, for example, this frame
  133          * is being sent because the station is being timedout and
  134          * the frame being sent is a DEAUTH message.  We could stick
  135          * this in an m_tag and tack that on to the mbuf.  However
  136          * that's rather expensive to do for every frame so instead
  137          * we stuff it in the rcvif field since outbound frames do
  138          * not (presently) use this.
  139          */
  140         M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
  141         if (m == NULL)
  142                 return ENOMEM;
  143 #ifdef __FreeBSD__
  144         KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
  145 #endif
  146         m->m_pkthdr.rcvif = (void *)ni;
  147 
  148         wh = mtod(m, struct ieee80211_frame *);
  149         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type;
  150         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
  151         *(u_int16_t *)&wh->i_dur[0] = 0;
  152         *(u_int16_t *)&wh->i_seq[0] =
  153             htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
  154         ni->ni_txseq++;
  155         IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
  156         IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
  157         IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
  158 
  159         if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) {
  160                 m->m_flags &= ~M_LINK0;
  161                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
  162                         ("%s: encrypting frame for %s\n",
  163                         __func__, ether_sprintf(wh->i_addr1)));
  164                 wh->i_fc[1] |= IEEE80211_FC1_WEP;
  165         }
  166 #ifdef IEEE80211_DEBUG
  167         /* avoid printing too many frames */
  168         if ((ieee80211_msg_debug(ic) && doprint(ic, type)) ||
  169             ieee80211_msg_dumppkts(ic)) {
  170                 if_printf(ifp, "sending %s to %s on channel %u\n",
  171                     ieee80211_mgt_subtype_name[
  172                     (type & IEEE80211_FC0_SUBTYPE_MASK)
  173                     >> IEEE80211_FC0_SUBTYPE_SHIFT],
  174                     ether_sprintf(ni->ni_macaddr),
  175                     ieee80211_chan2ieee(ic, ni->ni_chan));
  176         }
  177 #endif
  178         IF_ENQUEUE(&ic->ic_mgtq, m);
  179         ifp->if_timer = 1;
  180         (*ifp->if_start)(ifp);
  181         return 0;
  182 }
  183 
  184 /*
  185  * Encapsulate an outbound data frame.  The mbuf chain is updated and
  186  * a reference to the destination node is returned.  If an error is
  187  * encountered NULL is returned and the node reference will also be NULL.
  188  *
  189  * NB: The caller is responsible for free'ing a returned node reference.
  190  *     The convention is ic_bss is not reference counted; the caller must
  191  *     maintain that.
  192  */
  193 struct mbuf *
  194 ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
  195 {
  196         struct ieee80211com *ic = (void *)ifp;
  197         struct ether_header eh;
  198         struct ieee80211_frame *wh;
  199         struct ieee80211_node *ni = NULL;
  200         struct llc *llc;
  201 
  202         if (m->m_len < sizeof(struct ether_header)) {
  203                 m = m_pullup(m, sizeof(struct ether_header));
  204                 if (m == NULL) {
  205                         ic->ic_stats.is_tx_nombuf++;
  206                         goto bad;
  207                 }
  208         }
  209         memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
  210 
  211         ni = ieee80211_find_txnode(ic, eh.ether_dhost);
  212         if (ni == NULL) {
  213                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_OUTPUT,
  214                         ("%s: no node for dst %s, discard frame\n",
  215                         __func__, ether_sprintf(eh.ether_dhost)));
  216                 ic->ic_stats.is_tx_nonode++;
  217                 goto bad;
  218         }
  219         ni->ni_inact = 0;
  220 
  221         m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
  222         llc = mtod(m, struct llc *);
  223         llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
  224         llc->llc_control = LLC_UI;
  225         llc->llc_snap.org_code[0] = 0;
  226         llc->llc_snap.org_code[1] = 0;
  227         llc->llc_snap.org_code[2] = 0;
  228         llc->llc_snap.ether_type = eh.ether_type;
  229         M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
  230         if (m == NULL) {
  231                 ic->ic_stats.is_tx_nombuf++;
  232                 goto bad;
  233         }
  234         wh = mtod(m, struct ieee80211_frame *);
  235         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
  236         *(u_int16_t *)&wh->i_dur[0] = 0;
  237         *(u_int16_t *)&wh->i_seq[0] =
  238             htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
  239         ni->ni_txseq++;
  240         switch (ic->ic_opmode) {
  241         case IEEE80211_M_STA:
  242                 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
  243                 IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
  244                 IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
  245                 IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
  246                 break;
  247         case IEEE80211_M_IBSS:
  248         case IEEE80211_M_AHDEMO:
  249                 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
  250                 IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
  251                 IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
  252                 IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid);
  253                 break;
  254         case IEEE80211_M_HOSTAP:
  255                 wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
  256                 IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
  257                 IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
  258                 IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
  259                 break;
  260         case IEEE80211_M_MONITOR:
  261                 goto bad;
  262         }
  263         if (ic->ic_flags & IEEE80211_F_PRIVACY)
  264                 wh->i_fc[1] |= IEEE80211_FC1_WEP;
  265         *pni = ni;
  266         return m;
  267 bad:
  268         if (m != NULL)
  269                 m_freem(m);
  270         if (ni != NULL)
  271                 ieee80211_release_node(ic, ni);
  272         *pni = NULL;
  273         return NULL;
  274 }
  275 
  276 /*
  277  * Arguments in:
  278  *
  279  * paylen:  payload length (no FCS, no WEP header)
  280  *
  281  * hdrlen:  header length
  282  *
  283  * rate:    MSDU speed, units 500kb/s
  284  *
  285  * flags:   IEEE80211_F_SHPREAMBLE (use short preamble),
  286  *          IEEE80211_F_SHSLOT (use short slot length)
  287  *
  288  * Arguments out:
  289  *
  290  * d:       802.11 Duration field for RTS,
  291  *          802.11 Duration field for data frame,
  292  *          PLCP Length for data frame,
  293  *          residual octets at end of data slot
  294  */
  295 static int
  296 ieee80211_compute_duration1(int len, int use_ack, uint32_t flags, int rate,
  297     struct ieee80211_duration *d)
  298 {
  299         int pre, ctsrate;
  300         int ack, bitlen, data_dur, remainder;
  301 
  302         /* RTS reserves medium for SIFS | CTS | SIFS | (DATA) | SIFS | ACK
  303          * DATA reserves medium for SIFS | ACK
  304          *
  305          * XXXMYC: no ACK on multicast/broadcast or control packets
  306          */
  307 
  308         bitlen = len * 8;
  309 
  310         pre = IEEE80211_DUR_DS_SIFS;
  311         if ((flags & IEEE80211_F_SHPREAMBLE) != 0)
  312                 pre += IEEE80211_DUR_DS_SHORT_PREAMBLE + IEEE80211_DUR_DS_FAST_PLCPHDR;
  313         else
  314                 pre += IEEE80211_DUR_DS_LONG_PREAMBLE + IEEE80211_DUR_DS_SLOW_PLCPHDR;
  315 
  316         d->d_residue = 0;
  317         data_dur = (bitlen * 2) / rate;
  318         remainder = (bitlen * 2) % rate;
  319         if (remainder != 0) {
  320                 d->d_residue = (rate - remainder) / 16;
  321                 data_dur++;
  322         }
  323 
  324         switch (rate) {
  325         case 2:         /* 1 Mb/s */
  326         case 4:         /* 2 Mb/s */
  327                 /* 1 - 2 Mb/s WLAN: send ACK/CTS at 1 Mb/s */
  328                 ctsrate = 2;
  329                 break;
  330         case 11:        /* 5.5 Mb/s */
  331         case 22:        /* 11  Mb/s */
  332         case 44:        /* 22  Mb/s */
  333                 /* 5.5 - 11 Mb/s WLAN: send ACK/CTS at 2 Mb/s */
  334                 ctsrate = 4;
  335                 break;
  336         default:
  337                 /* TBD */
  338                 return -1;
  339         }
  340 
  341         d->d_plcp_len = data_dur;
  342 
  343         ack = (use_ack) ? pre + (IEEE80211_DUR_DS_SLOW_ACK * 2) / ctsrate : 0;
  344 
  345         d->d_rts_dur =
  346             pre + (IEEE80211_DUR_DS_SLOW_CTS * 2) / ctsrate +
  347             pre + data_dur +
  348             ack;
  349 
  350         d->d_data_dur = ack;
  351 
  352         return 0;
  353 }
  354 
  355 /*
  356  * Arguments in:
  357  *
  358  * wh:      802.11 header
  359  *
  360  * paylen:  payload length (no FCS, no WEP header)
  361  *
  362  * rate:    MSDU speed, units 500kb/s
  363  *
  364  * fraglen: fragment length, set to maximum (or higher) for no
  365  *          fragmentation
  366  *
  367  * flags:   IEEE80211_F_PRIVACY (hardware adds WEP),
  368  *          IEEE80211_F_SHPREAMBLE (use short preamble),
  369  *          IEEE80211_F_SHSLOT (use short slot length)
  370  *
  371  * Arguments out:
  372  *
  373  * d0: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
  374  *     of first/only fragment
  375  *
  376  * dn: 802.11 Duration fields (RTS/Data), PLCP Length, Service fields
  377  *     of first/only fragment
  378  */
  379 int
  380 ieee80211_compute_duration(struct ieee80211_frame *wh, int len,
  381     uint32_t flags, int fraglen, int rate, struct ieee80211_duration *d0,
  382     struct ieee80211_duration *dn, int *npktp, int debug)
  383 {
  384         int ack, rc;
  385         int firstlen, hdrlen, lastlen, lastlen0, npkt, overlen, paylen;
  386 
  387         if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) == IEEE80211_FC1_DIR_DSTODS)
  388                 hdrlen = sizeof(struct ieee80211_frame_addr4);
  389         else
  390                 hdrlen = sizeof(struct ieee80211_frame);
  391 
  392         paylen = len - hdrlen;
  393 
  394         if ((flags & IEEE80211_F_PRIVACY) != 0)
  395                 overlen = IEEE80211_WEP_TOTLEN + IEEE80211_CRC_LEN;
  396         else
  397                 overlen = IEEE80211_CRC_LEN;
  398 
  399         npkt = paylen / fraglen;
  400         lastlen0 = paylen % fraglen;
  401 
  402         if (npkt == 0)                  /* no fragments */
  403                 lastlen = paylen + overlen;
  404         else if (lastlen0 != 0) {       /* a short "tail" fragment */
  405                 lastlen = lastlen0 + overlen;
  406                 npkt++;
  407         } else                          /* full-length "tail" fragment */
  408                 lastlen = fraglen + overlen;
  409 
  410         if (npktp != NULL)
  411                 *npktp = npkt;
  412 
  413         if (npkt > 1)
  414                 firstlen = fraglen + overlen;
  415         else
  416                 firstlen = paylen + overlen;
  417 
  418         if (debug) {
  419                 printf("%s: npkt %d firstlen %d lastlen0 %d lastlen %d "
  420                     "fraglen %d overlen %d len %d rate %d flags %08x\n",
  421                     __func__, npkt, firstlen, lastlen0, lastlen, fraglen,
  422                     overlen, len, rate, flags);
  423         }
  424 
  425         ack = !IEEE80211_IS_MULTICAST(wh->i_addr1) &&
  426             (wh->i_fc[1] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL;
  427 
  428         rc = ieee80211_compute_duration1(firstlen + hdrlen,
  429             ack, flags, rate, d0);
  430         if (rc == -1)
  431                 return rc;
  432 
  433         if (npkt <= 1) {
  434                 *dn = *d0;
  435                 return 0;
  436         }
  437         return ieee80211_compute_duration1(lastlen + hdrlen, ack, flags, rate,
  438             dn);
  439 }
  440 
  441 /*
  442  * Add a supported rates element id to a frame.
  443  */
  444 u_int8_t *
  445 ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs)
  446 {
  447         int nrates;
  448 
  449         *frm++ = IEEE80211_ELEMID_RATES;
  450         nrates = rs->rs_nrates;
  451         if (nrates > IEEE80211_RATE_SIZE)
  452                 nrates = IEEE80211_RATE_SIZE;
  453         *frm++ = nrates;
  454         memcpy(frm, rs->rs_rates, nrates);
  455         return frm + nrates;
  456 }
  457 
  458 /*
  459  * Add an extended supported rates element id to a frame.
  460  */
  461 u_int8_t *
  462 ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs)
  463 {
  464         /*
  465          * Add an extended supported rates element if operating in 11g mode.
  466          */
  467         if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
  468                 int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
  469                 *frm++ = IEEE80211_ELEMID_XRATES;
  470                 *frm++ = nrates;
  471                 memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
  472                 frm += nrates;
  473         }
  474         return frm;
  475 }
  476 
  477 /*
  478  * Add an ssid elemet to a frame.
  479  */
  480 static u_int8_t *
  481 ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
  482 {
  483         *frm++ = IEEE80211_ELEMID_SSID;
  484         *frm++ = len;
  485         memcpy(frm, ssid, len);
  486         return frm + len;
  487 }
  488 
  489 static struct mbuf *
  490 ieee80211_getmbuf(int flags, int type, u_int pktlen)
  491 {
  492         struct mbuf *m;
  493 
  494         IASSERT(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen));
  495         MGETHDR(m, flags, type);
  496         if (m == NULL || pktlen <= MHLEN)
  497                 return m;
  498         MCLGET(m, flags);
  499         if ((m->m_flags & M_EXT) != 0)
  500                 return m;
  501         m_free(m);
  502         return NULL;
  503 }
  504 
  505 /*
  506  * Send a management frame.  The node is for the destination (or ic_bss
  507  * when in station mode).  Nodes other than ic_bss have their reference
  508  * count bumped to reflect our use for an indeterminant time.
  509  */
  510 int
  511 ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
  512         int type, int arg)
  513 {
  514 #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
  515         struct ifnet *ifp = &ic->ic_if;
  516         struct mbuf *m;
  517         u_int8_t *frm;
  518         enum ieee80211_phymode mode;
  519         u_int16_t capinfo;
  520         int has_challenge, is_shared_key, ret, timer;
  521 
  522         IASSERT(ni != NULL, ("null node"));
  523 
  524         /*
  525          * Hold a reference on the node so it doesn't go away until after
  526          * the xmit is complete all the way in the driver.  On error we
  527          * will remove our reference.
  528          */
  529         ieee80211_ref_node(ni);
  530         timer = 0;
  531         switch (type) {
  532         case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
  533                 /*
  534                  * prreq frame format
  535                  *      [tlv] ssid
  536                  *      [tlv] supported rates
  537                  *      [tlv] extended supported rates
  538                  */
  539                 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
  540                          2 + ic->ic_des_esslen
  541                        + 2 + IEEE80211_RATE_SIZE
  542                        + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
  543                 if (m == NULL)
  544                         senderr(ENOMEM, is_tx_nombuf);
  545                 m->m_data += sizeof(struct ieee80211_frame);
  546                 frm = mtod(m, u_int8_t *);
  547                 frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
  548                 mode = ieee80211_chan2mode(ic, ni->ni_chan);
  549                 frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
  550                 frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
  551                 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
  552 
  553                 timer = IEEE80211_TRANS_WAIT;
  554                 break;
  555 
  556         case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
  557                 /*
  558                  * probe response frame format
  559                  *      [8] time stamp
  560                  *      [2] beacon interval
  561                  *      [2] cabability information
  562                  *      [tlv] ssid
  563                  *      [tlv] supported rates
  564                  *      [tlv] parameter set (FH/DS)
  565                  *      [tlv] parameter set (IBSS)
  566                  *      [tlv] extended supported rates
  567                  */
  568                 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
  569                          8 + 2 + 2 + 2
  570                        + 2 + ni->ni_esslen
  571                        + 2 + IEEE80211_RATE_SIZE
  572                        + (ic->ic_phytype == IEEE80211_T_FH ? 7 : 3)
  573                        + 6
  574                        + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
  575                 if (m == NULL)
  576                         senderr(ENOMEM, is_tx_nombuf);
  577                 m->m_data += sizeof(struct ieee80211_frame);
  578                 frm = mtod(m, u_int8_t *);
  579 
  580                 memset(frm, 0, 8);      /* timestamp should be filled later */
  581                 frm += 8;
  582                 *(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval);
  583                 frm += 2;
  584                 if (ic->ic_opmode == IEEE80211_M_IBSS)
  585                         capinfo = IEEE80211_CAPINFO_IBSS;
  586                 else
  587                         capinfo = IEEE80211_CAPINFO_ESS;
  588                 if (ic->ic_flags & IEEE80211_F_PRIVACY)
  589                         capinfo |= IEEE80211_CAPINFO_PRIVACY;
  590                 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
  591                     IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
  592                         capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
  593                 *(u_int16_t *)frm = htole16(capinfo);
  594                 frm += 2;
  595 
  596                 frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid,
  597                                 ic->ic_bss->ni_esslen);
  598                 frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates);
  599 
  600                 if (ic->ic_phytype == IEEE80211_T_FH) {
  601                         *frm++ = IEEE80211_ELEMID_FHPARMS;
  602                         *frm++ = 5;
  603                         *frm++ = ni->ni_fhdwell & 0x00ff;
  604                         *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff;
  605                         *frm++ = IEEE80211_FH_CHANSET(
  606                             ieee80211_chan2ieee(ic, ni->ni_chan));
  607                         *frm++ = IEEE80211_FH_CHANPAT(
  608                             ieee80211_chan2ieee(ic, ni->ni_chan));
  609                         *frm++ = ni->ni_fhindex;
  610                 } else {
  611                         *frm++ = IEEE80211_ELEMID_DSPARMS;
  612                         *frm++ = 1;
  613                         *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
  614                 }
  615 
  616                 if (ic->ic_opmode == IEEE80211_M_IBSS) {
  617                         *frm++ = IEEE80211_ELEMID_IBSSPARMS;
  618                         *frm++ = 2;
  619                         *frm++ = 0; *frm++ = 0;         /* TODO: ATIM window */
  620                 } else {        /* IEEE80211_M_HOSTAP */
  621                         /* TODO: TIM */
  622                         *frm++ = IEEE80211_ELEMID_TIM;
  623                         *frm++ = 4;     /* length */
  624                         *frm++ = 0;     /* DTIM count */
  625                         *frm++ = 1;     /* DTIM period */
  626                         *frm++ = 0;     /* bitmap control */
  627                         *frm++ = 0;     /* Partial Virtual Bitmap (variable length) */
  628                 }
  629                 frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates);
  630                 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
  631                 break;
  632 
  633         case IEEE80211_FC0_SUBTYPE_AUTH:
  634                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  635                 if (m == NULL)
  636                         senderr(ENOMEM, is_tx_nombuf);
  637 
  638                 has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
  639                     arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
  640                     ni->ni_challenge != NULL);
  641 
  642                 is_shared_key = has_challenge || (ni->ni_challenge != NULL &&
  643                     arg == IEEE80211_AUTH_SHARED_PASS);
  644 
  645                 if (has_challenge) {
  646                         MH_ALIGN(m, 2 * 3 + 2 + IEEE80211_CHALLENGE_LEN);
  647                         m->m_pkthdr.len = m->m_len =
  648                             2 * 3 + 2 + IEEE80211_CHALLENGE_LEN;
  649                 } else {
  650                         MH_ALIGN(m, 2 * 3);
  651                         m->m_pkthdr.len = m->m_len = 2 * 3;
  652                 }
  653                 frm = mtod(m, u_int8_t *);
  654                 ((u_int16_t *)frm)[0] =
  655                     (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
  656                                     : htole16(IEEE80211_AUTH_ALG_OPEN);
  657                 ((u_int16_t *)frm)[1] = htole16(arg);   /* sequence number */
  658                 ((u_int16_t *)frm)[2] = 0;              /* status */
  659 
  660                 if (has_challenge) {
  661                         ((u_int16_t *)frm)[3] =
  662                             htole16((IEEE80211_CHALLENGE_LEN << 8) |
  663                             IEEE80211_ELEMID_CHALLENGE);
  664                         memcpy(&((u_int16_t *)frm)[4], ni->ni_challenge,
  665                             IEEE80211_CHALLENGE_LEN);
  666                         if (arg == IEEE80211_AUTH_SHARED_RESPONSE) {
  667                                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
  668                                     ("%s: request encrypt frame\n", __func__));
  669                                 m->m_flags |= M_LINK0; /* WEP-encrypt, please */
  670                         }
  671                 }
  672                 if (ic->ic_opmode == IEEE80211_M_STA)
  673                         timer = IEEE80211_TRANS_WAIT;
  674                 break;
  675 
  676         case IEEE80211_FC0_SUBTYPE_DEAUTH:
  677                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_AUTH,
  678                         ("send station %s deauthenticate (reason %d)\n",
  679                         ether_sprintf(ni->ni_macaddr), arg));
  680                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  681                 if (m == NULL)
  682                         senderr(ENOMEM, is_tx_nombuf);
  683                 MH_ALIGN(m, 2);
  684                 m->m_pkthdr.len = m->m_len = 2;
  685                 *mtod(m, u_int16_t *) = htole16(arg);   /* reason */
  686                 break;
  687 
  688         case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
  689         case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
  690                 /*
  691                  * asreq frame format
  692                  *      [2] capability information
  693                  *      [2] listen interval
  694                  *      [6*] current AP address (reassoc only)
  695                  *      [tlv] ssid
  696                  *      [tlv] supported rates
  697                  *      [tlv] extended supported rates
  698                  */
  699                 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
  700                          sizeof(capinfo)
  701                        + sizeof(u_int16_t)
  702                        + IEEE80211_ADDR_LEN
  703                        + 2 + ni->ni_esslen
  704                        + 2 + IEEE80211_RATE_SIZE
  705                        + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
  706                 if (m == NULL)
  707                         senderr(ENOMEM, is_tx_nombuf);
  708                 m->m_data += sizeof(struct ieee80211_frame);
  709                 frm = mtod(m, u_int8_t *);
  710 
  711                 capinfo = 0;
  712                 if (ic->ic_opmode == IEEE80211_M_IBSS)
  713                         capinfo |= IEEE80211_CAPINFO_IBSS;
  714                 else            /* IEEE80211_M_STA */
  715                         capinfo |= IEEE80211_CAPINFO_ESS;
  716                 if (ic->ic_flags & IEEE80211_F_PRIVACY)
  717                         capinfo |= IEEE80211_CAPINFO_PRIVACY;
  718                 /*
  719                  * NB: Some 11a AP's reject the request when
  720                  *     short premable is set.
  721                  */
  722                 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
  723                     IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
  724                         capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
  725                 if (ic->ic_flags & IEEE80211_F_SHSLOT)
  726                         capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
  727                 *(u_int16_t *)frm = htole16(capinfo);
  728                 frm += 2;
  729 
  730                 *(u_int16_t *)frm = htole16(ic->ic_lintval);
  731                 frm += 2;
  732 
  733                 if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
  734                         IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid);
  735                         frm += IEEE80211_ADDR_LEN;
  736                 }
  737 
  738                 frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
  739                 frm = ieee80211_add_rates(frm, &ni->ni_rates);
  740                 frm = ieee80211_add_xrates(frm, &ni->ni_rates);
  741                 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
  742 
  743                 timer = IEEE80211_TRANS_WAIT;
  744                 break;
  745 
  746         case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
  747         case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
  748                 /*
  749                  * asreq frame format
  750                  *      [2] capability information
  751                  *      [2] status
  752                  *      [2] association ID
  753                  *      [tlv] supported rates
  754                  *      [tlv] extended supported rates
  755                  */
  756                 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
  757                          sizeof(capinfo)
  758                        + sizeof(u_int16_t)
  759                        + sizeof(u_int16_t)
  760                        + 2 + IEEE80211_RATE_SIZE
  761                        + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
  762                 if (m == NULL)
  763                         senderr(ENOMEM, is_tx_nombuf);
  764                 m->m_data += sizeof(struct ieee80211_frame);
  765                 frm = mtod(m, u_int8_t *);
  766 
  767                 capinfo = IEEE80211_CAPINFO_ESS;
  768                 if (ic->ic_flags & IEEE80211_F_PRIVACY)
  769                         capinfo |= IEEE80211_CAPINFO_PRIVACY;
  770                 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
  771                     IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
  772                         capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
  773                 *(u_int16_t *)frm = htole16(capinfo);
  774                 frm += 2;
  775 
  776                 *(u_int16_t *)frm = htole16(arg);       /* status */
  777                 frm += 2;
  778 
  779                 if (arg == IEEE80211_STATUS_SUCCESS)
  780                         *(u_int16_t *)frm = htole16(ni->ni_associd);
  781                 frm += 2;
  782 
  783                 frm = ieee80211_add_rates(frm, &ni->ni_rates);
  784                 frm = ieee80211_add_xrates(frm, &ni->ni_rates);
  785                 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
  786                 break;
  787 
  788         case IEEE80211_FC0_SUBTYPE_DISASSOC:
  789                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ASSOC,
  790                         ("send station %s disassociate (reason %d)\n",
  791                         ether_sprintf(ni->ni_macaddr), arg));
  792                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  793                 if (m == NULL)
  794                         senderr(ENOMEM, is_tx_nombuf);
  795                 MH_ALIGN(m, 2);
  796                 m->m_pkthdr.len = m->m_len = 2;
  797                 *mtod(m, u_int16_t *) = htole16(arg);   /* reason */
  798                 break;
  799 
  800         default:
  801                 IEEE80211_DPRINTF(ic, IEEE80211_MSG_ANY,
  802                         ("%s: invalid mgmt frame type %u\n", __func__, type));
  803                 senderr(EINVAL, is_tx_unknownmgt);
  804                 /* NOTREACHED */
  805         }
  806 
  807         ret = ieee80211_mgmt_output(ifp, ni, m, type);
  808         if (ret == 0) {
  809                 if (timer)
  810                         ic->ic_mgt_timer = timer;
  811         } else {
  812 bad:
  813                 ieee80211_release_node(ic, ni);
  814         }
  815         return ret;
  816 #undef senderr
  817 }
  818 
  819 void
  820 ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni,
  821                   struct mbuf *m)
  822 {
  823         /* Store the new packet on our queue, changing the TIM if necessary */
  824 
  825         if (IF_IS_EMPTY(&ni->ni_savedq)) {
  826                 ic->ic_set_tim(ic, ni->ni_associd, 1);
  827         }
  828         if (ni->ni_savedq.ifq_len >= IEEE80211_PS_MAX_QUEUE) {
  829                 IF_DROP(&ni->ni_savedq);
  830                 m_freem(m);
  831                 if (ic->ic_if.if_flags & IFF_DEBUG)
  832                         printf("%s: station %s power save queue overflow"
  833                                " of size %d drops %d\n",
  834                                ic->ic_if.if_xname,
  835                                ether_sprintf(ni->ni_macaddr),
  836                                IEEE80211_PS_MAX_QUEUE,
  837                                ni->ni_savedq.ifq_drops);
  838         } else {
  839                 /* Similar to ieee80211_mgmt_output, store the node in
  840                  * the rcvif field.
  841                  */
  842                 IF_ENQUEUE(&ni->ni_savedq, m);
  843                 m->m_pkthdr.rcvif = (void *)ni;
  844         }
  845 }
  846 

Cache object: 88d776b49ae613aed634848d2e3b1e90


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