Annotation of sys/net80211/ieee80211_output.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ieee80211_output.c,v 1.55 2007/08/05 21:41:11 claudio Exp $ */
! 2: /* $NetBSD: ieee80211_output.c,v 1.13 2004/05/31 11:02:55 dyoung Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2001 Atsushi Onoe
! 6: * Copyright (c) 2002, 2003 Sam Leffler, Errno Consulting
! 7: * Copyright (c) 2007 Damien Bergamini
! 8: * All rights reserved.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. The name of the author may not be used to endorse or promote products
! 19: * derived from this software without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 22: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 23: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 24: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 25: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 26: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 27: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 28: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 29: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 30: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 31: */
! 32:
! 33: #include "bpfilter.h"
! 34: #include "vlan.h"
! 35:
! 36: #include <sys/param.h>
! 37: #include <sys/systm.h>
! 38: #include <sys/mbuf.h>
! 39: #include <sys/kernel.h>
! 40: #include <sys/socket.h>
! 41: #include <sys/sockio.h>
! 42: #include <sys/endian.h>
! 43: #include <sys/errno.h>
! 44: #include <sys/proc.h>
! 45: #include <sys/sysctl.h>
! 46:
! 47: #include <net/if.h>
! 48: #include <net/if_dl.h>
! 49: #include <net/if_media.h>
! 50: #include <net/if_arp.h>
! 51: #include <net/if_llc.h>
! 52: #include <net/bpf.h>
! 53:
! 54: #ifdef INET
! 55: #include <netinet/in.h>
! 56: #include <netinet/if_ether.h>
! 57: #include <netinet/in_systm.h>
! 58: #include <netinet/ip.h>
! 59: #endif
! 60:
! 61: #if NVLAN > 0
! 62: #include <net/if_types.h>
! 63: #include <net/if_vlan_var.h>
! 64: #endif
! 65:
! 66: #include <net80211/ieee80211_var.h>
! 67:
! 68: #include <dev/rndvar.h>
! 69:
! 70: enum ieee80211_edca_ac ieee80211_up_to_ac(struct ieee80211com *, int);
! 71: int ieee80211_classify(struct ieee80211com *, struct mbuf *);
! 72: int ieee80211_mgmt_output(struct ifnet *, struct ieee80211_node *,
! 73: struct mbuf *, int);
! 74: u_int8_t *ieee80211_add_rsn_body(u_int8_t *, struct ieee80211com *,
! 75: const struct ieee80211_node *, int);
! 76: struct mbuf *ieee80211_getmbuf(int, int, u_int);
! 77: struct mbuf *ieee80211_get_probe_req(struct ieee80211com *,
! 78: struct ieee80211_node *);
! 79: struct mbuf *ieee80211_get_probe_resp(struct ieee80211com *,
! 80: struct ieee80211_node *);
! 81: struct mbuf *ieee80211_get_auth(struct ieee80211com *,
! 82: struct ieee80211_node *, u_int16_t, u_int16_t);
! 83: struct mbuf *ieee80211_get_deauth(struct ieee80211com *,
! 84: struct ieee80211_node *, u_int16_t);
! 85: struct mbuf *ieee80211_get_assoc_req(struct ieee80211com *,
! 86: struct ieee80211_node *, int);
! 87: struct mbuf *ieee80211_get_assoc_resp(struct ieee80211com *,
! 88: struct ieee80211_node *, u_int16_t);
! 89: struct mbuf *ieee80211_get_disassoc(struct ieee80211com *,
! 90: struct ieee80211_node *, u_int16_t);
! 91: int ieee80211_send_eapol_key(struct ieee80211com *, struct mbuf *,
! 92: struct ieee80211_node *);
! 93: u_int8_t *ieee80211_add_gtk_kde(u_int8_t *, const struct ieee80211_key *);
! 94: u_int8_t *ieee80211_add_pmkid_kde(u_int8_t *, const u_int8_t *);
! 95: struct mbuf *ieee80211_get_eapol_key(int, int, u_int);
! 96:
! 97:
! 98: /*
! 99: * IEEE 802.11 output routine. Normally this will directly call the
! 100: * Ethernet output routine because 802.11 encapsulation is called
! 101: * later by the driver. This function can be used to send raw frames
! 102: * if the mbuf has been tagged with a 802.11 data link type.
! 103: */
! 104: int
! 105: ieee80211_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
! 106: struct rtentry *rt)
! 107: {
! 108: u_int dlt = 0;
! 109: int s, error = 0;
! 110: struct m_tag *mtag;
! 111:
! 112: /* Interface has to be up and running */
! 113: if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) !=
! 114: (IFF_UP | IFF_RUNNING)) {
! 115: error = ENETDOWN;
! 116: goto bad;
! 117: }
! 118:
! 119: /* Try to get the DLT from a mbuf tag */
! 120: if ((mtag = m_tag_find(m, PACKET_TAG_DLT, NULL)) != NULL) {
! 121: dlt = *(u_int *)(mtag + 1);
! 122:
! 123: /* Fallback to ethernet for non-802.11 linktypes */
! 124: if (!(dlt == DLT_IEEE802_11 || dlt == DLT_IEEE802_11_RADIO))
! 125: goto fallback;
! 126:
! 127: /*
! 128: * Queue message on interface without adding any
! 129: * further headers, and start output if interface not
! 130: * yet active.
! 131: */
! 132: s = splnet();
! 133: IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
! 134: if (error) {
! 135: /* mbuf is already freed */
! 136: splx(s);
! 137: printf("%s: failed to queue raw tx frame\n",
! 138: ifp->if_xname);
! 139: return (error);
! 140: }
! 141: ifp->if_obytes += m->m_pkthdr.len;
! 142: if (m->m_flags & M_MCAST)
! 143: ifp->if_omcasts++;
! 144: if ((ifp->if_flags & IFF_OACTIVE) == 0)
! 145: (*ifp->if_start)(ifp);
! 146: splx(s);
! 147:
! 148: return (error);
! 149: }
! 150:
! 151: fallback:
! 152: return (ether_output(ifp, m, dst, rt));
! 153:
! 154: bad:
! 155: if (m)
! 156: m_freem(m);
! 157: return (error);
! 158: }
! 159:
! 160: /*
! 161: * Send a management frame to the specified node. The node pointer
! 162: * must have a reference as the pointer will be passed to the driver
! 163: * and potentially held for a long time. If the frame is successfully
! 164: * dispatched to the driver, then it is responsible for freeing the
! 165: * reference (and potentially free'ing up any associated storage).
! 166: */
! 167: int
! 168: ieee80211_mgmt_output(struct ifnet *ifp, struct ieee80211_node *ni,
! 169: struct mbuf *m, int type)
! 170: {
! 171: struct ieee80211com *ic = (void *)ifp;
! 172: struct ieee80211_frame *wh;
! 173:
! 174: if (ni == NULL)
! 175: panic("null node");
! 176: ni->ni_inact = 0;
! 177:
! 178: /*
! 179: * Yech, hack alert! We want to pass the node down to the
! 180: * driver's start routine. We could stick this in an m_tag
! 181: * and tack that on to the mbuf. However that's rather
! 182: * expensive to do for every frame so instead we stuff it in
! 183: * the rcvif field since outbound frames do not (presently)
! 184: * use this.
! 185: */
! 186: M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT);
! 187: if (m == NULL)
! 188: return ENOMEM;
! 189: m->m_pkthdr.rcvif = (void *)ni;
! 190:
! 191: wh = mtod(m, struct ieee80211_frame *);
! 192: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | type;
! 193: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 194: *(u_int16_t *)&wh->i_dur[0] = 0;
! 195: *(u_int16_t *)&wh->i_seq[0] =
! 196: htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
! 197: ni->ni_txseq++;
! 198: IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr);
! 199: IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
! 200: IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
! 201:
! 202: if (ifp->if_flags & IFF_DEBUG) {
! 203: /* avoid to print too many frames */
! 204: if (ic->ic_opmode == IEEE80211_M_IBSS ||
! 205: #ifdef IEEE80211_DEBUG
! 206: ieee80211_debug > 1 ||
! 207: #endif
! 208: (type & IEEE80211_FC0_SUBTYPE_MASK) !=
! 209: IEEE80211_FC0_SUBTYPE_PROBE_RESP)
! 210: printf("%s: sending %s to %s on channel %u mode %s\n",
! 211: ifp->if_xname,
! 212: ieee80211_mgt_subtype_name[
! 213: (type & IEEE80211_FC0_SUBTYPE_MASK)
! 214: >> IEEE80211_FC0_SUBTYPE_SHIFT],
! 215: ether_sprintf(ni->ni_macaddr),
! 216: ieee80211_chan2ieee(ic, ni->ni_chan),
! 217: ieee80211_phymode_name[
! 218: ieee80211_chan2mode(ic, ni->ni_chan)]);
! 219: }
! 220:
! 221: IF_ENQUEUE(&ic->ic_mgtq, m);
! 222: ifp->if_timer = 1;
! 223: (*ifp->if_start)(ifp);
! 224: return 0;
! 225: }
! 226:
! 227: /*-
! 228: * EDCA tables are computed using the following formulas:
! 229: *
! 230: * 1) EDCATable (non-AP QSTA)
! 231: *
! 232: * AC CWmin CWmax AIFSN TXOP limit(ms)
! 233: * -------------------------------------------------------------
! 234: * AC_BK aCWmin aCWmax 7 0
! 235: * AC_BE aCWmin aCWmax 3 0
! 236: * AC_VI (aCWmin+1)/2-1 aCWmin 2 agn=3.008 b=6.016 others=0
! 237: * AC_VO (aCWmin+1)/4-1 (aCWmin+1)/2-1 2 agn=1.504 b=3.264 others=0
! 238: *
! 239: * 2) QAPEDCATable (QAP)
! 240: *
! 241: * AC CWmin CWmax AIFSN TXOP limit(ms)
! 242: * -------------------------------------------------------------
! 243: * AC_BK aCWmin aCWmax 7 0
! 244: * AC_BE aCWmin 4*(aCWmin+1)-1 3 0
! 245: * AC_VI (aCWmin+1)/2-1 aCWmin 1 agn=3.008 b=6.016 others=0
! 246: * AC_VO (aCWmin+1)/4-1 (aCWmin+1)/2-1 1 agn=1.504 b=3.264 others=0
! 247: *
! 248: * and the following aCWmin/aCWmax values:
! 249: *
! 250: * PHY aCWmin aCWmax
! 251: * ---------------------------
! 252: * 11A 15 1023
! 253: * 11B 31 1023
! 254: * 11G 15* 1023 (*) aCWmin(1)
! 255: * FH 15 1023
! 256: * Turbo A/G 7 1023 (Atheros proprietary mode)
! 257: */
! 258: static const struct ieee80211_edca_ac_params
! 259: ieee80211_edca_table[IEEE80211_MODE_MAX][EDCA_NUM_AC] = {
! 260: [IEEE80211_MODE_FH] = {
! 261: [EDCA_AC_BK] = { 4, 10, 7, 0 },
! 262: [EDCA_AC_BE] = { 4, 10, 3, 0 },
! 263: [EDCA_AC_VI] = { 3, 4, 2, 0 },
! 264: [EDCA_AC_VO] = { 2, 3, 2, 0 }
! 265: },
! 266: [IEEE80211_MODE_11B] = {
! 267: [EDCA_AC_BK] = { 5, 10, 7, 0 },
! 268: [EDCA_AC_BE] = { 5, 10, 3, 0 },
! 269: [EDCA_AC_VI] = { 4, 5, 2, 188 },
! 270: [EDCA_AC_VO] = { 3, 4, 2, 102 }
! 271: },
! 272: [IEEE80211_MODE_11A] = {
! 273: [EDCA_AC_BK] = { 4, 10, 7, 0 },
! 274: [EDCA_AC_BE] = { 4, 10, 3, 0 },
! 275: [EDCA_AC_VI] = { 3, 4, 2, 94 },
! 276: [EDCA_AC_VO] = { 2, 3, 2, 47 }
! 277: },
! 278: [IEEE80211_MODE_11G] = {
! 279: [EDCA_AC_BK] = { 4, 10, 7, 0 },
! 280: [EDCA_AC_BE] = { 4, 10, 3, 0 },
! 281: [EDCA_AC_VI] = { 3, 4, 2, 94 },
! 282: [EDCA_AC_VO] = { 2, 3, 2, 47 }
! 283: },
! 284: [IEEE80211_MODE_TURBO] = {
! 285: [EDCA_AC_BK] = { 3, 10, 7, 0 },
! 286: [EDCA_AC_BE] = { 3, 10, 2, 0 },
! 287: [EDCA_AC_VI] = { 2, 3, 2, 94 },
! 288: [EDCA_AC_VO] = { 2, 2, 1, 47 }
! 289: }
! 290: };
! 291:
! 292: static const struct ieee80211_edca_ac_params
! 293: ieee80211_qap_edca_table[IEEE80211_MODE_MAX][EDCA_NUM_AC] = {
! 294: [IEEE80211_MODE_FH] = {
! 295: [EDCA_AC_BK] = { 4, 10, 7, 0 },
! 296: [EDCA_AC_BE] = { 4, 6, 3, 0 },
! 297: [EDCA_AC_VI] = { 3, 4, 1, 0 },
! 298: [EDCA_AC_VO] = { 2, 3, 1, 0 }
! 299: },
! 300: [IEEE80211_MODE_11B] = {
! 301: [EDCA_AC_BK] = { 5, 10, 7, 0 },
! 302: [EDCA_AC_BE] = { 5, 7, 3, 0 },
! 303: [EDCA_AC_VI] = { 4, 5, 1, 188 },
! 304: [EDCA_AC_VO] = { 3, 4, 1, 102 }
! 305: },
! 306: [IEEE80211_MODE_11A] = {
! 307: [EDCA_AC_BK] = { 4, 10, 7, 0 },
! 308: [EDCA_AC_BE] = { 4, 6, 3, 0 },
! 309: [EDCA_AC_VI] = { 3, 4, 1, 94 },
! 310: [EDCA_AC_VO] = { 2, 3, 1, 47 }
! 311: },
! 312: [IEEE80211_MODE_11G] = {
! 313: [EDCA_AC_BK] = { 4, 10, 7, 0 },
! 314: [EDCA_AC_BE] = { 4, 6, 3, 0 },
! 315: [EDCA_AC_VI] = { 3, 4, 1, 94 },
! 316: [EDCA_AC_VO] = { 2, 3, 1, 47 }
! 317: },
! 318: [IEEE80211_MODE_TURBO] = {
! 319: [EDCA_AC_BK] = { 3, 10, 7, 0 },
! 320: [EDCA_AC_BE] = { 3, 5, 2, 0 },
! 321: [EDCA_AC_VI] = { 2, 3, 1, 94 },
! 322: [EDCA_AC_VO] = { 2, 2, 1, 47 }
! 323: }
! 324: };
! 325:
! 326: /*
! 327: * Return the EDCA Access Category to be used for transmitting a frame with
! 328: * user-priority `up'.
! 329: */
! 330: enum ieee80211_edca_ac
! 331: ieee80211_up_to_ac(struct ieee80211com *ic, int up)
! 332: {
! 333: /* IEEE Std 802.11e-2005, table 20i */
! 334: static const enum ieee80211_edca_ac up_to_ac[] = {
! 335: EDCA_AC_BE, /* BE */
! 336: EDCA_AC_BK, /* BK */
! 337: EDCA_AC_BK, /* -- */
! 338: EDCA_AC_BE, /* EE */
! 339: EDCA_AC_VI, /* CL */
! 340: EDCA_AC_VI, /* VI */
! 341: EDCA_AC_VO, /* VO */
! 342: EDCA_AC_VO /* NC */
! 343: };
! 344: enum ieee80211_edca_ac ac;
! 345:
! 346: ac = (up <= 7) ? up_to_ac[up] : EDCA_AC_BE;
! 347:
! 348: if (ic->ic_opmode == IEEE80211_M_HOSTAP)
! 349: return ac;
! 350:
! 351: /*
! 352: * We do not support the admission control procedure defined in
! 353: * IEEE Std 802.11e-2005 section 9.9.3.1.2. The spec says that
! 354: * non-AP QSTAs that don't support this procedure shall use EDCA
! 355: * parameters of a lower priority AC that does not require
! 356: * admission control.
! 357: */
! 358: while (ac != EDCA_AC_BK && ic->ic_edca_ac[ac].ac_acm) {
! 359: switch (ac) {
! 360: case EDCA_AC_BK:
! 361: /* can't get there */
! 362: break;
! 363: case EDCA_AC_BE:
! 364: /* BE shouldn't require admission control */
! 365: ac = EDCA_AC_BK;
! 366: break;
! 367: case EDCA_AC_VI:
! 368: ac = EDCA_AC_BE;
! 369: break;
! 370: case EDCA_AC_VO:
! 371: ac = EDCA_AC_VI;
! 372: break;
! 373: }
! 374: }
! 375: return ac;
! 376: }
! 377:
! 378: /*
! 379: * Get mbuf's user-priority: if mbuf is not VLAN tagged, select user-priority
! 380: * based on the DSCP (Differentiated Services Codepoint) field.
! 381: */
! 382: int
! 383: ieee80211_classify(struct ieee80211com *ic, struct mbuf *m)
! 384: {
! 385: #ifdef INET
! 386: const struct ether_header *eh;
! 387: #endif
! 388: #if NVLAN > 0
! 389: if ((m->m_flags & M_PROTO1) == M_PROTO1 && m->m_pkthdr.rcvif != NULL) {
! 390: const struct ifvlan *ifv = m->m_pkthdr.rcvif->if_softc;
! 391:
! 392: /* use VLAN 802.1D user-priority */
! 393: if (ifv->ifv_prio <= 7)
! 394: return ifv->ifv_prio;
! 395: }
! 396: #endif
! 397: #ifdef INET
! 398: eh = mtod(m, struct ether_header *);
! 399: if (eh->ether_type == htons(ETHERTYPE_IP)) {
! 400: const struct ip *ip = (const struct ip *)(eh + 1);
! 401: /*
! 402: * Map Differentiated Services Codepoint field (see RFC2474).
! 403: * Preserves backward compatibility with IP Precedence field.
! 404: */
! 405: switch (ip->ip_tos & 0xfc) {
! 406: case IPTOS_PREC_PRIORITY:
! 407: return 2;
! 408: case IPTOS_PREC_IMMEDIATE:
! 409: return 1;
! 410: case IPTOS_PREC_FLASH:
! 411: return 3;
! 412: case IPTOS_PREC_FLASHOVERRIDE:
! 413: return 4;
! 414: case IPTOS_PREC_CRITIC_ECP:
! 415: return 5;
! 416: case IPTOS_PREC_INTERNETCONTROL:
! 417: return 6;
! 418: case IPTOS_PREC_NETCONTROL:
! 419: return 7;
! 420: }
! 421: }
! 422: #endif
! 423: return 0; /* default to Best-Effort */
! 424: }
! 425:
! 426: /*
! 427: * Encapsulate an outbound data frame. The mbuf chain is updated and
! 428: * a reference to the destination node is returned. If an error is
! 429: * encountered NULL is returned and the node reference will also be NULL.
! 430: *
! 431: * NB: The caller is responsible for free'ing a returned node reference.
! 432: * The convention is ic_bss is not reference counted; the caller must
! 433: * maintain that.
! 434: */
! 435: struct mbuf *
! 436: ieee80211_encap(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node **pni)
! 437: {
! 438: struct ieee80211com *ic = (void *)ifp;
! 439: struct ether_header eh;
! 440: struct ieee80211_frame *wh;
! 441: struct ieee80211_node *ni = NULL;
! 442: struct llc *llc;
! 443: struct m_tag *mtag;
! 444: u_int8_t *addr;
! 445: u_int dlt, hdrlen;
! 446: int addqos, tid;
! 447:
! 448: /* Handle raw frames if mbuf is tagged as 802.11 */
! 449: if ((mtag = m_tag_find(m, PACKET_TAG_DLT, NULL)) != NULL) {
! 450: dlt = *(u_int *)(mtag + 1);
! 451:
! 452: if (!(dlt == DLT_IEEE802_11 || dlt == DLT_IEEE802_11_RADIO))
! 453: goto fallback;
! 454:
! 455: wh = mtod(m, struct ieee80211_frame *);
! 456:
! 457: if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_min))
! 458: goto bad;
! 459:
! 460: if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) !=
! 461: IEEE80211_FC0_VERSION_0)
! 462: goto bad;
! 463:
! 464: switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
! 465: case IEEE80211_FC1_DIR_NODS:
! 466: case IEEE80211_FC1_DIR_FROMDS:
! 467: addr = wh->i_addr1;
! 468: break;
! 469: case IEEE80211_FC1_DIR_DSTODS:
! 470: case IEEE80211_FC1_DIR_TODS:
! 471: addr = wh->i_addr3;
! 472: break;
! 473: default:
! 474: goto bad;
! 475: }
! 476:
! 477: ni = ieee80211_find_txnode(ic, addr);
! 478: if (ni == NULL)
! 479: ni = ieee80211_ref_node(ic->ic_bss);
! 480: if (ni == NULL) {
! 481: printf("%s: no node for dst %s, "
! 482: "discard raw tx frame\n", ifp->if_xname,
! 483: ether_sprintf(addr));
! 484: ic->ic_stats.is_tx_nonode++;
! 485: goto bad;
! 486: }
! 487: ni->ni_inact = 0;
! 488:
! 489: *pni = ni;
! 490: return (m);
! 491: }
! 492:
! 493: fallback:
! 494: if (m->m_len < sizeof(struct ether_header)) {
! 495: m = m_pullup(m, sizeof(struct ether_header));
! 496: if (m == NULL) {
! 497: ic->ic_stats.is_tx_nombuf++;
! 498: goto bad;
! 499: }
! 500: }
! 501: memcpy(&eh, mtod(m, caddr_t), sizeof(struct ether_header));
! 502:
! 503: ni = ieee80211_find_txnode(ic, eh.ether_dhost);
! 504: if (ni == NULL) {
! 505: IEEE80211_DPRINTF(("%s: no node for dst %s, discard frame\n",
! 506: __func__, ether_sprintf(eh.ether_dhost)));
! 507: ic->ic_stats.is_tx_nonode++;
! 508: goto bad;
! 509: }
! 510: #if 0
! 511: if (!ni->ni_port_valid && eh.ether_type != htons(ETHERTYPE_PAE)) {
! 512: IEEE80211_DPRINTF(("%s: port not valid: %s\n",
! 513: __func__, ether_sprintf(eh.ether_dhost)));
! 514: ic->ic_stats.is_tx_noauth++;
! 515: goto bad;
! 516: }
! 517: #endif
! 518: ni->ni_inact = 0;
! 519:
! 520: if ((ic->ic_flags & IEEE80211_F_QOS) &&
! 521: (ni->ni_flags & IEEE80211_NODE_QOS) &&
! 522: /* do not QoS-encapsulate EAPOL frames */
! 523: eh.ether_type != htons(ETHERTYPE_PAE)) {
! 524: tid = ieee80211_classify(ic, m);
! 525: hdrlen = sizeof(struct ieee80211_qosframe);
! 526: addqos = 1;
! 527: } else {
! 528: hdrlen = sizeof(struct ieee80211_frame);
! 529: addqos = 0;
! 530: }
! 531: m_adj(m, sizeof(struct ether_header) - sizeof(struct llc));
! 532: llc = mtod(m, struct llc *);
! 533: llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP;
! 534: llc->llc_control = LLC_UI;
! 535: llc->llc_snap.org_code[0] = 0;
! 536: llc->llc_snap.org_code[1] = 0;
! 537: llc->llc_snap.org_code[2] = 0;
! 538: llc->llc_snap.ether_type = eh.ether_type;
! 539: M_PREPEND(m, hdrlen, M_DONTWAIT);
! 540: if (m == NULL) {
! 541: ic->ic_stats.is_tx_nombuf++;
! 542: goto bad;
! 543: }
! 544: wh = mtod(m, struct ieee80211_frame *);
! 545: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA;
! 546: *(u_int16_t *)&wh->i_dur[0] = 0;
! 547: if (addqos) {
! 548: struct ieee80211_qosframe *qwh =
! 549: (struct ieee80211_qosframe *)wh;
! 550: qwh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS;
! 551: qwh->i_qos[0] = tid & IEEE80211_QOS_TID;
! 552: qwh->i_qos[1] = 0; /* no TXOP requested */
! 553: *(u_int16_t *)&qwh->i_seq[0] =
! 554: htole16(ni->ni_qos_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT);
! 555: ni->ni_qos_txseqs[tid]++;
! 556: } else {
! 557: *(u_int16_t *)&wh->i_seq[0] =
! 558: htole16(ni->ni_txseq << IEEE80211_SEQ_SEQ_SHIFT);
! 559: ni->ni_txseq++;
! 560: }
! 561: switch (ic->ic_opmode) {
! 562: case IEEE80211_M_STA:
! 563: wh->i_fc[1] = IEEE80211_FC1_DIR_TODS;
! 564: IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid);
! 565: IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
! 566: IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost);
! 567: break;
! 568: case IEEE80211_M_IBSS:
! 569: case IEEE80211_M_AHDEMO:
! 570: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 571: IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
! 572: IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost);
! 573: IEEE80211_ADDR_COPY(wh->i_addr3, ic->ic_bss->ni_bssid);
! 574: break;
! 575: case IEEE80211_M_HOSTAP:
! 576: wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS;
! 577: IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost);
! 578: IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid);
! 579: IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost);
! 580: break;
! 581: case IEEE80211_M_MONITOR:
! 582: goto bad;
! 583: }
! 584: if (ic->ic_flags & IEEE80211_F_WEPON)
! 585: wh->i_fc[1] |= IEEE80211_FC1_WEP;
! 586: *pni = ni;
! 587: return m;
! 588: bad:
! 589: if (m != NULL)
! 590: m_freem(m);
! 591: if (ni != NULL)
! 592: ieee80211_release_node(ic, ni);
! 593: *pni = NULL;
! 594: return NULL;
! 595: }
! 596:
! 597: /* unaligned little endian access */
! 598: #define LE_WRITE_2(p, v) do { \
! 599: ((u_int8_t *)(p))[0] = (v) & 0xff; \
! 600: ((u_int8_t *)(p))[1] = (v) >> 8; \
! 601: } while (0)
! 602:
! 603: /*
! 604: * Add a Capability Information field to a frame (see 7.3.1.4).
! 605: */
! 606: u_int8_t *
! 607: ieee80211_add_capinfo(u_int8_t *frm, struct ieee80211com *ic,
! 608: const struct ieee80211_node *ni)
! 609: {
! 610: u_int16_t capinfo;
! 611:
! 612: if (ic->ic_opmode == IEEE80211_M_IBSS)
! 613: capinfo = IEEE80211_CAPINFO_IBSS;
! 614: else if (ic->ic_opmode == IEEE80211_M_HOSTAP)
! 615: capinfo = IEEE80211_CAPINFO_ESS;
! 616: else
! 617: capinfo = 0;
! 618: if (ic->ic_flags & IEEE80211_F_WEPON)
! 619: capinfo |= IEEE80211_CAPINFO_PRIVACY;
! 620: /* NB: some 11a AP's reject the request when short preamble is set */
! 621: if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
! 622: IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
! 623: capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
! 624: if (ic->ic_flags & IEEE80211_F_SHSLOT)
! 625: capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
! 626: LE_WRITE_2(frm, capinfo);
! 627: return frm + 2;
! 628: }
! 629:
! 630: /*
! 631: * Add an SSID element to a frame (see 7.3.2.1).
! 632: */
! 633: u_int8_t *
! 634: ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
! 635: {
! 636: *frm++ = IEEE80211_ELEMID_SSID;
! 637: *frm++ = len;
! 638: memcpy(frm, ssid, len);
! 639: return frm + len;
! 640: }
! 641:
! 642: /*
! 643: * Add a supported rates element to a frame (see 7.3.2.2).
! 644: */
! 645: u_int8_t *
! 646: ieee80211_add_rates(u_int8_t *frm, const struct ieee80211_rateset *rs)
! 647: {
! 648: int nrates;
! 649:
! 650: *frm++ = IEEE80211_ELEMID_RATES;
! 651: nrates = min(rs->rs_nrates, IEEE80211_RATE_SIZE);
! 652: *frm++ = nrates;
! 653: memcpy(frm, rs->rs_rates, nrates);
! 654: return frm + nrates;
! 655: }
! 656:
! 657: /*
! 658: * Add a FH Parameter Set element to a frame (see 7.3.2.3).
! 659: */
! 660: u_int8_t *
! 661: ieee80211_add_fh_params(u_int8_t *frm, struct ieee80211com *ic,
! 662: const struct ieee80211_node *ni)
! 663: {
! 664: u_int chan = ieee80211_chan2ieee(ic, ni->ni_chan);
! 665:
! 666: *frm++ = IEEE80211_ELEMID_FHPARMS;
! 667: *frm++ = 5;
! 668: LE_WRITE_2(frm, ni->ni_fhdwell); frm += 2;
! 669: *frm++ = IEEE80211_FH_CHANSET(chan);
! 670: *frm++ = IEEE80211_FH_CHANPAT(chan);
! 671: *frm++ = ni->ni_fhindex;
! 672: return frm;
! 673: }
! 674:
! 675: /*
! 676: * Add a DS Parameter Set element to a frame (see 7.3.2.4).
! 677: */
! 678: u_int8_t *
! 679: ieee80211_add_ds_params(u_int8_t *frm, struct ieee80211com *ic,
! 680: const struct ieee80211_node *ni)
! 681: {
! 682: *frm++ = IEEE80211_ELEMID_DSPARMS;
! 683: *frm++ = 1;
! 684: *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan);
! 685: return frm;
! 686: }
! 687:
! 688: /*
! 689: * Add a TIM element to a frame (see 7.3.2.6 and Annex L).
! 690: */
! 691: u_int8_t *
! 692: ieee80211_add_tim(u_int8_t *frm, struct ieee80211com *ic)
! 693: {
! 694: u_int i, offset = 0, len;
! 695:
! 696: /* find first non-zero octet in the virtual bit map */
! 697: for (i = 0; i < ic->ic_tim_len && ic->ic_tim_bitmap[i] == 0; i++);
! 698:
! 699: /* clear the lsb as it is reserved for the broadcast indication bit */
! 700: if (i < ic->ic_tim_len)
! 701: offset = i & ~1;
! 702:
! 703: /* find last non-zero octet in the virtual bit map */
! 704: for (i = ic->ic_tim_len - 1; i > 0 && ic->ic_tim_bitmap[i] == 0; i--);
! 705:
! 706: len = i - offset + 1;
! 707:
! 708: *frm++ = IEEE80211_ELEMID_TIM;
! 709: *frm++ = len + 3; /* length */
! 710: *frm++ = ic->ic_dtim_count; /* DTIM count */
! 711: *frm++ = ic->ic_dtim_period; /* DTIM period */
! 712:
! 713: /* Bitmap Control */
! 714: *frm = offset;
! 715: /* set broadcast/multicast indication bit if necessary */
! 716: if (ic->ic_dtim_count == 0 && ic->ic_tim_mcast)
! 717: *frm |= 0x01;
! 718: frm++;
! 719:
! 720: /* Partial Virtual Bitmap */
! 721: memcpy(frm, &ic->ic_tim_bitmap[offset], len);
! 722: return frm + len;
! 723: }
! 724:
! 725: /*
! 726: * Add an IBSS Parameter Set element to a frame (see 7.3.2.7).
! 727: */
! 728: u_int8_t *
! 729: ieee80211_add_ibss_params(u_int8_t *frm, const struct ieee80211_node *ni)
! 730: {
! 731: *frm++ = IEEE80211_ELEMID_IBSSPARMS;
! 732: *frm++ = 2;
! 733: LE_WRITE_2(frm, 0); /* TODO: ATIM window */
! 734: return frm + 2;
! 735: }
! 736:
! 737: /*
! 738: * Add an EDCA Parameter Set element to a frame (see 7.3.2.29).
! 739: */
! 740: u_int8_t *
! 741: ieee80211_add_edca_params(u_int8_t *frm, struct ieee80211com *ic)
! 742: {
! 743: const struct ieee80211_edca_ac_params *edca;
! 744: int aci;
! 745:
! 746: *frm++ = IEEE80211_ELEMID_EDCAPARMS;
! 747: *frm++ = 18; /* length */
! 748: *frm++ = 0; /* QoS Info */
! 749: *frm++ = 0; /* reserved */
! 750:
! 751: /* setup AC Parameter Records */
! 752: edca = ieee80211_qap_edca_table[ic->ic_curmode];
! 753: for (aci = 0; aci < EDCA_NUM_AC; aci++) {
! 754: const struct ieee80211_edca_ac_params *ac = &edca[aci];
! 755:
! 756: *frm++ = (aci << 5) | ((ac->ac_acm & 0x1) << 4) |
! 757: (ac->ac_aifsn & 0xf);
! 758: *frm++ = (ac->ac_ecwmax << 4) |
! 759: (ac->ac_ecwmin & 0xf);
! 760: LE_WRITE_2(frm, ac->ac_txoplimit); frm += 2;
! 761: }
! 762: return frm;
! 763: }
! 764:
! 765: /*
! 766: * Add an ERP element to a frame (see 7.3.2.13).
! 767: */
! 768: u_int8_t *
! 769: ieee80211_add_erp(u_int8_t *frm, struct ieee80211com *ic)
! 770: {
! 771: u_int8_t erp;
! 772:
! 773: *frm++ = IEEE80211_ELEMID_ERP;
! 774: *frm++ = 1;
! 775: erp = 0;
! 776: /*
! 777: * The NonERP_Present bit shall be set to 1 when a NonERP STA
! 778: * is associated with the BSS.
! 779: */
! 780: if (ic->ic_nonerpsta != 0)
! 781: erp |= IEEE80211_ERP_NON_ERP_PRESENT;
! 782: /*
! 783: * If one or more NonERP STAs are associated in the BSS, the
! 784: * Use_Protection bit shall be set to 1 in transmitted ERP
! 785: * Information Elements.
! 786: */
! 787: if (ic->ic_flags & IEEE80211_F_USEPROT)
! 788: erp |= IEEE80211_ERP_USE_PROTECTION;
! 789: /*
! 790: * The Barker_Preamble_Mode bit shall be set to 1 by the ERP
! 791: * Information Element sender if one or more associated NonERP
! 792: * STAs are not short preamble capable.
! 793: */
! 794: if (!(ic->ic_flags & IEEE80211_F_SHPREAMBLE))
! 795: erp |= IEEE80211_ERP_BARKER_MODE;
! 796: *frm++ = erp;
! 797: return frm;
! 798: }
! 799:
! 800: /*
! 801: * Add a QoS Capability element to a frame (see 7.3.2.35).
! 802: */
! 803: u_int8_t *
! 804: ieee80211_add_qos_capability(u_int8_t *frm, struct ieee80211com *ic)
! 805: {
! 806: *frm++ = IEEE80211_ELEMID_QOS_CAP;
! 807: *frm++ = 1;
! 808: *frm++ = 0; /* QoS Info */
! 809: return frm;
! 810: }
! 811:
! 812: /*
! 813: * Add an RSN element to a frame (see 7.3.2.25).
! 814: */
! 815: u_int8_t *
! 816: ieee80211_add_rsn_body(u_int8_t *frm, struct ieee80211com *ic,
! 817: const struct ieee80211_node *ni, int wpa1)
! 818: {
! 819: const u_int8_t *oui = wpa1 ? MICROSOFT_OUI : IEEE80211_OUI;
! 820: u_int8_t *pcount;
! 821: u_int16_t count;
! 822:
! 823: /* write Version field */
! 824: LE_WRITE_2(frm, 1); frm += 2;
! 825:
! 826: /* write Group Cipher Suite field (see Table 20da) */
! 827: memcpy(frm, oui, 3); frm += 3;
! 828: switch (ni->ni_group_cipher) {
! 829: case IEEE80211_CIPHER_USEGROUP:
! 830: /* can't get there */
! 831: panic("invalid group cipher!");
! 832: break;
! 833: case IEEE80211_CIPHER_WEP40:
! 834: *frm++ = 1;
! 835: break;
! 836: case IEEE80211_CIPHER_TKIP:
! 837: *frm++ = 2;
! 838: break;
! 839: case IEEE80211_CIPHER_CCMP:
! 840: *frm++ = 4;
! 841: break;
! 842: case IEEE80211_CIPHER_WEP104:
! 843: *frm++ = 5;
! 844: break;
! 845: }
! 846:
! 847: pcount = frm; frm += 2;
! 848: count = 0;
! 849: /* write Pairwise Cipher Suite List */
! 850: if (ni->ni_pairwise_cipherset & IEEE80211_CIPHER_USEGROUP) {
! 851: memcpy(frm, oui, 3); frm += 3;
! 852: *frm++ = 0;
! 853: count++;
! 854: }
! 855: if (ni->ni_pairwise_cipherset & IEEE80211_CIPHER_TKIP) {
! 856: memcpy(frm, oui, 3); frm += 3;
! 857: *frm++ = 2;
! 858: count++;
! 859: }
! 860: if (ni->ni_pairwise_cipherset & IEEE80211_CIPHER_CCMP) {
! 861: memcpy(frm, oui, 3); frm += 3;
! 862: *frm++ = 4;
! 863: count++;
! 864: }
! 865: /* write Pairwise Cipher Suite Count field */
! 866: LE_WRITE_2(pcount, count);
! 867:
! 868: pcount = frm; frm += 2;
! 869: count = 0;
! 870: /* write AKM Suite List (see Table 20dc) */
! 871: if (ni->ni_akmset & IEEE80211_AKM_IEEE8021X) {
! 872: memcpy(frm, oui, 3); frm += 3;
! 873: *frm++ = 1;
! 874: count++;
! 875: }
! 876: if (ni->ni_akmset & IEEE80211_AKM_PSK) {
! 877: memcpy(frm, oui, 3); frm += 3;
! 878: *frm++ = 2;
! 879: count++;
! 880: }
! 881: /* write AKM Suite List Count field */
! 882: LE_WRITE_2(pcount, count);
! 883:
! 884: /* write RSN Capabilities field */
! 885: LE_WRITE_2(frm, ni->ni_rsncaps); frm += 2;
! 886:
! 887: /* no PMKID List for now */
! 888:
! 889: return frm;
! 890: }
! 891:
! 892: u_int8_t *
! 893: ieee80211_add_rsn(u_int8_t *frm, struct ieee80211com *ic,
! 894: const struct ieee80211_node *ni)
! 895: {
! 896: u_int8_t *plen;
! 897:
! 898: *frm++ = IEEE80211_ELEMID_RSN;
! 899: plen = frm++; /* length filled in later */
! 900: frm = ieee80211_add_rsn_body(frm, ic, ni, 0);
! 901:
! 902: /* write length field */
! 903: *plen = frm - plen - 1;
! 904: return frm;
! 905: }
! 906:
! 907: /*
! 908: * Add a vendor specific WPA1 element to a frame.
! 909: * This is required for compatibility with Wi-Fi Alliance WPA1/WPA1+WPA2.
! 910: */
! 911: u_int8_t *
! 912: ieee80211_add_wpa1(u_int8_t *frm, struct ieee80211com *ic,
! 913: const struct ieee80211_node *ni)
! 914: {
! 915: u_int8_t *plen;
! 916:
! 917: *frm++ = IEEE80211_ELEMID_VENDOR;
! 918: plen = frm++; /* length filled in later */
! 919: memcpy(frm, MICROSOFT_OUI, 3); frm += 3;
! 920: *frm++ = 1; /* WPA1 */
! 921: frm = ieee80211_add_rsn_body(frm, ic, ni, 1);
! 922:
! 923: /* write length field */
! 924: *plen = frm - plen - 1;
! 925: return frm;
! 926: }
! 927:
! 928: /*
! 929: * Add an extended supported rates element to a frame (see 7.3.2.14).
! 930: */
! 931: u_int8_t *
! 932: ieee80211_add_xrates(u_int8_t *frm, const struct ieee80211_rateset *rs)
! 933: {
! 934: int nrates;
! 935:
! 936: KASSERT(rs->rs_nrates > IEEE80211_RATE_SIZE);
! 937:
! 938: *frm++ = IEEE80211_ELEMID_XRATES;
! 939: nrates = rs->rs_nrates - IEEE80211_RATE_SIZE;
! 940: *frm++ = nrates;
! 941: memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates);
! 942: return frm + nrates;
! 943: }
! 944:
! 945: struct mbuf *
! 946: ieee80211_getmbuf(int flags, int type, u_int pktlen)
! 947: {
! 948: struct mbuf *m;
! 949:
! 950: /* account for 802.11 header */
! 951: pktlen += sizeof(struct ieee80211_frame);
! 952:
! 953: if (pktlen > MCLBYTES)
! 954: panic("802.11 packet too large: %u", pktlen);
! 955: MGETHDR(m, flags, type);
! 956: if (m != NULL && pktlen > MHLEN) {
! 957: MCLGET(m, flags);
! 958: if (!(m->m_flags & M_EXT))
! 959: m = m_free(m);
! 960: }
! 961: return m;
! 962: }
! 963:
! 964: /*-
! 965: * Probe request frame format:
! 966: * [tlv] SSID
! 967: * [tlv] Supported rates
! 968: * [tlv] Extended Supported Rates (802.11g)
! 969: */
! 970: struct mbuf *
! 971: ieee80211_get_probe_req(struct ieee80211com *ic, struct ieee80211_node *ni)
! 972: {
! 973: const struct ieee80211_rateset *rs =
! 974: &ic->ic_sup_rates[ieee80211_chan2mode(ic, ni->ni_chan)];
! 975: struct mbuf *m;
! 976: u_int8_t *frm;
! 977:
! 978: m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
! 979: 2 + ic->ic_des_esslen +
! 980: 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
! 981: ((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
! 982: 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0));
! 983: if (m == NULL)
! 984: return NULL;
! 985:
! 986: m->m_data += sizeof(struct ieee80211_frame);
! 987:
! 988: frm = mtod(m, u_int8_t *);
! 989: frm = ieee80211_add_ssid(frm, ic->ic_des_essid, ic->ic_des_esslen);
! 990: frm = ieee80211_add_rates(frm, rs);
! 991: if (rs->rs_nrates > IEEE80211_RATE_SIZE)
! 992: frm = ieee80211_add_xrates(frm, rs);
! 993:
! 994: m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
! 995:
! 996: return m;
! 997: }
! 998:
! 999: /*-
! 1000: * Probe response frame format:
! 1001: * [8] Timestamp
! 1002: * [2] Beacon interval
! 1003: * [2] Capability
! 1004: * [tlv] Service Set Identifier (SSID)
! 1005: * [tlv] Supported rates
! 1006: * [tlv*] Frequency-Hopping (FH) Parameter Set
! 1007: * [tlv*] DS Parameter Set (802.11g)
! 1008: * [tlv] ERP Information (802.11g)
! 1009: * [tlv] Extended Supported Rates (802.11g)
! 1010: * [tlv] RSN (802.11i)
! 1011: * [tlv] EDCA Parameter Set (802.11e)
! 1012: */
! 1013: struct mbuf *
! 1014: ieee80211_get_probe_resp(struct ieee80211com *ic, struct ieee80211_node *ni)
! 1015: {
! 1016: const struct ieee80211_rateset *rs = &ic->ic_bss->ni_rates;
! 1017: struct mbuf *m;
! 1018: u_int8_t *frm;
! 1019:
! 1020: m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
! 1021: 8 + 2 + 2 +
! 1022: 2 + ni->ni_esslen +
! 1023: 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
! 1024: 2 + ((ic->ic_phytype == IEEE80211_T_FH) ? 5 : 1) +
! 1025: ((ic->ic_opmode == IEEE80211_M_IBSS) ? 2 + 2 : 0) +
! 1026: ((ic->ic_curmode == IEEE80211_MODE_11G) ? 2 + 1 : 0) +
! 1027: ((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
! 1028: 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
! 1029: ((ic->ic_flags & IEEE80211_F_RSN) ? 2 + 44 : 0) +
! 1030: ((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 18 : 0) +
! 1031: ((ic->ic_flags & IEEE80211_F_WPA1) ? 2 + 48 : 0));
! 1032: if (m == NULL)
! 1033: return NULL;
! 1034:
! 1035: m->m_data += sizeof(struct ieee80211_frame);
! 1036:
! 1037: frm = mtod(m, u_int8_t *);
! 1038: memset(frm, 0, 8); frm += 8; /* timestamp is set by hardware */
! 1039: LE_WRITE_2(frm, ic->ic_bss->ni_intval); frm += 2;
! 1040: frm = ieee80211_add_capinfo(frm, ic, ni);
! 1041: frm = ieee80211_add_ssid(frm, ic->ic_bss->ni_essid,
! 1042: ic->ic_bss->ni_esslen);
! 1043: frm = ieee80211_add_rates(frm, rs);
! 1044: if (ic->ic_phytype == IEEE80211_T_FH)
! 1045: frm = ieee80211_add_fh_params(frm, ic, ni);
! 1046: else
! 1047: frm = ieee80211_add_ds_params(frm, ic, ni);
! 1048: if (ic->ic_opmode == IEEE80211_M_IBSS)
! 1049: frm = ieee80211_add_ibss_params(frm, ni);
! 1050: if (ic->ic_curmode == IEEE80211_MODE_11G)
! 1051: frm = ieee80211_add_erp(frm, ic);
! 1052: if (rs->rs_nrates > IEEE80211_RATE_SIZE)
! 1053: frm = ieee80211_add_xrates(frm, rs);
! 1054: if (ic->ic_flags & IEEE80211_F_RSN)
! 1055: frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
! 1056: if (ic->ic_flags & IEEE80211_F_QOS)
! 1057: frm = ieee80211_add_edca_params(frm, ic);
! 1058: if (ic->ic_flags & IEEE80211_F_WPA1)
! 1059: frm = ieee80211_add_wpa1(frm, ic, ic->ic_bss);
! 1060:
! 1061: m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
! 1062:
! 1063: return m;
! 1064: }
! 1065:
! 1066: /*-
! 1067: * Authentication frame format:
! 1068: * [2] Authentication algorithm number
! 1069: * [2] Authentication transaction sequence number
! 1070: * [2] Status code
! 1071: */
! 1072: struct mbuf *
! 1073: ieee80211_get_auth(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1074: u_int16_t status, u_int16_t seq)
! 1075: {
! 1076: struct mbuf *m;
! 1077: u_int8_t *frm;
! 1078:
! 1079: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1080: if (m == NULL)
! 1081: return NULL;
! 1082: MH_ALIGN(m, 2 * 3);
! 1083: m->m_pkthdr.len = m->m_len = 2 * 3;
! 1084:
! 1085: frm = mtod(m, u_int8_t *);
! 1086: LE_WRITE_2(frm, IEEE80211_AUTH_ALG_OPEN); frm += 2;
! 1087: LE_WRITE_2(frm, seq); frm += 2;
! 1088: LE_WRITE_2(frm, status);
! 1089:
! 1090: return m;
! 1091: }
! 1092:
! 1093: /*-
! 1094: * Deauthentication frame format:
! 1095: * [2] Reason code
! 1096: */
! 1097: struct mbuf *
! 1098: ieee80211_get_deauth(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1099: u_int16_t reason)
! 1100: {
! 1101: struct mbuf *m;
! 1102:
! 1103: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1104: if (m == NULL)
! 1105: return NULL;
! 1106: MH_ALIGN(m, 2);
! 1107:
! 1108: m->m_pkthdr.len = m->m_len = 2;
! 1109: *mtod(m, u_int16_t *) = htole16(reason);
! 1110:
! 1111: return m;
! 1112: }
! 1113:
! 1114: /*-
! 1115: * (Re)Association request frame format:
! 1116: * [2] Capability information
! 1117: * [2] Listen interval
! 1118: * [6*] Current AP address (Reassociation only)
! 1119: * [tlv] SSID
! 1120: * [tlv] Supported rates
! 1121: * [tlv] Extended Supported Rates (802.11g)
! 1122: * [tlv] RSN (802.11i)
! 1123: * [tlv] QoS Capability (802.11e)
! 1124: */
! 1125: struct mbuf *
! 1126: ieee80211_get_assoc_req(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1127: int reassoc)
! 1128: {
! 1129: const struct ieee80211_rateset *rs = &ni->ni_rates;
! 1130: struct mbuf *m;
! 1131: u_int8_t *frm;
! 1132: u_int16_t capinfo;
! 1133:
! 1134: m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
! 1135: 2 + 2 +
! 1136: ((reassoc == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) ?
! 1137: IEEE80211_ADDR_LEN : 0) +
! 1138: 2 + ni->ni_esslen +
! 1139: 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
! 1140: ((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
! 1141: 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
! 1142: ((ic->ic_flags & IEEE80211_F_RSN) ? 2 + 44 : 0) +
! 1143: ((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 1 : 0) +
! 1144: ((ic->ic_flags & IEEE80211_F_WPA1) ? 2 + 48 : 0));
! 1145: if (m == NULL)
! 1146: return NULL;
! 1147:
! 1148: m->m_data += sizeof(struct ieee80211_frame);
! 1149:
! 1150: frm = mtod(m, u_int8_t *);
! 1151: capinfo = IEEE80211_CAPINFO_ESS;
! 1152: if (ic->ic_flags & IEEE80211_F_WEPON)
! 1153: capinfo |= IEEE80211_CAPINFO_PRIVACY;
! 1154: if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
! 1155: IEEE80211_IS_CHAN_2GHZ(ni->ni_chan))
! 1156: capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE;
! 1157: if ((ni->ni_capinfo & IEEE80211_CAPINFO_SHORT_SLOTTIME) &&
! 1158: (ic->ic_flags & IEEE80211_F_SHSLOT))
! 1159: capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME;
! 1160: LE_WRITE_2(frm, capinfo); frm += 2;
! 1161: LE_WRITE_2(frm, ic->ic_lintval); frm += 2;
! 1162: if (reassoc == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
! 1163: IEEE80211_ADDR_COPY(frm, ic->ic_bss->ni_bssid);
! 1164: frm += IEEE80211_ADDR_LEN;
! 1165: }
! 1166: frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
! 1167: frm = ieee80211_add_rates(frm, rs);
! 1168: if (rs->rs_nrates > IEEE80211_RATE_SIZE)
! 1169: frm = ieee80211_add_xrates(frm, rs);
! 1170: if (ic->ic_flags & IEEE80211_F_RSN)
! 1171: frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
! 1172: if ((ic->ic_flags & IEEE80211_F_QOS) &&
! 1173: (ni->ni_flags & IEEE80211_NODE_QOS))
! 1174: frm = ieee80211_add_qos_capability(frm, ic);
! 1175: if (ic->ic_flags & IEEE80211_F_WPA1)
! 1176: frm = ieee80211_add_wpa1(frm, ic, ic->ic_bss);
! 1177:
! 1178: m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
! 1179:
! 1180: return m;
! 1181: }
! 1182:
! 1183: /*-
! 1184: * (Re)Association response frame format:
! 1185: * [2] Capability information
! 1186: * [2] Status code
! 1187: * [2] Association ID (AID)
! 1188: * [tlv] Supported rates
! 1189: * [tlv] Extended Supported Rates (802.11g)
! 1190: * [tlv] EDCA Parameter Set (802.11e)
! 1191: */
! 1192: struct mbuf *
! 1193: ieee80211_get_assoc_resp(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1194: u_int16_t status)
! 1195: {
! 1196: const struct ieee80211_rateset *rs = &ni->ni_rates;
! 1197: struct mbuf *m;
! 1198: u_int8_t *frm;
! 1199:
! 1200: m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
! 1201: 2 + 2 + 2 +
! 1202: 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
! 1203: ((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
! 1204: 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
! 1205: ((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 18 : 0));
! 1206: if (m == NULL)
! 1207: return NULL;
! 1208:
! 1209: m->m_data += sizeof(struct ieee80211_frame);
! 1210:
! 1211: frm = mtod(m, u_int8_t *);
! 1212: frm = ieee80211_add_capinfo(frm, ic, ni);
! 1213: LE_WRITE_2(frm, status); frm += 2;
! 1214: if (status == IEEE80211_STATUS_SUCCESS)
! 1215: LE_WRITE_2(frm, ni->ni_associd);
! 1216: else
! 1217: LE_WRITE_2(frm, 0);
! 1218: frm += 2;
! 1219: frm = ieee80211_add_rates(frm, rs);
! 1220: if (rs->rs_nrates > IEEE80211_RATE_SIZE)
! 1221: frm = ieee80211_add_xrates(frm, rs);
! 1222: if ((ic->ic_flags & IEEE80211_F_QOS) &&
! 1223: (ni->ni_flags & IEEE80211_NODE_QOS))
! 1224: frm = ieee80211_add_edca_params(frm, ic);
! 1225:
! 1226: m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
! 1227:
! 1228: return m;
! 1229: }
! 1230:
! 1231: /*-
! 1232: * Disassociation frame format:
! 1233: * [2] Reason code
! 1234: */
! 1235: struct mbuf *
! 1236: ieee80211_get_disassoc(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1237: u_int16_t reason)
! 1238: {
! 1239: struct mbuf *m;
! 1240:
! 1241: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1242: if (m == NULL)
! 1243: return NULL;
! 1244: MH_ALIGN(m, 2);
! 1245:
! 1246: m->m_pkthdr.len = m->m_len = 2;
! 1247: *mtod(m, u_int16_t *) = htole16(reason);
! 1248:
! 1249: return m;
! 1250: }
! 1251:
! 1252: /*
! 1253: * Send a management frame. The node is for the destination (or ic_bss
! 1254: * when in station mode). Nodes other than ic_bss have their reference
! 1255: * count bumped to reflect our use for an indeterminant time.
! 1256: */
! 1257: int
! 1258: ieee80211_send_mgmt(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1259: int type, int arg)
! 1260: {
! 1261: #define senderr(_x, _v) do { ic->ic_stats._v++; ret = _x; goto bad; } while (0)
! 1262: struct ifnet *ifp = &ic->ic_if;
! 1263: struct mbuf *m;
! 1264: int ret, timer;
! 1265:
! 1266: if (ni == NULL)
! 1267: panic("null node");
! 1268:
! 1269: /*
! 1270: * Hold a reference on the node so it doesn't go away until after
! 1271: * the xmit is complete all the way in the driver. On error we
! 1272: * will remove our reference.
! 1273: */
! 1274: ieee80211_ref_node(ni);
! 1275: timer = 0;
! 1276: switch (type) {
! 1277: case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
! 1278: if ((m = ieee80211_get_probe_req(ic, ni)) == NULL)
! 1279: senderr(ENOMEM, is_tx_nombuf);
! 1280:
! 1281: timer = IEEE80211_TRANS_WAIT;
! 1282: break;
! 1283:
! 1284: case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
! 1285: if ((m = ieee80211_get_probe_resp(ic, ni)) == NULL)
! 1286: senderr(ENOMEM, is_tx_nombuf);
! 1287: break;
! 1288:
! 1289: case IEEE80211_FC0_SUBTYPE_AUTH:
! 1290: m = ieee80211_get_auth(ic, ni, arg >> 16, arg & 0xffff);
! 1291: if (m == NULL)
! 1292: senderr(ENOMEM, is_tx_nombuf);
! 1293:
! 1294: if (ic->ic_opmode == IEEE80211_M_STA)
! 1295: timer = IEEE80211_TRANS_WAIT;
! 1296: break;
! 1297:
! 1298: case IEEE80211_FC0_SUBTYPE_DEAUTH:
! 1299: if ((m = ieee80211_get_deauth(ic, ni, arg)) == NULL)
! 1300: senderr(ENOMEM, is_tx_nombuf);
! 1301:
! 1302: if (ifp->if_flags & IFF_DEBUG) {
! 1303: printf("%s: station %s deauthenticate (reason %d)\n",
! 1304: ifp->if_xname, ether_sprintf(ni->ni_macaddr), arg);
! 1305: }
! 1306: break;
! 1307:
! 1308: case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
! 1309: case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
! 1310: if ((m = ieee80211_get_assoc_req(ic, ni, type)) == NULL)
! 1311: senderr(ENOMEM, is_tx_nombuf);
! 1312:
! 1313: timer = IEEE80211_TRANS_WAIT;
! 1314: break;
! 1315:
! 1316: case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
! 1317: case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
! 1318: if ((m = ieee80211_get_assoc_resp(ic, ni, arg)) == NULL)
! 1319: senderr(ENOMEM, is_tx_nombuf);
! 1320: break;
! 1321:
! 1322: case IEEE80211_FC0_SUBTYPE_DISASSOC:
! 1323: if ((m = ieee80211_get_disassoc(ic, ni, arg)) == NULL)
! 1324: senderr(ENOMEM, is_tx_nombuf);
! 1325:
! 1326: if (ifp->if_flags & IFF_DEBUG) {
! 1327: printf("%s: station %s disassociate (reason %d)\n",
! 1328: ifp->if_xname, ether_sprintf(ni->ni_macaddr), arg);
! 1329: }
! 1330: break;
! 1331:
! 1332: default:
! 1333: IEEE80211_DPRINTF(("%s: invalid mgmt frame type %u\n",
! 1334: __func__, type));
! 1335: senderr(EINVAL, is_tx_unknownmgt);
! 1336: /* NOTREACHED */
! 1337: }
! 1338:
! 1339: ret = ieee80211_mgmt_output(ifp, ni, m, type);
! 1340: if (ret == 0) {
! 1341: if (timer)
! 1342: ic->ic_mgt_timer = timer;
! 1343: } else {
! 1344: bad:
! 1345: ieee80211_release_node(ic, ni);
! 1346: }
! 1347: return ret;
! 1348: #undef senderr
! 1349: }
! 1350:
! 1351: /*
! 1352: * Build a RTS (Request To Send) control frame (see 7.2.1.1).
! 1353: */
! 1354: struct mbuf *
! 1355: ieee80211_get_rts(struct ieee80211com *ic, const struct ieee80211_frame *wh,
! 1356: u_int16_t dur)
! 1357: {
! 1358: struct ieee80211_frame_rts *rts;
! 1359: struct mbuf *m;
! 1360:
! 1361: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1362: if (m == NULL)
! 1363: return NULL;
! 1364:
! 1365: m->m_pkthdr.len = m->m_len = sizeof (struct ieee80211_frame_rts);
! 1366:
! 1367: rts = mtod(m, struct ieee80211_frame_rts *);
! 1368: rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL |
! 1369: IEEE80211_FC0_SUBTYPE_RTS;
! 1370: rts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 1371: *(u_int16_t *)rts->i_dur = htole16(dur);
! 1372: IEEE80211_ADDR_COPY(rts->i_ra, wh->i_addr1);
! 1373: IEEE80211_ADDR_COPY(rts->i_ta, wh->i_addr2);
! 1374:
! 1375: return m;
! 1376: }
! 1377:
! 1378: /*
! 1379: * Build a CTS-to-self (Clear To Send) control frame (see 7.2.1.2).
! 1380: */
! 1381: struct mbuf *
! 1382: ieee80211_get_cts_to_self(struct ieee80211com *ic, u_int16_t dur)
! 1383: {
! 1384: struct ieee80211_frame_cts *cts;
! 1385: struct mbuf *m;
! 1386:
! 1387: MGETHDR(m, M_DONTWAIT, MT_DATA);
! 1388: if (m == NULL)
! 1389: return NULL;
! 1390:
! 1391: m->m_pkthdr.len = m->m_len = sizeof (struct ieee80211_frame_cts);
! 1392:
! 1393: cts = mtod(m, struct ieee80211_frame_cts *);
! 1394: cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_CTL |
! 1395: IEEE80211_FC0_SUBTYPE_CTS;
! 1396: cts->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 1397: *(u_int16_t *)cts->i_dur = htole16(dur);
! 1398: IEEE80211_ADDR_COPY(cts->i_ra, ic->ic_myaddr);
! 1399:
! 1400: return m;
! 1401: }
! 1402:
! 1403: /*-
! 1404: * Beacon frame format:
! 1405: * [8] Timestamp
! 1406: * [2] Beacon interval
! 1407: * [2] Capability
! 1408: * [tlv] Service Set Identifier (SSID)
! 1409: * [tlv] Supported rates
! 1410: * [tlv*] Frequency-Hopping (FH) Parameter Set
! 1411: * [tlv*] DS Parameter Set (802.11g)
! 1412: * [tlv*] IBSS Parameter Set
! 1413: * [tlv] Traffic Indication Map (TIM)
! 1414: * [tlv] ERP Information (802.11g)
! 1415: * [tlv] Extended Supported Rates (802.11g)
! 1416: * [tlv] RSN (802.11i)
! 1417: * [tlv] EDCA Parameter Set (802.11e)
! 1418: */
! 1419: struct mbuf *
! 1420: ieee80211_beacon_alloc(struct ieee80211com *ic, struct ieee80211_node *ni)
! 1421: {
! 1422: const struct ieee80211_rateset *rs = &ni->ni_rates;
! 1423: struct ieee80211_frame *wh;
! 1424: struct mbuf *m;
! 1425: u_int8_t *frm;
! 1426:
! 1427: m = ieee80211_getmbuf(M_DONTWAIT, MT_DATA,
! 1428: 8 + 2 + 2 +
! 1429: 2 + ((ic->ic_flags & IEEE80211_F_HIDENWID) ? 0 : ni->ni_esslen) +
! 1430: 2 + min(rs->rs_nrates, IEEE80211_RATE_SIZE) +
! 1431: 2 + ((ic->ic_phytype == IEEE80211_T_FH) ? 5 : 1) +
! 1432: 2 + ((ic->ic_opmode == IEEE80211_M_IBSS) ? 2 : 254) +
! 1433: ((ic->ic_curmode == IEEE80211_MODE_11G) ? 2 + 1 : 0) +
! 1434: ((rs->rs_nrates > IEEE80211_RATE_SIZE) ?
! 1435: 2 + rs->rs_nrates - IEEE80211_RATE_SIZE : 0) +
! 1436: ((ic->ic_flags & IEEE80211_F_RSN) ? 2 + 44 : 0) +
! 1437: ((ic->ic_flags & IEEE80211_F_QOS) ? 2 + 18 : 0) +
! 1438: ((ic->ic_flags & IEEE80211_F_WPA1) ? 2 + 48 : 0));
! 1439: if (m == NULL)
! 1440: return NULL;
! 1441:
! 1442: wh = mtod(m, struct ieee80211_frame *);
! 1443: wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT |
! 1444: IEEE80211_FC0_SUBTYPE_BEACON;
! 1445: wh->i_fc[1] = IEEE80211_FC1_DIR_NODS;
! 1446: *(u_int16_t *)wh->i_dur = 0;
! 1447: IEEE80211_ADDR_COPY(wh->i_addr1, etherbroadcastaddr);
! 1448: IEEE80211_ADDR_COPY(wh->i_addr2, ic->ic_myaddr);
! 1449: IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid);
! 1450: *(u_int16_t *)wh->i_seq = 0;
! 1451:
! 1452: frm = (u_int8_t *)&wh[1];
! 1453: memset(frm, 0, 8); frm += 8; /* timestamp is set by hardware */
! 1454: LE_WRITE_2(frm, ni->ni_intval); frm += 2;
! 1455: frm = ieee80211_add_capinfo(frm, ic, ni);
! 1456: if (ic->ic_flags & IEEE80211_F_HIDENWID)
! 1457: frm = ieee80211_add_ssid(frm, NULL, 0);
! 1458: else
! 1459: frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen);
! 1460: frm = ieee80211_add_rates(frm, rs);
! 1461: if (ic->ic_phytype == IEEE80211_T_FH)
! 1462: frm = ieee80211_add_fh_params(frm, ic, ni);
! 1463: else
! 1464: frm = ieee80211_add_ds_params(frm, ic, ni);
! 1465: if (ic->ic_opmode == IEEE80211_M_IBSS)
! 1466: frm = ieee80211_add_ibss_params(frm, ni);
! 1467: else
! 1468: frm = ieee80211_add_tim(frm, ic);
! 1469: if (ic->ic_curmode == IEEE80211_MODE_11G)
! 1470: frm = ieee80211_add_erp(frm, ic);
! 1471: if (rs->rs_nrates > IEEE80211_RATE_SIZE)
! 1472: frm = ieee80211_add_xrates(frm, rs);
! 1473: if (ic->ic_flags & IEEE80211_F_RSN)
! 1474: frm = ieee80211_add_rsn(frm, ic, ni);
! 1475: if (ic->ic_flags & IEEE80211_F_QOS)
! 1476: frm = ieee80211_add_edca_params(frm, ic);
! 1477: if (ic->ic_flags & IEEE80211_F_WPA1)
! 1478: frm = ieee80211_add_wpa1(frm, ic, ni);
! 1479:
! 1480: m->m_pkthdr.len = m->m_len = frm - mtod(m, u_int8_t *);
! 1481: m->m_pkthdr.rcvif = (void *)ni;
! 1482:
! 1483: return m;
! 1484: }
! 1485:
! 1486: /* unaligned big endian access */
! 1487: #define BE_READ_2(p) \
! 1488: ((u_int16_t)(p)[0] << 8 | (u_int16_t)(p)[1])
! 1489:
! 1490: #define BE_WRITE_2(p, v) do { \
! 1491: (p)[0] = (v) >> 8; (p)[1] = (v); \
! 1492: } while (0)
! 1493:
! 1494: #define BE_WRITE_8(p, v) do { \
! 1495: (p)[0] = (v) >> 56; (p)[1] = (v) >> 48; \
! 1496: (p)[2] = (v) >> 40; (p)[3] = (v) >> 32; \
! 1497: (p)[4] = (v) >> 24; (p)[5] = (v) >> 16; \
! 1498: (p)[6] = (v) >> 8; (p)[7] = (v); \
! 1499: } while (0)
! 1500:
! 1501: /* unaligned little endian access */
! 1502: #define LE_WRITE_8(p, v) do { \
! 1503: (p)[7] = (v) >> 56; (p)[6] = (v) >> 48; \
! 1504: (p)[5] = (v) >> 40; (p)[4] = (v) >> 32; \
! 1505: (p)[3] = (v) >> 24; (p)[2] = (v) >> 16; \
! 1506: (p)[1] = (v) >> 8; (p)[0] = (v); \
! 1507: } while (0)
! 1508:
! 1509: int
! 1510: ieee80211_send_eapol_key(struct ieee80211com *ic, struct mbuf *m,
! 1511: struct ieee80211_node *ni)
! 1512: {
! 1513: struct ifnet *ifp = &ic->ic_if;
! 1514: struct ether_header *eh;
! 1515: struct ieee80211_eapol_key *key;
! 1516: u_int16_t len, info;
! 1517: int s, error;
! 1518:
! 1519: M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT);
! 1520: if (m == NULL)
! 1521: return ENOMEM;
! 1522: eh = mtod(m, struct ether_header *);
! 1523: eh->ether_type = htons(ETHERTYPE_PAE);
! 1524: IEEE80211_ADDR_COPY(eh->ether_shost, ic->ic_myaddr);
! 1525: IEEE80211_ADDR_COPY(eh->ether_dhost, ni->ni_macaddr);
! 1526:
! 1527: key = (struct ieee80211_eapol_key *)&eh[1];
! 1528: key->version = EAPOL_VERSION;
! 1529: key->type = EAPOL_KEY;
! 1530: key->desc = ni->ni_eapol_desc;
! 1531:
! 1532: info = BE_READ_2(key->info);
! 1533: /* use V2 descriptor only when pairwise cipher is CCMP */
! 1534: info |= (ni->ni_pairwise_cipher != IEEE80211_CIPHER_CCMP) ?
! 1535: EAPOL_KEY_DESC_V1 : EAPOL_KEY_DESC_V2;
! 1536: BE_WRITE_2(key->info, info);
! 1537:
! 1538: len = m->m_len - sizeof(struct ether_header);
! 1539: BE_WRITE_2(key->paylen, len - sizeof(*key));
! 1540: BE_WRITE_2(key->len, len - 4);
! 1541:
! 1542: KASSERT((info & (EAPOL_KEY_ENCRYPTED | EAPOL_KEY_KEYMIC)) == 0 ||
! 1543: ni->ni_ptk_ok);
! 1544:
! 1545: if (info & EAPOL_KEY_ENCRYPTED)
! 1546: ieee80211_eapol_key_encrypt(ic, key, ni->ni_ptk.kek);
! 1547:
! 1548: if (info & EAPOL_KEY_KEYMIC)
! 1549: ieee80211_eapol_key_mic(key, ni->ni_ptk.kck);
! 1550:
! 1551: s = splnet();
! 1552: IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
! 1553: if (error) {
! 1554: splx(s);
! 1555: return error;
! 1556: }
! 1557: ifp->if_obytes += m->m_pkthdr.len;
! 1558: if ((ifp->if_flags & IFF_OACTIVE) == 0)
! 1559: (*ifp->if_start)(ifp);
! 1560: splx(s);
! 1561:
! 1562: return 0;
! 1563: }
! 1564:
! 1565: /*
! 1566: * Add a GTK KDE to an EAPOL-Key frame (see Figure 144).
! 1567: */
! 1568: u_int8_t *
! 1569: ieee80211_add_gtk_kde(u_int8_t *frm, const struct ieee80211_key *k)
! 1570: {
! 1571: KASSERT(k->k_flags & IEEE80211_KEY_GROUP);
! 1572:
! 1573: *frm++ = IEEE80211_ELEMID_VENDOR;
! 1574: *frm++ = 6 + k->k_len;
! 1575: memcpy(frm, IEEE80211_OUI, 3); frm += 3;
! 1576: *frm++ = IEEE80211_KDE_GTK;
! 1577: *frm = k->k_id & 3;
! 1578: if (k->k_flags & IEEE80211_KEY_TX)
! 1579: *frm |= 1 << 2; /* set the Tx bit */
! 1580: frm++;
! 1581: *frm++ = 0; /* reserved */
! 1582: memcpy(frm, k->k_key, k->k_len);
! 1583: return frm + k->k_len;
! 1584: }
! 1585:
! 1586: /*
! 1587: * Add a PMKID KDE to an EAPOL-Key frame (see Figure 146).
! 1588: */
! 1589: u_int8_t *
! 1590: ieee80211_add_pmkid_kde(u_int8_t *frm, const u_int8_t *pmkid)
! 1591: {
! 1592: *frm++ = IEEE80211_ELEMID_VENDOR;
! 1593: *frm++ = 20;
! 1594: memcpy(frm, IEEE80211_OUI, 3); frm += 3;
! 1595: *frm++ = IEEE80211_KDE_PMKID;
! 1596: memcpy(frm, pmkid, IEEE80211_PMKID_LEN);
! 1597: return frm + IEEE80211_PMKID_LEN;
! 1598: }
! 1599:
! 1600: struct mbuf *
! 1601: ieee80211_get_eapol_key(int flags, int type, u_int pktlen)
! 1602: {
! 1603: struct mbuf *m;
! 1604:
! 1605: pktlen += sizeof(struct ether_header) +
! 1606: sizeof(struct ieee80211_eapol_key);
! 1607:
! 1608: if (pktlen > MCLBYTES)
! 1609: panic("EAPOL-Key frame too large: %u", pktlen);
! 1610: MGETHDR(m, flags, type);
! 1611: if (m != NULL && pktlen > MHLEN) {
! 1612: MCLGET(m, flags);
! 1613: if (!(m->m_flags & M_EXT))
! 1614: m = m_free(m);
! 1615: }
! 1616: m->m_data += sizeof(struct ether_header);
! 1617: return m;
! 1618: }
! 1619:
! 1620: /*
! 1621: * 4-Way Handshake Message 1 is sent by the authenticator to the supplicant
! 1622: * (see 8.5.3.1).
! 1623: */
! 1624: int
! 1625: ieee80211_send_4way_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
! 1626: {
! 1627: struct ieee80211_eapol_key *key;
! 1628: struct mbuf *m;
! 1629: u_int16_t info, keylen;
! 1630: u_int8_t *pmkid;
! 1631: u_int8_t *frm;
! 1632:
! 1633: m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
! 1634: (ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) ? 2 + 20 : 0);
! 1635: if (m == NULL)
! 1636: return ENOMEM;
! 1637: key = mtod(m, struct ieee80211_eapol_key *);
! 1638: memset(key, 0, sizeof(*key));
! 1639:
! 1640: info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYACK;
! 1641: BE_WRITE_2(key->info, info);
! 1642:
! 1643: /* generate a new nonce ANonce */
! 1644: get_random_bytes(ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
! 1645: memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
! 1646:
! 1647: keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
! 1648: BE_WRITE_2(key->keylen, keylen);
! 1649:
! 1650: frm = (u_int8_t *)&key[1];
! 1651: /* WPA1 does not have PMKID KDE */
! 1652: if (ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) {
! 1653: /* XXX retrieve PMKID from the PMKSA cache */
! 1654: frm = ieee80211_add_pmkid_kde(frm, pmkid);
! 1655: }
! 1656:
! 1657: m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
! 1658:
! 1659: if (ic->ic_if.if_flags & IFF_DEBUG)
! 1660: printf("%s: sending msg %d/%d of the %s handshake to %s\n",
! 1661: ic->ic_if.if_xname, 1, 4, "4-way",
! 1662: ether_sprintf(ni->ni_macaddr));
! 1663:
! 1664: return ieee80211_send_eapol_key(ic, m, ni);
! 1665: }
! 1666:
! 1667: /*
! 1668: * 4-Way Handshake Message 2 is sent by the supplicant to the authenticator
! 1669: * (see 8.5.3.2).
! 1670: */
! 1671: int
! 1672: ieee80211_send_4way_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1673: const u_int8_t *snonce)
! 1674: {
! 1675: struct ieee80211_eapol_key *key;
! 1676: struct mbuf *m;
! 1677: u_int16_t info;
! 1678: u_int8_t *frm;
! 1679:
! 1680: m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
! 1681: 2 + 48);
! 1682: if (m == NULL)
! 1683: return ENOMEM;
! 1684: key = mtod(m, struct ieee80211_eapol_key *);
! 1685: memset(key, 0, sizeof(*key));
! 1686:
! 1687: info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC;
! 1688: BE_WRITE_2(key->info, info);
! 1689:
! 1690: /* copy key replay counter from authenticator */
! 1691: BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
! 1692:
! 1693: /* copy the supplicant's nonce (SNonce) */
! 1694: memcpy(key->nonce, snonce, EAPOL_KEY_NONCE_LEN);
! 1695:
! 1696: frm = (u_int8_t *)&key[1];
! 1697: /* add the WPA/RSN IE used in the (Re)Association Request */
! 1698: if (ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) {
! 1699: u_int16_t keylen;
! 1700: frm = ieee80211_add_wpa1(frm, ic, ni);
! 1701: /* WPA1 sets the key length field here */
! 1702: keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
! 1703: BE_WRITE_2(key->keylen, keylen);
! 1704: } else /* RSN */
! 1705: frm = ieee80211_add_rsn(frm, ic, ni);
! 1706:
! 1707: m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
! 1708:
! 1709: if (ic->ic_if.if_flags & IFF_DEBUG)
! 1710: printf("%s: sending msg %d/%d of the %s handshake to %s\n",
! 1711: ic->ic_if.if_xname, 2, 4, "4-way",
! 1712: ether_sprintf(ni->ni_macaddr));
! 1713:
! 1714: return ieee80211_send_eapol_key(ic, m, ni);
! 1715: }
! 1716:
! 1717: /*
! 1718: * 4-Way Handshake Message 3 is sent by the authenticator to the supplicant
! 1719: * (see 8.5.3.3).
! 1720: */
! 1721: int
! 1722: ieee80211_send_4way_msg3(struct ieee80211com *ic, struct ieee80211_node *ni)
! 1723: {
! 1724: struct ieee80211_eapol_key *key;
! 1725: struct ieee80211_key *gtk;
! 1726: struct mbuf *m;
! 1727: u_int16_t info, keylen;
! 1728: u_int8_t *frm;
! 1729:
! 1730: m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
! 1731: 2 + 48 +
! 1732: ((ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) ?
! 1733: 2 + 6 + gtk->k_len : 0) +
! 1734: 8);
! 1735: if (m == NULL)
! 1736: return ENOMEM;
! 1737: key = mtod(m, struct ieee80211_eapol_key *);
! 1738: memset(key, 0, sizeof(*key));
! 1739:
! 1740: info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_INSTALL | EAPOL_KEY_KEYACK |
! 1741: EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE;
! 1742:
! 1743: BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
! 1744: /* use same nonce as in Message 1 */
! 1745: memcpy(key->nonce, ni->ni_nonce, EAPOL_KEY_NONCE_LEN);
! 1746:
! 1747: keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
! 1748: BE_WRITE_2(key->keylen, keylen);
! 1749:
! 1750: frm = (u_int8_t *)&key[1];
! 1751: /* add the WPA/RSN IE included in Beacon/Probe Response */
! 1752: if (ni->ni_eapol_desc == EAPOL_KEY_DESC_IEEE80211) {
! 1753: frm = ieee80211_add_rsn(frm, ic, ic->ic_bss);
! 1754: /* RSN: encapsulate the GTK and ask for encryption */
! 1755: frm = ieee80211_add_gtk_kde(frm, gtk);
! 1756: LE_WRITE_8(key->rsc, gtk->k_rsc);
! 1757: info |= EAPOL_KEY_ENCRYPTED;
! 1758: } else /* WPA1 */
! 1759: frm = ieee80211_add_wpa1(frm, ic, ic->ic_bss);
! 1760:
! 1761: /* write the key info field */
! 1762: BE_WRITE_2(key->info, info);
! 1763:
! 1764: m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
! 1765:
! 1766: if (ic->ic_if.if_flags & IFF_DEBUG)
! 1767: printf("%s: sending msg %d/%d of the %s handshake to %s\n",
! 1768: ic->ic_if.if_xname, 3, 4, "4-way",
! 1769: ether_sprintf(ni->ni_macaddr));
! 1770:
! 1771: return ieee80211_send_eapol_key(ic, m, ni);
! 1772: }
! 1773:
! 1774: /*
! 1775: * 4-Way Handshake Message 4 is sent by the supplicant to the authenticator
! 1776: * (see 8.5.3.4).
! 1777: */
! 1778: int
! 1779: ieee80211_send_4way_msg4(struct ieee80211com *ic, struct ieee80211_node *ni)
! 1780: {
! 1781: struct ieee80211_eapol_key *key;
! 1782: struct mbuf *m;
! 1783: u_int16_t info;
! 1784:
! 1785: m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
! 1786: if (m == NULL)
! 1787: return ENOMEM;
! 1788: key = mtod(m, struct ieee80211_eapol_key *);
! 1789: memset(key, 0, sizeof(*key));
! 1790:
! 1791: info = EAPOL_KEY_PAIRWISE | EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE;
! 1792: BE_WRITE_2(key->info, info);
! 1793:
! 1794: /* copy key replay counter from authenticator */
! 1795: BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
! 1796:
! 1797: if (ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) {
! 1798: u_int16_t keylen;
! 1799: /* WPA1 sets the key length field here */
! 1800: keylen = ieee80211_cipher_keylen(ni->ni_pairwise_cipher);
! 1801: BE_WRITE_2(key->keylen, keylen);
! 1802: }
! 1803:
! 1804: /* empty key data field */
! 1805: m->m_pkthdr.len = m->m_len = sizeof(*key);
! 1806:
! 1807: if (ic->ic_if.if_flags & IFF_DEBUG)
! 1808: printf("%s: sending msg %d/%d of the %s handshake to %s\n",
! 1809: ic->ic_if.if_xname, 4, 4, "4-way",
! 1810: ether_sprintf(ni->ni_macaddr));
! 1811:
! 1812: return ieee80211_send_eapol_key(ic, m, ni);
! 1813: }
! 1814:
! 1815: /*
! 1816: * Group Key Handshake Message 1 is sent by the authenticator to the
! 1817: * supplicant (see 8.5.4.1).
! 1818: */
! 1819: int
! 1820: ieee80211_send_group_msg1(struct ieee80211com *ic, struct ieee80211_node *ni)
! 1821: {
! 1822: struct ieee80211_eapol_key *key;
! 1823: struct ieee80211_key *gtk;
! 1824: struct mbuf *m;
! 1825: u_int16_t info;
! 1826: u_int8_t *frm;
! 1827:
! 1828: m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA,
! 1829: ((ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) ?
! 1830: gtk->k_len : 2 + 6 + gtk->k_len) +
! 1831: 8);
! 1832: if (m == NULL)
! 1833: return ENOMEM;
! 1834: key = mtod(m, struct ieee80211_eapol_key *);
! 1835: memset(key, 0, sizeof(*key));
! 1836:
! 1837: info = EAPOL_KEY_KEYACK | EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE |
! 1838: EAPOL_KEY_ENCRYPTED;
! 1839:
! 1840: BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
! 1841:
! 1842: frm = (u_int8_t *)&key[1];
! 1843: if (ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) {
! 1844: /* WPA1 does not have GTK KDE */
! 1845: BE_WRITE_2(key->keylen, gtk->k_len);
! 1846: memcpy(frm, gtk->k_key, gtk->k_len);
! 1847: frm += gtk->k_len;
! 1848: info |= gtk->k_id << EAPOL_KEY_WPA_KID_SHIFT;
! 1849: if (gtk->k_flags & IEEE80211_KEY_TX)
! 1850: info |= EAPOL_KEY_WPA_TX;
! 1851: } else /* RSN */
! 1852: frm = ieee80211_add_gtk_kde(frm, gtk);
! 1853:
! 1854: LE_WRITE_8(key->rsc, gtk->k_rsc);
! 1855:
! 1856: /* write the key info field */
! 1857: BE_WRITE_2(key->info, info);
! 1858:
! 1859: m->m_pkthdr.len = m->m_len = frm - (u_int8_t *)key;
! 1860:
! 1861: if (ic->ic_if.if_flags & IFF_DEBUG)
! 1862: printf("%s: sending msg %d/%d of the %s handshake to %s\n",
! 1863: ic->ic_if.if_xname, 1, 2, "group key",
! 1864: ether_sprintf(ni->ni_macaddr));
! 1865:
! 1866: return ieee80211_send_eapol_key(ic, m, ni);
! 1867: }
! 1868:
! 1869: /*
! 1870: * Group Key Handshake Message 2 is sent by the supplicant to the
! 1871: * authenticator (see 8.5.4.2).
! 1872: */
! 1873: int
! 1874: ieee80211_send_group_msg2(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1875: const struct ieee80211_key *gtk)
! 1876: {
! 1877: struct ieee80211_eapol_key *key;
! 1878: u_int16_t info;
! 1879: struct mbuf *m;
! 1880:
! 1881: m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
! 1882: if (m == NULL)
! 1883: return ENOMEM;
! 1884: key = mtod(m, struct ieee80211_eapol_key *);
! 1885: memset(key, 0, sizeof(*key));
! 1886:
! 1887: info = EAPOL_KEY_KEYMIC | EAPOL_KEY_SECURE;
! 1888:
! 1889: /* copy key replay counter from authenticator */
! 1890: BE_WRITE_8(key->replaycnt, ni->ni_replaycnt);
! 1891:
! 1892: if (ni->ni_eapol_desc == EAPOL_KEY_DESC_WPA1) {
! 1893: /* WPA1 sets the key length and key id fields here */
! 1894: BE_WRITE_2(key->keylen, gtk->k_len);
! 1895: info |= (gtk->k_id & 3) << EAPOL_KEY_WPA_KID_SHIFT;
! 1896: }
! 1897:
! 1898: /* write the key info field */
! 1899: BE_WRITE_2(key->info, info);
! 1900:
! 1901: /* empty key data field */
! 1902: m->m_pkthdr.len = m->m_len = sizeof(*key);
! 1903:
! 1904: if (ic->ic_if.if_flags & IFF_DEBUG)
! 1905: printf("%s: sending msg %d/%d of the %s handshake to %s\n",
! 1906: ic->ic_if.if_xname, 2, 2, "group key",
! 1907: ether_sprintf(ni->ni_macaddr));
! 1908:
! 1909: return ieee80211_send_eapol_key(ic, m, ni);
! 1910: }
! 1911:
! 1912: /*
! 1913: * EAPOL-Key Request frames are sent by the supplicant to request that the
! 1914: * authenticator initiate either a 4-Way Handshake or Group Key Handshake
! 1915: * and to report a MIC failure in a TKIP MSDU.
! 1916: */
! 1917: int
! 1918: ieee80211_send_eapol_key_req(struct ieee80211com *ic,
! 1919: struct ieee80211_node *ni, u_int16_t info, u_int64_t tsc)
! 1920: {
! 1921: struct ieee80211_eapol_key *key;
! 1922: struct mbuf *m;
! 1923:
! 1924: m = ieee80211_get_eapol_key(M_DONTWAIT, MT_DATA, 0);
! 1925: if (m == NULL)
! 1926: return ENOMEM;
! 1927: key = mtod(m, struct ieee80211_eapol_key *);
! 1928: memset(key, 0, sizeof(*key));
! 1929:
! 1930: BE_WRITE_2(key->info, info);
! 1931:
! 1932: /* in case of TKIP MIC failure, fill the RSC field */
! 1933: if (info & EAPOL_KEY_ERROR)
! 1934: LE_WRITE_8(key->rsc, tsc);
! 1935:
! 1936: /* use our separate key replay counter for key requests */
! 1937: BE_WRITE_8(key->replaycnt, ic->ic_keyreplaycnt);
! 1938: ic->ic_keyreplaycnt++;
! 1939:
! 1940: if (ic->ic_if.if_flags & IFF_DEBUG)
! 1941: printf("%s: sending EAPOL-Key request to %s\n",
! 1942: ic->ic_if.if_xname, ether_sprintf(ni->ni_macaddr));
! 1943:
! 1944: return ieee80211_send_eapol_key(ic, m, ni);
! 1945: }
! 1946:
! 1947: void
! 1948: ieee80211_pwrsave(struct ieee80211com *ic, struct ieee80211_node *ni,
! 1949: struct mbuf *m)
! 1950: {
! 1951: /* store the new packet on our queue, changing the TIM if necessary */
! 1952: if (IF_IS_EMPTY(&ni->ni_savedq))
! 1953: (*ic->ic_set_tim)(ic, ni->ni_associd, 1);
! 1954:
! 1955: if (ni->ni_savedq.ifq_len >= IEEE80211_PS_MAX_QUEUE) {
! 1956: IF_DROP(&ni->ni_savedq);
! 1957: m_freem(m);
! 1958: if (ic->ic_if.if_flags & IFF_DEBUG)
! 1959: printf("%s: station %s power save queue overflow"
! 1960: " of size %d drops %d\n",
! 1961: ic->ic_if.if_xname,
! 1962: ether_sprintf(ni->ni_macaddr),
! 1963: IEEE80211_PS_MAX_QUEUE,
! 1964: ni->ni_savedq.ifq_drops);
! 1965: } else {
! 1966: /*
! 1967: * Similar to ieee80211_mgmt_output, store the node in
! 1968: * the rcvif field.
! 1969: */
! 1970: IF_ENQUEUE(&ni->ni_savedq, m);
! 1971: m->m_pkthdr.rcvif = (void *)ni;
! 1972: }
! 1973: }
CVSweb