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.11 2004/01/13 23:37:30 dyoung 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.9 2003/10/17 23:15:30 sam Exp $");
   37 #else
   38 __KERNEL_RCSID(0, "$NetBSD: ieee80211_output.c,v 1.11 2004/01/13 23:37:30 dyoung 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 /*
   94  * Send a management frame to the specified node.  The node pointer
   95  * must have a reference as the pointer will be passed to the driver
   96  * and potentially held for a long time.  If the frame is successfully
   97  * dispatched to the driver, then it is responsible for freeing the
   98  * reference (and potentially free'ing up any associated storage).
   99  */
  100 static int
  101 ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
  102     struct mbuf *m, int type)
  103 {
  104         struct ieee80211com *ic = (void *)ifp;
  105         struct ieee80211_frame *wh;
  106 
  107         IASSERT(ni != NULL, ("null node"));
  108         ni->ni_inact = 0;
  109 
  110         /*
  111          * Yech, hack alert!  We want to pass the node down to the
  112          * driver's start routine.  If we don't do so then the start
  113          * routine must immediately look it up again and that can
  114          * cause a lock order reversal if, for example, this frame
  115          * is being sent because the station is being timedout and
  116          * the frame being sent is a DEAUTH message.  We could stick
  117          * this in an m_tag and tack that on to the mbuf.  However
  118          * that's rather expensive to do for every frame so instead
  119          * we stuff it in the rcvif field since outbound frames do
  120          * not (presently) use this.
  121          */
  122         M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
  123         if (m == NULL)
  124                 return ENOMEM;
  125 #ifdef __FreeBSD__
  126         KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
  127 #endif
  128         m->m_pkthdr.rcvif = (void *)ni;
  129 
  130         wh = mtod(m, struct ieee80211_frame *);
  131         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type;
  132         wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
  133         *(u_int16_t *)&wh->i_dur[0] = 0;
  134         *(u_int16_t *)&wh->i_seq[0] =
  135             htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
  136         ni->ni_txseq++;
  137         IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
  138         IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
  139         IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
  140 
  141         if ((m->m_flags & M_LINK0) != 0 && ni->ni_challenge != NULL) {
  142                 m->m_flags &= ~M_LINK0;
  143                 IEEE80211_DPRINTF(("%s: encrypting frame for %s\n", __func__,
  144                     ether_sprintf(wh->i_addr1)));
  145                 wh->i_fc[1] |= IEEE80211_FC1_WEP;
  146         }
  147 
  148         if (ifp->if_flags & IFF_DEBUG) {
  149                 /* avoid to print too many frames */
  150                 if (ic->ic_opmode == IEEE80211_M_IBSS ||
  151 #ifdef IEEE80211_DEBUG
  152                     ieee80211_debug > 1 ||
  153 #endif
  154                     (type & IEEE80211_FC0_SUBTYPE_MASK) !=
  155                     IEEE80211_FC0_SUBTYPE_PROBE_RESP)
  156                         if_printf(ifp, "sending %s to %s on channel %u\n",
  157                             ieee80211_mgt_subtype_name[
  158                             (type & IEEE80211_FC0_SUBTYPE_MASK)
  159                             >> IEEE80211_FC0_SUBTYPE_SHIFT],
  160                             ether_sprintf(ni->ni_macaddr),
  161                             ieee80211_chan2ieee(ic, ni->ni_chan));
  162         }
  163 
  164         IF_ENQUEUE(&ic->ic_mgtq, m);
  165         ifp->if_timer = 1;
  166         (*ifp->if_start)(ifp);
  167         return 0;
  168 }
  169 
  170 /*
  171  * Encapsulate an outbound data frame.  The mbuf chain is updated and
  172  * a reference to the destination node is returned.  If an error is
  173  * encountered NULL is returned and the node reference will also be NULL.
  174  * 
  175  * NB: The caller is responsible for free'ing a returned node reference.
  176  *     The convention is ic_bss is not reference counted; the caller must
  177  *     maintain that.
  178  */
  179 struct mbuf *
  180 ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
  181 {
  182         struct ieee80211com *ic = (void *)ifp;
  183         struct ether_header eh;
  184         struct ieee80211_frame *wh;
  185         struct ieee80211_node *ni = NULL;
  186         struct llc *llc;
  187 
  188         if (m->m_len < sizeof(struct ether_header)) {
  189                 m = m_pullup(m, sizeof(struct ether_header));
  190                 if (m == NULL) {
  191                         ic->ic_stats.is_tx_nombuf++;
  192                         goto bad;
  193                 }
  194         }
  195         memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
  196 
  197         if ((ni = ieee80211_find_txnode(ic, eh.ether_dhost)) == NULL)
  198                 goto bad;
  199 
  200         ni->ni_inact = 0;
  201 
  202         m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
  203         llc = mtod(m, struct llc *);
  204         llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
  205         llc->llc_control = LLC_UI;
  206         llc->llc_snap.org_code[0] = 0;
  207         llc->llc_snap.org_code[1] = 0;
  208         llc->llc_snap.org_code[2] = 0;
  209         llc->llc_snap.ether_type = eh.ether_type;
  210         M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
  211         if (m == NULL) {
  212                 ic->ic_stats.is_tx_nombuf++;
  213                 goto bad;
  214         }
  215         wh = mtod(m, struct ieee80211_frame *);
  216         wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
  217         *(u_int16_t *)&wh->i_dur[0] = 0;
  218         *(u_int16_t *)&wh->i_seq[0] =
  219             htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
  220         ni->ni_txseq++;
  221         switch (ic->ic_opmode) {
  222         case IEEE80211_M_STA:
  223                 wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
  224                 IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
  225                 IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
  226                 IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
  227                 break;
  228         case IEEE80211_M_IBSS:
  229         case IEEE80211_M_AHDEMO:
  230                 wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
  231                 IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
  232                 IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
  233                 IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
  234                 break;
  235         case IEEE80211_M_HOSTAP:
  236                 wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
  237                 IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
  238                 IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
  239                 IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
  240                 break;
  241         case IEEE80211_M_MONITOR:
  242                 goto bad;
  243         }
  244         *pni = ni;
  245         return m;
  246 bad:
  247         if (m != NULL)
  248                 m_freem(m);
  249         if (ni && ni != ic->ic_bss)
  250                 ieee80211_free_node(ic, ni);
  251         *pni = NULL;
  252         return NULL;
  253 }
  254 
  255 /*
  256  * Add a supported rates element id to a frame.
  257  */
  258 u_int8_t *
  259 ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs)
  260 {
  261         int nrates;
  262 
  263         *frm++ = IEEE80211_ELEMID_RATES;
  264         nrates = rs->rs_nrates;
  265         if (nrates > IEEE80211_RATE_SIZE)
  266                 nrates = IEEE80211_RATE_SIZE;
  267         *frm++ = nrates;
  268         memcpy(frm, rs->rs_rates, nrates);
  269         return frm + nrates;
  270 }
  271 
  272 /*
  273  * Add an extended supported rates element id to a frame.
  274  */
  275 u_int8_t *
  276 ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs)
  277 {
  278         /*
  279          * Add an extended supported rates element if operating in 11g mode.
  280          */
  281         if (rs->rs_nrates > IEEE80211_RATE_SIZE) {
  282                 int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
  283                 *frm++ = IEEE80211_ELEMID_XRATES;
  284                 *frm++ = nrates;
  285                 memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
  286                 frm += nrates;
  287         }
  288         return frm;
  289 }
  290 
  291 /* 
  292  * Add an ssid elemet to a frame.
  293  */
  294 static u_int8_t *
  295 ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
  296 {
  297         *frm++ = IEEE80211_ELEMID_SSID;
  298         *frm++ = len;
  299         memcpy(frm, ssid, len);
  300         return frm + len;
  301 }
  302 
  303 static struct mbuf *
  304 ieee80211_getmbuf(int flags, int type, u_int pktlen)
  305 {
  306         struct mbuf *m;
  307 
  308         IASSERT(pktlen <= MCLBYTES, ("802.11 packet too large: %u", pktlen));
  309 #ifdef __FreeBSD__
  310         if (pktlen <= MHLEN)
  311                 MGETHDR(m, flags, type);
  312         else
  313                 m = m_getcl(flags, type, M_PKTHDR);
  314 #else
  315         MGETHDR(m, flags, type);
  316         if (m != NULL && pktlen > MHLEN)
  317                 MCLGET(m, flags);
  318 #endif
  319         return m;
  320 }
  321 
  322 /*
  323  * Send a management frame.  The node is for the destination (or ic_bss
  324  * when in station mode).  Nodes other than ic_bss have their reference
  325  * count bumped to reflect our use for an indeterminant time.
  326  */
  327 int
  328 ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
  329         int type, int arg)
  330 {
  331 #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
  332         struct ifnet *ifp = &ic->ic_if;
  333         struct mbuf *m;
  334         u_int8_t *frm;
  335         enum ieee80211_phymode mode;
  336         u_int16_t capinfo;
  337         int has_challenge, is_shared_key, ret, timer;
  338 
  339         IASSERT(ni != NULL, ("null node"));
  340 
  341         /*
  342          * Hold a reference on the node so it doesn't go away until after
  343          * the xmit is complete all the way in the driver.  On error we
  344          * will remove our reference.
  345          */
  346         if (ni != ic->ic_bss)
  347                 ieee80211_ref_node(ni);
  348         timer = 0;
  349         switch (type) {
  350         case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
  351                 /*
  352                  * prreq frame format
  353                  *      [tlv] ssid
  354                  *      [tlv] supported rates
  355                  *      [tlv] extended supported rates
  356                  */
  357                 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
  358                          2 + ic->ic_des_esslen
  359                        + 2 + IEEE80211_RATE_SIZE
  360                        + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
  361                 if (m == NULL)
  362                         senderr(ENOMEM, is_tx_nombuf);
  363                 m->m_data += sizeof(struct ieee80211_frame);
  364                 frm = mtod(m, u_int8_t *);
  365                 frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
  366                 mode = ieee80211_chan2mode(ic, ni->ni_chan);
  367                 frm = ieee80211_add_rates(frm, &ic->ic_sup_rates[mode]);
  368                 frm = ieee80211_add_xrates(frm, &ic->ic_sup_rates[mode]);
  369                 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
  370 
  371                 timer = IEEE80211_TRANS_WAIT;
  372                 break;
  373 
  374         case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
  375                 /*
  376                  * probe response frame format
  377                  *      [8] time stamp
  378                  *      [2] beacon interval
  379                  *      [2] cabability information
  380                  *      [tlv] ssid
  381                  *      [tlv] supported rates
  382                  *      [tlv] parameter set (FH/DS)
  383                  *      [tlv] parameter set (IBSS)
  384                  *      [tlv] extended supported rates
  385                  */
  386                 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
  387                          8 + 2 + 2 + 2
  388                        + 2 + ni->ni_esslen
  389                        + 2 + IEEE80211_RATE_SIZE
  390                        + (ic->ic_phytype == IEEE80211_T_FH ? 7 : 3)
  391                        + 6
  392                        + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
  393                 if (m == NULL)
  394                         senderr(ENOMEM, is_tx_nombuf);
  395                 m->m_data += sizeof(struct ieee80211_frame);
  396                 frm = mtod(m, u_int8_t *);
  397 
  398                 memset(frm, 0, 8);      /* timestamp should be filled later */
  399                 frm += 8;
  400                 *(u_int16_t *)frm = htole16(ic->ic_bss->ni_intval);
  401                 frm += 2;
  402                 if (ic->ic_opmode == IEEE80211_M_IBSS)
  403                         capinfo = IEEE80211_CAPINFO_IBSS;
  404                 else
  405                         capinfo = IEEE80211_CAPINFO_ESS;
  406                 if (ic->ic_flags & IEEE80211_F_WEPON)
  407                         capinfo |= IEEE80211_CAPINFO_PRIVACY;
  408                 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
  409                     IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
  410                         capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
  411                 *(u_int16_t *)frm = htole16(capinfo);
  412                 frm += 2;
  413 
  414                 frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid,
  415                                 ic->ic_bss->ni_esslen);
  416                 frm = ieee80211_add_rates(frm, &ic->ic_bss->ni_rates);
  417 
  418                 if (ic->ic_phytype == IEEE80211_T_FH) {
  419                         *frm++ = IEEE80211_ELEMID_FHPARMS;
  420                         *frm++ = 5;
  421                         *frm++ = ni->ni_fhdwell & 0x00ff;
  422                         *frm++ = (ni->ni_fhdwell >> 8) & 0x00ff;
  423                         *frm++ = IEEE80211_FH_CHANSET(
  424                             ieee80211_chan2ieee(ic, ni->ni_chan));
  425                         *frm++ = IEEE80211_FH_CHANPAT(
  426                             ieee80211_chan2ieee(ic, ni->ni_chan));
  427                         *frm++ = ni->ni_fhindex;
  428                 } else {
  429                         *frm++ = IEEE80211_ELEMID_DSPARMS;
  430                         *frm++ = 1;
  431                         *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
  432                 }
  433 
  434                 if (ic->ic_opmode == IEEE80211_M_IBSS) {
  435                         *frm++ = IEEE80211_ELEMID_IBSSPARMS;
  436                         *frm++ = 2;
  437                         *frm++ = 0; *frm++ = 0;         /* TODO: ATIM window */
  438                 } else {        /* IEEE80211_M_HOSTAP */
  439                         /* TODO: TIM */
  440                         *frm++ = IEEE80211_ELEMID_TIM;
  441                         *frm++ = 4;     /* length */
  442                         *frm++ = 0;     /* DTIM count */
  443                         *frm++ = 1;     /* DTIM period */
  444                         *frm++ = 0;     /* bitmap control */
  445                         *frm++ = 0;     /* Partial Virtual Bitmap (variable length) */
  446                 }
  447                 frm = ieee80211_add_xrates(frm, &ic->ic_bss->ni_rates);
  448                 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
  449                 break;
  450 
  451         case IEEE80211_FC0_SUBTYPE_AUTH:
  452                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  453                 if (m == NULL)
  454                         senderr(ENOMEM, is_tx_nombuf);
  455 
  456                 has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE ||
  457                     arg == IEEE80211_AUTH_SHARED_RESPONSE) &&
  458                     ni->ni_challenge != NULL);
  459 
  460                 is_shared_key = has_challenge || (ni->ni_challenge != NULL &&
  461                     arg == IEEE80211_AUTH_SHARED_PASS);
  462 
  463                 if (has_challenge) {
  464                         MH_ALIGN(m, 2 * 3 + 2 + IEEE80211_CHALLENGE_LEN);
  465                         m->m_pkthdr.len = m->m_len =
  466                             2 * 3 + 2 + IEEE80211_CHALLENGE_LEN;
  467                 } else {
  468                         MH_ALIGN(m, 2 * 3);
  469                         m->m_pkthdr.len = m->m_len = 2 * 3;
  470                 }
  471                 frm = mtod(m, u_int8_t *);
  472                 ((u_int16_t *)frm)[0] =
  473                     (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED)
  474                                     : htole16(IEEE80211_AUTH_ALG_OPEN);
  475                 ((u_int16_t *)frm)[1] = htole16(arg);   /* sequence number */
  476                 ((u_int16_t *)frm)[2] = 0;              /* status */
  477 
  478                 if (has_challenge) {
  479                         ((u_int16_t *)frm)[3] =
  480                             htole16((IEEE80211_CHALLENGE_LEN << 8) |
  481                             IEEE80211_ELEMID_CHALLENGE);
  482                         memcpy(&((u_int16_t *)frm)[4], ni->ni_challenge,
  483                             IEEE80211_CHALLENGE_LEN);
  484                         if (arg == IEEE80211_AUTH_SHARED_RESPONSE) {
  485                                 IEEE80211_DPRINTF((
  486                                     "%s: request encrypt frame\n", __func__));
  487                                 m->m_flags |= M_LINK0; /* WEP-encrypt, please */
  488                         }
  489                 }
  490                 if (ic->ic_opmode == IEEE80211_M_STA)
  491                         timer = IEEE80211_TRANS_WAIT;
  492                 break;
  493 
  494         case IEEE80211_FC0_SUBTYPE_DEAUTH:
  495                 if (ifp->if_flags & IFF_DEBUG)
  496                         if_printf(ifp, "station %s deauthenticate (reason %d)\n",
  497                             ether_sprintf(ni->ni_macaddr), arg);
  498                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  499                 if (m == NULL)
  500                         senderr(ENOMEM, is_tx_nombuf);
  501                 MH_ALIGN(m, 2);
  502                 m->m_pkthdr.len = m->m_len = 2;
  503                 *mtod(m, u_int16_t *) = htole16(arg);   /* reason */
  504                 break;
  505 
  506         case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
  507         case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
  508                 /*
  509                  * asreq frame format
  510                  *      [2] capability information
  511                  *      [2] listen interval
  512                  *      [6*] current AP address (reassoc only)
  513                  *      [tlv] ssid
  514                  *      [tlv] supported rates
  515                  *      [tlv] extended supported rates
  516                  */
  517                 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
  518                          sizeof(capinfo)
  519                        + sizeof(u_int16_t)
  520                        + IEEE80211_ADDR_LEN
  521                        + 2 + ni->ni_esslen
  522                        + 2 + IEEE80211_RATE_SIZE
  523                        + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
  524                 if (m == NULL)
  525                         senderr(ENOMEM, is_tx_nombuf);
  526                 m->m_data += sizeof(struct ieee80211_frame);
  527                 frm = mtod(m, u_int8_t *);
  528 
  529                 capinfo = 0;
  530                 if (ic->ic_opmode == IEEE80211_M_IBSS)
  531                         capinfo |= IEEE80211_CAPINFO_IBSS;
  532                 else            /* IEEE80211_M_STA */
  533                         capinfo |= IEEE80211_CAPINFO_ESS;
  534                 if (ic->ic_flags & IEEE80211_F_WEPON)
  535                         capinfo |= IEEE80211_CAPINFO_PRIVACY;
  536                 /*
  537                  * NB: Some 11a AP's reject the request when
  538                  *     short premable is set.
  539                  */
  540                 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
  541                     IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
  542                         capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
  543                 if (ic->ic_flags & IEEE80211_F_SHSLOT)
  544                         capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
  545                 *(u_int16_t *)frm = htole16(capinfo);
  546                 frm += 2;
  547 
  548                 *(u_int16_t *)frm = htole16(ic->ic_lintval);
  549                 frm += 2;
  550 
  551                 if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
  552                         IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid);
  553                         frm += IEEE80211_ADDR_LEN;
  554                 }
  555 
  556                 frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
  557                 frm = ieee80211_add_rates(frm, &ni->ni_rates);
  558                 frm = ieee80211_add_xrates(frm, &ni->ni_rates);
  559                 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
  560 
  561                 timer = IEEE80211_TRANS_WAIT;
  562                 break;
  563 
  564         case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
  565         case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
  566                 /*
  567                  * asreq frame format
  568                  *      [2] capability information
  569                  *      [2] status
  570                  *      [2] association ID
  571                  *      [tlv] supported rates
  572                  *      [tlv] extended supported rates
  573                  */
  574                 m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
  575                          sizeof(capinfo)
  576                        + sizeof(u_int16_t)
  577                        + sizeof(u_int16_t)
  578                        + 2 + IEEE80211_RATE_SIZE
  579                        + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE));
  580                 if (m == NULL)
  581                         senderr(ENOMEM, is_tx_nombuf);
  582                 m->m_data += sizeof(struct ieee80211_frame);
  583                 frm = mtod(m, u_int8_t *);
  584 
  585                 capinfo = IEEE80211_CAPINFO_ESS;
  586                 if (ic->ic_flags & IEEE80211_F_WEPON)
  587                         capinfo |= IEEE80211_CAPINFO_PRIVACY;
  588                 if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
  589                     IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
  590                         capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
  591                 *(u_int16_t *)frm = htole16(capinfo);
  592                 frm += 2;
  593 
  594                 *(u_int16_t *)frm = htole16(arg);       /* status */
  595                 frm += 2;
  596 
  597                 if (arg == IEEE80211_STATUS_SUCCESS)
  598                         *(u_int16_t *)frm = htole16(ni->ni_associd);
  599                 frm += 2;
  600 
  601                 frm = ieee80211_add_rates(frm, &ni->ni_rates);
  602                 frm = ieee80211_add_xrates(frm, &ni->ni_rates);
  603                 m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
  604                 break;
  605 
  606         case IEEE80211_FC0_SUBTYPE_DISASSOC:
  607                 if (ifp->if_flags & IFF_DEBUG)
  608                         if_printf(ifp, "station %s disassociate (reason %d)\n",
  609                             ether_sprintf(ni->ni_macaddr), arg);
  610                 MGETHDR(m, M_DONTWAIT, MT_DATA);
  611                 if (m == NULL)
  612                         senderr(ENOMEM, is_tx_nombuf);
  613                 MH_ALIGN(m, 2);
  614                 m->m_pkthdr.len = m->m_len = 2;
  615                 *mtod(m, u_int16_t *) = htole16(arg);   /* reason */
  616                 break;
  617 
  618         default:
  619                 IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n",
  620                         __func__, type));
  621                 senderr(EINVAL, is_tx_unknownmgt);
  622                 /* NOTREACHED */
  623         }
  624 
  625         ret = ieee80211_mgmt_output(ifp, ni, m, type);
  626         if (ret == 0) {
  627                 if (timer)
  628                         ic->ic_mgt_timer = timer;
  629         } else {
  630 bad:
  631                 if (ni != ic->ic_bss)           /* remove ref we added */
  632                         ieee80211_free_node(ic, ni);
  633         }
  634         return ret;
  635 #undef senderr
  636 }
  637 
  638 void
  639 ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni, 
  640                   struct mbuf *m)
  641 {
  642         /* Store the new packet on our queue, changing the TIM if necessary */
  643 
  644         if (IF_IS_EMPTY(&ni->ni_savedq)) {
  645                 ic->ic_set_tim(ic, ni->ni_associd, 1);
  646         }
  647         if (ni->ni_savedq.ifq_len >= IEEE80211_PS_MAX_QUEUE) {
  648                 IF_DROP(&ni->ni_savedq);
  649                 m_freem(m);
  650                 if (ic->ic_if.if_flags & IFF_DEBUG)
  651                         printf("%s: station %s power save queue overflow"
  652                                " of size %d drops %d\n",
  653                                ic->ic_if.if_xname, 
  654                                ether_sprintf(ni->ni_macaddr), 
  655                                IEEE80211_PS_MAX_QUEUE,
  656                                ni->ni_savedq.ifq_drops);
  657         } else {
  658                 /* Similar to ieee80211_mgmt_output, store the node in
  659                  * the rcvif field.
  660                  */
  661                 IF_ENQUEUE(&ni->ni_savedq, m);
  662                 m->m_pkthdr.rcvif = (void *)ni;
  663         }
  664 }
  665 

Cache object: 53560865cacf656f0cfe62703a83b354


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