ieee80211_output.c revision 193655
1116742Ssam/*- 2116904Ssam * Copyright (c) 2001 Atsushi Onoe 3186904Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 4116742Ssam * All rights reserved. 5116742Ssam * 6116742Ssam * Redistribution and use in source and binary forms, with or without 7116742Ssam * modification, are permitted provided that the following conditions 8116742Ssam * are met: 9116742Ssam * 1. Redistributions of source code must retain the above copyright 10116904Ssam * notice, this list of conditions and the following disclaimer. 11116904Ssam * 2. Redistributions in binary form must reproduce the above copyright 12116904Ssam * notice, this list of conditions and the following disclaimer in the 13116904Ssam * documentation and/or other materials provided with the distribution. 14116742Ssam * 15116904Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16116904Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17116904Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18116904Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19116904Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20116904Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21116904Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22116904Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23116904Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24116904Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25116742Ssam */ 26116742Ssam 27116742Ssam#include <sys/cdefs.h> 28116742Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_output.c 193655 2009-06-07 22:00:22Z sam $"); 29116742Ssam 30116742Ssam#include "opt_inet.h" 31178354Ssam#include "opt_wlan.h" 32116742Ssam 33116742Ssam#include <sys/param.h> 34116742Ssam#include <sys/systm.h> 35116742Ssam#include <sys/mbuf.h> 36116742Ssam#include <sys/kernel.h> 37116742Ssam#include <sys/endian.h> 38116742Ssam 39138568Ssam#include <sys/socket.h> 40116742Ssam 41138568Ssam#include <net/bpf.h> 42138568Ssam#include <net/ethernet.h> 43116742Ssam#include <net/if.h> 44138568Ssam#include <net/if_llc.h> 45116742Ssam#include <net/if_media.h> 46138568Ssam#include <net/if_vlan_var.h> 47116742Ssam 48116742Ssam#include <net80211/ieee80211_var.h> 49170530Ssam#include <net80211/ieee80211_regdomain.h> 50190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 51190391Ssam#include <net80211/ieee80211_superg.h> 52190391Ssam#endif 53186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 54186904Ssam#include <net80211/ieee80211_tdma.h> 55186904Ssam#endif 56178354Ssam#include <net80211/ieee80211_wds.h> 57116742Ssam 58116742Ssam#ifdef INET 59116742Ssam#include <netinet/in.h> 60116742Ssam#include <netinet/if_ether.h> 61138568Ssam#include <netinet/in_systm.h> 62138568Ssam#include <netinet/ip.h> 63116742Ssam#endif 64116742Ssam 65193504Srwatson#include <security/mac/mac_framework.h> 66193504Srwatson 67170530Ssam#define ETHER_HEADER_COPY(dst, src) \ 68170530Ssam memcpy(dst, src, sizeof(struct ether_header)) 69170530Ssam 70178354Ssamstatic int ieee80211_fragment(struct ieee80211vap *, struct mbuf *, 71170530Ssam u_int hdrsize, u_int ciphdrsize, u_int mtu); 72170530Ssamstatic void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int); 73170530Ssam 74138568Ssam#ifdef IEEE80211_DEBUG 75119150Ssam/* 76138568Ssam * Decide if an outbound management frame should be 77138568Ssam * printed when debugging is enabled. This filters some 78138568Ssam * of the less interesting frames that come frequently 79138568Ssam * (e.g. beacons). 80138568Ssam */ 81138568Ssamstatic __inline int 82178354Ssamdoprint(struct ieee80211vap *vap, int subtype) 83138568Ssam{ 84138568Ssam switch (subtype) { 85138568Ssam case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 86178354Ssam return (vap->iv_opmode == IEEE80211_M_IBSS); 87138568Ssam } 88138568Ssam return 1; 89138568Ssam} 90138568Ssam#endif 91138568Ssam 92138568Ssam/* 93178354Ssam * Start method for vap's. All packets from the stack come 94178354Ssam * through here. We handle common processing of the packets 95178354Ssam * before dispatching them to the underlying device. 96178354Ssam */ 97178354Ssamvoid 98178354Ssamieee80211_start(struct ifnet *ifp) 99178354Ssam{ 100178354Ssam#define IS_DWDS(vap) \ 101178354Ssam (vap->iv_opmode == IEEE80211_M_WDS && \ 102178354Ssam (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0) 103178354Ssam struct ieee80211vap *vap = ifp->if_softc; 104178354Ssam struct ieee80211com *ic = vap->iv_ic; 105178354Ssam struct ifnet *parent = ic->ic_ifp; 106178354Ssam struct ieee80211_node *ni; 107178354Ssam struct mbuf *m; 108178354Ssam struct ether_header *eh; 109178354Ssam int error; 110178354Ssam 111178354Ssam /* NB: parent must be up and running */ 112178354Ssam if (!IFNET_IS_UP_RUNNING(parent)) { 113178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 114178354Ssam "%s: ignore queue, parent %s not up+running\n", 115178354Ssam __func__, parent->if_xname); 116178354Ssam /* XXX stat */ 117178354Ssam return; 118178354Ssam } 119178354Ssam if (vap->iv_state == IEEE80211_S_SLEEP) { 120178354Ssam /* 121178354Ssam * In power save, wakeup device for transmit. 122178354Ssam */ 123178354Ssam ieee80211_new_state(vap, IEEE80211_S_RUN, 0); 124178354Ssam return; 125178354Ssam } 126178354Ssam /* 127178354Ssam * No data frames go out unless we're running. 128178354Ssam * Note in particular this covers CAC and CSA 129178354Ssam * states (though maybe we should check muting 130178354Ssam * for CSA). 131178354Ssam */ 132178354Ssam if (vap->iv_state != IEEE80211_S_RUN) { 133178354Ssam IEEE80211_LOCK(ic); 134178354Ssam /* re-check under the com lock to avoid races */ 135178354Ssam if (vap->iv_state != IEEE80211_S_RUN) { 136178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 137178354Ssam "%s: ignore queue, in %s state\n", 138178354Ssam __func__, ieee80211_state_name[vap->iv_state]); 139178354Ssam vap->iv_stats.is_tx_badstate++; 140178354Ssam ifp->if_drv_flags |= IFF_DRV_OACTIVE; 141178354Ssam IEEE80211_UNLOCK(ic); 142178354Ssam return; 143178354Ssam } 144178354Ssam IEEE80211_UNLOCK(ic); 145178354Ssam } 146178354Ssam for (;;) { 147178354Ssam IFQ_DEQUEUE(&ifp->if_snd, m); 148178354Ssam if (m == NULL) 149178354Ssam break; 150178354Ssam /* 151178354Ssam * Sanitize mbuf flags for net80211 use. We cannot 152178354Ssam * clear M_PWR_SAV because this may be set for frames 153178354Ssam * that are re-submitted from the power save queue. 154178354Ssam * 155178354Ssam * NB: This must be done before ieee80211_classify as 156178354Ssam * it marks EAPOL in frames with M_EAPOL. 157178354Ssam */ 158178354Ssam m->m_flags &= ~(M_80211_TX - M_PWR_SAV); 159178354Ssam /* 160178354Ssam * Cancel any background scan. 161178354Ssam */ 162178354Ssam if (ic->ic_flags & IEEE80211_F_SCAN) 163178354Ssam ieee80211_cancel_anyscan(vap); 164178354Ssam /* 165178354Ssam * Find the node for the destination so we can do 166178354Ssam * things like power save and fast frames aggregation. 167178354Ssam * 168178354Ssam * NB: past this point various code assumes the first 169178354Ssam * mbuf has the 802.3 header present (and contiguous). 170178354Ssam */ 171178354Ssam ni = NULL; 172178354Ssam if (m->m_len < sizeof(struct ether_header) && 173178354Ssam (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 174178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 175178354Ssam "discard frame, %s\n", "m_pullup failed"); 176178354Ssam vap->iv_stats.is_tx_nobuf++; /* XXX */ 177178354Ssam ifp->if_oerrors++; 178178354Ssam continue; 179178354Ssam } 180178354Ssam eh = mtod(m, struct ether_header *); 181178354Ssam if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 182178354Ssam if (IS_DWDS(vap)) { 183178354Ssam /* 184178354Ssam * Only unicast frames from the above go out 185178354Ssam * DWDS vaps; multicast frames are handled by 186178354Ssam * dispatching the frame as it comes through 187178354Ssam * the AP vap (see below). 188178354Ssam */ 189178354Ssam IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS, 190178354Ssam eh->ether_dhost, "mcast", "%s", "on DWDS"); 191178354Ssam vap->iv_stats.is_dwds_mcast++; 192178354Ssam m_freem(m); 193178354Ssam continue; 194178354Ssam } 195178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 196178354Ssam /* 197178354Ssam * Spam DWDS vap's w/ multicast traffic. 198178354Ssam */ 199178354Ssam /* XXX only if dwds in use? */ 200178354Ssam ieee80211_dwds_mcast(vap, m); 201178354Ssam } 202178354Ssam } 203178354Ssam ni = ieee80211_find_txnode(vap, eh->ether_dhost); 204178354Ssam if (ni == NULL) { 205178354Ssam /* NB: ieee80211_find_txnode does stat+msg */ 206178354Ssam ifp->if_oerrors++; 207178354Ssam m_freem(m); 208178354Ssam continue; 209178354Ssam } 210184271Ssam if (ni->ni_associd == 0 && 211186099Ssam (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { 212184271Ssam IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 213184271Ssam eh->ether_dhost, NULL, 214184271Ssam "sta not associated (type 0x%04x)", 215184271Ssam htons(eh->ether_type)); 216184271Ssam vap->iv_stats.is_tx_notassoc++; 217184271Ssam ifp->if_oerrors++; 218184271Ssam m_freem(m); 219184271Ssam ieee80211_free_node(ni); 220184271Ssam continue; 221178354Ssam } 222190579Ssam 223178354Ssam if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 224178354Ssam (m->m_flags & M_PWR_SAV) == 0) { 225178354Ssam /* 226178354Ssam * Station in power save mode; pass the frame 227178354Ssam * to the 802.11 layer and continue. We'll get 228178354Ssam * the frame back when the time is right. 229178354Ssam * XXX lose WDS vap linkage? 230178354Ssam */ 231184288Ssam (void) ieee80211_pwrsave(ni, m); 232178354Ssam ieee80211_free_node(ni); 233178354Ssam continue; 234178354Ssam } 235178354Ssam /* calculate priority so drivers can find the tx queue */ 236178354Ssam if (ieee80211_classify(ni, m)) { 237178354Ssam IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 238178354Ssam eh->ether_dhost, NULL, 239178354Ssam "%s", "classification failure"); 240178354Ssam vap->iv_stats.is_tx_classify++; 241178354Ssam ifp->if_oerrors++; 242178354Ssam m_freem(m); 243178354Ssam ieee80211_free_node(ni); 244178354Ssam continue; 245178354Ssam } 246191550Ssam /* 247191550Ssam * Stash the node pointer. Note that we do this after 248191550Ssam * any call to ieee80211_dwds_mcast because that code 249191550Ssam * uses any existing value for rcvif to identify the 250191550Ssam * interface it (might have been) received on. 251191550Ssam */ 252191550Ssam m->m_pkthdr.rcvif = (void *)ni; 253178354Ssam 254190579Ssam BPF_MTAP(ifp, m); /* 802.3 tx */ 255190579Ssam 256191553Ssam /* 257191553Ssam * Check if A-MPDU tx aggregation is setup or if we 258191553Ssam * should try to enable it. The sta must be associated 259191553Ssam * with HT and A-MPDU enabled for use. When the policy 260191553Ssam * routine decides we should enable A-MPDU we issue an 261191553Ssam * ADDBA request and wait for a reply. The frame being 262191553Ssam * encapsulated will go out w/o using A-MPDU, or possibly 263191553Ssam * it might be collected by the driver and held/retransmit. 264191553Ssam * The default ic_ampdu_enable routine handles staggering 265191553Ssam * ADDBA requests in case the receiver NAK's us or we are 266191553Ssam * otherwise unable to establish a BA stream. 267191553Ssam */ 268191553Ssam if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && 269193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) && 270191553Ssam (m->m_flags & M_EAPOL) == 0) { 271191553Ssam const int ac = M_WME_GETAC(m); 272191553Ssam struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; 273191553Ssam 274191553Ssam ieee80211_txampdu_count_packet(tap); 275191553Ssam if (IEEE80211_AMPDU_RUNNING(tap)) { 276191553Ssam /* 277191553Ssam * Operational, mark frame for aggregation. 278191553Ssam * 279191553Ssam * XXX do tx aggregation here 280191553Ssam */ 281191553Ssam m->m_flags |= M_AMPDU_MPDU; 282191553Ssam } else if (!IEEE80211_AMPDU_REQUESTED(tap) && 283191553Ssam ic->ic_ampdu_enable(ni, tap)) { 284191553Ssam /* 285191553Ssam * Not negotiated yet, request service. 286191553Ssam */ 287191553Ssam ieee80211_ampdu_request(ni, tap); 288191553Ssam /* XXX hold frame for reply? */ 289191553Ssam } 290191553Ssam } 291190579Ssam#ifdef IEEE80211_SUPPORT_SUPERG 292191553Ssam else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { 293190579Ssam m = ieee80211_ff_check(ni, m); 294190579Ssam if (m == NULL) { 295190579Ssam /* NB: any ni ref held on stageq */ 296190579Ssam continue; 297190579Ssam } 298190579Ssam } 299190579Ssam#endif /* IEEE80211_SUPPORT_SUPERG */ 300190850Ssam if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { 301190850Ssam /* 302190850Ssam * Encapsulate the packet in prep for transmission. 303190850Ssam */ 304190850Ssam m = ieee80211_encap(vap, ni, m); 305190850Ssam if (m == NULL) { 306190850Ssam /* NB: stat+msg handled in ieee80211_encap */ 307190850Ssam ieee80211_free_node(ni); 308190850Ssam continue; 309190850Ssam } 310190579Ssam } 311178354Ssam 312186658Ssam error = parent->if_transmit(parent, m); 313178354Ssam if (error != 0) { 314178354Ssam /* NB: IFQ_HANDOFF reclaims mbuf */ 315178354Ssam ieee80211_free_node(ni); 316178354Ssam } else { 317178354Ssam ifp->if_opackets++; 318178354Ssam } 319178354Ssam ic->ic_lastdata = ticks; 320178354Ssam } 321178354Ssam#undef IS_DWDS 322178354Ssam} 323178354Ssam 324178354Ssam/* 325178354Ssam * 802.11 output routine. This is (currently) used only to 326178354Ssam * connect bpf write calls to the 802.11 layer for injecting 327191538Ssam * raw 802.11 frames. 328178354Ssam */ 329178354Ssamint 330178354Ssamieee80211_output(struct ifnet *ifp, struct mbuf *m, 331191148Skmacy struct sockaddr *dst, struct route *ro) 332178354Ssam{ 333178354Ssam#define senderr(e) do { error = (e); goto bad;} while (0) 334178354Ssam struct ieee80211_node *ni = NULL; 335178354Ssam struct ieee80211vap *vap; 336178354Ssam struct ieee80211_frame *wh; 337178354Ssam int error; 338178354Ssam 339178354Ssam if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 340178354Ssam /* 341178354Ssam * Short-circuit requests if the vap is marked OACTIVE 342178354Ssam * as this is used when tearing down state to indicate 343178354Ssam * the vap may be gone. This can also happen because a 344178354Ssam * packet came down through ieee80211_start before the 345178354Ssam * vap entered RUN state in which case it's also ok to 346178354Ssam * just drop the frame. This should not be necessary 347178354Ssam * but callers of if_output don't check OACTIVE. 348178354Ssam */ 349178354Ssam senderr(ENETDOWN); 350178354Ssam } 351178354Ssam vap = ifp->if_softc; 352178354Ssam /* 353178354Ssam * Hand to the 802.3 code if not tagged as 354178354Ssam * a raw 802.11 frame. 355178354Ssam */ 356178354Ssam if (dst->sa_family != AF_IEEE80211) 357191148Skmacy return vap->iv_output(ifp, m, dst, ro); 358178354Ssam#ifdef MAC 359193504Srwatson error = mac_ifnet_check_transmit(ifp, m); 360178354Ssam if (error) 361178354Ssam senderr(error); 362178354Ssam#endif 363178354Ssam if (ifp->if_flags & IFF_MONITOR) 364178354Ssam senderr(ENETDOWN); 365178354Ssam if (!IFNET_IS_UP_RUNNING(ifp)) 366178354Ssam senderr(ENETDOWN); 367178354Ssam if (vap->iv_state == IEEE80211_S_CAC) { 368178354Ssam IEEE80211_DPRINTF(vap, 369178354Ssam IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 370178354Ssam "block %s frame in CAC state\n", "raw data"); 371178354Ssam vap->iv_stats.is_tx_badstate++; 372178354Ssam senderr(EIO); /* XXX */ 373178354Ssam } 374178354Ssam /* XXX bypass bridge, pfil, carp, etc. */ 375178354Ssam 376178354Ssam if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) 377178354Ssam senderr(EIO); /* XXX */ 378178354Ssam wh = mtod(m, struct ieee80211_frame *); 379178354Ssam if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 380178354Ssam IEEE80211_FC0_VERSION_0) 381178354Ssam senderr(EIO); /* XXX */ 382178354Ssam 383178354Ssam /* locate destination node */ 384178354Ssam switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 385178354Ssam case IEEE80211_FC1_DIR_NODS: 386178354Ssam case IEEE80211_FC1_DIR_FROMDS: 387178354Ssam ni = ieee80211_find_txnode(vap, wh->i_addr1); 388178354Ssam break; 389178354Ssam case IEEE80211_FC1_DIR_TODS: 390178354Ssam case IEEE80211_FC1_DIR_DSTODS: 391178354Ssam if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) 392178354Ssam senderr(EIO); /* XXX */ 393178354Ssam ni = ieee80211_find_txnode(vap, wh->i_addr3); 394178354Ssam break; 395178354Ssam default: 396178354Ssam senderr(EIO); /* XXX */ 397178354Ssam } 398178354Ssam if (ni == NULL) { 399178354Ssam /* 400178354Ssam * Permit packets w/ bpf params through regardless 401178354Ssam * (see below about sa_len). 402178354Ssam */ 403178354Ssam if (dst->sa_len == 0) 404178354Ssam senderr(EHOSTUNREACH); 405178354Ssam ni = ieee80211_ref_node(vap->iv_bss); 406178354Ssam } 407178354Ssam 408178354Ssam /* 409178354Ssam * Sanitize mbuf for net80211 flags leaked from above. 410178354Ssam * 411178354Ssam * NB: This must be done before ieee80211_classify as 412178354Ssam * it marks EAPOL in frames with M_EAPOL. 413178354Ssam */ 414178354Ssam m->m_flags &= ~M_80211_TX; 415178354Ssam 416178354Ssam /* calculate priority so drivers can find the tx queue */ 417178354Ssam /* XXX assumes an 802.3 frame */ 418178354Ssam if (ieee80211_classify(ni, m)) 419178354Ssam senderr(EIO); /* XXX */ 420178354Ssam 421191536Ssam IEEE80211_NODE_STAT(ni, tx_data); 422191536Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 423191536Ssam IEEE80211_NODE_STAT(ni, tx_mcast); 424191536Ssam m->m_flags |= M_MCAST; 425191536Ssam } else 426191536Ssam IEEE80211_NODE_STAT(ni, tx_ucast); 427191536Ssam /* NB: ieee80211_encap does not include 802.11 header */ 428191536Ssam IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len); 429191536Ssam 430178354Ssam /* 431178354Ssam * NB: DLT_IEEE802_11_RADIO identifies the parameters are 432178354Ssam * present by setting the sa_len field of the sockaddr (yes, 433178354Ssam * this is a hack). 434178354Ssam * NB: we assume sa_data is suitably aligned to cast. 435178354Ssam */ 436178354Ssam return vap->iv_ic->ic_raw_xmit(ni, m, 437178354Ssam (const struct ieee80211_bpf_params *)(dst->sa_len ? 438178354Ssam dst->sa_data : NULL)); 439178354Ssambad: 440178354Ssam if (m != NULL) 441178354Ssam m_freem(m); 442178354Ssam if (ni != NULL) 443178354Ssam ieee80211_free_node(ni); 444178354Ssam return error; 445178354Ssam#undef senderr 446178354Ssam} 447178354Ssam 448178354Ssam/* 449148314Ssam * Set the direction field and address fields of an outgoing 450184285Ssam * frame. Note this should be called early on in constructing 451184285Ssam * a frame as it sets i_fc[1]; other bits can then be or'd in. 452148314Ssam */ 453148314Ssamstatic void 454178354Ssamieee80211_send_setup( 455148314Ssam struct ieee80211_node *ni, 456191544Ssam struct mbuf *m, 457184282Ssam int type, int tid, 458170530Ssam const uint8_t sa[IEEE80211_ADDR_LEN], 459170530Ssam const uint8_t da[IEEE80211_ADDR_LEN], 460170530Ssam const uint8_t bssid[IEEE80211_ADDR_LEN]) 461148314Ssam{ 462148314Ssam#define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) 463191544Ssam struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 464191544Ssam ieee80211_seq seqno; 465148314Ssam 466148314Ssam wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; 467148314Ssam if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 468178354Ssam struct ieee80211vap *vap = ni->ni_vap; 469178354Ssam 470178354Ssam switch (vap->iv_opmode) { 471148314Ssam case IEEE80211_M_STA: 472148314Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 473148314Ssam IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 474148314Ssam IEEE80211_ADDR_COPY(wh->i_addr2, sa); 475148314Ssam IEEE80211_ADDR_COPY(wh->i_addr3, da); 476148314Ssam break; 477148314Ssam case IEEE80211_M_IBSS: 478148314Ssam case IEEE80211_M_AHDEMO: 479148314Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 480148314Ssam IEEE80211_ADDR_COPY(wh->i_addr1, da); 481148314Ssam IEEE80211_ADDR_COPY(wh->i_addr2, sa); 482148314Ssam IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 483148314Ssam break; 484148314Ssam case IEEE80211_M_HOSTAP: 485148314Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 486148314Ssam IEEE80211_ADDR_COPY(wh->i_addr1, da); 487148314Ssam IEEE80211_ADDR_COPY(wh->i_addr2, bssid); 488148314Ssam IEEE80211_ADDR_COPY(wh->i_addr3, sa); 489148314Ssam break; 490170530Ssam case IEEE80211_M_WDS: 491170530Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 492178354Ssam IEEE80211_ADDR_COPY(wh->i_addr1, da); 493178354Ssam IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 494170530Ssam IEEE80211_ADDR_COPY(wh->i_addr3, da); 495170530Ssam IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 496170530Ssam break; 497148314Ssam case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ 498148314Ssam break; 499148314Ssam } 500148314Ssam } else { 501148314Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 502148314Ssam IEEE80211_ADDR_COPY(wh->i_addr1, da); 503148314Ssam IEEE80211_ADDR_COPY(wh->i_addr2, sa); 504148314Ssam IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 505148314Ssam } 506170530Ssam *(uint16_t *)&wh->i_dur[0] = 0; 507191544Ssam 508191544Ssam seqno = ni->ni_txseqs[tid]++; 509191544Ssam *(uint16_t *)&wh->i_seq[0] = htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 510191571Ssam M_SEQNO_SET(m, seqno); 511191544Ssam 512191544Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 513191544Ssam m->m_flags |= M_MCAST; 514148314Ssam#undef WH4 515148314Ssam} 516148314Ssam 517148314Ssam/* 518119150Ssam * Send a management frame to the specified node. The node pointer 519119150Ssam * must have a reference as the pointer will be passed to the driver 520119150Ssam * and potentially held for a long time. If the frame is successfully 521119150Ssam * dispatched to the driver, then it is responsible for freeing the 522178354Ssam * reference (and potentially free'ing up any associated storage); 523178354Ssam * otherwise deal with reclaiming any reference (on error). 524119150Ssam */ 525170530Ssamint 526184282Ssamieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, 527184282Ssam struct ieee80211_bpf_params *params) 528116742Ssam{ 529178354Ssam struct ieee80211vap *vap = ni->ni_vap; 530178354Ssam struct ieee80211com *ic = ni->ni_ic; 531116742Ssam struct ieee80211_frame *wh; 532116742Ssam 533119150Ssam KASSERT(ni != NULL, ("null node")); 534116742Ssam 535178354Ssam if (vap->iv_state == IEEE80211_S_CAC) { 536178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 537178354Ssam ni, "block %s frame in CAC state", 538178354Ssam ieee80211_mgt_subtype_name[ 539178354Ssam (type & IEEE80211_FC0_SUBTYPE_MASK) >> 540178354Ssam IEEE80211_FC0_SUBTYPE_SHIFT]); 541178354Ssam vap->iv_stats.is_tx_badstate++; 542178354Ssam ieee80211_free_node(ni); 543178354Ssam m_freem(m); 544178354Ssam return EIO; /* XXX */ 545178354Ssam } 546178354Ssam 547116742Ssam M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 548178354Ssam if (m == NULL) { 549178354Ssam ieee80211_free_node(ni); 550116742Ssam return ENOMEM; 551178354Ssam } 552119150Ssam 553116742Ssam wh = mtod(m, struct ieee80211_frame *); 554191544Ssam ieee80211_send_setup(ni, m, 555184282Ssam IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, 556184282Ssam vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 557184282Ssam if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 558178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, 559178354Ssam "encrypting frame (%s)", __func__); 560138568Ssam wh->i_fc[1] |= IEEE80211_FC1_WEP; 561138568Ssam } 562184286Ssam m->m_flags |= M_ENCAP; /* mark encapsulated */ 563184282Ssam 564184282Ssam KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); 565184282Ssam M_WME_SETAC(m, params->ibp_pri); 566184282Ssam 567116742Ssam#ifdef IEEE80211_DEBUG 568138568Ssam /* avoid printing too many frames */ 569178354Ssam if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || 570178354Ssam ieee80211_msg_dumppkts(vap)) { 571138568Ssam printf("[%s] send %s on channel %u\n", 572138568Ssam ether_sprintf(wh->i_addr1), 573138568Ssam ieee80211_mgt_subtype_name[ 574138568Ssam (type & IEEE80211_FC0_SUBTYPE_MASK) >> 575138568Ssam IEEE80211_FC0_SUBTYPE_SHIFT], 576148936Ssam ieee80211_chan2ieee(ic, ic->ic_curchan)); 577138568Ssam } 578116742Ssam#endif 579138568Ssam IEEE80211_NODE_STAT(ni, tx_mgmt); 580170530Ssam 581184282Ssam return ic->ic_raw_xmit(ni, m, params); 582116742Ssam} 583116742Ssam 584119150Ssam/* 585184283Ssam * Send a null data frame to the specified node. If the station 586184283Ssam * is setup for QoS then a QoS Null Data frame is constructed. 587184283Ssam * If this is a WDS station then a 4-address frame is constructed. 588148582Ssam * 589148582Ssam * NB: the caller is assumed to have setup a node reference 590148582Ssam * for use; this is necessary to deal with a race condition 591178354Ssam * when probing for inactive stations. Like ieee80211_mgmt_output 592178354Ssam * we must cleanup any node reference on error; however we 593178354Ssam * can safely just unref it as we know it will never be the 594178354Ssam * last reference to the node. 595119150Ssam */ 596138568Ssamint 597148301Ssamieee80211_send_nulldata(struct ieee80211_node *ni) 598138568Ssam{ 599178354Ssam struct ieee80211vap *vap = ni->ni_vap; 600148301Ssam struct ieee80211com *ic = ni->ni_ic; 601138568Ssam struct mbuf *m; 602138568Ssam struct ieee80211_frame *wh; 603184283Ssam int hdrlen; 604184283Ssam uint8_t *frm; 605138568Ssam 606178354Ssam if (vap->iv_state == IEEE80211_S_CAC) { 607178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 608178354Ssam ni, "block %s frame in CAC state", "null data"); 609178354Ssam ieee80211_unref_node(&ni); 610178354Ssam vap->iv_stats.is_tx_badstate++; 611178354Ssam return EIO; /* XXX */ 612178354Ssam } 613178354Ssam 614184283Ssam if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) 615184283Ssam hdrlen = sizeof(struct ieee80211_qosframe); 616184283Ssam else 617184283Ssam hdrlen = sizeof(struct ieee80211_frame); 618184283Ssam /* NB: only WDS vap's get 4-address frames */ 619184283Ssam if (vap->iv_opmode == IEEE80211_M_WDS) 620184283Ssam hdrlen += IEEE80211_ADDR_LEN; 621184283Ssam if (ic->ic_flags & IEEE80211_F_DATAPAD) 622184283Ssam hdrlen = roundup(hdrlen, sizeof(uint32_t)); 623184283Ssam 624184283Ssam m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); 625138568Ssam if (m == NULL) { 626138568Ssam /* XXX debug msg */ 627170530Ssam ieee80211_unref_node(&ni); 628178354Ssam vap->iv_stats.is_tx_nobuf++; 629138568Ssam return ENOMEM; 630138568Ssam } 631184283Ssam KASSERT(M_LEADINGSPACE(m) >= hdrlen, 632184283Ssam ("leading space %zd", M_LEADINGSPACE(m))); 633184283Ssam M_PREPEND(m, hdrlen, M_DONTWAIT); 634184283Ssam if (m == NULL) { 635184283Ssam /* NB: cannot happen */ 636184283Ssam ieee80211_free_node(ni); 637184283Ssam return ENOMEM; 638184283Ssam } 639138568Ssam 640184283Ssam wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ 641184283Ssam if (ni->ni_flags & IEEE80211_NODE_QOS) { 642184283Ssam const int tid = WME_AC_TO_TID(WME_AC_BE); 643184283Ssam uint8_t *qos; 644184283Ssam 645191544Ssam ieee80211_send_setup(ni, m, 646184283Ssam IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, 647184283Ssam tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 648184283Ssam 649184283Ssam if (vap->iv_opmode == IEEE80211_M_WDS) 650184283Ssam qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 651184283Ssam else 652184283Ssam qos = ((struct ieee80211_qosframe *) wh)->i_qos; 653184283Ssam qos[0] = tid & IEEE80211_QOS_TID; 654184283Ssam if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) 655184283Ssam qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 656184283Ssam qos[1] = 0; 657184283Ssam } else { 658191544Ssam ieee80211_send_setup(ni, m, 659184283Ssam IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 660184283Ssam IEEE80211_NONQOS_TID, 661184283Ssam vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 662184283Ssam } 663178354Ssam if (vap->iv_opmode != IEEE80211_M_WDS) { 664178354Ssam /* NB: power management bit is never sent by an AP */ 665178354Ssam if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 666178354Ssam vap->iv_opmode != IEEE80211_M_HOSTAP) 667178354Ssam wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 668178354Ssam } 669184283Ssam m->m_len = m->m_pkthdr.len = hdrlen; 670184286Ssam m->m_flags |= M_ENCAP; /* mark encapsulated */ 671184283Ssam 672172231Ssam M_WME_SETAC(m, WME_AC_BE); 673138568Ssam 674138568Ssam IEEE80211_NODE_STAT(ni, tx_data); 675138568Ssam 676178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, 677184283Ssam "send %snull data frame on channel %u, pwr mgt %s", 678184283Ssam ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", 679148936Ssam ieee80211_chan2ieee(ic, ic->ic_curchan), 680148314Ssam wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 681148314Ssam 682178354Ssam return ic->ic_raw_xmit(ni, m, NULL); 683138568Ssam} 684138568Ssam 685138568Ssam/* 686138568Ssam * Assign priority to a frame based on any vlan tag assigned 687138568Ssam * to the station and/or any Diffserv setting in an IP header. 688138568Ssam * Finally, if an ACM policy is setup (in station mode) it's 689138568Ssam * applied. 690138568Ssam */ 691138568Ssamint 692178354Ssamieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) 693138568Ssam{ 694178354Ssam const struct ether_header *eh = mtod(m, struct ether_header *); 695138568Ssam int v_wme_ac, d_wme_ac, ac; 696138568Ssam 697178354Ssam /* 698178354Ssam * Always promote PAE/EAPOL frames to high priority. 699178354Ssam */ 700178354Ssam if (eh->ether_type == htons(ETHERTYPE_PAE)) { 701178354Ssam /* NB: mark so others don't need to check header */ 702178354Ssam m->m_flags |= M_EAPOL; 703178354Ssam ac = WME_AC_VO; 704178354Ssam goto done; 705178354Ssam } 706178354Ssam /* 707178354Ssam * Non-qos traffic goes to BE. 708178354Ssam */ 709138568Ssam if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { 710138568Ssam ac = WME_AC_BE; 711138568Ssam goto done; 712138568Ssam } 713138568Ssam 714138568Ssam /* 715138568Ssam * If node has a vlan tag then all traffic 716138568Ssam * to it must have a matching tag. 717138568Ssam */ 718138568Ssam v_wme_ac = 0; 719138568Ssam if (ni->ni_vlan != 0) { 720162375Sandre if ((m->m_flags & M_VLANTAG) == 0) { 721138568Ssam IEEE80211_NODE_STAT(ni, tx_novlantag); 722138568Ssam return 1; 723138568Ssam } 724162375Sandre if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 725138568Ssam EVL_VLANOFTAG(ni->ni_vlan)) { 726138568Ssam IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 727138568Ssam return 1; 728138568Ssam } 729138568Ssam /* map vlan priority to AC */ 730173867Ssam v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); 731138568Ssam } 732138568Ssam 733138568Ssam#ifdef INET 734138568Ssam if (eh->ether_type == htons(ETHERTYPE_IP)) { 735173867Ssam uint8_t tos; 736138568Ssam /* 737173867Ssam * IP frame, map the DSCP bits from the TOS field. 738138568Ssam */ 739173867Ssam /* XXX m_copydata may be too slow for fast path */ 740173867Ssam /* NB: ip header may not be in first mbuf */ 741173867Ssam m_copydata(m, sizeof(struct ether_header) + 742173867Ssam offsetof(struct ip, ip_tos), sizeof(tos), &tos); 743173867Ssam tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 744173867Ssam d_wme_ac = TID_TO_WME_AC(tos); 745138568Ssam } else { 746138568Ssam#endif /* INET */ 747138568Ssam d_wme_ac = WME_AC_BE; 748138568Ssam#ifdef INET 749138568Ssam } 750138568Ssam#endif 751138568Ssam /* 752138568Ssam * Use highest priority AC. 753138568Ssam */ 754138568Ssam if (v_wme_ac > d_wme_ac) 755138568Ssam ac = v_wme_ac; 756138568Ssam else 757138568Ssam ac = d_wme_ac; 758138568Ssam 759138568Ssam /* 760138568Ssam * Apply ACM policy. 761138568Ssam */ 762178354Ssam if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { 763138568Ssam static const int acmap[4] = { 764138568Ssam WME_AC_BK, /* WME_AC_BE */ 765138568Ssam WME_AC_BK, /* WME_AC_BK */ 766138568Ssam WME_AC_BE, /* WME_AC_VI */ 767138568Ssam WME_AC_VI, /* WME_AC_VO */ 768138568Ssam }; 769178354Ssam struct ieee80211com *ic = ni->ni_ic; 770178354Ssam 771138568Ssam while (ac != WME_AC_BK && 772138568Ssam ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) 773138568Ssam ac = acmap[ac]; 774138568Ssam } 775138568Ssamdone: 776138568Ssam M_WME_SETAC(m, ac); 777138568Ssam return 0; 778138568Ssam} 779138568Ssam 780138568Ssam/* 781139527Ssam * Insure there is sufficient contiguous space to encapsulate the 782139527Ssam * 802.11 data frame. If room isn't already there, arrange for it. 783139527Ssam * Drivers and cipher modules assume we have done the necessary work 784139527Ssam * and fail rudely if they don't find the space they need. 785139527Ssam */ 786190391Ssamstruct mbuf * 787178354Ssamieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, 788139527Ssam struct ieee80211_key *key, struct mbuf *m) 789139527Ssam{ 790164805Ssam#define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) 791178354Ssam int needed_space = vap->iv_ic->ic_headroom + hdrsize; 792139527Ssam 793139527Ssam if (key != NULL) { 794139527Ssam /* XXX belongs in crypto code? */ 795139527Ssam needed_space += key->wk_cipher->ic_header; 796139527Ssam /* XXX frags */ 797156758Ssam /* 798156758Ssam * When crypto is being done in the host we must insure 799156758Ssam * the data are writable for the cipher routines; clone 800156758Ssam * a writable mbuf chain. 801156758Ssam * XXX handle SWMIC specially 802156758Ssam */ 803179394Ssam if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { 804156758Ssam m = m_unshare(m, M_NOWAIT); 805156758Ssam if (m == NULL) { 806178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 807156758Ssam "%s: cannot get writable mbuf\n", __func__); 808178354Ssam vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ 809156758Ssam return NULL; 810156758Ssam } 811156758Ssam } 812139527Ssam } 813139527Ssam /* 814139527Ssam * We know we are called just before stripping an Ethernet 815139527Ssam * header and prepending an LLC header. This means we know 816139527Ssam * there will be 817164805Ssam * sizeof(struct ether_header) - sizeof(struct llc) 818139527Ssam * bytes recovered to which we need additional space for the 819139527Ssam * 802.11 header and any crypto header. 820139527Ssam */ 821139527Ssam /* XXX check trailing space and copy instead? */ 822139527Ssam if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { 823139527Ssam struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); 824139527Ssam if (n == NULL) { 825178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 826139527Ssam "%s: cannot expand storage\n", __func__); 827178354Ssam vap->iv_stats.is_tx_nobuf++; 828139527Ssam m_freem(m); 829139527Ssam return NULL; 830139527Ssam } 831139527Ssam KASSERT(needed_space <= MHLEN, 832139527Ssam ("not enough room, need %u got %zu\n", needed_space, MHLEN)); 833139527Ssam /* 834139527Ssam * Setup new mbuf to have leading space to prepend the 835139527Ssam * 802.11 header and any crypto header bits that are 836139527Ssam * required (the latter are added when the driver calls 837139527Ssam * back to ieee80211_crypto_encap to do crypto encapsulation). 838139527Ssam */ 839139527Ssam /* NB: must be first 'cuz it clobbers m_data */ 840139527Ssam m_move_pkthdr(n, m); 841139527Ssam n->m_len = 0; /* NB: m_gethdr does not set */ 842139527Ssam n->m_data += needed_space; 843139527Ssam /* 844139527Ssam * Pull up Ethernet header to create the expected layout. 845139527Ssam * We could use m_pullup but that's overkill (i.e. we don't 846139527Ssam * need the actual data) and it cannot fail so do it inline 847139527Ssam * for speed. 848139527Ssam */ 849139527Ssam /* NB: struct ether_header is known to be contiguous */ 850139527Ssam n->m_len += sizeof(struct ether_header); 851139527Ssam m->m_len -= sizeof(struct ether_header); 852139527Ssam m->m_data += sizeof(struct ether_header); 853139527Ssam /* 854139527Ssam * Replace the head of the chain. 855139527Ssam */ 856139527Ssam n->m_next = m; 857139527Ssam m = n; 858139527Ssam } 859139527Ssam return m; 860139527Ssam#undef TO_BE_RECLAIMED 861139527Ssam} 862139527Ssam 863139527Ssam/* 864139527Ssam * Return the transmit key to use in sending a unicast frame. 865139527Ssam * If a unicast key is set we use that. When no unicast key is set 866139527Ssam * we fall back to the default transmit key. 867138568Ssam */ 868138568Ssamstatic __inline struct ieee80211_key * 869178354Ssamieee80211_crypto_getucastkey(struct ieee80211vap *vap, 870178354Ssam struct ieee80211_node *ni) 871138568Ssam{ 872167432Ssam if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { 873178354Ssam if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 874178354Ssam IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 875138568Ssam return NULL; 876178354Ssam return &vap->iv_nw_keys[vap->iv_def_txkey]; 877138568Ssam } else { 878138568Ssam return &ni->ni_ucastkey; 879138568Ssam } 880138568Ssam} 881138568Ssam 882138568Ssam/* 883139527Ssam * Return the transmit key to use in sending a multicast frame. 884139527Ssam * Multicast traffic always uses the group key which is installed as 885139527Ssam * the default tx key. 886139527Ssam */ 887139527Ssamstatic __inline struct ieee80211_key * 888178354Ssamieee80211_crypto_getmcastkey(struct ieee80211vap *vap, 889178354Ssam struct ieee80211_node *ni) 890139527Ssam{ 891178354Ssam if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 892178354Ssam IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 893139527Ssam return NULL; 894178354Ssam return &vap->iv_nw_keys[vap->iv_def_txkey]; 895139527Ssam} 896139527Ssam 897139527Ssam/* 898138568Ssam * Encapsulate an outbound data frame. The mbuf chain is updated. 899138568Ssam * If an error is encountered NULL is returned. The caller is required 900138568Ssam * to provide a node reference and pullup the ethernet header in the 901138568Ssam * first mbuf. 902178354Ssam * 903178354Ssam * NB: Packet is assumed to be processed by ieee80211_classify which 904178354Ssam * marked EAPOL frames w/ M_EAPOL. 905138568Ssam */ 906116742Ssamstruct mbuf * 907190579Ssamieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni, 908190579Ssam struct mbuf *m) 909116742Ssam{ 910178354Ssam#define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) 911178354Ssam struct ieee80211com *ic = ni->ni_ic; 912116742Ssam struct ether_header eh; 913116742Ssam struct ieee80211_frame *wh; 914138568Ssam struct ieee80211_key *key; 915116742Ssam struct llc *llc; 916190391Ssam int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr; 917191544Ssam ieee80211_seq seqno; 918116742Ssam 919170530Ssam /* 920170530Ssam * Copy existing Ethernet header to a safe place. The 921170530Ssam * rest of the code assumes it's ok to strip it when 922170530Ssam * reorganizing state for the final encapsulation. 923170530Ssam */ 924138568Ssam KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); 925178354Ssam ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); 926116742Ssam 927138568Ssam /* 928138568Ssam * Insure space for additional headers. First identify 929138568Ssam * transmit key to use in calculating any buffer adjustments 930138568Ssam * required. This is also used below to do privacy 931138568Ssam * encapsulation work. Then calculate the 802.11 header 932138568Ssam * size and any padding required by the driver. 933138568Ssam * 934138568Ssam * Note key may be NULL if we fall back to the default 935138568Ssam * transmit key and that is not set. In that case the 936138568Ssam * buffer may not be expanded as needed by the cipher 937138568Ssam * routines, but they will/should discard it. 938138568Ssam */ 939178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) { 940178354Ssam if (vap->iv_opmode == IEEE80211_M_STA || 941178354Ssam !IEEE80211_IS_MULTICAST(eh.ether_dhost) || 942178354Ssam (vap->iv_opmode == IEEE80211_M_WDS && 943178354Ssam (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) 944178354Ssam key = ieee80211_crypto_getucastkey(vap, ni); 945139527Ssam else 946178354Ssam key = ieee80211_crypto_getmcastkey(vap, ni); 947178354Ssam if (key == NULL && (m->m_flags & M_EAPOL) == 0) { 948178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, 949178354Ssam eh.ether_dhost, 950178354Ssam "no default transmit key (%s) deftxkey %u", 951178354Ssam __func__, vap->iv_def_txkey); 952178354Ssam vap->iv_stats.is_tx_nodefkey++; 953171950Ssam goto bad; 954138568Ssam } 955138568Ssam } else 956138568Ssam key = NULL; 957139527Ssam /* 958139527Ssam * XXX Some ap's don't handle QoS-encapsulated EAPOL 959139527Ssam * frames so suppress use. This may be an issue if other 960139527Ssam * ap's require all data frames to be QoS-encapsulated 961139527Ssam * once negotiated in which case we'll need to make this 962139527Ssam * configurable. 963139527Ssam */ 964170530Ssam addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) && 965178354Ssam (m->m_flags & M_EAPOL) == 0; 966139527Ssam if (addqos) 967138568Ssam hdrsize = sizeof(struct ieee80211_qosframe); 968138568Ssam else 969138568Ssam hdrsize = sizeof(struct ieee80211_frame); 970178354Ssam /* 971178354Ssam * 4-address frames need to be generated for: 972190672Ssam * o packets sent through a WDS vap (IEEE80211_M_WDS) 973191555Ssam * o packets sent through a vap marked for relaying 974191555Ssam * (e.g. a station operating with dynamic WDS) 975178354Ssam */ 976190672Ssam is4addr = vap->iv_opmode == IEEE80211_M_WDS || 977191555Ssam ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) && 978178354Ssam !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); 979178354Ssam if (is4addr) 980178354Ssam hdrsize += IEEE80211_ADDR_LEN; 981178354Ssam /* 982178354Ssam * Honor driver DATAPAD requirement. 983178354Ssam */ 984138568Ssam if (ic->ic_flags & IEEE80211_F_DATAPAD) 985178354Ssam hdrspace = roundup(hdrsize, sizeof(uint32_t)); 986178354Ssam else 987178354Ssam hdrspace = hdrsize; 988170530Ssam 989190391Ssam if (__predict_true((m->m_flags & M_FF) == 0)) { 990170530Ssam /* 991170530Ssam * Normal frame. 992170530Ssam */ 993178354Ssam m = ieee80211_mbuf_adjust(vap, hdrspace, key, m); 994170530Ssam if (m == NULL) { 995170530Ssam /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 996170530Ssam goto bad; 997170530Ssam } 998170530Ssam /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ 999170530Ssam m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 1000170530Ssam llc = mtod(m, struct llc *); 1001170530Ssam llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 1002170530Ssam llc->llc_control = LLC_UI; 1003170530Ssam llc->llc_snap.org_code[0] = 0; 1004170530Ssam llc->llc_snap.org_code[1] = 0; 1005170530Ssam llc->llc_snap.org_code[2] = 0; 1006170530Ssam llc->llc_snap.ether_type = eh.ether_type; 1007190391Ssam } else { 1008190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1009190579Ssam /* 1010190579Ssam * Aggregated frame. 1011190579Ssam */ 1012190391Ssam m = ieee80211_ff_encap(vap, m, hdrspace, key); 1013190391Ssam if (m == NULL) 1014190391Ssam#endif 1015190391Ssam goto bad; 1016127772Ssam } 1017138568Ssam datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ 1018138568Ssam 1019178354Ssam M_PREPEND(m, hdrspace, M_DONTWAIT); 1020121180Ssam if (m == NULL) { 1021178354Ssam vap->iv_stats.is_tx_nobuf++; 1022119150Ssam goto bad; 1023121180Ssam } 1024116742Ssam wh = mtod(m, struct ieee80211_frame *); 1025116742Ssam wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 1026170530Ssam *(uint16_t *)wh->i_dur = 0; 1027178354Ssam if (is4addr) { 1028178354Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 1029178354Ssam IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 1030178354Ssam IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1031178354Ssam IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1032178354Ssam IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 1033178354Ssam } else switch (vap->iv_opmode) { 1034116742Ssam case IEEE80211_M_STA: 1035116742Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 1036116742Ssam IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 1037116742Ssam IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1038116742Ssam IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1039116742Ssam break; 1040116742Ssam case IEEE80211_M_IBSS: 1041116742Ssam case IEEE80211_M_AHDEMO: 1042116742Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 1043116742Ssam IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 1044116742Ssam IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1045140636Ssam /* 1046178354Ssam * NB: always use the bssid from iv_bss as the 1047140636Ssam * neighbor's may be stale after an ibss merge 1048140636Ssam */ 1049178354Ssam IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); 1050116742Ssam break; 1051116742Ssam case IEEE80211_M_HOSTAP: 1052116742Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 1053116742Ssam IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 1054116742Ssam IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 1055116742Ssam IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 1056116742Ssam break; 1057117817Ssam case IEEE80211_M_MONITOR: 1058178354Ssam case IEEE80211_M_WDS: /* NB: is4addr should always be true */ 1059119150Ssam goto bad; 1060116742Ssam } 1061190678Ssam if (m->m_flags & M_MORE_DATA) 1062147789Ssam wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 1063139527Ssam if (addqos) { 1064178354Ssam uint8_t *qos; 1065138568Ssam int ac, tid; 1066138568Ssam 1067178354Ssam if (is4addr) { 1068178354Ssam qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 1069178354Ssam } else 1070178354Ssam qos = ((struct ieee80211_qosframe *) wh)->i_qos; 1071138568Ssam ac = M_WME_GETAC(m); 1072138568Ssam /* map from access class/queue to 11e header priorty value */ 1073138568Ssam tid = WME_AC_TO_TID(ac); 1074178354Ssam qos[0] = tid & IEEE80211_QOS_TID; 1075138568Ssam if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) 1076178354Ssam qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 1077178354Ssam qos[1] = 0; 1078178354Ssam wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; 1079138568Ssam 1080183247Ssam if ((m->m_flags & M_AMPDU_MPDU) == 0) { 1081183247Ssam /* 1082183247Ssam * NB: don't assign a sequence # to potential 1083183247Ssam * aggregates; we expect this happens at the 1084183247Ssam * point the frame comes off any aggregation q 1085183247Ssam * as otherwise we may introduce holes in the 1086183247Ssam * BA sequence space and/or make window accouting 1087183247Ssam * more difficult. 1088183247Ssam * 1089183247Ssam * XXX may want to control this with a driver 1090183247Ssam * capability; this may also change when we pull 1091183247Ssam * aggregation up into net80211 1092183247Ssam */ 1093191544Ssam seqno = ni->ni_txseqs[tid]++; 1094183247Ssam *(uint16_t *)wh->i_seq = 1095191544Ssam htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 1096191571Ssam M_SEQNO_SET(m, seqno); 1097183247Ssam } 1098138568Ssam } else { 1099191544Ssam seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 1100170530Ssam *(uint16_t *)wh->i_seq = 1101191544Ssam htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 1102191571Ssam M_SEQNO_SET(m, seqno); 1103138568Ssam } 1104191571Ssam 1105170530Ssam /* check if xmit fragmentation is required */ 1106178354Ssam txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && 1107170530Ssam !IEEE80211_IS_MULTICAST(wh->i_addr1) && 1108178354Ssam (vap->iv_caps & IEEE80211_C_TXFRAG) && 1109191545Ssam (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0); 1110139527Ssam if (key != NULL) { 1111139527Ssam /* 1112139527Ssam * IEEE 802.1X: send EAPOL frames always in the clear. 1113139527Ssam * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 1114139527Ssam */ 1115178354Ssam if ((m->m_flags & M_EAPOL) == 0 || 1116178354Ssam ((vap->iv_flags & IEEE80211_F_WPA) && 1117178354Ssam (vap->iv_opmode == IEEE80211_M_STA ? 1118167432Ssam !IEEE80211_KEY_UNDEFINED(key) : 1119167432Ssam !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { 1120139527Ssam wh->i_fc[1] |= IEEE80211_FC1_WEP; 1121178354Ssam if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { 1122178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, 1123178354Ssam eh.ether_dhost, 1124178354Ssam "%s", "enmic failed, discard frame"); 1125178354Ssam vap->iv_stats.is_crypto_enmicfail++; 1126139527Ssam goto bad; 1127139527Ssam } 1128139527Ssam } 1129139527Ssam } 1130178354Ssam if (txfrag && !ieee80211_fragment(vap, m, hdrsize, 1131178354Ssam key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) 1132170530Ssam goto bad; 1133138568Ssam 1134184286Ssam m->m_flags |= M_ENCAP; /* mark encapsulated */ 1135184286Ssam 1136138568Ssam IEEE80211_NODE_STAT(ni, tx_data); 1137191544Ssam if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1138161144Ssam IEEE80211_NODE_STAT(ni, tx_mcast); 1139191544Ssam m->m_flags |= M_MCAST; 1140191544Ssam } else 1141161144Ssam IEEE80211_NODE_STAT(ni, tx_ucast); 1142138568Ssam IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); 1143138568Ssam 1144116742Ssam return m; 1145119150Ssambad: 1146119150Ssam if (m != NULL) 1147119150Ssam m_freem(m); 1148119150Ssam return NULL; 1149178354Ssam#undef WH4 1150116742Ssam} 1151116742Ssam 1152116742Ssam/* 1153170530Ssam * Fragment the frame according to the specified mtu. 1154170530Ssam * The size of the 802.11 header (w/o padding) is provided 1155170530Ssam * so we don't need to recalculate it. We create a new 1156170530Ssam * mbuf for each fragment and chain it through m_nextpkt; 1157170530Ssam * we might be able to optimize this by reusing the original 1158170530Ssam * packet's mbufs but that is significantly more complicated. 1159170530Ssam */ 1160170530Ssamstatic int 1161178354Ssamieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, 1162170530Ssam u_int hdrsize, u_int ciphdrsize, u_int mtu) 1163170530Ssam{ 1164170530Ssam struct ieee80211_frame *wh, *whf; 1165170530Ssam struct mbuf *m, *prev, *next; 1166170530Ssam u_int totalhdrsize, fragno, fragsize, off, remainder, payload; 1167170530Ssam 1168170530Ssam KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); 1169170530Ssam KASSERT(m0->m_pkthdr.len > mtu, 1170170530Ssam ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); 1171170530Ssam 1172170530Ssam wh = mtod(m0, struct ieee80211_frame *); 1173170530Ssam /* NB: mark the first frag; it will be propagated below */ 1174170530Ssam wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; 1175170530Ssam totalhdrsize = hdrsize + ciphdrsize; 1176170530Ssam fragno = 1; 1177170530Ssam off = mtu - ciphdrsize; 1178170530Ssam remainder = m0->m_pkthdr.len - off; 1179170530Ssam prev = m0; 1180170530Ssam do { 1181170530Ssam fragsize = totalhdrsize + remainder; 1182170530Ssam if (fragsize > mtu) 1183170530Ssam fragsize = mtu; 1184178354Ssam /* XXX fragsize can be >2048! */ 1185170530Ssam KASSERT(fragsize < MCLBYTES, 1186170530Ssam ("fragment size %u too big!", fragsize)); 1187170530Ssam if (fragsize > MHLEN) 1188170530Ssam m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 1189170530Ssam else 1190170530Ssam m = m_gethdr(M_DONTWAIT, MT_DATA); 1191170530Ssam if (m == NULL) 1192170530Ssam goto bad; 1193170530Ssam /* leave room to prepend any cipher header */ 1194170530Ssam m_align(m, fragsize - ciphdrsize); 1195170530Ssam 1196170530Ssam /* 1197170530Ssam * Form the header in the fragment. Note that since 1198170530Ssam * we mark the first fragment with the MORE_FRAG bit 1199170530Ssam * it automatically is propagated to each fragment; we 1200170530Ssam * need only clear it on the last fragment (done below). 1201170530Ssam */ 1202170530Ssam whf = mtod(m, struct ieee80211_frame *); 1203170530Ssam memcpy(whf, wh, hdrsize); 1204170530Ssam *(uint16_t *)&whf->i_seq[0] |= htole16( 1205170530Ssam (fragno & IEEE80211_SEQ_FRAG_MASK) << 1206170530Ssam IEEE80211_SEQ_FRAG_SHIFT); 1207170530Ssam fragno++; 1208170530Ssam 1209170530Ssam payload = fragsize - totalhdrsize; 1210170530Ssam /* NB: destination is known to be contiguous */ 1211170530Ssam m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrsize); 1212170530Ssam m->m_len = hdrsize + payload; 1213170530Ssam m->m_pkthdr.len = hdrsize + payload; 1214170530Ssam m->m_flags |= M_FRAG; 1215170530Ssam 1216170530Ssam /* chain up the fragment */ 1217170530Ssam prev->m_nextpkt = m; 1218170530Ssam prev = m; 1219170530Ssam 1220170530Ssam /* deduct fragment just formed */ 1221170530Ssam remainder -= payload; 1222170530Ssam off += payload; 1223170530Ssam } while (remainder != 0); 1224188380Sweongyo 1225188380Sweongyo /* set the last fragment */ 1226188380Sweongyo m->m_flags |= M_LASTFRAG; 1227170530Ssam whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; 1228170530Ssam 1229170530Ssam /* strip first mbuf now that everything has been copied */ 1230170530Ssam m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); 1231170530Ssam m0->m_flags |= M_FIRSTFRAG | M_FRAG; 1232170530Ssam 1233178354Ssam vap->iv_stats.is_tx_fragframes++; 1234178354Ssam vap->iv_stats.is_tx_frags += fragno-1; 1235170530Ssam 1236170530Ssam return 1; 1237170530Ssambad: 1238170530Ssam /* reclaim fragments but leave original frame for caller to free */ 1239170530Ssam for (m = m0->m_nextpkt; m != NULL; m = next) { 1240170530Ssam next = m->m_nextpkt; 1241170530Ssam m->m_nextpkt = NULL; /* XXX paranoid */ 1242170530Ssam m_freem(m); 1243170530Ssam } 1244170530Ssam m0->m_nextpkt = NULL; 1245170530Ssam return 0; 1246170530Ssam} 1247170530Ssam 1248170530Ssam/* 1249116742Ssam * Add a supported rates element id to a frame. 1250116742Ssam */ 1251170530Ssamstatic uint8_t * 1252170530Ssamieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 1253116742Ssam{ 1254116742Ssam int nrates; 1255116742Ssam 1256116742Ssam *frm++ = IEEE80211_ELEMID_RATES; 1257116742Ssam nrates = rs->rs_nrates; 1258116742Ssam if (nrates > IEEE80211_RATE_SIZE) 1259116742Ssam nrates = IEEE80211_RATE_SIZE; 1260116742Ssam *frm++ = nrates; 1261116742Ssam memcpy(frm, rs->rs_rates, nrates); 1262116742Ssam return frm + nrates; 1263116742Ssam} 1264116742Ssam 1265116742Ssam/* 1266116742Ssam * Add an extended supported rates element id to a frame. 1267116742Ssam */ 1268170530Ssamstatic uint8_t * 1269170530Ssamieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 1270116742Ssam{ 1271116742Ssam /* 1272116742Ssam * Add an extended supported rates element if operating in 11g mode. 1273116742Ssam */ 1274116742Ssam if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 1275116742Ssam int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 1276116742Ssam *frm++ = IEEE80211_ELEMID_XRATES; 1277116742Ssam *frm++ = nrates; 1278116742Ssam memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 1279116742Ssam frm += nrates; 1280116742Ssam } 1281116742Ssam return frm; 1282116742Ssam} 1283116742Ssam 1284116742Ssam/* 1285178354Ssam * Add an ssid element to a frame. 1286116742Ssam */ 1287170530Ssamstatic uint8_t * 1288170530Ssamieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) 1289116742Ssam{ 1290116742Ssam *frm++ = IEEE80211_ELEMID_SSID; 1291116742Ssam *frm++ = len; 1292116742Ssam memcpy(frm, ssid, len); 1293116742Ssam return frm + len; 1294116742Ssam} 1295116742Ssam 1296138568Ssam/* 1297138568Ssam * Add an erp element to a frame. 1298138568Ssam */ 1299170530Ssamstatic uint8_t * 1300170530Ssamieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) 1301116742Ssam{ 1302170530Ssam uint8_t erp; 1303116742Ssam 1304138568Ssam *frm++ = IEEE80211_ELEMID_ERP; 1305138568Ssam *frm++ = 1; 1306138568Ssam erp = 0; 1307138568Ssam if (ic->ic_nonerpsta != 0) 1308138568Ssam erp |= IEEE80211_ERP_NON_ERP_PRESENT; 1309138568Ssam if (ic->ic_flags & IEEE80211_F_USEPROT) 1310138568Ssam erp |= IEEE80211_ERP_USE_PROTECTION; 1311138568Ssam if (ic->ic_flags & IEEE80211_F_USEBARKER) 1312138568Ssam erp |= IEEE80211_ERP_LONG_PREAMBLE; 1313138568Ssam *frm++ = erp; 1314138568Ssam return frm; 1315138568Ssam} 1316138568Ssam 1317178354Ssam/* 1318178354Ssam * Add a CFParams element to a frame. 1319178354Ssam */ 1320170530Ssamstatic uint8_t * 1321178354Ssamieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) 1322138568Ssam{ 1323138568Ssam#define ADDSHORT(frm, v) do { \ 1324138568Ssam frm[0] = (v) & 0xff; \ 1325138568Ssam frm[1] = (v) >> 8; \ 1326138568Ssam frm += 2; \ 1327138568Ssam} while (0) 1328178354Ssam *frm++ = IEEE80211_ELEMID_CFPARMS; 1329178354Ssam *frm++ = 6; 1330178354Ssam *frm++ = 0; /* CFP count */ 1331178354Ssam *frm++ = 2; /* CFP period */ 1332178354Ssam ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ 1333178354Ssam ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ 1334138568Ssam return frm; 1335138568Ssam#undef ADDSHORT 1336116742Ssam} 1337116742Ssam 1338178354Ssamstatic __inline uint8_t * 1339178354Ssamadd_appie(uint8_t *frm, const struct ieee80211_appie *ie) 1340138568Ssam{ 1341178354Ssam memcpy(frm, ie->ie_data, ie->ie_len); 1342178354Ssam return frm + ie->ie_len; 1343138568Ssam} 1344138568Ssam 1345178354Ssamstatic __inline uint8_t * 1346178354Ssamadd_ie(uint8_t *frm, const uint8_t *ie) 1347138568Ssam{ 1348178354Ssam memcpy(frm, ie, 2 + ie[1]); 1349178354Ssam return frm + 2 + ie[1]; 1350138568Ssam} 1351138568Ssam 1352138568Ssam#define WME_OUI_BYTES 0x00, 0x50, 0xf2 1353138568Ssam/* 1354138568Ssam * Add a WME information element to a frame. 1355138568Ssam */ 1356170530Ssamstatic uint8_t * 1357170530Ssamieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 1358138568Ssam{ 1359138568Ssam static const struct ieee80211_wme_info info = { 1360138568Ssam .wme_id = IEEE80211_ELEMID_VENDOR, 1361138568Ssam .wme_len = sizeof(struct ieee80211_wme_info) - 2, 1362138568Ssam .wme_oui = { WME_OUI_BYTES }, 1363138568Ssam .wme_type = WME_OUI_TYPE, 1364138568Ssam .wme_subtype = WME_INFO_OUI_SUBTYPE, 1365138568Ssam .wme_version = WME_VERSION, 1366138568Ssam .wme_info = 0, 1367138568Ssam }; 1368138568Ssam memcpy(frm, &info, sizeof(info)); 1369138568Ssam return frm + sizeof(info); 1370138568Ssam} 1371138568Ssam 1372138568Ssam/* 1373138568Ssam * Add a WME parameters element to a frame. 1374138568Ssam */ 1375170530Ssamstatic uint8_t * 1376170530Ssamieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 1377138568Ssam{ 1378138568Ssam#define SM(_v, _f) (((_v) << _f##_S) & _f) 1379138568Ssam#define ADDSHORT(frm, v) do { \ 1380138568Ssam frm[0] = (v) & 0xff; \ 1381138568Ssam frm[1] = (v) >> 8; \ 1382138568Ssam frm += 2; \ 1383138568Ssam} while (0) 1384138568Ssam /* NB: this works 'cuz a param has an info at the front */ 1385138568Ssam static const struct ieee80211_wme_info param = { 1386138568Ssam .wme_id = IEEE80211_ELEMID_VENDOR, 1387138568Ssam .wme_len = sizeof(struct ieee80211_wme_param) - 2, 1388138568Ssam .wme_oui = { WME_OUI_BYTES }, 1389138568Ssam .wme_type = WME_OUI_TYPE, 1390138568Ssam .wme_subtype = WME_PARAM_OUI_SUBTYPE, 1391138568Ssam .wme_version = WME_VERSION, 1392138568Ssam }; 1393138568Ssam int i; 1394138568Ssam 1395138568Ssam memcpy(frm, ¶m, sizeof(param)); 1396138568Ssam frm += __offsetof(struct ieee80211_wme_info, wme_info); 1397138568Ssam *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 1398138568Ssam *frm++ = 0; /* reserved field */ 1399138568Ssam for (i = 0; i < WME_NUM_AC; i++) { 1400138568Ssam const struct wmeParams *ac = 1401138568Ssam &wme->wme_bssChanParams.cap_wmeParams[i]; 1402138568Ssam *frm++ = SM(i, WME_PARAM_ACI) 1403138568Ssam | SM(ac->wmep_acm, WME_PARAM_ACM) 1404138568Ssam | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) 1405138568Ssam ; 1406138568Ssam *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 1407138568Ssam | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) 1408138568Ssam ; 1409138568Ssam ADDSHORT(frm, ac->wmep_txopLimit); 1410138568Ssam } 1411138568Ssam return frm; 1412138568Ssam#undef SM 1413138568Ssam#undef ADDSHORT 1414138568Ssam} 1415138568Ssam#undef WME_OUI_BYTES 1416138568Ssam 1417138568Ssam/* 1418178354Ssam * Add an 11h Power Constraint element to a frame. 1419178354Ssam */ 1420178354Ssamstatic uint8_t * 1421178354Ssamieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) 1422178354Ssam{ 1423178354Ssam const struct ieee80211_channel *c = vap->iv_bss->ni_chan; 1424178354Ssam /* XXX per-vap tx power limit? */ 1425178354Ssam int8_t limit = vap->iv_ic->ic_txpowlimit / 2; 1426178354Ssam 1427178354Ssam frm[0] = IEEE80211_ELEMID_PWRCNSTR; 1428178354Ssam frm[1] = 1; 1429178354Ssam frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; 1430178354Ssam return frm + 3; 1431178354Ssam} 1432178354Ssam 1433178354Ssam/* 1434178354Ssam * Add an 11h Power Capability element to a frame. 1435178354Ssam */ 1436178354Ssamstatic uint8_t * 1437178354Ssamieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) 1438178354Ssam{ 1439178354Ssam frm[0] = IEEE80211_ELEMID_PWRCAP; 1440178354Ssam frm[1] = 2; 1441178354Ssam frm[2] = c->ic_minpower; 1442178354Ssam frm[3] = c->ic_maxpower; 1443178354Ssam return frm + 4; 1444178354Ssam} 1445178354Ssam 1446178354Ssam/* 1447178354Ssam * Add an 11h Supported Channels element to a frame. 1448178354Ssam */ 1449178354Ssamstatic uint8_t * 1450178354Ssamieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) 1451178354Ssam{ 1452178354Ssam static const int ielen = 26; 1453178354Ssam 1454178354Ssam frm[0] = IEEE80211_ELEMID_SUPPCHAN; 1455178354Ssam frm[1] = ielen; 1456178354Ssam /* XXX not correct */ 1457178354Ssam memcpy(frm+2, ic->ic_chan_avail, ielen); 1458178354Ssam return frm + 2 + ielen; 1459178354Ssam} 1460178354Ssam 1461178354Ssam/* 1462178354Ssam * Add an 11h Channel Switch Announcement element to a frame. 1463178354Ssam * Note that we use the per-vap CSA count to adjust the global 1464178354Ssam * counter so we can use this routine to form probe response 1465178354Ssam * frames and get the current count. 1466178354Ssam */ 1467178354Ssamstatic uint8_t * 1468178354Ssamieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) 1469178354Ssam{ 1470178354Ssam struct ieee80211com *ic = vap->iv_ic; 1471178354Ssam struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; 1472178354Ssam 1473193439Ssam csa->csa_ie = IEEE80211_ELEMID_CSA; 1474178354Ssam csa->csa_len = 3; 1475178354Ssam csa->csa_mode = 1; /* XXX force quiet on channel */ 1476178354Ssam csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); 1477178354Ssam csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; 1478178354Ssam return frm + sizeof(*csa); 1479178354Ssam} 1480178354Ssam 1481178354Ssam/* 1482178354Ssam * Add an 11h country information element to a frame. 1483178354Ssam */ 1484178354Ssamstatic uint8_t * 1485178354Ssamieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) 1486178354Ssam{ 1487178354Ssam 1488178354Ssam if (ic->ic_countryie == NULL || 1489178354Ssam ic->ic_countryie_chan != ic->ic_bsschan) { 1490178354Ssam /* 1491178354Ssam * Handle lazy construction of ie. This is done on 1492178354Ssam * first use and after a channel change that requires 1493178354Ssam * re-calculation. 1494178354Ssam */ 1495178354Ssam if (ic->ic_countryie != NULL) 1496178354Ssam free(ic->ic_countryie, M_80211_NODE_IE); 1497178354Ssam ic->ic_countryie = ieee80211_alloc_countryie(ic); 1498178354Ssam if (ic->ic_countryie == NULL) 1499178354Ssam return frm; 1500178354Ssam ic->ic_countryie_chan = ic->ic_bsschan; 1501178354Ssam } 1502178354Ssam return add_appie(frm, ic->ic_countryie); 1503178354Ssam} 1504178354Ssam 1505178354Ssam/* 1506148315Ssam * Send a probe request frame with the specified ssid 1507148315Ssam * and any optional information element data. 1508148315Ssam */ 1509148315Ssamint 1510148315Ssamieee80211_send_probereq(struct ieee80211_node *ni, 1511170530Ssam const uint8_t sa[IEEE80211_ADDR_LEN], 1512170530Ssam const uint8_t da[IEEE80211_ADDR_LEN], 1513170530Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], 1514178354Ssam const uint8_t *ssid, size_t ssidlen) 1515148315Ssam{ 1516178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1517148315Ssam struct ieee80211com *ic = ni->ni_ic; 1518184284Ssam const struct ieee80211_txparam *tp; 1519184284Ssam struct ieee80211_bpf_params params; 1520148315Ssam struct ieee80211_frame *wh; 1521165569Ssam const struct ieee80211_rateset *rs; 1522148315Ssam struct mbuf *m; 1523170530Ssam uint8_t *frm; 1524148315Ssam 1525178354Ssam if (vap->iv_state == IEEE80211_S_CAC) { 1526178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 1527178354Ssam "block %s frame in CAC state", "probe request"); 1528178354Ssam vap->iv_stats.is_tx_badstate++; 1529178354Ssam return EIO; /* XXX */ 1530178354Ssam } 1531178354Ssam 1532148315Ssam /* 1533148315Ssam * Hold a reference on the node so it doesn't go away until after 1534148315Ssam * the xmit is complete all the way in the driver. On error we 1535148315Ssam * will remove our reference. 1536148315Ssam */ 1537178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1538148315Ssam "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 1539148315Ssam __func__, __LINE__, 1540148315Ssam ni, ether_sprintf(ni->ni_macaddr), 1541148315Ssam ieee80211_node_refcnt(ni)+1); 1542148315Ssam ieee80211_ref_node(ni); 1543148315Ssam 1544148315Ssam /* 1545148315Ssam * prreq frame format 1546148315Ssam * [tlv] ssid 1547148315Ssam * [tlv] supported rates 1548178354Ssam * [tlv] RSN (optional) 1549148315Ssam * [tlv] extended supported rates 1550178354Ssam * [tlv] WPA (optional) 1551148315Ssam * [tlv] user-specified ie's 1552148315Ssam */ 1553148315Ssam m = ieee80211_getmgtframe(&frm, 1554170530Ssam ic->ic_headroom + sizeof(struct ieee80211_frame), 1555178354Ssam 2 + IEEE80211_NWID_LEN 1556148315Ssam + 2 + IEEE80211_RATE_SIZE 1557178354Ssam + sizeof(struct ieee80211_ie_wpa) 1558148315Ssam + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1559178354Ssam + sizeof(struct ieee80211_ie_wpa) 1560178354Ssam + (vap->iv_appie_probereq != NULL ? 1561178354Ssam vap->iv_appie_probereq->ie_len : 0) 1562148315Ssam ); 1563148315Ssam if (m == NULL) { 1564178354Ssam vap->iv_stats.is_tx_nobuf++; 1565148315Ssam ieee80211_free_node(ni); 1566148315Ssam return ENOMEM; 1567148315Ssam } 1568148315Ssam 1569148315Ssam frm = ieee80211_add_ssid(frm, ssid, ssidlen); 1570165569Ssam rs = ieee80211_get_suprates(ic, ic->ic_curchan); 1571165569Ssam frm = ieee80211_add_rates(frm, rs); 1572178354Ssam if (vap->iv_flags & IEEE80211_F_WPA2) { 1573178354Ssam if (vap->iv_rsn_ie != NULL) 1574178354Ssam frm = add_ie(frm, vap->iv_rsn_ie); 1575178354Ssam /* XXX else complain? */ 1576178354Ssam } 1577165569Ssam frm = ieee80211_add_xrates(frm, rs); 1578178354Ssam if (vap->iv_flags & IEEE80211_F_WPA1) { 1579178354Ssam if (vap->iv_wpa_ie != NULL) 1580178354Ssam frm = add_ie(frm, vap->iv_wpa_ie); 1581178354Ssam /* XXX else complain? */ 1582148315Ssam } 1583178354Ssam if (vap->iv_appie_probereq != NULL) 1584178354Ssam frm = add_appie(frm, vap->iv_appie_probereq); 1585170530Ssam m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 1586148315Ssam 1587184284Ssam KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), 1588184284Ssam ("leading space %zd", M_LEADINGSPACE(m))); 1589148315Ssam M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 1590184284Ssam if (m == NULL) { 1591184284Ssam /* NB: cannot happen */ 1592184284Ssam ieee80211_free_node(ni); 1593148315Ssam return ENOMEM; 1594184284Ssam } 1595148315Ssam 1596148315Ssam wh = mtod(m, struct ieee80211_frame *); 1597191544Ssam ieee80211_send_setup(ni, m, 1598184282Ssam IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 1599184282Ssam IEEE80211_NONQOS_TID, sa, da, bssid); 1600148315Ssam /* XXX power management? */ 1601184286Ssam m->m_flags |= M_ENCAP; /* mark encapsulated */ 1602148315Ssam 1603178354Ssam M_WME_SETAC(m, WME_AC_BE); 1604178354Ssam 1605148315Ssam IEEE80211_NODE_STAT(ni, tx_probereq); 1606148315Ssam IEEE80211_NODE_STAT(ni, tx_mgmt); 1607148315Ssam 1608178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 1609178354Ssam "send probe req on channel %u bssid %s ssid \"%.*s\"\n", 1610178354Ssam ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid), 1611178354Ssam ssidlen, ssid); 1612148315Ssam 1613184284Ssam memset(¶ms, 0, sizeof(params)); 1614184284Ssam params.ibp_pri = M_WME_GETAC(m); 1615184284Ssam tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 1616184284Ssam params.ibp_rate0 = tp->mgmtrate; 1617184284Ssam if (IEEE80211_IS_MULTICAST(da)) { 1618184284Ssam params.ibp_flags |= IEEE80211_BPF_NOACK; 1619184284Ssam params.ibp_try0 = 1; 1620184284Ssam } else 1621184284Ssam params.ibp_try0 = tp->maxretry; 1622184284Ssam params.ibp_power = ni->ni_txpower; 1623184284Ssam return ic->ic_raw_xmit(ni, m, ¶ms); 1624148315Ssam} 1625148315Ssam 1626148315Ssam/* 1627155999Ssam * Calculate capability information for mgt frames. 1628155999Ssam */ 1629170530Ssamstatic uint16_t 1630178354Ssamgetcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) 1631155999Ssam{ 1632178354Ssam struct ieee80211com *ic = vap->iv_ic; 1633170530Ssam uint16_t capinfo; 1634155999Ssam 1635178354Ssam KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); 1636155999Ssam 1637178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP) 1638155999Ssam capinfo = IEEE80211_CAPINFO_ESS; 1639178354Ssam else if (vap->iv_opmode == IEEE80211_M_IBSS) 1640155999Ssam capinfo = IEEE80211_CAPINFO_IBSS; 1641155999Ssam else 1642155999Ssam capinfo = 0; 1643178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) 1644155999Ssam capinfo |= IEEE80211_CAPINFO_PRIVACY; 1645155999Ssam if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 1646155999Ssam IEEE80211_IS_CHAN_2GHZ(chan)) 1647155999Ssam capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 1648155999Ssam if (ic->ic_flags & IEEE80211_F_SHSLOT) 1649155999Ssam capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 1650178354Ssam if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) 1651178354Ssam capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 1652155999Ssam return capinfo; 1653155999Ssam} 1654155999Ssam 1655155999Ssam/* 1656119150Ssam * Send a management frame. The node is for the destination (or ic_bss 1657119150Ssam * when in station mode). Nodes other than ic_bss have their reference 1658119150Ssam * count bumped to reflect our use for an indeterminant time. 1659119150Ssam */ 1660116742Ssamint 1661178354Ssamieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) 1662116742Ssam{ 1663173273Ssam#define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) 1664178354Ssam#define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) 1665178354Ssam struct ieee80211vap *vap = ni->ni_vap; 1666178354Ssam struct ieee80211com *ic = ni->ni_ic; 1667178354Ssam struct ieee80211_node *bss = vap->iv_bss; 1668184282Ssam struct ieee80211_bpf_params params; 1669116742Ssam struct mbuf *m; 1670170530Ssam uint8_t *frm; 1671170530Ssam uint16_t capinfo; 1672170530Ssam int has_challenge, is_shared_key, ret, status; 1673116742Ssam 1674119150Ssam KASSERT(ni != NULL, ("null node")); 1675119150Ssam 1676119150Ssam /* 1677119150Ssam * Hold a reference on the node so it doesn't go away until after 1678119150Ssam * the xmit is complete all the way in the driver. On error we 1679119150Ssam * will remove our reference. 1680119150Ssam */ 1681178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1682140766Ssam "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 1683138568Ssam __func__, __LINE__, 1684140766Ssam ni, ether_sprintf(ni->ni_macaddr), 1685140766Ssam ieee80211_node_refcnt(ni)+1); 1686138568Ssam ieee80211_ref_node(ni); 1687138568Ssam 1688184282Ssam memset(¶ms, 0, sizeof(params)); 1689116742Ssam switch (type) { 1690116742Ssam 1691116742Ssam case IEEE80211_FC0_SUBTYPE_AUTH: 1692138568Ssam status = arg >> 16; 1693138568Ssam arg &= 0xffff; 1694138568Ssam has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 1695138568Ssam arg == IEEE80211_AUTH_SHARED_RESPONSE) && 1696138568Ssam ni->ni_challenge != NULL); 1697138568Ssam 1698138568Ssam /* 1699138568Ssam * Deduce whether we're doing open authentication or 1700138568Ssam * shared key authentication. We do the latter if 1701138568Ssam * we're in the middle of a shared key authentication 1702138568Ssam * handshake or if we're initiating an authentication 1703138568Ssam * request and configured to use shared key. 1704138568Ssam */ 1705138568Ssam is_shared_key = has_challenge || 1706138568Ssam arg >= IEEE80211_AUTH_SHARED_RESPONSE || 1707138568Ssam (arg == IEEE80211_AUTH_SHARED_REQUEST && 1708178354Ssam bss->ni_authmode == IEEE80211_AUTH_SHARED); 1709138568Ssam 1710138568Ssam m = ieee80211_getmgtframe(&frm, 1711184282Ssam ic->ic_headroom + sizeof(struct ieee80211_frame), 1712170530Ssam 3 * sizeof(uint16_t) 1713138568Ssam + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 1714170530Ssam sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) 1715138568Ssam ); 1716116742Ssam if (m == NULL) 1717138568Ssam senderr(ENOMEM, is_tx_nobuf); 1718138568Ssam 1719170530Ssam ((uint16_t *)frm)[0] = 1720138568Ssam (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) 1721138568Ssam : htole16(IEEE80211_AUTH_ALG_OPEN); 1722170530Ssam ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ 1723170530Ssam ((uint16_t *)frm)[2] = htole16(status);/* status */ 1724138568Ssam 1725138568Ssam if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 1726170530Ssam ((uint16_t *)frm)[3] = 1727138568Ssam htole16((IEEE80211_CHALLENGE_LEN << 8) | 1728138568Ssam IEEE80211_ELEMID_CHALLENGE); 1729170530Ssam memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, 1730138568Ssam IEEE80211_CHALLENGE_LEN); 1731138568Ssam m->m_pkthdr.len = m->m_len = 1732170530Ssam 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; 1733138568Ssam if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { 1734178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1735178354Ssam "request encrypt frame (%s)", __func__); 1736184282Ssam /* mark frame for encryption */ 1737184282Ssam params.ibp_flags |= IEEE80211_BPF_CRYPTO; 1738138568Ssam } 1739138568Ssam } else 1740170530Ssam m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); 1741138568Ssam 1742138568Ssam /* XXX not right for shared key */ 1743138568Ssam if (status == IEEE80211_STATUS_SUCCESS) 1744138568Ssam IEEE80211_NODE_STAT(ni, tx_auth); 1745138568Ssam else 1746138568Ssam IEEE80211_NODE_STAT(ni, tx_auth_fail); 1747138568Ssam 1748178354Ssam if (vap->iv_opmode == IEEE80211_M_STA) 1749170530Ssam ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 1750178354Ssam (void *) vap->iv_state); 1751116742Ssam break; 1752116742Ssam 1753116742Ssam case IEEE80211_FC0_SUBTYPE_DEAUTH: 1754178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1755178354Ssam "send station deauthenticate (reason %d)", arg); 1756170530Ssam m = ieee80211_getmgtframe(&frm, 1757170530Ssam ic->ic_headroom + sizeof(struct ieee80211_frame), 1758170530Ssam sizeof(uint16_t)); 1759116742Ssam if (m == NULL) 1760138568Ssam senderr(ENOMEM, is_tx_nobuf); 1761170530Ssam *(uint16_t *)frm = htole16(arg); /* reason */ 1762170530Ssam m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 1763138568Ssam 1764138568Ssam IEEE80211_NODE_STAT(ni, tx_deauth); 1765138568Ssam IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); 1766138568Ssam 1767148302Ssam ieee80211_node_unauthorize(ni); /* port closed */ 1768116742Ssam break; 1769116742Ssam 1770116742Ssam case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 1771116742Ssam case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 1772116742Ssam /* 1773116742Ssam * asreq frame format 1774116742Ssam * [2] capability information 1775116742Ssam * [2] listen interval 1776116742Ssam * [6*] current AP address (reassoc only) 1777116742Ssam * [tlv] ssid 1778116742Ssam * [tlv] supported rates 1779116742Ssam * [tlv] extended supported rates 1780178354Ssam * [4] power capability (optional) 1781178354Ssam * [28] supported channels (optional) 1782170530Ssam * [tlv] HT capabilities 1783178354Ssam * [tlv] WME (optional) 1784170530Ssam * [tlv] Vendor OUI HT capabilities (optional) 1785170530Ssam * [tlv] Atheros capabilities (if negotiated) 1786178354Ssam * [tlv] AppIE's (optional) 1787116742Ssam */ 1788138568Ssam m = ieee80211_getmgtframe(&frm, 1789170530Ssam ic->ic_headroom + sizeof(struct ieee80211_frame), 1790170530Ssam sizeof(uint16_t) 1791170530Ssam + sizeof(uint16_t) 1792116742Ssam + IEEE80211_ADDR_LEN 1793138568Ssam + 2 + IEEE80211_NWID_LEN 1794116742Ssam + 2 + IEEE80211_RATE_SIZE 1795138568Ssam + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1796178354Ssam + 4 1797178354Ssam + 2 + 26 1798138568Ssam + sizeof(struct ieee80211_wme_info) 1799178354Ssam + sizeof(struct ieee80211_ie_htcap) 1800178354Ssam + 4 + sizeof(struct ieee80211_ie_htcap) 1801190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1802170530Ssam + sizeof(struct ieee80211_ath_ie) 1803190391Ssam#endif 1804178354Ssam + (vap->iv_appie_wpa != NULL ? 1805178354Ssam vap->iv_appie_wpa->ie_len : 0) 1806178354Ssam + (vap->iv_appie_assocreq != NULL ? 1807178354Ssam vap->iv_appie_assocreq->ie_len : 0) 1808138568Ssam ); 1809116742Ssam if (m == NULL) 1810138568Ssam senderr(ENOMEM, is_tx_nobuf); 1811116742Ssam 1812178354Ssam KASSERT(vap->iv_opmode == IEEE80211_M_STA, 1813178354Ssam ("wrong mode %u", vap->iv_opmode)); 1814155999Ssam capinfo = IEEE80211_CAPINFO_ESS; 1815178354Ssam if (vap->iv_flags & IEEE80211_F_PRIVACY) 1816116742Ssam capinfo |= IEEE80211_CAPINFO_PRIVACY; 1817120070Ssam /* 1818120070Ssam * NB: Some 11a AP's reject the request when 1819120070Ssam * short premable is set. 1820120070Ssam */ 1821120070Ssam if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 1822148936Ssam IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 1823116742Ssam capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 1824170530Ssam if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 1825138568Ssam (ic->ic_caps & IEEE80211_C_SHSLOT)) 1826116742Ssam capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 1827173273Ssam if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && 1828178354Ssam (vap->iv_flags & IEEE80211_F_DOTH)) 1829173273Ssam capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 1830170530Ssam *(uint16_t *)frm = htole16(capinfo); 1831116742Ssam frm += 2; 1832116742Ssam 1833178354Ssam KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); 1834170530Ssam *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, 1835178354Ssam bss->ni_intval)); 1836116742Ssam frm += 2; 1837116742Ssam 1838116742Ssam if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 1839178354Ssam IEEE80211_ADDR_COPY(frm, bss->ni_bssid); 1840116742Ssam frm += IEEE80211_ADDR_LEN; 1841116742Ssam } 1842116742Ssam 1843116742Ssam frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 1844116742Ssam frm = ieee80211_add_rates(frm, &ni->ni_rates); 1845178354Ssam if (vap->iv_flags & IEEE80211_F_WPA2) { 1846178354Ssam if (vap->iv_rsn_ie != NULL) 1847178354Ssam frm = add_ie(frm, vap->iv_rsn_ie); 1848178354Ssam /* XXX else complain? */ 1849178354Ssam } 1850116742Ssam frm = ieee80211_add_xrates(frm, &ni->ni_rates); 1851178354Ssam if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { 1852178354Ssam frm = ieee80211_add_powercapability(frm, 1853178354Ssam ic->ic_curchan); 1854178354Ssam frm = ieee80211_add_supportedchannels(frm, ic); 1855178354Ssam } 1856193655Ssam if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 1857178354Ssam ni->ni_ies.htcap_ie != NULL && 1858178354Ssam ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 1859173273Ssam frm = ieee80211_add_htcap(frm, ni); 1860178354Ssam if (vap->iv_flags & IEEE80211_F_WPA1) { 1861178354Ssam if (vap->iv_wpa_ie != NULL) 1862178354Ssam frm = add_ie(frm, vap->iv_wpa_ie); 1863178354Ssam /* XXX else complain */ 1864178354Ssam } 1865178354Ssam if ((ic->ic_flags & IEEE80211_F_WME) && 1866178354Ssam ni->ni_ies.wme_ie != NULL) 1867138568Ssam frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 1868193655Ssam if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 1869178354Ssam ni->ni_ies.htcap_ie != NULL && 1870178354Ssam ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 1871173273Ssam frm = ieee80211_add_htcap_vendor(frm, ni); 1872190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1873190451Ssam if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { 1874190451Ssam frm = ieee80211_add_ath(frm, 1875178354Ssam IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 1876190451Ssam ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 1877190451Ssam ni->ni_authmode != IEEE80211_AUTH_8021X) ? 1878190451Ssam vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 1879190451Ssam } 1880190391Ssam#endif /* IEEE80211_SUPPORT_SUPERG */ 1881178354Ssam if (vap->iv_appie_assocreq != NULL) 1882178354Ssam frm = add_appie(frm, vap->iv_appie_assocreq); 1883170530Ssam m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 1884116742Ssam 1885170530Ssam ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 1886178354Ssam (void *) vap->iv_state); 1887116742Ssam break; 1888116742Ssam 1889116742Ssam case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 1890116742Ssam case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 1891116742Ssam /* 1892170530Ssam * asresp frame format 1893116742Ssam * [2] capability information 1894116742Ssam * [2] status 1895116742Ssam * [2] association ID 1896116742Ssam * [tlv] supported rates 1897116742Ssam * [tlv] extended supported rates 1898178354Ssam * [tlv] HT capabilities (standard, if STA enabled) 1899178354Ssam * [tlv] HT information (standard, if STA enabled) 1900178354Ssam * [tlv] WME (if configured and STA enabled) 1901178354Ssam * [tlv] HT capabilities (vendor OUI, if STA enabled) 1902178354Ssam * [tlv] HT information (vendor OUI, if STA enabled) 1903178354Ssam * [tlv] Atheros capabilities (if STA enabled) 1904178354Ssam * [tlv] AppIE's (optional) 1905116742Ssam */ 1906138568Ssam m = ieee80211_getmgtframe(&frm, 1907170530Ssam ic->ic_headroom + sizeof(struct ieee80211_frame), 1908170530Ssam sizeof(uint16_t) 1909170530Ssam + sizeof(uint16_t) 1910170530Ssam + sizeof(uint16_t) 1911116742Ssam + 2 + IEEE80211_RATE_SIZE 1912138568Ssam + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1913170530Ssam + sizeof(struct ieee80211_ie_htcap) + 4 1914170530Ssam + sizeof(struct ieee80211_ie_htinfo) + 4 1915178354Ssam + sizeof(struct ieee80211_wme_param) 1916190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1917170530Ssam + sizeof(struct ieee80211_ath_ie) 1918190391Ssam#endif 1919178354Ssam + (vap->iv_appie_assocresp != NULL ? 1920178354Ssam vap->iv_appie_assocresp->ie_len : 0) 1921138568Ssam ); 1922116742Ssam if (m == NULL) 1923138568Ssam senderr(ENOMEM, is_tx_nobuf); 1924116742Ssam 1925178354Ssam capinfo = getcapinfo(vap, bss->ni_chan); 1926170530Ssam *(uint16_t *)frm = htole16(capinfo); 1927116742Ssam frm += 2; 1928116742Ssam 1929170530Ssam *(uint16_t *)frm = htole16(arg); /* status */ 1930116742Ssam frm += 2; 1931116742Ssam 1932138568Ssam if (arg == IEEE80211_STATUS_SUCCESS) { 1933170530Ssam *(uint16_t *)frm = htole16(ni->ni_associd); 1934138568Ssam IEEE80211_NODE_STAT(ni, tx_assoc); 1935138568Ssam } else 1936138568Ssam IEEE80211_NODE_STAT(ni, tx_assoc_fail); 1937116742Ssam frm += 2; 1938116742Ssam 1939119150Ssam frm = ieee80211_add_rates(frm, &ni->ni_rates); 1940119150Ssam frm = ieee80211_add_xrates(frm, &ni->ni_rates); 1941173273Ssam /* NB: respond according to what we received */ 1942173273Ssam if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { 1943173273Ssam frm = ieee80211_add_htcap(frm, ni); 1944173273Ssam frm = ieee80211_add_htinfo(frm, ni); 1945173273Ssam } 1946178354Ssam if ((vap->iv_flags & IEEE80211_F_WME) && 1947178354Ssam ni->ni_ies.wme_ie != NULL) 1948138568Ssam frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 1949173273Ssam if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { 1950173273Ssam frm = ieee80211_add_htcap_vendor(frm, ni); 1951173273Ssam frm = ieee80211_add_htinfo_vendor(frm, ni); 1952170530Ssam } 1953190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 1954178354Ssam if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 1955190451Ssam frm = ieee80211_add_ath(frm, 1956178354Ssam IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 1957190451Ssam ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 1958190451Ssam ni->ni_authmode != IEEE80211_AUTH_8021X) ? 1959190451Ssam vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 1960190391Ssam#endif /* IEEE80211_SUPPORT_SUPERG */ 1961178354Ssam if (vap->iv_appie_assocresp != NULL) 1962178354Ssam frm = add_appie(frm, vap->iv_appie_assocresp); 1963170530Ssam m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 1964116742Ssam break; 1965116742Ssam 1966116742Ssam case IEEE80211_FC0_SUBTYPE_DISASSOC: 1967178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 1968178354Ssam "send station disassociate (reason %d)", arg); 1969170530Ssam m = ieee80211_getmgtframe(&frm, 1970170530Ssam ic->ic_headroom + sizeof(struct ieee80211_frame), 1971170530Ssam sizeof(uint16_t)); 1972116742Ssam if (m == NULL) 1973138568Ssam senderr(ENOMEM, is_tx_nobuf); 1974170530Ssam *(uint16_t *)frm = htole16(arg); /* reason */ 1975170530Ssam m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 1976138568Ssam 1977138568Ssam IEEE80211_NODE_STAT(ni, tx_disassoc); 1978138568Ssam IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); 1979116742Ssam break; 1980116742Ssam 1981116742Ssam default: 1982178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 1983178354Ssam "invalid mgmt frame type %u", type); 1984121180Ssam senderr(EINVAL, is_tx_unknownmgt); 1985119150Ssam /* NOTREACHED */ 1986116742Ssam } 1987170530Ssam 1988184282Ssam /* NB: force non-ProbeResp frames to the highest queue */ 1989184282Ssam params.ibp_pri = WME_AC_VO; 1990184282Ssam params.ibp_rate0 = bss->ni_txparms->mgmtrate; 1991184282Ssam /* NB: we know all frames are unicast */ 1992184282Ssam params.ibp_try0 = bss->ni_txparms->maxretry; 1993184282Ssam params.ibp_power = bss->ni_txpower; 1994184282Ssam return ieee80211_mgmt_output(ni, m, type, ¶ms); 1995119150Ssambad: 1996170530Ssam ieee80211_free_node(ni); 1997116742Ssam return ret; 1998119150Ssam#undef senderr 1999173273Ssam#undef HTFLAGS 2000116742Ssam} 2001138568Ssam 2002178354Ssam/* 2003178354Ssam * Return an mbuf with a probe response frame in it. 2004178354Ssam * Space is left to prepend and 802.11 header at the 2005178354Ssam * front but it's left to the caller to fill in. 2006178354Ssam */ 2007178354Ssamstruct mbuf * 2008178354Ssamieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) 2009178354Ssam{ 2010178354Ssam struct ieee80211vap *vap = bss->ni_vap; 2011178354Ssam struct ieee80211com *ic = bss->ni_ic; 2012178354Ssam const struct ieee80211_rateset *rs; 2013178354Ssam struct mbuf *m; 2014178354Ssam uint16_t capinfo; 2015178354Ssam uint8_t *frm; 2016178354Ssam 2017178354Ssam /* 2018178354Ssam * probe response frame format 2019178354Ssam * [8] time stamp 2020178354Ssam * [2] beacon interval 2021178354Ssam * [2] cabability information 2022178354Ssam * [tlv] ssid 2023178354Ssam * [tlv] supported rates 2024178354Ssam * [tlv] parameter set (FH/DS) 2025178354Ssam * [tlv] parameter set (IBSS) 2026178354Ssam * [tlv] country (optional) 2027178354Ssam * [3] power control (optional) 2028178354Ssam * [5] channel switch announcement (CSA) (optional) 2029178354Ssam * [tlv] extended rate phy (ERP) 2030178354Ssam * [tlv] extended supported rates 2031180351Ssam * [tlv] RSN (optional) 2032178354Ssam * [tlv] HT capabilities 2033178354Ssam * [tlv] HT information 2034178354Ssam * [tlv] WPA (optional) 2035178354Ssam * [tlv] WME (optional) 2036178354Ssam * [tlv] Vendor OUI HT capabilities (optional) 2037178354Ssam * [tlv] Vendor OUI HT information (optional) 2038178354Ssam * [tlv] Atheros capabilities 2039178354Ssam * [tlv] AppIE's (optional) 2040178354Ssam */ 2041178354Ssam m = ieee80211_getmgtframe(&frm, 2042178354Ssam ic->ic_headroom + sizeof(struct ieee80211_frame), 2043178354Ssam 8 2044178354Ssam + sizeof(uint16_t) 2045178354Ssam + sizeof(uint16_t) 2046178354Ssam + 2 + IEEE80211_NWID_LEN 2047178354Ssam + 2 + IEEE80211_RATE_SIZE 2048178354Ssam + 7 /* max(7,3) */ 2049178354Ssam + IEEE80211_COUNTRY_MAX_SIZE 2050178354Ssam + 3 2051178354Ssam + sizeof(struct ieee80211_csa_ie) 2052178354Ssam + 3 2053178354Ssam + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2054180351Ssam + sizeof(struct ieee80211_ie_wpa) 2055178354Ssam + sizeof(struct ieee80211_ie_htcap) 2056178354Ssam + sizeof(struct ieee80211_ie_htinfo) 2057178354Ssam + sizeof(struct ieee80211_ie_wpa) 2058178354Ssam + sizeof(struct ieee80211_wme_param) 2059178354Ssam + 4 + sizeof(struct ieee80211_ie_htcap) 2060178354Ssam + 4 + sizeof(struct ieee80211_ie_htinfo) 2061190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 2062178354Ssam + sizeof(struct ieee80211_ath_ie) 2063190391Ssam#endif 2064178354Ssam + (vap->iv_appie_proberesp != NULL ? 2065178354Ssam vap->iv_appie_proberesp->ie_len : 0) 2066178354Ssam ); 2067178354Ssam if (m == NULL) { 2068178354Ssam vap->iv_stats.is_tx_nobuf++; 2069178354Ssam return NULL; 2070178354Ssam } 2071178354Ssam 2072178354Ssam memset(frm, 0, 8); /* timestamp should be filled later */ 2073178354Ssam frm += 8; 2074178354Ssam *(uint16_t *)frm = htole16(bss->ni_intval); 2075178354Ssam frm += 2; 2076178354Ssam capinfo = getcapinfo(vap, bss->ni_chan); 2077178354Ssam *(uint16_t *)frm = htole16(capinfo); 2078178354Ssam frm += 2; 2079178354Ssam 2080178354Ssam frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); 2081178354Ssam rs = ieee80211_get_suprates(ic, bss->ni_chan); 2082178354Ssam frm = ieee80211_add_rates(frm, rs); 2083178354Ssam 2084178354Ssam if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { 2085178354Ssam *frm++ = IEEE80211_ELEMID_FHPARMS; 2086178354Ssam *frm++ = 5; 2087178354Ssam *frm++ = bss->ni_fhdwell & 0x00ff; 2088178354Ssam *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; 2089178354Ssam *frm++ = IEEE80211_FH_CHANSET( 2090178354Ssam ieee80211_chan2ieee(ic, bss->ni_chan)); 2091178354Ssam *frm++ = IEEE80211_FH_CHANPAT( 2092178354Ssam ieee80211_chan2ieee(ic, bss->ni_chan)); 2093178354Ssam *frm++ = bss->ni_fhindex; 2094178354Ssam } else { 2095178354Ssam *frm++ = IEEE80211_ELEMID_DSPARMS; 2096178354Ssam *frm++ = 1; 2097178354Ssam *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); 2098178354Ssam } 2099178354Ssam 2100178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS) { 2101178354Ssam *frm++ = IEEE80211_ELEMID_IBSSPARMS; 2102178354Ssam *frm++ = 2; 2103178354Ssam *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 2104178354Ssam } 2105178354Ssam if ((vap->iv_flags & IEEE80211_F_DOTH) || 2106178354Ssam (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2107178354Ssam frm = ieee80211_add_countryie(frm, ic); 2108178354Ssam if (vap->iv_flags & IEEE80211_F_DOTH) { 2109178354Ssam if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) 2110178354Ssam frm = ieee80211_add_powerconstraint(frm, vap); 2111178354Ssam if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2112178354Ssam frm = ieee80211_add_csa(frm, vap); 2113178354Ssam } 2114178354Ssam if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) 2115178354Ssam frm = ieee80211_add_erp(frm, ic); 2116178354Ssam frm = ieee80211_add_xrates(frm, rs); 2117180351Ssam if (vap->iv_flags & IEEE80211_F_WPA2) { 2118180351Ssam if (vap->iv_rsn_ie != NULL) 2119180351Ssam frm = add_ie(frm, vap->iv_rsn_ie); 2120180351Ssam /* XXX else complain? */ 2121180351Ssam } 2122178354Ssam /* 2123178354Ssam * NB: legacy 11b clients do not get certain ie's. 2124178354Ssam * The caller identifies such clients by passing 2125178354Ssam * a token in legacy to us. Could expand this to be 2126178354Ssam * any legacy client for stuff like HT ie's. 2127178354Ssam */ 2128178354Ssam if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 2129178354Ssam legacy != IEEE80211_SEND_LEGACY_11B) { 2130178354Ssam frm = ieee80211_add_htcap(frm, bss); 2131178354Ssam frm = ieee80211_add_htinfo(frm, bss); 2132178354Ssam } 2133178354Ssam if (vap->iv_flags & IEEE80211_F_WPA1) { 2134178354Ssam if (vap->iv_wpa_ie != NULL) 2135178354Ssam frm = add_ie(frm, vap->iv_wpa_ie); 2136178354Ssam /* XXX else complain? */ 2137178354Ssam } 2138178354Ssam if (vap->iv_flags & IEEE80211_F_WME) 2139178354Ssam frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 2140178354Ssam if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 2141193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) && 2142178354Ssam legacy != IEEE80211_SEND_LEGACY_11B) { 2143178354Ssam frm = ieee80211_add_htcap_vendor(frm, bss); 2144178354Ssam frm = ieee80211_add_htinfo_vendor(frm, bss); 2145178354Ssam } 2146190391Ssam#ifdef IEEE80211_SUPPORT_SUPERG 2147190451Ssam if ((vap->iv_flags & IEEE80211_F_ATHEROS) && 2148190451Ssam legacy != IEEE80211_SEND_LEGACY_11B) 2149190451Ssam frm = ieee80211_add_athcaps(frm, bss); 2150190391Ssam#endif 2151178354Ssam if (vap->iv_appie_proberesp != NULL) 2152178354Ssam frm = add_appie(frm, vap->iv_appie_proberesp); 2153178354Ssam m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2154178354Ssam 2155178354Ssam return m; 2156178354Ssam} 2157178354Ssam 2158178354Ssam/* 2159178354Ssam * Send a probe response frame to the specified mac address. 2160178354Ssam * This does not go through the normal mgt frame api so we 2161178354Ssam * can specify the destination address and re-use the bss node 2162178354Ssam * for the sta reference. 2163178354Ssam */ 2164178354Ssamint 2165178354Ssamieee80211_send_proberesp(struct ieee80211vap *vap, 2166178354Ssam const uint8_t da[IEEE80211_ADDR_LEN], int legacy) 2167178354Ssam{ 2168178354Ssam struct ieee80211_node *bss = vap->iv_bss; 2169178354Ssam struct ieee80211com *ic = vap->iv_ic; 2170178354Ssam struct ieee80211_frame *wh; 2171178354Ssam struct mbuf *m; 2172178354Ssam 2173178354Ssam if (vap->iv_state == IEEE80211_S_CAC) { 2174178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, 2175178354Ssam "block %s frame in CAC state", "probe response"); 2176178354Ssam vap->iv_stats.is_tx_badstate++; 2177178354Ssam return EIO; /* XXX */ 2178178354Ssam } 2179178354Ssam 2180178354Ssam /* 2181178354Ssam * Hold a reference on the node so it doesn't go away until after 2182178354Ssam * the xmit is complete all the way in the driver. On error we 2183178354Ssam * will remove our reference. 2184178354Ssam */ 2185178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 2186178354Ssam "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2187178354Ssam __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), 2188178354Ssam ieee80211_node_refcnt(bss)+1); 2189178354Ssam ieee80211_ref_node(bss); 2190178354Ssam 2191178354Ssam m = ieee80211_alloc_proberesp(bss, legacy); 2192178354Ssam if (m == NULL) { 2193178354Ssam ieee80211_free_node(bss); 2194178354Ssam return ENOMEM; 2195178354Ssam } 2196178354Ssam 2197178354Ssam M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 2198178354Ssam KASSERT(m != NULL, ("no room for header")); 2199178354Ssam 2200178354Ssam wh = mtod(m, struct ieee80211_frame *); 2201191544Ssam ieee80211_send_setup(bss, m, 2202184282Ssam IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, 2203184282Ssam IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); 2204178354Ssam /* XXX power management? */ 2205184286Ssam m->m_flags |= M_ENCAP; /* mark encapsulated */ 2206178354Ssam 2207178354Ssam M_WME_SETAC(m, WME_AC_BE); 2208178354Ssam 2209178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 2210178354Ssam "send probe resp on channel %u to %s%s\n", 2211178354Ssam ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), 2212178354Ssam legacy ? " <legacy>" : ""); 2213178354Ssam IEEE80211_NODE_STAT(bss, tx_mgmt); 2214178354Ssam 2215178354Ssam return ic->ic_raw_xmit(bss, m, NULL); 2216178354Ssam} 2217178354Ssam 2218178354Ssam/* 2219178354Ssam * Allocate and build a RTS (Request To Send) control frame. 2220178354Ssam */ 2221178354Ssamstruct mbuf * 2222178354Ssamieee80211_alloc_rts(struct ieee80211com *ic, 2223178354Ssam const uint8_t ra[IEEE80211_ADDR_LEN], 2224178354Ssam const uint8_t ta[IEEE80211_ADDR_LEN], 2225178354Ssam uint16_t dur) 2226178354Ssam{ 2227178354Ssam struct ieee80211_frame_rts *rts; 2228178354Ssam struct mbuf *m; 2229178354Ssam 2230178354Ssam /* XXX honor ic_headroom */ 2231178354Ssam m = m_gethdr(M_DONTWAIT, MT_DATA); 2232178354Ssam if (m != NULL) { 2233178354Ssam rts = mtod(m, struct ieee80211_frame_rts *); 2234178354Ssam rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2235178354Ssam IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; 2236178354Ssam rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2237178354Ssam *(u_int16_t *)rts->i_dur = htole16(dur); 2238178354Ssam IEEE80211_ADDR_COPY(rts->i_ra, ra); 2239178354Ssam IEEE80211_ADDR_COPY(rts->i_ta, ta); 2240178354Ssam 2241178354Ssam m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); 2242178354Ssam } 2243178354Ssam return m; 2244178354Ssam} 2245178354Ssam 2246178354Ssam/* 2247178354Ssam * Allocate and build a CTS (Clear To Send) control frame. 2248178354Ssam */ 2249178354Ssamstruct mbuf * 2250178354Ssamieee80211_alloc_cts(struct ieee80211com *ic, 2251178354Ssam const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) 2252178354Ssam{ 2253178354Ssam struct ieee80211_frame_cts *cts; 2254178354Ssam struct mbuf *m; 2255178354Ssam 2256178354Ssam /* XXX honor ic_headroom */ 2257178354Ssam m = m_gethdr(M_DONTWAIT, MT_DATA); 2258178354Ssam if (m != NULL) { 2259178354Ssam cts = mtod(m, struct ieee80211_frame_cts *); 2260178354Ssam cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2261178354Ssam IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; 2262178354Ssam cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2263178354Ssam *(u_int16_t *)cts->i_dur = htole16(dur); 2264178354Ssam IEEE80211_ADDR_COPY(cts->i_ra, ra); 2265178354Ssam 2266178354Ssam m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); 2267178354Ssam } 2268178354Ssam return m; 2269178354Ssam} 2270178354Ssam 2271170530Ssamstatic void 2272170530Ssamieee80211_tx_mgt_timeout(void *arg) 2273170530Ssam{ 2274170530Ssam struct ieee80211_node *ni = arg; 2275178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2276170530Ssam 2277178354Ssam if (vap->iv_state != IEEE80211_S_INIT && 2278178354Ssam (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { 2279170530Ssam /* 2280170530Ssam * NB: it's safe to specify a timeout as the reason here; 2281170530Ssam * it'll only be used in the right state. 2282170530Ssam */ 2283178354Ssam ieee80211_new_state(vap, IEEE80211_S_SCAN, 2284170530Ssam IEEE80211_SCAN_FAIL_TIMEOUT); 2285170530Ssam } 2286170530Ssam} 2287170530Ssam 2288170530Ssamstatic void 2289170530Ssamieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) 2290170530Ssam{ 2291178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2292170530Ssam enum ieee80211_state ostate = (enum ieee80211_state) arg; 2293170530Ssam 2294170530Ssam /* 2295170530Ssam * Frame transmit completed; arrange timer callback. If 2296170530Ssam * transmit was successfuly we wait for response. Otherwise 2297170530Ssam * we arrange an immediate callback instead of doing the 2298170530Ssam * callback directly since we don't know what state the driver 2299170530Ssam * is in (e.g. what locks it is holding). This work should 2300170530Ssam * not be too time-critical and not happen too often so the 2301170530Ssam * added overhead is acceptable. 2302170530Ssam * 2303170530Ssam * XXX what happens if !acked but response shows up before callback? 2304170530Ssam */ 2305178354Ssam if (vap->iv_state == ostate) 2306178354Ssam callout_reset(&vap->iv_mgtsend, 2307170530Ssam status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, 2308170530Ssam ieee80211_tx_mgt_timeout, ni); 2309170530Ssam} 2310170530Ssam 2311178354Ssamstatic void 2312178354Ssamieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, 2313178354Ssam struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni) 2314138568Ssam{ 2315178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2316172211Ssam struct ieee80211com *ic = ni->ni_ic; 2317178354Ssam struct ieee80211_rateset *rs = &ni->ni_rates; 2318170530Ssam uint16_t capinfo; 2319138568Ssam 2320138568Ssam /* 2321138568Ssam * beacon frame format 2322138568Ssam * [8] time stamp 2323138568Ssam * [2] beacon interval 2324138568Ssam * [2] cabability information 2325138568Ssam * [tlv] ssid 2326138568Ssam * [tlv] supported rates 2327138568Ssam * [3] parameter set (DS) 2328178354Ssam * [8] CF parameter set (optional) 2329138568Ssam * [tlv] parameter set (IBSS/TIM) 2330178354Ssam * [tlv] country (optional) 2331178354Ssam * [3] power control (optional) 2332178354Ssam * [5] channel switch announcement (CSA) (optional) 2333138568Ssam * [tlv] extended rate phy (ERP) 2334138568Ssam * [tlv] extended supported rates 2335180351Ssam * [tlv] RSN parameters 2336170530Ssam * [tlv] HT capabilities 2337170530Ssam * [tlv] HT information 2338178354Ssam * XXX Vendor-specific OIDs (e.g. Atheros) 2339178354Ssam * [tlv] WPA parameters 2340178354Ssam * [tlv] WME parameters 2341170530Ssam * [tlv] Vendor OUI HT capabilities (optional) 2342170530Ssam * [tlv] Vendor OUI HT information (optional) 2343190451Ssam * [tlv] Atheros capabilities (optional) 2344186904Ssam * [tlv] TDMA parameters (optional) 2345178354Ssam * [tlv] application data (optional) 2346138568Ssam */ 2347138568Ssam 2348173273Ssam memset(bo, 0, sizeof(*bo)); 2349173273Ssam 2350138568Ssam memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ 2351138568Ssam frm += 8; 2352170530Ssam *(uint16_t *)frm = htole16(ni->ni_intval); 2353138568Ssam frm += 2; 2354178354Ssam capinfo = getcapinfo(vap, ni->ni_chan); 2355170530Ssam bo->bo_caps = (uint16_t *)frm; 2356170530Ssam *(uint16_t *)frm = htole16(capinfo); 2357138568Ssam frm += 2; 2358138568Ssam *frm++ = IEEE80211_ELEMID_SSID; 2359178354Ssam if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { 2360138568Ssam *frm++ = ni->ni_esslen; 2361138568Ssam memcpy(frm, ni->ni_essid, ni->ni_esslen); 2362138568Ssam frm += ni->ni_esslen; 2363138568Ssam } else 2364138568Ssam *frm++ = 0; 2365138568Ssam frm = ieee80211_add_rates(frm, rs); 2366178354Ssam if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { 2367138568Ssam *frm++ = IEEE80211_ELEMID_DSPARMS; 2368138568Ssam *frm++ = 1; 2369178354Ssam *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); 2370138568Ssam } 2371178354Ssam if (ic->ic_flags & IEEE80211_F_PCF) { 2372178354Ssam bo->bo_cfp = frm; 2373178354Ssam frm = ieee80211_add_cfparms(frm, ic); 2374178354Ssam } 2375138568Ssam bo->bo_tim = frm; 2376178354Ssam if (vap->iv_opmode == IEEE80211_M_IBSS) { 2377138568Ssam *frm++ = IEEE80211_ELEMID_IBSSPARMS; 2378138568Ssam *frm++ = 2; 2379138568Ssam *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 2380138568Ssam bo->bo_tim_len = 0; 2381178354Ssam } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 2382138568Ssam struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; 2383138568Ssam 2384138568Ssam tie->tim_ie = IEEE80211_ELEMID_TIM; 2385138568Ssam tie->tim_len = 4; /* length */ 2386138568Ssam tie->tim_count = 0; /* DTIM count */ 2387178354Ssam tie->tim_period = vap->iv_dtim_period; /* DTIM period */ 2388138568Ssam tie->tim_bitctl = 0; /* bitmap control */ 2389138568Ssam tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 2390138568Ssam frm += sizeof(struct ieee80211_tim_ie); 2391138568Ssam bo->bo_tim_len = 1; 2392138568Ssam } 2393172211Ssam bo->bo_tim_trailer = frm; 2394178354Ssam if ((vap->iv_flags & IEEE80211_F_DOTH) || 2395178354Ssam (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2396178354Ssam frm = ieee80211_add_countryie(frm, ic); 2397178354Ssam if (vap->iv_flags & IEEE80211_F_DOTH) { 2398178354Ssam if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 2399178354Ssam frm = ieee80211_add_powerconstraint(frm, vap); 2400178354Ssam bo->bo_csa = frm; 2401178354Ssam if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2402178354Ssam frm = ieee80211_add_csa(frm, vap); 2403178354Ssam } else 2404178354Ssam bo->bo_csa = frm; 2405178354Ssam if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { 2406153973Ssam bo->bo_erp = frm; 2407138568Ssam frm = ieee80211_add_erp(frm, ic); 2408173273Ssam } 2409170530Ssam frm = ieee80211_add_xrates(frm, rs); 2410180351Ssam if (vap->iv_flags & IEEE80211_F_WPA2) { 2411180351Ssam if (vap->iv_rsn_ie != NULL) 2412180351Ssam frm = add_ie(frm, vap->iv_rsn_ie); 2413180351Ssam /* XXX else complain */ 2414180351Ssam } 2415178354Ssam if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { 2416170530Ssam frm = ieee80211_add_htcap(frm, ni); 2417170530Ssam bo->bo_htinfo = frm; 2418170530Ssam frm = ieee80211_add_htinfo(frm, ni); 2419173273Ssam } 2420178354Ssam if (vap->iv_flags & IEEE80211_F_WPA1) { 2421178354Ssam if (vap->iv_wpa_ie != NULL) 2422178354Ssam frm = add_ie(frm, vap->iv_wpa_ie); 2423178354Ssam /* XXX else complain */ 2424178354Ssam } 2425178354Ssam if (vap->iv_flags & IEEE80211_F_WME) { 2426173273Ssam bo->bo_wme = frm; 2427173273Ssam frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 2428173273Ssam } 2429178354Ssam if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && 2430193655Ssam (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) { 2431173273Ssam frm = ieee80211_add_htcap_vendor(frm, ni); 2432173273Ssam frm = ieee80211_add_htinfo_vendor(frm, ni); 2433173273Ssam } 2434190451Ssam#ifdef IEEE80211_SUPPORT_SUPERG 2435190451Ssam if (vap->iv_flags & IEEE80211_F_ATHEROS) { 2436190451Ssam bo->bo_ath = frm; 2437190451Ssam frm = ieee80211_add_athcaps(frm, ni); 2438190451Ssam } 2439190451Ssam#endif 2440186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 2441186904Ssam if (vap->iv_caps & IEEE80211_C_TDMA) { 2442186904Ssam bo->bo_tdma = frm; 2443186904Ssam frm = ieee80211_add_tdma(frm, vap); 2444186904Ssam } 2445186904Ssam#endif 2446178354Ssam if (vap->iv_appie_beacon != NULL) { 2447178354Ssam bo->bo_appie = frm; 2448178354Ssam bo->bo_appie_len = vap->iv_appie_beacon->ie_len; 2449178354Ssam frm = add_appie(frm, vap->iv_appie_beacon); 2450178354Ssam } 2451172211Ssam bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; 2452178354Ssam bo->bo_csa_trailer_len = frm - bo->bo_csa; 2453170530Ssam m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2454178354Ssam} 2455138568Ssam 2456178354Ssam/* 2457178354Ssam * Allocate a beacon frame and fillin the appropriate bits. 2458178354Ssam */ 2459178354Ssamstruct mbuf * 2460178354Ssamieee80211_beacon_alloc(struct ieee80211_node *ni, 2461178354Ssam struct ieee80211_beacon_offsets *bo) 2462178354Ssam{ 2463178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2464178354Ssam struct ieee80211com *ic = ni->ni_ic; 2465178354Ssam struct ifnet *ifp = vap->iv_ifp; 2466178354Ssam struct ieee80211_frame *wh; 2467178354Ssam struct mbuf *m; 2468178354Ssam int pktlen; 2469178354Ssam uint8_t *frm; 2470178354Ssam 2471178354Ssam /* 2472178354Ssam * beacon frame format 2473178354Ssam * [8] time stamp 2474178354Ssam * [2] beacon interval 2475178354Ssam * [2] cabability information 2476178354Ssam * [tlv] ssid 2477178354Ssam * [tlv] supported rates 2478178354Ssam * [3] parameter set (DS) 2479178354Ssam * [8] CF parameter set (optional) 2480178354Ssam * [tlv] parameter set (IBSS/TIM) 2481178354Ssam * [tlv] country (optional) 2482178354Ssam * [3] power control (optional) 2483178354Ssam * [5] channel switch announcement (CSA) (optional) 2484178354Ssam * [tlv] extended rate phy (ERP) 2485178354Ssam * [tlv] extended supported rates 2486178354Ssam * [tlv] RSN parameters 2487178354Ssam * [tlv] HT capabilities 2488178354Ssam * [tlv] HT information 2489178354Ssam * [tlv] Vendor OUI HT capabilities (optional) 2490178354Ssam * [tlv] Vendor OUI HT information (optional) 2491178354Ssam * XXX Vendor-specific OIDs (e.g. Atheros) 2492178354Ssam * [tlv] WPA parameters 2493178354Ssam * [tlv] WME parameters 2494186904Ssam * [tlv] TDMA parameters (optional) 2495178354Ssam * [tlv] application data (optional) 2496178354Ssam * NB: we allocate the max space required for the TIM bitmap. 2497178354Ssam * XXX how big is this? 2498178354Ssam */ 2499178354Ssam pktlen = 8 /* time stamp */ 2500178354Ssam + sizeof(uint16_t) /* beacon interval */ 2501178354Ssam + sizeof(uint16_t) /* capabilities */ 2502178354Ssam + 2 + ni->ni_esslen /* ssid */ 2503178354Ssam + 2 + IEEE80211_RATE_SIZE /* supported rates */ 2504178354Ssam + 2 + 1 /* DS parameters */ 2505178354Ssam + 2 + 6 /* CF parameters */ 2506178354Ssam + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ 2507178354Ssam + IEEE80211_COUNTRY_MAX_SIZE /* country */ 2508178354Ssam + 2 + 1 /* power control */ 2509178354Ssam + sizeof(struct ieee80211_csa_ie) /* CSA */ 2510178354Ssam + 2 + 1 /* ERP */ 2511178354Ssam + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2512178354Ssam + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2513178354Ssam 2*sizeof(struct ieee80211_ie_wpa) : 0) 2514178354Ssam /* XXX conditional? */ 2515178354Ssam + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ 2516178354Ssam + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ 2517178354Ssam + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ 2518178354Ssam sizeof(struct ieee80211_wme_param) : 0) 2519190451Ssam#ifdef IEEE80211_SUPPORT_SUPERG 2520190451Ssam + sizeof(struct ieee80211_ath_ie) /* ATH */ 2521190451Ssam#endif 2522186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 2523186904Ssam + (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */ 2524186904Ssam sizeof(struct ieee80211_tdma_param) : 0) 2525186904Ssam#endif 2526178354Ssam + IEEE80211_MAX_APPIE 2527178354Ssam ; 2528178354Ssam m = ieee80211_getmgtframe(&frm, 2529178354Ssam ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); 2530178354Ssam if (m == NULL) { 2531178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 2532178354Ssam "%s: cannot get buf; size %u\n", __func__, pktlen); 2533178354Ssam vap->iv_stats.is_tx_nobuf++; 2534178354Ssam return NULL; 2535178354Ssam } 2536178354Ssam ieee80211_beacon_construct(m, frm, bo, ni); 2537178354Ssam 2538138568Ssam M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 2539138568Ssam KASSERT(m != NULL, ("no space for 802.11 header?")); 2540138568Ssam wh = mtod(m, struct ieee80211_frame *); 2541138568Ssam wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 2542138568Ssam IEEE80211_FC0_SUBTYPE_BEACON; 2543138568Ssam wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2544170530Ssam *(uint16_t *)wh->i_dur = 0; 2545138568Ssam IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 2546178354Ssam IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 2547138568Ssam IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 2548170530Ssam *(uint16_t *)wh->i_seq = 0; 2549138568Ssam 2550138568Ssam return m; 2551138568Ssam} 2552138568Ssam 2553138568Ssam/* 2554138568Ssam * Update the dynamic parts of a beacon frame based on the current state. 2555138568Ssam */ 2556138568Ssamint 2557172211Ssamieee80211_beacon_update(struct ieee80211_node *ni, 2558138568Ssam struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) 2559138568Ssam{ 2560178354Ssam struct ieee80211vap *vap = ni->ni_vap; 2561172211Ssam struct ieee80211com *ic = ni->ni_ic; 2562138568Ssam int len_changed = 0; 2563170530Ssam uint16_t capinfo; 2564138568Ssam 2565178354Ssam IEEE80211_LOCK(ic); 2566178354Ssam /* 2567178354Ssam * Handle 11h channel change when we've reached the count. 2568178354Ssam * We must recalculate the beacon frame contents to account 2569178354Ssam * for the new channel. Note we do this only for the first 2570178354Ssam * vap that reaches this point; subsequent vaps just update 2571178354Ssam * their beacon state to reflect the recalculated channel. 2572178354Ssam */ 2573178354Ssam if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && 2574178354Ssam vap->iv_csa_count == ic->ic_csa_count) { 2575178354Ssam vap->iv_csa_count = 0; 2576178354Ssam /* 2577178354Ssam * Effect channel change before reconstructing the beacon 2578178354Ssam * frame contents as many places reference ni_chan. 2579178354Ssam */ 2580178354Ssam if (ic->ic_csa_newchan != NULL) 2581178354Ssam ieee80211_csa_completeswitch(ic); 2582178354Ssam /* 2583178354Ssam * NB: ieee80211_beacon_construct clears all pending 2584178354Ssam * updates in bo_flags so we don't need to explicitly 2585178354Ssam * clear IEEE80211_BEACON_CSA. 2586178354Ssam */ 2587178354Ssam ieee80211_beacon_construct(m, 2588178354Ssam mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni); 2589178354Ssam 2590178354Ssam /* XXX do WME aggressive mode processing? */ 2591178354Ssam IEEE80211_UNLOCK(ic); 2592178354Ssam return 1; /* just assume length changed */ 2593178354Ssam } 2594178354Ssam 2595138568Ssam /* XXX faster to recalculate entirely or just changes? */ 2596178354Ssam capinfo = getcapinfo(vap, ni->ni_chan); 2597138568Ssam *bo->bo_caps = htole16(capinfo); 2598138568Ssam 2599178354Ssam if (vap->iv_flags & IEEE80211_F_WME) { 2600138568Ssam struct ieee80211_wme_state *wme = &ic->ic_wme; 2601138568Ssam 2602138568Ssam /* 2603138568Ssam * Check for agressive mode change. When there is 2604138568Ssam * significant high priority traffic in the BSS 2605138568Ssam * throttle back BE traffic by using conservative 2606138568Ssam * parameters. Otherwise BE uses agressive params 2607138568Ssam * to optimize performance of legacy/non-QoS traffic. 2608138568Ssam */ 2609138568Ssam if (wme->wme_flags & WME_F_AGGRMODE) { 2610138568Ssam if (wme->wme_hipri_traffic > 2611138568Ssam wme->wme_hipri_switch_thresh) { 2612178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 2613138568Ssam "%s: traffic %u, disable aggressive mode\n", 2614138568Ssam __func__, wme->wme_hipri_traffic); 2615138568Ssam wme->wme_flags &= ~WME_F_AGGRMODE; 2616178354Ssam ieee80211_wme_updateparams_locked(vap); 2617138568Ssam wme->wme_hipri_traffic = 2618138568Ssam wme->wme_hipri_switch_hysteresis; 2619138568Ssam } else 2620138568Ssam wme->wme_hipri_traffic = 0; 2621138568Ssam } else { 2622138568Ssam if (wme->wme_hipri_traffic <= 2623138568Ssam wme->wme_hipri_switch_thresh) { 2624178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 2625138568Ssam "%s: traffic %u, enable aggressive mode\n", 2626138568Ssam __func__, wme->wme_hipri_traffic); 2627138568Ssam wme->wme_flags |= WME_F_AGGRMODE; 2628178354Ssam ieee80211_wme_updateparams_locked(vap); 2629138568Ssam wme->wme_hipri_traffic = 0; 2630138568Ssam } else 2631138568Ssam wme->wme_hipri_traffic = 2632138568Ssam wme->wme_hipri_switch_hysteresis; 2633138568Ssam } 2634172211Ssam if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { 2635138568Ssam (void) ieee80211_add_wme_param(bo->bo_wme, wme); 2636172211Ssam clrbit(bo->bo_flags, IEEE80211_BEACON_WME); 2637138568Ssam } 2638138568Ssam } 2639138568Ssam 2640178354Ssam if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { 2641178354Ssam ieee80211_ht_update_beacon(vap, bo); 2642172211Ssam clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); 2643170530Ssam } 2644186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 2645186904Ssam if (vap->iv_caps & IEEE80211_C_TDMA) { 2646186904Ssam /* 2647186904Ssam * NB: the beacon is potentially updated every TBTT. 2648186904Ssam */ 2649186904Ssam ieee80211_tdma_update_beacon(vap, bo); 2650186904Ssam } 2651186904Ssam#endif 2652178354Ssam if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/ 2653138568Ssam struct ieee80211_tim_ie *tie = 2654138568Ssam (struct ieee80211_tim_ie *) bo->bo_tim; 2655172211Ssam if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { 2656138568Ssam u_int timlen, timoff, i; 2657138568Ssam /* 2658138568Ssam * ATIM/DTIM needs updating. If it fits in the 2659138568Ssam * current space allocated then just copy in the 2660138568Ssam * new bits. Otherwise we need to move any trailing 2661138568Ssam * data to make room. Note that we know there is 2662138568Ssam * contiguous space because ieee80211_beacon_allocate 2663138568Ssam * insures there is space in the mbuf to write a 2664178354Ssam * maximal-size virtual bitmap (based on iv_max_aid). 2665138568Ssam */ 2666138568Ssam /* 2667138568Ssam * Calculate the bitmap size and offset, copy any 2668138568Ssam * trailer out of the way, and then copy in the 2669138568Ssam * new bitmap and update the information element. 2670138568Ssam * Note that the tim bitmap must contain at least 2671138568Ssam * one byte and any offset must be even. 2672138568Ssam */ 2673178354Ssam if (vap->iv_ps_pending != 0) { 2674138568Ssam timoff = 128; /* impossibly large */ 2675178354Ssam for (i = 0; i < vap->iv_tim_len; i++) 2676178354Ssam if (vap->iv_tim_bitmap[i]) { 2677138568Ssam timoff = i &~ 1; 2678138568Ssam break; 2679138568Ssam } 2680138568Ssam KASSERT(timoff != 128, ("tim bitmap empty!")); 2681178354Ssam for (i = vap->iv_tim_len-1; i >= timoff; i--) 2682178354Ssam if (vap->iv_tim_bitmap[i]) 2683138568Ssam break; 2684138568Ssam timlen = 1 + (i - timoff); 2685138568Ssam } else { 2686138568Ssam timoff = 0; 2687138568Ssam timlen = 1; 2688138568Ssam } 2689138568Ssam if (timlen != bo->bo_tim_len) { 2690138568Ssam /* copy up/down trailer */ 2691153973Ssam int adjust = tie->tim_bitmap+timlen 2692172211Ssam - bo->bo_tim_trailer; 2693172211Ssam ovbcopy(bo->bo_tim_trailer, 2694172211Ssam bo->bo_tim_trailer+adjust, 2695172211Ssam bo->bo_tim_trailer_len); 2696172211Ssam bo->bo_tim_trailer += adjust; 2697153973Ssam bo->bo_erp += adjust; 2698170530Ssam bo->bo_htinfo += adjust; 2699190451Ssam#ifdef IEEE80211_SUPERG_SUPPORT 2700190451Ssam bo->bo_ath += adjust; 2701190451Ssam#endif 2702190448Ssam#ifdef IEEE80211_TDMA_SUPPORT 2703190448Ssam bo->bo_tdma += adjust; 2704190448Ssam#endif 2705178354Ssam bo->bo_appie += adjust; 2706178354Ssam bo->bo_wme += adjust; 2707178354Ssam bo->bo_csa += adjust; 2708138568Ssam bo->bo_tim_len = timlen; 2709138568Ssam 2710138568Ssam /* update information element */ 2711138568Ssam tie->tim_len = 3 + timlen; 2712138568Ssam tie->tim_bitctl = timoff; 2713138568Ssam len_changed = 1; 2714138568Ssam } 2715178354Ssam memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, 2716138568Ssam bo->bo_tim_len); 2717138568Ssam 2718172211Ssam clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); 2719138568Ssam 2720178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 2721138568Ssam "%s: TIM updated, pending %u, off %u, len %u\n", 2722178354Ssam __func__, vap->iv_ps_pending, timoff, timlen); 2723138568Ssam } 2724138568Ssam /* count down DTIM period */ 2725138568Ssam if (tie->tim_count == 0) 2726138568Ssam tie->tim_count = tie->tim_period - 1; 2727138568Ssam else 2728138568Ssam tie->tim_count--; 2729138568Ssam /* update state for buffered multicast frames on DTIM */ 2730153139Ssam if (mcast && tie->tim_count == 0) 2731138568Ssam tie->tim_bitctl |= 1; 2732138568Ssam else 2733138568Ssam tie->tim_bitctl &= ~1; 2734178354Ssam if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { 2735178354Ssam struct ieee80211_csa_ie *csa = 2736178354Ssam (struct ieee80211_csa_ie *) bo->bo_csa; 2737178354Ssam 2738178354Ssam /* 2739178354Ssam * Insert or update CSA ie. If we're just starting 2740178354Ssam * to count down to the channel switch then we need 2741178354Ssam * to insert the CSA ie. Otherwise we just need to 2742178354Ssam * drop the count. The actual change happens above 2743178354Ssam * when the vap's count reaches the target count. 2744178354Ssam */ 2745178354Ssam if (vap->iv_csa_count == 0) { 2746178354Ssam memmove(&csa[1], csa, bo->bo_csa_trailer_len); 2747178354Ssam bo->bo_erp += sizeof(*csa); 2748190449Ssam bo->bo_htinfo += sizeof(*csa); 2749178354Ssam bo->bo_wme += sizeof(*csa); 2750190451Ssam#ifdef IEEE80211_SUPERG_SUPPORT 2751190451Ssam bo->bo_ath += sizeof(*csa); 2752190451Ssam#endif 2753190448Ssam#ifdef IEEE80211_TDMA_SUPPORT 2754190448Ssam bo->bo_tdma += sizeof(*csa); 2755190448Ssam#endif 2756178354Ssam bo->bo_appie += sizeof(*csa); 2757178354Ssam bo->bo_csa_trailer_len += sizeof(*csa); 2758178354Ssam bo->bo_tim_trailer_len += sizeof(*csa); 2759178354Ssam m->m_len += sizeof(*csa); 2760178354Ssam m->m_pkthdr.len += sizeof(*csa); 2761178354Ssam 2762178354Ssam ieee80211_add_csa(bo->bo_csa, vap); 2763178354Ssam } else 2764178354Ssam csa->csa_count--; 2765178354Ssam vap->iv_csa_count++; 2766178354Ssam /* NB: don't clear IEEE80211_BEACON_CSA */ 2767178354Ssam } 2768172211Ssam if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { 2769153973Ssam /* 2770153973Ssam * ERP element needs updating. 2771153973Ssam */ 2772153973Ssam (void) ieee80211_add_erp(bo->bo_erp, ic); 2773172211Ssam clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); 2774153973Ssam } 2775190451Ssam#ifdef IEEE80211_SUPPORT_SUPERG 2776190451Ssam if (isset(bo->bo_flags, IEEE80211_BEACON_ATH)) { 2777190451Ssam ieee80211_add_athcaps(bo->bo_ath, ni); 2778190451Ssam clrbit(bo->bo_flags, IEEE80211_BEACON_ATH); 2779190451Ssam } 2780190451Ssam#endif 2781138568Ssam } 2782178354Ssam if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { 2783178354Ssam const struct ieee80211_appie *aie = vap->iv_appie_beacon; 2784178354Ssam int aielen; 2785178354Ssam uint8_t *frm; 2786138568Ssam 2787178354Ssam aielen = 0; 2788178354Ssam if (aie != NULL) 2789178354Ssam aielen += aie->ie_len; 2790178354Ssam if (aielen != bo->bo_appie_len) { 2791178354Ssam /* copy up/down trailer */ 2792178354Ssam int adjust = aielen - bo->bo_appie_len; 2793178354Ssam ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, 2794178354Ssam bo->bo_tim_trailer_len); 2795178354Ssam bo->bo_tim_trailer += adjust; 2796178354Ssam bo->bo_appie += adjust; 2797178354Ssam bo->bo_appie_len = aielen; 2798178354Ssam 2799178354Ssam len_changed = 1; 2800178354Ssam } 2801178354Ssam frm = bo->bo_appie; 2802178354Ssam if (aie != NULL) 2803178354Ssam frm = add_appie(frm, aie); 2804178354Ssam clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); 2805178354Ssam } 2806178354Ssam IEEE80211_UNLOCK(ic); 2807178354Ssam 2808138568Ssam return len_changed; 2809138568Ssam} 2810