11a1e1d21SSam Leffler /*- 27535e66aSSam Leffler * Copyright (c) 2001 Atsushi Onoe 3b032f27cSSam Leffler * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting 41a1e1d21SSam Leffler * All rights reserved. 51a1e1d21SSam Leffler * 61a1e1d21SSam Leffler * Redistribution and use in source and binary forms, with or without 71a1e1d21SSam Leffler * modification, are permitted provided that the following conditions 81a1e1d21SSam Leffler * are met: 91a1e1d21SSam Leffler * 1. Redistributions of source code must retain the above copyright 107535e66aSSam Leffler * notice, this list of conditions and the following disclaimer. 117535e66aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 127535e66aSSam Leffler * notice, this list of conditions and the following disclaimer in the 137535e66aSSam Leffler * documentation and/or other materials provided with the distribution. 141a1e1d21SSam Leffler * 157535e66aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 167535e66aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 177535e66aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 187535e66aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 197535e66aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 207535e66aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 217535e66aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 227535e66aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 237535e66aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 247535e66aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251a1e1d21SSam Leffler */ 261a1e1d21SSam Leffler 271a1e1d21SSam Leffler #include <sys/cdefs.h> 281a1e1d21SSam Leffler __FBSDID("$FreeBSD$"); 291a1e1d21SSam Leffler 301a1e1d21SSam Leffler #include "opt_inet.h" 31b032f27cSSam Leffler #include "opt_wlan.h" 321a1e1d21SSam Leffler 331a1e1d21SSam Leffler #include <sys/param.h> 341a1e1d21SSam Leffler #include <sys/systm.h> 351a1e1d21SSam Leffler #include <sys/mbuf.h> 361a1e1d21SSam Leffler #include <sys/kernel.h> 371a1e1d21SSam Leffler #include <sys/endian.h> 381a1e1d21SSam Leffler 398a1b9b6aSSam Leffler #include <sys/socket.h> 401a1e1d21SSam Leffler 411a1e1d21SSam Leffler #include <net/bpf.h> 428a1b9b6aSSam Leffler #include <net/ethernet.h> 438a1b9b6aSSam Leffler #include <net/if.h> 448a1b9b6aSSam Leffler #include <net/if_llc.h> 458a1b9b6aSSam Leffler #include <net/if_media.h> 468a1b9b6aSSam Leffler #include <net/if_vlan_var.h> 478a1b9b6aSSam Leffler 488a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h> 4968e8e04eSSam Leffler #include <net80211/ieee80211_regdomain.h> 50b032f27cSSam Leffler #include <net80211/ieee80211_wds.h> 511a1e1d21SSam Leffler 521a1e1d21SSam Leffler #ifdef INET 531a1e1d21SSam Leffler #include <netinet/in.h> 541a1e1d21SSam Leffler #include <netinet/if_ether.h> 558a1b9b6aSSam Leffler #include <netinet/in_systm.h> 568a1b9b6aSSam Leffler #include <netinet/ip.h> 578a1b9b6aSSam Leffler #endif 588a1b9b6aSSam Leffler 5968e8e04eSSam Leffler #define ETHER_HEADER_COPY(dst, src) \ 6068e8e04eSSam Leffler memcpy(dst, src, sizeof(struct ether_header)) 6168e8e04eSSam Leffler 62b032f27cSSam Leffler static struct mbuf *ieee80211_encap_fastframe(struct ieee80211vap *, 6368e8e04eSSam Leffler struct mbuf *m1, const struct ether_header *eh1, 6468e8e04eSSam Leffler struct mbuf *m2, const struct ether_header *eh2); 65b032f27cSSam Leffler static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *, 6668e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu); 6768e8e04eSSam Leffler static void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int); 6868e8e04eSSam Leffler 698a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 708a1b9b6aSSam Leffler /* 718a1b9b6aSSam Leffler * Decide if an outbound management frame should be 728a1b9b6aSSam Leffler * printed when debugging is enabled. This filters some 738a1b9b6aSSam Leffler * of the less interesting frames that come frequently 748a1b9b6aSSam Leffler * (e.g. beacons). 758a1b9b6aSSam Leffler */ 768a1b9b6aSSam Leffler static __inline int 77b032f27cSSam Leffler doprint(struct ieee80211vap *vap, int subtype) 788a1b9b6aSSam Leffler { 798a1b9b6aSSam Leffler switch (subtype) { 808a1b9b6aSSam Leffler case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 81b032f27cSSam Leffler return (vap->iv_opmode == IEEE80211_M_IBSS); 828a1b9b6aSSam Leffler } 838a1b9b6aSSam Leffler return 1; 848a1b9b6aSSam Leffler } 851a1e1d21SSam Leffler #endif 861a1e1d21SSam Leffler 870a915fadSSam Leffler /* 88b032f27cSSam Leffler * Start method for vap's. All packets from the stack come 89b032f27cSSam Leffler * through here. We handle common processing of the packets 90b032f27cSSam Leffler * before dispatching them to the underlying device. 91b032f27cSSam Leffler */ 92b032f27cSSam Leffler void 93b032f27cSSam Leffler ieee80211_start(struct ifnet *ifp) 94b032f27cSSam Leffler { 95b032f27cSSam Leffler #define IS_DWDS(vap) \ 96b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_WDS && \ 97b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0) 98b032f27cSSam Leffler struct ieee80211vap *vap = ifp->if_softc; 99b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 100b032f27cSSam Leffler struct ifnet *parent = ic->ic_ifp; 101b032f27cSSam Leffler struct ieee80211_node *ni; 102b032f27cSSam Leffler struct mbuf *m; 103b032f27cSSam Leffler struct ether_header *eh; 104b032f27cSSam Leffler int error; 105b032f27cSSam Leffler 106b032f27cSSam Leffler /* NB: parent must be up and running */ 107b032f27cSSam Leffler if (!IFNET_IS_UP_RUNNING(parent)) { 108b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 109b032f27cSSam Leffler "%s: ignore queue, parent %s not up+running\n", 110b032f27cSSam Leffler __func__, parent->if_xname); 111b032f27cSSam Leffler /* XXX stat */ 112b032f27cSSam Leffler return; 113b032f27cSSam Leffler } 114b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_SLEEP) { 115b032f27cSSam Leffler /* 116b032f27cSSam Leffler * In power save, wakeup device for transmit. 117b032f27cSSam Leffler */ 118b032f27cSSam Leffler ieee80211_new_state(vap, IEEE80211_S_RUN, 0); 119b032f27cSSam Leffler return; 120b032f27cSSam Leffler } 121b032f27cSSam Leffler /* 122b032f27cSSam Leffler * No data frames go out unless we're running. 123b032f27cSSam Leffler * Note in particular this covers CAC and CSA 124b032f27cSSam Leffler * states (though maybe we should check muting 125b032f27cSSam Leffler * for CSA). 126b032f27cSSam Leffler */ 127b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_RUN) { 128b032f27cSSam Leffler IEEE80211_LOCK(ic); 129b032f27cSSam Leffler /* re-check under the com lock to avoid races */ 130b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_RUN) { 131b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 132b032f27cSSam Leffler "%s: ignore queue, in %s state\n", 133b032f27cSSam Leffler __func__, ieee80211_state_name[vap->iv_state]); 134b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 135b032f27cSSam Leffler ifp->if_drv_flags |= IFF_DRV_OACTIVE; 136b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 137b032f27cSSam Leffler return; 138b032f27cSSam Leffler } 139b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 140b032f27cSSam Leffler } 141b032f27cSSam Leffler for (;;) { 142b032f27cSSam Leffler IFQ_DEQUEUE(&ifp->if_snd, m); 143b032f27cSSam Leffler if (m == NULL) 144b032f27cSSam Leffler break; 145b032f27cSSam Leffler /* 146b032f27cSSam Leffler * Sanitize mbuf flags for net80211 use. We cannot 147b032f27cSSam Leffler * clear M_PWR_SAV because this may be set for frames 148b032f27cSSam Leffler * that are re-submitted from the power save queue. 149b032f27cSSam Leffler * 150b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 151b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 152b032f27cSSam Leffler */ 153b032f27cSSam Leffler m->m_flags &= ~(M_80211_TX - M_PWR_SAV); 154b032f27cSSam Leffler /* 155b032f27cSSam Leffler * Cancel any background scan. 156b032f27cSSam Leffler */ 157b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_SCAN) 158b032f27cSSam Leffler ieee80211_cancel_anyscan(vap); 159b032f27cSSam Leffler /* 160b032f27cSSam Leffler * Find the node for the destination so we can do 161b032f27cSSam Leffler * things like power save and fast frames aggregation. 162b032f27cSSam Leffler * 163b032f27cSSam Leffler * NB: past this point various code assumes the first 164b032f27cSSam Leffler * mbuf has the 802.3 header present (and contiguous). 165b032f27cSSam Leffler */ 166b032f27cSSam Leffler ni = NULL; 167b032f27cSSam Leffler if (m->m_len < sizeof(struct ether_header) && 168b032f27cSSam Leffler (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 169b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 170b032f27cSSam Leffler "discard frame, %s\n", "m_pullup failed"); 171b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX */ 172b032f27cSSam Leffler ifp->if_oerrors++; 173b032f27cSSam Leffler continue; 174b032f27cSSam Leffler } 175b032f27cSSam Leffler eh = mtod(m, struct ether_header *); 176b032f27cSSam Leffler if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 177b032f27cSSam Leffler if (IS_DWDS(vap)) { 178b032f27cSSam Leffler /* 179b032f27cSSam Leffler * Only unicast frames from the above go out 180b032f27cSSam Leffler * DWDS vaps; multicast frames are handled by 181b032f27cSSam Leffler * dispatching the frame as it comes through 182b032f27cSSam Leffler * the AP vap (see below). 183b032f27cSSam Leffler */ 184b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS, 185b032f27cSSam Leffler eh->ether_dhost, "mcast", "%s", "on DWDS"); 186b032f27cSSam Leffler vap->iv_stats.is_dwds_mcast++; 187b032f27cSSam Leffler m_freem(m); 188b032f27cSSam Leffler continue; 189b032f27cSSam Leffler } 190b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 191b032f27cSSam Leffler /* 192b032f27cSSam Leffler * Spam DWDS vap's w/ multicast traffic. 193b032f27cSSam Leffler */ 194b032f27cSSam Leffler /* XXX only if dwds in use? */ 195b032f27cSSam Leffler ieee80211_dwds_mcast(vap, m); 196b032f27cSSam Leffler } 197b032f27cSSam Leffler } 198b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, eh->ether_dhost); 199b032f27cSSam Leffler if (ni == NULL) { 200b032f27cSSam Leffler /* NB: ieee80211_find_txnode does stat+msg */ 201b032f27cSSam Leffler ifp->if_oerrors++; 202b032f27cSSam Leffler m_freem(m); 203b032f27cSSam Leffler continue; 204b032f27cSSam Leffler } 205b032f27cSSam Leffler /* XXX AUTH'd */ 2066ff2e10aSSam Leffler /* XXX mark vap to identify if associd is required */ 2076ff2e10aSSam Leffler if (ni->ni_associd == 0 && 2086ff2e10aSSam Leffler (vap->iv_opmode == IEEE80211_M_STA || 2096ff2e10aSSam Leffler vap->iv_opmode == IEEE80211_M_HOSTAP || IS_DWDS(vap))) { 210b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 211b032f27cSSam Leffler eh->ether_dhost, NULL, 212b032f27cSSam Leffler "sta not associated (type 0x%04x)", 213b032f27cSSam Leffler htons(eh->ether_type)); 214b032f27cSSam Leffler vap->iv_stats.is_tx_notassoc++; 215b032f27cSSam Leffler ifp->if_oerrors++; 216b032f27cSSam Leffler m_freem(m); 217b032f27cSSam Leffler ieee80211_free_node(ni); 218b032f27cSSam Leffler continue; 219b032f27cSSam Leffler } 220b032f27cSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 221b032f27cSSam Leffler (m->m_flags & M_PWR_SAV) == 0) { 222b032f27cSSam Leffler /* 223b032f27cSSam Leffler * Station in power save mode; pass the frame 224b032f27cSSam Leffler * to the 802.11 layer and continue. We'll get 225b032f27cSSam Leffler * the frame back when the time is right. 226b032f27cSSam Leffler * XXX lose WDS vap linkage? 227b032f27cSSam Leffler */ 228b032f27cSSam Leffler ieee80211_pwrsave(ni, m); 229b032f27cSSam Leffler ieee80211_free_node(ni); 230b032f27cSSam Leffler continue; 231b032f27cSSam Leffler } 232b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 233b032f27cSSam Leffler if (ieee80211_classify(ni, m)) { 234b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 235b032f27cSSam Leffler eh->ether_dhost, NULL, 236b032f27cSSam Leffler "%s", "classification failure"); 237b032f27cSSam Leffler vap->iv_stats.is_tx_classify++; 238b032f27cSSam Leffler ifp->if_oerrors++; 239b032f27cSSam Leffler m_freem(m); 240b032f27cSSam Leffler ieee80211_free_node(ni); 241b032f27cSSam Leffler continue; 242b032f27cSSam Leffler } 243b032f27cSSam Leffler 244b032f27cSSam Leffler BPF_MTAP(ifp, m); /* 802.11 tx path */ 245b032f27cSSam Leffler 246b032f27cSSam Leffler /* 247b032f27cSSam Leffler * XXX When ni is associated with a WDS link then 248b032f27cSSam Leffler * the vap will be the WDS vap but ni_vap will point 249b032f27cSSam Leffler * to the ap vap the station associated to. Once 250b032f27cSSam Leffler * we handoff the packet to the driver the callback 251b032f27cSSam Leffler * to ieee80211_encap won't be able to tell if the 252b032f27cSSam Leffler * packet should be encapsulated for WDS or not (e.g. 253b032f27cSSam Leffler * multicast frames will not be handled correctly). 254b032f27cSSam Leffler * We hack this by marking the mbuf so ieee80211_encap 255b032f27cSSam Leffler * can do the right thing. 256b032f27cSSam Leffler */ 257b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 258b032f27cSSam Leffler m->m_flags |= M_WDS; 259b032f27cSSam Leffler else 260b032f27cSSam Leffler m->m_flags &= ~M_WDS; 261b032f27cSSam Leffler 262b032f27cSSam Leffler /* 263b032f27cSSam Leffler * Stash the node pointer and hand the frame off to 264b032f27cSSam Leffler * the underlying device. Note that we do this after 265b032f27cSSam Leffler * any call to ieee80211_dwds_mcast because that code 266b032f27cSSam Leffler * uses any existing value for rcvif. 267b032f27cSSam Leffler */ 268b032f27cSSam Leffler m->m_pkthdr.rcvif = (void *)ni; 269b032f27cSSam Leffler 270b032f27cSSam Leffler /* XXX defer if_start calls? */ 271b032f27cSSam Leffler IFQ_HANDOFF(parent, m, error); 272b032f27cSSam Leffler if (error != 0) { 273b032f27cSSam Leffler /* NB: IFQ_HANDOFF reclaims mbuf */ 274b032f27cSSam Leffler ieee80211_free_node(ni); 275b032f27cSSam Leffler } else { 276b032f27cSSam Leffler ifp->if_opackets++; 277b032f27cSSam Leffler } 278b032f27cSSam Leffler ic->ic_lastdata = ticks; 279b032f27cSSam Leffler } 280b032f27cSSam Leffler #undef IS_DWDS 281b032f27cSSam Leffler } 282b032f27cSSam Leffler 283b032f27cSSam Leffler /* 284b032f27cSSam Leffler * 802.11 output routine. This is (currently) used only to 285b032f27cSSam Leffler * connect bpf write calls to the 802.11 layer for injecting 286b032f27cSSam Leffler * raw 802.11 frames. Note we locate the ieee80211com from 287b032f27cSSam Leffler * the ifnet using a spare field setup at attach time. This 288b032f27cSSam Leffler * will go away when the virtual ap support comes in. 289b032f27cSSam Leffler */ 290b032f27cSSam Leffler int 291b032f27cSSam Leffler ieee80211_output(struct ifnet *ifp, struct mbuf *m, 292b032f27cSSam Leffler struct sockaddr *dst, struct rtentry *rt0) 293b032f27cSSam Leffler { 294b032f27cSSam Leffler #define senderr(e) do { error = (e); goto bad;} while (0) 295b032f27cSSam Leffler struct ieee80211_node *ni = NULL; 296b032f27cSSam Leffler struct ieee80211vap *vap; 297b032f27cSSam Leffler struct ieee80211_frame *wh; 298b032f27cSSam Leffler int error; 299b032f27cSSam Leffler 300b032f27cSSam Leffler if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 301b032f27cSSam Leffler /* 302b032f27cSSam Leffler * Short-circuit requests if the vap is marked OACTIVE 303b032f27cSSam Leffler * as this is used when tearing down state to indicate 304b032f27cSSam Leffler * the vap may be gone. This can also happen because a 305b032f27cSSam Leffler * packet came down through ieee80211_start before the 306b032f27cSSam Leffler * vap entered RUN state in which case it's also ok to 307b032f27cSSam Leffler * just drop the frame. This should not be necessary 308b032f27cSSam Leffler * but callers of if_output don't check OACTIVE. 309b032f27cSSam Leffler */ 310b032f27cSSam Leffler senderr(ENETDOWN); 311b032f27cSSam Leffler } 312b032f27cSSam Leffler vap = ifp->if_softc; 313b032f27cSSam Leffler /* 314b032f27cSSam Leffler * Hand to the 802.3 code if not tagged as 315b032f27cSSam Leffler * a raw 802.11 frame. 316b032f27cSSam Leffler */ 317b032f27cSSam Leffler if (dst->sa_family != AF_IEEE80211) 318b032f27cSSam Leffler return vap->iv_output(ifp, m, dst, rt0); 319b032f27cSSam Leffler #ifdef MAC 320b032f27cSSam Leffler error = mac_check_ifnet_transmit(ifp, m); 321b032f27cSSam Leffler if (error) 322b032f27cSSam Leffler senderr(error); 323b032f27cSSam Leffler #endif 324b032f27cSSam Leffler if (ifp->if_flags & IFF_MONITOR) 325b032f27cSSam Leffler senderr(ENETDOWN); 326b032f27cSSam Leffler if (!IFNET_IS_UP_RUNNING(ifp)) 327b032f27cSSam Leffler senderr(ENETDOWN); 328b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 329b032f27cSSam Leffler IEEE80211_DPRINTF(vap, 330b032f27cSSam Leffler IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 331b032f27cSSam Leffler "block %s frame in CAC state\n", "raw data"); 332b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 333b032f27cSSam Leffler senderr(EIO); /* XXX */ 334b032f27cSSam Leffler } 335b032f27cSSam Leffler /* XXX bypass bridge, pfil, carp, etc. */ 336b032f27cSSam Leffler 337b032f27cSSam Leffler if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) 338b032f27cSSam Leffler senderr(EIO); /* XXX */ 339b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 340b032f27cSSam Leffler if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 341b032f27cSSam Leffler IEEE80211_FC0_VERSION_0) 342b032f27cSSam Leffler senderr(EIO); /* XXX */ 343b032f27cSSam Leffler 344b032f27cSSam Leffler /* locate destination node */ 345b032f27cSSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 346b032f27cSSam Leffler case IEEE80211_FC1_DIR_NODS: 347b032f27cSSam Leffler case IEEE80211_FC1_DIR_FROMDS: 348b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr1); 349b032f27cSSam Leffler break; 350b032f27cSSam Leffler case IEEE80211_FC1_DIR_TODS: 351b032f27cSSam Leffler case IEEE80211_FC1_DIR_DSTODS: 352b032f27cSSam Leffler if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) 353b032f27cSSam Leffler senderr(EIO); /* XXX */ 354b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr3); 355b032f27cSSam Leffler break; 356b032f27cSSam Leffler default: 357b032f27cSSam Leffler senderr(EIO); /* XXX */ 358b032f27cSSam Leffler } 359b032f27cSSam Leffler if (ni == NULL) { 360b032f27cSSam Leffler /* 361b032f27cSSam Leffler * Permit packets w/ bpf params through regardless 362b032f27cSSam Leffler * (see below about sa_len). 363b032f27cSSam Leffler */ 364b032f27cSSam Leffler if (dst->sa_len == 0) 365b032f27cSSam Leffler senderr(EHOSTUNREACH); 366b032f27cSSam Leffler ni = ieee80211_ref_node(vap->iv_bss); 367b032f27cSSam Leffler } 368b032f27cSSam Leffler 369b032f27cSSam Leffler /* 370b032f27cSSam Leffler * Sanitize mbuf for net80211 flags leaked from above. 371b032f27cSSam Leffler * 372b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 373b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 374b032f27cSSam Leffler */ 375b032f27cSSam Leffler m->m_flags &= ~M_80211_TX; 376b032f27cSSam Leffler 377b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 378b032f27cSSam Leffler /* XXX assumes an 802.3 frame */ 379b032f27cSSam Leffler if (ieee80211_classify(ni, m)) 380b032f27cSSam Leffler senderr(EIO); /* XXX */ 381b032f27cSSam Leffler 382b032f27cSSam Leffler BPF_MTAP(ifp, m); 383b032f27cSSam Leffler 384b032f27cSSam Leffler /* 385b032f27cSSam Leffler * NB: DLT_IEEE802_11_RADIO identifies the parameters are 386b032f27cSSam Leffler * present by setting the sa_len field of the sockaddr (yes, 387b032f27cSSam Leffler * this is a hack). 388b032f27cSSam Leffler * NB: we assume sa_data is suitably aligned to cast. 389b032f27cSSam Leffler */ 390b032f27cSSam Leffler return vap->iv_ic->ic_raw_xmit(ni, m, 391b032f27cSSam Leffler (const struct ieee80211_bpf_params *)(dst->sa_len ? 392b032f27cSSam Leffler dst->sa_data : NULL)); 393b032f27cSSam Leffler bad: 394b032f27cSSam Leffler if (m != NULL) 395b032f27cSSam Leffler m_freem(m); 396b032f27cSSam Leffler if (ni != NULL) 397b032f27cSSam Leffler ieee80211_free_node(ni); 398b032f27cSSam Leffler return error; 399b032f27cSSam Leffler #undef senderr 400b032f27cSSam Leffler } 401b032f27cSSam Leffler 402b032f27cSSam Leffler /* 403add59d08SSam Leffler * Set the direction field and address fields of an outgoing 4040e66722dSSam Leffler * frame. Note this should be called early on in constructing 4050e66722dSSam Leffler * a frame as it sets i_fc[1]; other bits can then be or'd in. 406add59d08SSam Leffler */ 407add59d08SSam Leffler static void 408b032f27cSSam Leffler ieee80211_send_setup( 409add59d08SSam Leffler struct ieee80211_node *ni, 410add59d08SSam Leffler struct ieee80211_frame *wh, 4118ac160cdSSam Leffler int type, int tid, 41268e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 41368e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 41468e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN]) 415add59d08SSam Leffler { 416add59d08SSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) 417add59d08SSam Leffler 418add59d08SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; 419add59d08SSam Leffler if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 420b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 421b032f27cSSam Leffler 422b032f27cSSam Leffler switch (vap->iv_opmode) { 423add59d08SSam Leffler case IEEE80211_M_STA: 424add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 425add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 426add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 427add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 428add59d08SSam Leffler break; 429add59d08SSam Leffler case IEEE80211_M_IBSS: 430add59d08SSam Leffler case IEEE80211_M_AHDEMO: 431add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 432add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 433add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 434add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 435add59d08SSam Leffler break; 436add59d08SSam Leffler case IEEE80211_M_HOSTAP: 437add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 438add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 439add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, bssid); 440add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, sa); 441add59d08SSam Leffler break; 44268e8e04eSSam Leffler case IEEE80211_M_WDS: 44368e8e04eSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 444b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 445b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 44668e8e04eSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 44768e8e04eSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 44868e8e04eSSam Leffler break; 449add59d08SSam Leffler case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ 450add59d08SSam Leffler break; 451add59d08SSam Leffler } 452add59d08SSam Leffler } else { 453add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 454add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 455add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 456add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 457add59d08SSam Leffler } 45868e8e04eSSam Leffler *(uint16_t *)&wh->i_dur[0] = 0; 45968e8e04eSSam Leffler *(uint16_t *)&wh->i_seq[0] = 4608ac160cdSSam Leffler htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); 4618ac160cdSSam Leffler ni->ni_txseqs[tid]++; 462add59d08SSam Leffler #undef WH4 463add59d08SSam Leffler } 464add59d08SSam Leffler 465add59d08SSam Leffler /* 4660a915fadSSam Leffler * Send a management frame to the specified node. The node pointer 4670a915fadSSam Leffler * must have a reference as the pointer will be passed to the driver 4680a915fadSSam Leffler * and potentially held for a long time. If the frame is successfully 4690a915fadSSam Leffler * dispatched to the driver, then it is responsible for freeing the 470b032f27cSSam Leffler * reference (and potentially free'ing up any associated storage); 471b032f27cSSam Leffler * otherwise deal with reclaiming any reference (on error). 4720a915fadSSam Leffler */ 47368e8e04eSSam Leffler int 4748ac160cdSSam Leffler ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, 4758ac160cdSSam Leffler struct ieee80211_bpf_params *params) 4761a1e1d21SSam Leffler { 477b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 478b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 4791a1e1d21SSam Leffler struct ieee80211_frame *wh; 4801a1e1d21SSam Leffler 4810a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 4821a1e1d21SSam Leffler 483b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 484b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 485b032f27cSSam Leffler ni, "block %s frame in CAC state", 486b032f27cSSam Leffler ieee80211_mgt_subtype_name[ 487b032f27cSSam Leffler (type & IEEE80211_FC0_SUBTYPE_MASK) >> 488b032f27cSSam Leffler IEEE80211_FC0_SUBTYPE_SHIFT]); 489b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 490b032f27cSSam Leffler ieee80211_free_node(ni); 491b032f27cSSam Leffler m_freem(m); 492b032f27cSSam Leffler return EIO; /* XXX */ 493b032f27cSSam Leffler } 494b032f27cSSam Leffler 4951a1e1d21SSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 496b032f27cSSam Leffler if (m == NULL) { 497b032f27cSSam Leffler ieee80211_free_node(ni); 4981a1e1d21SSam Leffler return ENOMEM; 499b032f27cSSam Leffler } 5000a915fadSSam Leffler 5011a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 502b032f27cSSam Leffler ieee80211_send_setup(ni, wh, 5038ac160cdSSam Leffler IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, 504b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 5058ac160cdSSam Leffler if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 506b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, 507b032f27cSSam Leffler "encrypting frame (%s)", __func__); 5088a1b9b6aSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 5098a1b9b6aSSam Leffler } 5108ac160cdSSam Leffler 5118ac160cdSSam Leffler KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); 5128ac160cdSSam Leffler M_WME_SETAC(m, params->ibp_pri); 5138ac160cdSSam Leffler 5148a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 5158a1b9b6aSSam Leffler /* avoid printing too many frames */ 516b032f27cSSam Leffler if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || 517b032f27cSSam Leffler ieee80211_msg_dumppkts(vap)) { 5188a1b9b6aSSam Leffler printf("[%s] send %s on channel %u\n", 5198a1b9b6aSSam Leffler ether_sprintf(wh->i_addr1), 5208a1b9b6aSSam Leffler ieee80211_mgt_subtype_name[ 5218a1b9b6aSSam Leffler (type & IEEE80211_FC0_SUBTYPE_MASK) >> 5228a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_SHIFT], 523b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan)); 5248a1b9b6aSSam Leffler } 5258a1b9b6aSSam Leffler #endif 5268a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 52768e8e04eSSam Leffler 5288ac160cdSSam Leffler return ic->ic_raw_xmit(ni, m, params); 529246b5467SSam Leffler } 530246b5467SSam Leffler 531246b5467SSam Leffler /* 5326683931eSSam Leffler * Send a null data frame to the specified node. If the station 5336683931eSSam Leffler * is setup for QoS then a QoS Null Data frame is constructed. 5346683931eSSam Leffler * If this is a WDS station then a 4-address frame is constructed. 53519ad2dd7SSam Leffler * 53619ad2dd7SSam Leffler * NB: the caller is assumed to have setup a node reference 53719ad2dd7SSam Leffler * for use; this is necessary to deal with a race condition 538b032f27cSSam Leffler * when probing for inactive stations. Like ieee80211_mgmt_output 539b032f27cSSam Leffler * we must cleanup any node reference on error; however we 540b032f27cSSam Leffler * can safely just unref it as we know it will never be the 541b032f27cSSam Leffler * last reference to the node. 5428a1b9b6aSSam Leffler */ 5438a1b9b6aSSam Leffler int 544f62121ceSSam Leffler ieee80211_send_nulldata(struct ieee80211_node *ni) 5458a1b9b6aSSam Leffler { 546b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 547f62121ceSSam Leffler struct ieee80211com *ic = ni->ni_ic; 5488a1b9b6aSSam Leffler struct mbuf *m; 5498a1b9b6aSSam Leffler struct ieee80211_frame *wh; 5506683931eSSam Leffler int hdrlen; 5516683931eSSam Leffler uint8_t *frm; 5528a1b9b6aSSam Leffler 553b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 554b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 555b032f27cSSam Leffler ni, "block %s frame in CAC state", "null data"); 556b032f27cSSam Leffler ieee80211_unref_node(&ni); 557b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 558b032f27cSSam Leffler return EIO; /* XXX */ 559b032f27cSSam Leffler } 560b032f27cSSam Leffler 5616683931eSSam Leffler if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) 5626683931eSSam Leffler hdrlen = sizeof(struct ieee80211_qosframe); 5636683931eSSam Leffler else 5646683931eSSam Leffler hdrlen = sizeof(struct ieee80211_frame); 5656683931eSSam Leffler /* NB: only WDS vap's get 4-address frames */ 5666683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 5676683931eSSam Leffler hdrlen += IEEE80211_ADDR_LEN; 5686683931eSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 5696683931eSSam Leffler hdrlen = roundup(hdrlen, sizeof(uint32_t)); 5706683931eSSam Leffler 5716683931eSSam Leffler m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); 5728a1b9b6aSSam Leffler if (m == NULL) { 5738a1b9b6aSSam Leffler /* XXX debug msg */ 57419ad2dd7SSam Leffler ieee80211_unref_node(&ni); 575b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 5768a1b9b6aSSam Leffler return ENOMEM; 5778a1b9b6aSSam Leffler } 5786683931eSSam Leffler KASSERT(M_LEADINGSPACE(m) >= hdrlen, 5796683931eSSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 5806683931eSSam Leffler M_PREPEND(m, hdrlen, M_DONTWAIT); 5816683931eSSam Leffler if (m == NULL) { 5826683931eSSam Leffler /* NB: cannot happen */ 5836683931eSSam Leffler ieee80211_free_node(ni); 5846683931eSSam Leffler return ENOMEM; 5856683931eSSam Leffler } 5868a1b9b6aSSam Leffler 5876683931eSSam Leffler wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ 5886683931eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 5896683931eSSam Leffler const int tid = WME_AC_TO_TID(WME_AC_BE); 5906683931eSSam Leffler uint8_t *qos; 5916683931eSSam Leffler 5926683931eSSam Leffler ieee80211_send_setup(ni, wh, 5936683931eSSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, 5946683931eSSam Leffler tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 5956683931eSSam Leffler 5966683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 5976683931eSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 5986683931eSSam Leffler else 5996683931eSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 6006683931eSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 6016683931eSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) 6026683931eSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 6036683931eSSam Leffler qos[1] = 0; 6046683931eSSam Leffler } else { 605b032f27cSSam Leffler ieee80211_send_setup(ni, wh, 606add59d08SSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 6078ac160cdSSam Leffler IEEE80211_NONQOS_TID, 608b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 6096683931eSSam Leffler } 610b032f27cSSam Leffler if (vap->iv_opmode != IEEE80211_M_WDS) { 611add59d08SSam Leffler /* NB: power management bit is never sent by an AP */ 612add59d08SSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 613b032f27cSSam Leffler vap->iv_opmode != IEEE80211_M_HOSTAP) 614add59d08SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 615b032f27cSSam Leffler } 6166683931eSSam Leffler m->m_len = m->m_pkthdr.len = hdrlen; 6176683931eSSam Leffler 618bb239ce9SSam Leffler M_WME_SETAC(m, WME_AC_BE); 6198a1b9b6aSSam Leffler 6208a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 6218a1b9b6aSSam Leffler 622b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, 6236683931eSSam Leffler "send %snull data frame on channel %u, pwr mgt %s", 6246683931eSSam Leffler ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", 625b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), 626add59d08SSam Leffler wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 627add59d08SSam Leffler 628b032f27cSSam Leffler return ic->ic_raw_xmit(ni, m, NULL); 6298a1b9b6aSSam Leffler } 6308a1b9b6aSSam Leffler 6318a1b9b6aSSam Leffler /* 6328a1b9b6aSSam Leffler * Assign priority to a frame based on any vlan tag assigned 6338a1b9b6aSSam Leffler * to the station and/or any Diffserv setting in an IP header. 6348a1b9b6aSSam Leffler * Finally, if an ACM policy is setup (in station mode) it's 6358a1b9b6aSSam Leffler * applied. 6368a1b9b6aSSam Leffler */ 6378a1b9b6aSSam Leffler int 638b032f27cSSam Leffler ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) 6398a1b9b6aSSam Leffler { 640b032f27cSSam Leffler const struct ether_header *eh = mtod(m, struct ether_header *); 6418a1b9b6aSSam Leffler int v_wme_ac, d_wme_ac, ac; 6428a1b9b6aSSam Leffler 643b032f27cSSam Leffler /* 644b032f27cSSam Leffler * Always promote PAE/EAPOL frames to high priority. 645b032f27cSSam Leffler */ 646b032f27cSSam Leffler if (eh->ether_type == htons(ETHERTYPE_PAE)) { 647b032f27cSSam Leffler /* NB: mark so others don't need to check header */ 648b032f27cSSam Leffler m->m_flags |= M_EAPOL; 649b032f27cSSam Leffler ac = WME_AC_VO; 650b032f27cSSam Leffler goto done; 651b032f27cSSam Leffler } 652b032f27cSSam Leffler /* 653b032f27cSSam Leffler * Non-qos traffic goes to BE. 654b032f27cSSam Leffler */ 6558a1b9b6aSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { 6568a1b9b6aSSam Leffler ac = WME_AC_BE; 6578a1b9b6aSSam Leffler goto done; 6588a1b9b6aSSam Leffler } 6598a1b9b6aSSam Leffler 6608a1b9b6aSSam Leffler /* 6618a1b9b6aSSam Leffler * If node has a vlan tag then all traffic 6628a1b9b6aSSam Leffler * to it must have a matching tag. 6638a1b9b6aSSam Leffler */ 6648a1b9b6aSSam Leffler v_wme_ac = 0; 6658a1b9b6aSSam Leffler if (ni->ni_vlan != 0) { 66678ba57b9SAndre Oppermann if ((m->m_flags & M_VLANTAG) == 0) { 6678a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_novlantag); 6688a1b9b6aSSam Leffler return 1; 6698a1b9b6aSSam Leffler } 67078ba57b9SAndre Oppermann if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 6718a1b9b6aSSam Leffler EVL_VLANOFTAG(ni->ni_vlan)) { 6728a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 6738a1b9b6aSSam Leffler return 1; 6748a1b9b6aSSam Leffler } 6758a1b9b6aSSam Leffler /* map vlan priority to AC */ 676f4558c9aSSam Leffler v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); 6778a1b9b6aSSam Leffler } 6788a1b9b6aSSam Leffler 6798a1b9b6aSSam Leffler #ifdef INET 6808a1b9b6aSSam Leffler if (eh->ether_type == htons(ETHERTYPE_IP)) { 681f4558c9aSSam Leffler uint8_t tos; 6828a1b9b6aSSam Leffler /* 683f4558c9aSSam Leffler * IP frame, map the DSCP bits from the TOS field. 6848a1b9b6aSSam Leffler */ 685f4558c9aSSam Leffler /* XXX m_copydata may be too slow for fast path */ 686f4558c9aSSam Leffler /* NB: ip header may not be in first mbuf */ 687f4558c9aSSam Leffler m_copydata(m, sizeof(struct ether_header) + 688f4558c9aSSam Leffler offsetof(struct ip, ip_tos), sizeof(tos), &tos); 689f4558c9aSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 690f4558c9aSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 6918a1b9b6aSSam Leffler } else { 6928a1b9b6aSSam Leffler #endif /* INET */ 6938a1b9b6aSSam Leffler d_wme_ac = WME_AC_BE; 6948a1b9b6aSSam Leffler #ifdef INET 6958a1b9b6aSSam Leffler } 6968a1b9b6aSSam Leffler #endif 6978a1b9b6aSSam Leffler /* 6988a1b9b6aSSam Leffler * Use highest priority AC. 6998a1b9b6aSSam Leffler */ 7008a1b9b6aSSam Leffler if (v_wme_ac > d_wme_ac) 7018a1b9b6aSSam Leffler ac = v_wme_ac; 7028a1b9b6aSSam Leffler else 7038a1b9b6aSSam Leffler ac = d_wme_ac; 7048a1b9b6aSSam Leffler 7058a1b9b6aSSam Leffler /* 7068a1b9b6aSSam Leffler * Apply ACM policy. 7078a1b9b6aSSam Leffler */ 708b032f27cSSam Leffler if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { 7098a1b9b6aSSam Leffler static const int acmap[4] = { 7108a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BE */ 7118a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BK */ 7128a1b9b6aSSam Leffler WME_AC_BE, /* WME_AC_VI */ 7138a1b9b6aSSam Leffler WME_AC_VI, /* WME_AC_VO */ 7148a1b9b6aSSam Leffler }; 715b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 716b032f27cSSam Leffler 7178a1b9b6aSSam Leffler while (ac != WME_AC_BK && 7188a1b9b6aSSam Leffler ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) 7198a1b9b6aSSam Leffler ac = acmap[ac]; 7208a1b9b6aSSam Leffler } 7218a1b9b6aSSam Leffler done: 7228a1b9b6aSSam Leffler M_WME_SETAC(m, ac); 7238a1b9b6aSSam Leffler return 0; 7248a1b9b6aSSam Leffler } 7258a1b9b6aSSam Leffler 7268a1b9b6aSSam Leffler /* 7275e923d2eSSam Leffler * Insure there is sufficient contiguous space to encapsulate the 7285e923d2eSSam Leffler * 802.11 data frame. If room isn't already there, arrange for it. 7295e923d2eSSam Leffler * Drivers and cipher modules assume we have done the necessary work 7305e923d2eSSam Leffler * and fail rudely if they don't find the space they need. 7315e923d2eSSam Leffler */ 7325e923d2eSSam Leffler static struct mbuf * 733b032f27cSSam Leffler ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, 7345e923d2eSSam Leffler struct ieee80211_key *key, struct mbuf *m) 7355e923d2eSSam Leffler { 736ab96db10SSam Leffler #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) 737b032f27cSSam Leffler int needed_space = vap->iv_ic->ic_headroom + hdrsize; 7385e923d2eSSam Leffler 7395e923d2eSSam Leffler if (key != NULL) { 7405e923d2eSSam Leffler /* XXX belongs in crypto code? */ 7415e923d2eSSam Leffler needed_space += key->wk_cipher->ic_header; 7425e923d2eSSam Leffler /* XXX frags */ 74383a244dbSSam Leffler /* 74483a244dbSSam Leffler * When crypto is being done in the host we must insure 74583a244dbSSam Leffler * the data are writable for the cipher routines; clone 74683a244dbSSam Leffler * a writable mbuf chain. 74783a244dbSSam Leffler * XXX handle SWMIC specially 74883a244dbSSam Leffler */ 7495c1f7f19SSam Leffler if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { 75083a244dbSSam Leffler m = m_unshare(m, M_NOWAIT); 75183a244dbSSam Leffler if (m == NULL) { 752b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 75383a244dbSSam Leffler "%s: cannot get writable mbuf\n", __func__); 754b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ 75583a244dbSSam Leffler return NULL; 75683a244dbSSam Leffler } 75783a244dbSSam Leffler } 7585e923d2eSSam Leffler } 7595e923d2eSSam Leffler /* 7605e923d2eSSam Leffler * We know we are called just before stripping an Ethernet 7615e923d2eSSam Leffler * header and prepending an LLC header. This means we know 7625e923d2eSSam Leffler * there will be 763ab96db10SSam Leffler * sizeof(struct ether_header) - sizeof(struct llc) 7645e923d2eSSam Leffler * bytes recovered to which we need additional space for the 7655e923d2eSSam Leffler * 802.11 header and any crypto header. 7665e923d2eSSam Leffler */ 7675e923d2eSSam Leffler /* XXX check trailing space and copy instead? */ 7685e923d2eSSam Leffler if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { 7695e923d2eSSam Leffler struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); 7705e923d2eSSam Leffler if (n == NULL) { 771b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 7725e923d2eSSam Leffler "%s: cannot expand storage\n", __func__); 773b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 7745e923d2eSSam Leffler m_freem(m); 7755e923d2eSSam Leffler return NULL; 7765e923d2eSSam Leffler } 7775e923d2eSSam Leffler KASSERT(needed_space <= MHLEN, 7785e923d2eSSam Leffler ("not enough room, need %u got %zu\n", needed_space, MHLEN)); 7795e923d2eSSam Leffler /* 7805e923d2eSSam Leffler * Setup new mbuf to have leading space to prepend the 7815e923d2eSSam Leffler * 802.11 header and any crypto header bits that are 7825e923d2eSSam Leffler * required (the latter are added when the driver calls 7835e923d2eSSam Leffler * back to ieee80211_crypto_encap to do crypto encapsulation). 7845e923d2eSSam Leffler */ 7855e923d2eSSam Leffler /* NB: must be first 'cuz it clobbers m_data */ 7865e923d2eSSam Leffler m_move_pkthdr(n, m); 7875e923d2eSSam Leffler n->m_len = 0; /* NB: m_gethdr does not set */ 7885e923d2eSSam Leffler n->m_data += needed_space; 7895e923d2eSSam Leffler /* 7905e923d2eSSam Leffler * Pull up Ethernet header to create the expected layout. 7915e923d2eSSam Leffler * We could use m_pullup but that's overkill (i.e. we don't 7925e923d2eSSam Leffler * need the actual data) and it cannot fail so do it inline 7935e923d2eSSam Leffler * for speed. 7945e923d2eSSam Leffler */ 7955e923d2eSSam Leffler /* NB: struct ether_header is known to be contiguous */ 7965e923d2eSSam Leffler n->m_len += sizeof(struct ether_header); 7975e923d2eSSam Leffler m->m_len -= sizeof(struct ether_header); 7985e923d2eSSam Leffler m->m_data += sizeof(struct ether_header); 7995e923d2eSSam Leffler /* 8005e923d2eSSam Leffler * Replace the head of the chain. 8015e923d2eSSam Leffler */ 8025e923d2eSSam Leffler n->m_next = m; 8035e923d2eSSam Leffler m = n; 8045e923d2eSSam Leffler } 8055e923d2eSSam Leffler return m; 8065e923d2eSSam Leffler #undef TO_BE_RECLAIMED 8075e923d2eSSam Leffler } 8085e923d2eSSam Leffler 8095e923d2eSSam Leffler /* 8105e923d2eSSam Leffler * Return the transmit key to use in sending a unicast frame. 8115e923d2eSSam Leffler * If a unicast key is set we use that. When no unicast key is set 8125e923d2eSSam Leffler * we fall back to the default transmit key. 8138a1b9b6aSSam Leffler */ 8148a1b9b6aSSam Leffler static __inline struct ieee80211_key * 815b032f27cSSam Leffler ieee80211_crypto_getucastkey(struct ieee80211vap *vap, 816b032f27cSSam Leffler struct ieee80211_node *ni) 8178a1b9b6aSSam Leffler { 818cda15ce1SSam Leffler if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { 819b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 820b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 8218a1b9b6aSSam Leffler return NULL; 822b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 8238a1b9b6aSSam Leffler } else { 8248a1b9b6aSSam Leffler return &ni->ni_ucastkey; 8258a1b9b6aSSam Leffler } 8265e923d2eSSam Leffler } 8275e923d2eSSam Leffler 8285e923d2eSSam Leffler /* 8295e923d2eSSam Leffler * Return the transmit key to use in sending a multicast frame. 8305e923d2eSSam Leffler * Multicast traffic always uses the group key which is installed as 8315e923d2eSSam Leffler * the default tx key. 8325e923d2eSSam Leffler */ 8335e923d2eSSam Leffler static __inline struct ieee80211_key * 834b032f27cSSam Leffler ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, 835b032f27cSSam Leffler struct ieee80211_node *ni) 8365e923d2eSSam Leffler { 837b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 838b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 8395e923d2eSSam Leffler return NULL; 840b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 8418a1b9b6aSSam Leffler } 8428a1b9b6aSSam Leffler 8438a1b9b6aSSam Leffler /* 8448a1b9b6aSSam Leffler * Encapsulate an outbound data frame. The mbuf chain is updated. 8458a1b9b6aSSam Leffler * If an error is encountered NULL is returned. The caller is required 8468a1b9b6aSSam Leffler * to provide a node reference and pullup the ethernet header in the 8478a1b9b6aSSam Leffler * first mbuf. 848b032f27cSSam Leffler * 849b032f27cSSam Leffler * NB: Packet is assumed to be processed by ieee80211_classify which 850b032f27cSSam Leffler * marked EAPOL frames w/ M_EAPOL. 8510a915fadSSam Leffler */ 8521a1e1d21SSam Leffler struct mbuf * 853b032f27cSSam Leffler ieee80211_encap(struct ieee80211_node *ni, struct mbuf *m) 8541a1e1d21SSam Leffler { 855b032f27cSSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) 856b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 857b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 8581a1e1d21SSam Leffler struct ether_header eh; 8591a1e1d21SSam Leffler struct ieee80211_frame *wh; 8608a1b9b6aSSam Leffler struct ieee80211_key *key; 8611a1e1d21SSam Leffler struct llc *llc; 862b032f27cSSam Leffler int hdrsize, hdrspace, datalen, addqos, txfrag, isff, is4addr; 8631a1e1d21SSam Leffler 86468e8e04eSSam Leffler /* 86568e8e04eSSam Leffler * Copy existing Ethernet header to a safe place. The 86668e8e04eSSam Leffler * rest of the code assumes it's ok to strip it when 86768e8e04eSSam Leffler * reorganizing state for the final encapsulation. 86868e8e04eSSam Leffler */ 8698a1b9b6aSSam Leffler KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); 870b032f27cSSam Leffler ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); 8711a1e1d21SSam Leffler 8728a1b9b6aSSam Leffler /* 8738a1b9b6aSSam Leffler * Insure space for additional headers. First identify 8748a1b9b6aSSam Leffler * transmit key to use in calculating any buffer adjustments 8758a1b9b6aSSam Leffler * required. This is also used below to do privacy 8768a1b9b6aSSam Leffler * encapsulation work. Then calculate the 802.11 header 8778a1b9b6aSSam Leffler * size and any padding required by the driver. 8788a1b9b6aSSam Leffler * 8798a1b9b6aSSam Leffler * Note key may be NULL if we fall back to the default 8808a1b9b6aSSam Leffler * transmit key and that is not set. In that case the 8818a1b9b6aSSam Leffler * buffer may not be expanded as needed by the cipher 8828a1b9b6aSSam Leffler * routines, but they will/should discard it. 8838a1b9b6aSSam Leffler */ 884b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) { 885b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA || 886b032f27cSSam Leffler !IEEE80211_IS_MULTICAST(eh.ether_dhost) || 887b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_WDS && 888b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) 889b032f27cSSam Leffler key = ieee80211_crypto_getucastkey(vap, ni); 8905e923d2eSSam Leffler else 891b032f27cSSam Leffler key = ieee80211_crypto_getmcastkey(vap, ni); 892b032f27cSSam Leffler if (key == NULL && (m->m_flags & M_EAPOL) == 0) { 893b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, 894b032f27cSSam Leffler eh.ether_dhost, 895b032f27cSSam Leffler "no default transmit key (%s) deftxkey %u", 896b032f27cSSam Leffler __func__, vap->iv_def_txkey); 897b032f27cSSam Leffler vap->iv_stats.is_tx_nodefkey++; 898d72c7253SSam Leffler goto bad; 8998a1b9b6aSSam Leffler } 9008a1b9b6aSSam Leffler } else 9018a1b9b6aSSam Leffler key = NULL; 9025e923d2eSSam Leffler /* 9035e923d2eSSam Leffler * XXX Some ap's don't handle QoS-encapsulated EAPOL 9045e923d2eSSam Leffler * frames so suppress use. This may be an issue if other 9055e923d2eSSam Leffler * ap's require all data frames to be QoS-encapsulated 9065e923d2eSSam Leffler * once negotiated in which case we'll need to make this 9075e923d2eSSam Leffler * configurable. 9085e923d2eSSam Leffler */ 90968e8e04eSSam Leffler addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) && 910b032f27cSSam Leffler (m->m_flags & M_EAPOL) == 0; 9115e923d2eSSam Leffler if (addqos) 9128a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_qosframe); 9138a1b9b6aSSam Leffler else 9148a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_frame); 915b032f27cSSam Leffler /* 916b032f27cSSam Leffler * 4-address frames need to be generated for: 917b032f27cSSam Leffler * o packets sent through a WDS vap (M_WDS || IEEE80211_M_WDS) 918b032f27cSSam Leffler * o packets relayed by a station operating with dynamic WDS 919b032f27cSSam Leffler * (IEEE80211_M_STA+IEEE80211_F_DWDS and src address) 920b032f27cSSam Leffler */ 921b032f27cSSam Leffler is4addr = (m->m_flags & M_WDS) || 922b032f27cSSam Leffler vap->iv_opmode == IEEE80211_M_WDS || /* XXX redundant? */ 923b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_STA && 924b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_DWDS) && 925b032f27cSSam Leffler !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); 926b032f27cSSam Leffler if (is4addr) 927b032f27cSSam Leffler hdrsize += IEEE80211_ADDR_LEN; 928b032f27cSSam Leffler /* 929b032f27cSSam Leffler * Honor driver DATAPAD requirement. 930b032f27cSSam Leffler */ 9318a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 932b032f27cSSam Leffler hdrspace = roundup(hdrsize, sizeof(uint32_t)); 933b032f27cSSam Leffler else 934b032f27cSSam Leffler hdrspace = hdrsize; 93568e8e04eSSam Leffler 93668e8e04eSSam Leffler if ((isff = m->m_flags & M_FF) != 0) { 93768e8e04eSSam Leffler struct mbuf *m2; 93868e8e04eSSam Leffler struct ether_header eh2; 93968e8e04eSSam Leffler 94068e8e04eSSam Leffler /* 94168e8e04eSSam Leffler * Fast frame encapsulation. There must be two packets 94268e8e04eSSam Leffler * chained with m_nextpkt. We do header adjustment for 94368e8e04eSSam Leffler * each, add the tunnel encapsulation, and then concatenate 94468e8e04eSSam Leffler * the mbuf chains to form a single frame for transmission. 94568e8e04eSSam Leffler */ 94668e8e04eSSam Leffler m2 = m->m_nextpkt; 94768e8e04eSSam Leffler if (m2 == NULL) { 948b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 94968e8e04eSSam Leffler "%s: only one frame\n", __func__); 95068e8e04eSSam Leffler goto bad; 95168e8e04eSSam Leffler } 95268e8e04eSSam Leffler m->m_nextpkt = NULL; 95368e8e04eSSam Leffler /* 95468e8e04eSSam Leffler * Include fast frame headers in adjusting header 95568e8e04eSSam Leffler * layout; this allocates space according to what 95668e8e04eSSam Leffler * ieee80211_encap_fastframe will do. 95768e8e04eSSam Leffler */ 958b032f27cSSam Leffler m = ieee80211_mbuf_adjust(vap, 959b032f27cSSam Leffler hdrspace + sizeof(struct llc) + sizeof(uint32_t) + 2 + 96068e8e04eSSam Leffler sizeof(struct ether_header), 96168e8e04eSSam Leffler key, m); 96268e8e04eSSam Leffler if (m == NULL) { 96368e8e04eSSam Leffler /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 96468e8e04eSSam Leffler m_freem(m2); 96568e8e04eSSam Leffler goto bad; 96668e8e04eSSam Leffler } 96768e8e04eSSam Leffler /* 96868e8e04eSSam Leffler * Copy second frame's Ethernet header out of line 96968e8e04eSSam Leffler * and adjust for encapsulation headers. Note that 97068e8e04eSSam Leffler * we make room for padding in case there isn't room 97168e8e04eSSam Leffler * at the end of first frame. 97268e8e04eSSam Leffler */ 97368e8e04eSSam Leffler KASSERT(m2->m_len >= sizeof(eh2), ("no ethernet header!")); 974b032f27cSSam Leffler ETHER_HEADER_COPY(&eh2, mtod(m2, caddr_t)); 975b032f27cSSam Leffler m2 = ieee80211_mbuf_adjust(vap, 97668e8e04eSSam Leffler ATH_FF_MAX_HDR_PAD + sizeof(struct ether_header), 97768e8e04eSSam Leffler NULL, m2); 97868e8e04eSSam Leffler if (m2 == NULL) { 97968e8e04eSSam Leffler /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 98068e8e04eSSam Leffler goto bad; 98168e8e04eSSam Leffler } 982b032f27cSSam Leffler m = ieee80211_encap_fastframe(vap, m, &eh, m2, &eh2); 98368e8e04eSSam Leffler if (m == NULL) 98468e8e04eSSam Leffler goto bad; 98568e8e04eSSam Leffler } else { 98668e8e04eSSam Leffler /* 98768e8e04eSSam Leffler * Normal frame. 98868e8e04eSSam Leffler */ 989b032f27cSSam Leffler m = ieee80211_mbuf_adjust(vap, hdrspace, key, m); 9908a1b9b6aSSam Leffler if (m == NULL) { 9918a1b9b6aSSam Leffler /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 9920a915fadSSam Leffler goto bad; 9930a915fadSSam Leffler } 99468e8e04eSSam Leffler /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ 995ab96db10SSam Leffler m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 9961a1e1d21SSam Leffler llc = mtod(m, struct llc *); 9971a1e1d21SSam Leffler llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 9981a1e1d21SSam Leffler llc->llc_control = LLC_UI; 9991a1e1d21SSam Leffler llc->llc_snap.org_code[0] = 0; 10001a1e1d21SSam Leffler llc->llc_snap.org_code[1] = 0; 10011a1e1d21SSam Leffler llc->llc_snap.org_code[2] = 0; 10021a1e1d21SSam Leffler llc->llc_snap.ether_type = eh.ether_type; 100368e8e04eSSam Leffler } 10048a1b9b6aSSam Leffler datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ 10058a1b9b6aSSam Leffler 1006b032f27cSSam Leffler M_PREPEND(m, hdrspace, M_DONTWAIT); 10071be50176SSam Leffler if (m == NULL) { 1008b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 10090a915fadSSam Leffler goto bad; 10101be50176SSam Leffler } 10111a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 10121a1e1d21SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 101368e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 1014b032f27cSSam Leffler if (is4addr) { 1015b032f27cSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 1016b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 1017b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1018b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1019b032f27cSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 1020b032f27cSSam Leffler } else switch (vap->iv_opmode) { 10211a1e1d21SSam Leffler case IEEE80211_M_STA: 10221a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 10231a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 10241a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 10251a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 10261a1e1d21SSam Leffler break; 10271a1e1d21SSam Leffler case IEEE80211_M_IBSS: 10281a1e1d21SSam Leffler case IEEE80211_M_AHDEMO: 10291a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 10301a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 10311a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1032a8b16e87SSam Leffler /* 1033b032f27cSSam Leffler * NB: always use the bssid from iv_bss as the 1034a8b16e87SSam Leffler * neighbor's may be stale after an ibss merge 1035a8b16e87SSam Leffler */ 1036b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); 10371a1e1d21SSam Leffler break; 10381a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 10391a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 10401a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 10411a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 10421a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 10431a1e1d21SSam Leffler break; 10442bbe529dSSam Leffler case IEEE80211_M_MONITOR: 1045b032f27cSSam Leffler case IEEE80211_M_WDS: /* NB: is4addr should always be true */ 10460a915fadSSam Leffler goto bad; 10471a1e1d21SSam Leffler } 1048bc5627d9SSam Leffler if (m->m_flags & M_MORE_DATA) 1049bc5627d9SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 10505e923d2eSSam Leffler if (addqos) { 1051b032f27cSSam Leffler uint8_t *qos; 10528a1b9b6aSSam Leffler int ac, tid; 10538a1b9b6aSSam Leffler 1054b032f27cSSam Leffler if (is4addr) { 1055b032f27cSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 1056b032f27cSSam Leffler } else 1057b032f27cSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 10588a1b9b6aSSam Leffler ac = M_WME_GETAC(m); 10598a1b9b6aSSam Leffler /* map from access class/queue to 11e header priorty value */ 10608a1b9b6aSSam Leffler tid = WME_AC_TO_TID(ac); 1061b032f27cSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 106268e8e04eSSam Leffler /* 106368e8e04eSSam Leffler * Check if A-MPDU tx aggregation is setup or if we 106468e8e04eSSam Leffler * should try to enable it. The sta must be associated 1065b032f27cSSam Leffler * with HT and A-MPDU enabled for use. When the policy 1066b032f27cSSam Leffler * routine decides we should enable A-MPDU we issue an 1067b032f27cSSam Leffler * ADDBA request and wait for a reply. The frame being 1068b032f27cSSam Leffler * encapsulated will go out w/o using A-MPDU, or possibly 1069b032f27cSSam Leffler * it might be collected by the driver and held/retransmit. 1070b032f27cSSam Leffler * The default ic_ampdu_enable routine handles staggering 1071b032f27cSSam Leffler * ADDBA requests in case the receiver NAK's us or we are 1072b032f27cSSam Leffler * otherwise unable to establish a BA stream. 107368e8e04eSSam Leffler */ 10741b6167d2SSam Leffler if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && 1075b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_AMPDU_TX)) { 107668e8e04eSSam Leffler struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; 107768e8e04eSSam Leffler 1078b032f27cSSam Leffler ieee80211_txampdu_count_packet(tap); 107968e8e04eSSam Leffler if (IEEE80211_AMPDU_RUNNING(tap)) { 108068e8e04eSSam Leffler /* 108168e8e04eSSam Leffler * Operational, mark frame for aggregation. 108245f856e3SSam Leffler * 108345f856e3SSam Leffler * NB: We support only immediate BA's for 108445f856e3SSam Leffler * AMPDU which means we set the QoS control 108545f856e3SSam Leffler * field to "normal ack" (0) to get "implicit 108645f856e3SSam Leffler * block ack" behaviour. 108768e8e04eSSam Leffler */ 108845f856e3SSam Leffler m->m_flags |= M_AMPDU_MPDU; 1089b032f27cSSam Leffler } else if (!IEEE80211_AMPDU_REQUESTED(tap) && 1090b032f27cSSam Leffler ic->ic_ampdu_enable(ni, tap)) { 109168e8e04eSSam Leffler /* 109268e8e04eSSam Leffler * Not negotiated yet, request service. 109368e8e04eSSam Leffler */ 109468e8e04eSSam Leffler ieee80211_ampdu_request(ni, tap); 109568e8e04eSSam Leffler } 109668e8e04eSSam Leffler } 109768e8e04eSSam Leffler /* XXX works even when BA marked above */ 10988a1b9b6aSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) 1099b032f27cSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 1100b032f27cSSam Leffler qos[1] = 0; 1101b032f27cSSam Leffler wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; 11028a1b9b6aSSam Leffler 110345f856e3SSam Leffler if ((m->m_flags & M_AMPDU_MPDU) == 0) { 110445f856e3SSam Leffler /* 110545f856e3SSam Leffler * NB: don't assign a sequence # to potential 110645f856e3SSam Leffler * aggregates; we expect this happens at the 110745f856e3SSam Leffler * point the frame comes off any aggregation q 110845f856e3SSam Leffler * as otherwise we may introduce holes in the 110945f856e3SSam Leffler * BA sequence space and/or make window accouting 111045f856e3SSam Leffler * more difficult. 111145f856e3SSam Leffler * 111245f856e3SSam Leffler * XXX may want to control this with a driver 111345f856e3SSam Leffler * capability; this may also change when we pull 111445f856e3SSam Leffler * aggregation up into net80211 111545f856e3SSam Leffler */ 111668e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 11178a1b9b6aSSam Leffler htole16(ni->ni_txseqs[tid] << IEEE80211_SEQ_SEQ_SHIFT); 11188a1b9b6aSSam Leffler ni->ni_txseqs[tid]++; 111945f856e3SSam Leffler } 11208a1b9b6aSSam Leffler } else { 112168e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 1122801df4a5SSam Leffler htole16(ni->ni_txseqs[IEEE80211_NONQOS_TID] << IEEE80211_SEQ_SEQ_SHIFT); 1123801df4a5SSam Leffler ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 11248a1b9b6aSSam Leffler } 112568e8e04eSSam Leffler /* check if xmit fragmentation is required */ 1126b032f27cSSam Leffler txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && 112768e8e04eSSam Leffler !IEEE80211_IS_MULTICAST(wh->i_addr1) && 1128b032f27cSSam Leffler (vap->iv_caps & IEEE80211_C_TXFRAG) && 112968e8e04eSSam Leffler !isff); /* NB: don't fragment ff's */ 11305e923d2eSSam Leffler if (key != NULL) { 11315e923d2eSSam Leffler /* 11325e923d2eSSam Leffler * IEEE 802.1X: send EAPOL frames always in the clear. 11335e923d2eSSam Leffler * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 11345e923d2eSSam Leffler */ 1135b032f27cSSam Leffler if ((m->m_flags & M_EAPOL) == 0 || 1136b032f27cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) && 1137b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_STA ? 1138cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(key) : 1139cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { 11405e923d2eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 1141b032f27cSSam Leffler if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { 1142b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, 1143b032f27cSSam Leffler eh.ether_dhost, 1144b032f27cSSam Leffler "%s", "enmic failed, discard frame"); 1145b032f27cSSam Leffler vap->iv_stats.is_crypto_enmicfail++; 11465e923d2eSSam Leffler goto bad; 11475e923d2eSSam Leffler } 11485e923d2eSSam Leffler } 11495e923d2eSSam Leffler } 1150b032f27cSSam Leffler if (txfrag && !ieee80211_fragment(vap, m, hdrsize, 1151b032f27cSSam Leffler key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) 115268e8e04eSSam Leffler goto bad; 11538a1b9b6aSSam Leffler 11548a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 1155b6e9b119SSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 1156b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 1157b6e9b119SSam Leffler else 1158b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 11598a1b9b6aSSam Leffler IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); 11608a1b9b6aSSam Leffler 1161b032f27cSSam Leffler /* XXX fragmented frames not handled */ 1162b032f27cSSam Leffler if (bpf_peers_present(vap->iv_rawbpf)) 1163b032f27cSSam Leffler bpf_mtap(vap->iv_rawbpf, m); 1164b032f27cSSam Leffler 11651a1e1d21SSam Leffler return m; 11660a915fadSSam Leffler bad: 11670a915fadSSam Leffler if (m != NULL) 11680a915fadSSam Leffler m_freem(m); 11690a915fadSSam Leffler return NULL; 1170b032f27cSSam Leffler #undef WH4 11711a1e1d21SSam Leffler } 11721a1e1d21SSam Leffler 11731a1e1d21SSam Leffler /* 117468e8e04eSSam Leffler * Do Ethernet-LLC encapsulation for each payload in a fast frame 117568e8e04eSSam Leffler * tunnel encapsulation. The frame is assumed to have an Ethernet 117668e8e04eSSam Leffler * header at the front that must be stripped before prepending the 117768e8e04eSSam Leffler * LLC followed by the Ethernet header passed in (with an Ethernet 117868e8e04eSSam Leffler * type that specifies the payload size). 117968e8e04eSSam Leffler */ 118068e8e04eSSam Leffler static struct mbuf * 1181b032f27cSSam Leffler ieee80211_encap1(struct ieee80211vap *vap, struct mbuf *m, 118268e8e04eSSam Leffler const struct ether_header *eh) 118368e8e04eSSam Leffler { 118468e8e04eSSam Leffler struct llc *llc; 118568e8e04eSSam Leffler uint16_t payload; 118668e8e04eSSam Leffler 118768e8e04eSSam Leffler /* XXX optimize by combining m_adj+M_PREPEND */ 118868e8e04eSSam Leffler m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 118968e8e04eSSam Leffler llc = mtod(m, struct llc *); 119068e8e04eSSam Leffler llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 119168e8e04eSSam Leffler llc->llc_control = LLC_UI; 119268e8e04eSSam Leffler llc->llc_snap.org_code[0] = 0; 119368e8e04eSSam Leffler llc->llc_snap.org_code[1] = 0; 119468e8e04eSSam Leffler llc->llc_snap.org_code[2] = 0; 119568e8e04eSSam Leffler llc->llc_snap.ether_type = eh->ether_type; 119668e8e04eSSam Leffler payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */ 119768e8e04eSSam Leffler 119868e8e04eSSam Leffler M_PREPEND(m, sizeof(struct ether_header), M_DONTWAIT); 119968e8e04eSSam Leffler if (m == NULL) { /* XXX cannot happen */ 1200b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 120168e8e04eSSam Leffler "%s: no space for ether_header\n", __func__); 1202b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 120368e8e04eSSam Leffler return NULL; 120468e8e04eSSam Leffler } 120568e8e04eSSam Leffler ETHER_HEADER_COPY(mtod(m, void *), eh); 120668e8e04eSSam Leffler mtod(m, struct ether_header *)->ether_type = htons(payload); 120768e8e04eSSam Leffler return m; 120868e8e04eSSam Leffler } 120968e8e04eSSam Leffler 121068e8e04eSSam Leffler /* 121168e8e04eSSam Leffler * Do fast frame tunnel encapsulation. The two frames and 121268e8e04eSSam Leffler * Ethernet headers are supplied. The caller is assumed to 121368e8e04eSSam Leffler * have arrange for space in the mbuf chains for encapsulating 121468e8e04eSSam Leffler * headers (to avoid major mbuf fragmentation). 121568e8e04eSSam Leffler * 121668e8e04eSSam Leffler * The encapsulated frame is returned or NULL if there is a 121768e8e04eSSam Leffler * problem (should not happen). 121868e8e04eSSam Leffler */ 121968e8e04eSSam Leffler static struct mbuf * 1220b032f27cSSam Leffler ieee80211_encap_fastframe(struct ieee80211vap *vap, 122168e8e04eSSam Leffler struct mbuf *m1, const struct ether_header *eh1, 122268e8e04eSSam Leffler struct mbuf *m2, const struct ether_header *eh2) 122368e8e04eSSam Leffler { 122468e8e04eSSam Leffler struct llc *llc; 122568e8e04eSSam Leffler struct mbuf *m; 122668e8e04eSSam Leffler int pad; 122768e8e04eSSam Leffler 122868e8e04eSSam Leffler /* 122968e8e04eSSam Leffler * First, each frame gets a standard encapsulation. 123068e8e04eSSam Leffler */ 1231b032f27cSSam Leffler m1 = ieee80211_encap1(vap, m1, eh1); 123268e8e04eSSam Leffler if (m1 == NULL) { 123368e8e04eSSam Leffler m_freem(m2); 123468e8e04eSSam Leffler return NULL; 123568e8e04eSSam Leffler } 1236b032f27cSSam Leffler m2 = ieee80211_encap1(vap, m2, eh2); 123768e8e04eSSam Leffler if (m2 == NULL) { 123868e8e04eSSam Leffler m_freem(m1); 123968e8e04eSSam Leffler return NULL; 124068e8e04eSSam Leffler } 124168e8e04eSSam Leffler 124268e8e04eSSam Leffler /* 124368e8e04eSSam Leffler * Pad leading frame to a 4-byte boundary. If there 124468e8e04eSSam Leffler * is space at the end of the first frame, put it 124568e8e04eSSam Leffler * there; otherwise prepend to the front of the second 124668e8e04eSSam Leffler * frame. We know doing the second will always work 124768e8e04eSSam Leffler * because we reserve space above. We prefer appending 124868e8e04eSSam Leffler * as this typically has better DMA alignment properties. 124968e8e04eSSam Leffler */ 125068e8e04eSSam Leffler for (m = m1; m->m_next != NULL; m = m->m_next) 125168e8e04eSSam Leffler ; 125268e8e04eSSam Leffler pad = roundup2(m1->m_pkthdr.len, 4) - m1->m_pkthdr.len; 125368e8e04eSSam Leffler if (pad) { 125468e8e04eSSam Leffler if (M_TRAILINGSPACE(m) < pad) { /* prepend to second */ 125568e8e04eSSam Leffler m2->m_data -= pad; 125668e8e04eSSam Leffler m2->m_len += pad; 125768e8e04eSSam Leffler m2->m_pkthdr.len += pad; 125868e8e04eSSam Leffler } else { /* append to first */ 125968e8e04eSSam Leffler m->m_len += pad; 126068e8e04eSSam Leffler m1->m_pkthdr.len += pad; 126168e8e04eSSam Leffler } 126268e8e04eSSam Leffler } 126368e8e04eSSam Leffler 126468e8e04eSSam Leffler /* 126568e8e04eSSam Leffler * Now, stick 'em together and prepend the tunnel headers; 126668e8e04eSSam Leffler * first the Atheros tunnel header (all zero for now) and 126768e8e04eSSam Leffler * then a special fast frame LLC. 126868e8e04eSSam Leffler * 126968e8e04eSSam Leffler * XXX optimize by prepending together 127068e8e04eSSam Leffler */ 127168e8e04eSSam Leffler m->m_next = m2; /* NB: last mbuf from above */ 127268e8e04eSSam Leffler m1->m_pkthdr.len += m2->m_pkthdr.len; 127368e8e04eSSam Leffler M_PREPEND(m1, sizeof(uint32_t)+2, M_DONTWAIT); 127468e8e04eSSam Leffler if (m1 == NULL) { /* XXX cannot happen */ 1275b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 127668e8e04eSSam Leffler "%s: no space for tunnel header\n", __func__); 1277b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 127868e8e04eSSam Leffler return NULL; 127968e8e04eSSam Leffler } 128068e8e04eSSam Leffler memset(mtod(m1, void *), 0, sizeof(uint32_t)+2); 128168e8e04eSSam Leffler 128268e8e04eSSam Leffler M_PREPEND(m1, sizeof(struct llc), M_DONTWAIT); 128368e8e04eSSam Leffler if (m1 == NULL) { /* XXX cannot happen */ 1284b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 128568e8e04eSSam Leffler "%s: no space for llc header\n", __func__); 1286b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 128768e8e04eSSam Leffler return NULL; 128868e8e04eSSam Leffler } 128968e8e04eSSam Leffler llc = mtod(m1, struct llc *); 129068e8e04eSSam Leffler llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 129168e8e04eSSam Leffler llc->llc_control = LLC_UI; 129268e8e04eSSam Leffler llc->llc_snap.org_code[0] = ATH_FF_SNAP_ORGCODE_0; 129368e8e04eSSam Leffler llc->llc_snap.org_code[1] = ATH_FF_SNAP_ORGCODE_1; 129468e8e04eSSam Leffler llc->llc_snap.org_code[2] = ATH_FF_SNAP_ORGCODE_2; 129568e8e04eSSam Leffler llc->llc_snap.ether_type = htons(ATH_FF_ETH_TYPE); 129668e8e04eSSam Leffler 1297b032f27cSSam Leffler vap->iv_stats.is_ff_encap++; 129868e8e04eSSam Leffler 129968e8e04eSSam Leffler return m1; 130068e8e04eSSam Leffler } 130168e8e04eSSam Leffler 130268e8e04eSSam Leffler /* 130368e8e04eSSam Leffler * Fragment the frame according to the specified mtu. 130468e8e04eSSam Leffler * The size of the 802.11 header (w/o padding) is provided 130568e8e04eSSam Leffler * so we don't need to recalculate it. We create a new 130668e8e04eSSam Leffler * mbuf for each fragment and chain it through m_nextpkt; 130768e8e04eSSam Leffler * we might be able to optimize this by reusing the original 130868e8e04eSSam Leffler * packet's mbufs but that is significantly more complicated. 130968e8e04eSSam Leffler */ 131068e8e04eSSam Leffler static int 1311b032f27cSSam Leffler ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, 131268e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu) 131368e8e04eSSam Leffler { 131468e8e04eSSam Leffler struct ieee80211_frame *wh, *whf; 131568e8e04eSSam Leffler struct mbuf *m, *prev, *next; 131668e8e04eSSam Leffler u_int totalhdrsize, fragno, fragsize, off, remainder, payload; 131768e8e04eSSam Leffler 131868e8e04eSSam Leffler KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); 131968e8e04eSSam Leffler KASSERT(m0->m_pkthdr.len > mtu, 132068e8e04eSSam Leffler ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); 132168e8e04eSSam Leffler 132268e8e04eSSam Leffler wh = mtod(m0, struct ieee80211_frame *); 132368e8e04eSSam Leffler /* NB: mark the first frag; it will be propagated below */ 132468e8e04eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; 132568e8e04eSSam Leffler totalhdrsize = hdrsize + ciphdrsize; 132668e8e04eSSam Leffler fragno = 1; 132768e8e04eSSam Leffler off = mtu - ciphdrsize; 132868e8e04eSSam Leffler remainder = m0->m_pkthdr.len - off; 132968e8e04eSSam Leffler prev = m0; 133068e8e04eSSam Leffler do { 133168e8e04eSSam Leffler fragsize = totalhdrsize + remainder; 133268e8e04eSSam Leffler if (fragsize > mtu) 133368e8e04eSSam Leffler fragsize = mtu; 1334b032f27cSSam Leffler /* XXX fragsize can be >2048! */ 133568e8e04eSSam Leffler KASSERT(fragsize < MCLBYTES, 133668e8e04eSSam Leffler ("fragment size %u too big!", fragsize)); 133768e8e04eSSam Leffler if (fragsize > MHLEN) 133868e8e04eSSam Leffler m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 133968e8e04eSSam Leffler else 134068e8e04eSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 134168e8e04eSSam Leffler if (m == NULL) 134268e8e04eSSam Leffler goto bad; 134368e8e04eSSam Leffler /* leave room to prepend any cipher header */ 134468e8e04eSSam Leffler m_align(m, fragsize - ciphdrsize); 134568e8e04eSSam Leffler 134668e8e04eSSam Leffler /* 134768e8e04eSSam Leffler * Form the header in the fragment. Note that since 134868e8e04eSSam Leffler * we mark the first fragment with the MORE_FRAG bit 134968e8e04eSSam Leffler * it automatically is propagated to each fragment; we 135068e8e04eSSam Leffler * need only clear it on the last fragment (done below). 135168e8e04eSSam Leffler */ 135268e8e04eSSam Leffler whf = mtod(m, struct ieee80211_frame *); 135368e8e04eSSam Leffler memcpy(whf, wh, hdrsize); 135468e8e04eSSam Leffler *(uint16_t *)&whf->i_seq[0] |= htole16( 135568e8e04eSSam Leffler (fragno & IEEE80211_SEQ_FRAG_MASK) << 135668e8e04eSSam Leffler IEEE80211_SEQ_FRAG_SHIFT); 135768e8e04eSSam Leffler fragno++; 135868e8e04eSSam Leffler 135968e8e04eSSam Leffler payload = fragsize - totalhdrsize; 136068e8e04eSSam Leffler /* NB: destination is known to be contiguous */ 136168e8e04eSSam Leffler m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrsize); 136268e8e04eSSam Leffler m->m_len = hdrsize + payload; 136368e8e04eSSam Leffler m->m_pkthdr.len = hdrsize + payload; 136468e8e04eSSam Leffler m->m_flags |= M_FRAG; 136568e8e04eSSam Leffler 136668e8e04eSSam Leffler /* chain up the fragment */ 136768e8e04eSSam Leffler prev->m_nextpkt = m; 136868e8e04eSSam Leffler prev = m; 136968e8e04eSSam Leffler 137068e8e04eSSam Leffler /* deduct fragment just formed */ 137168e8e04eSSam Leffler remainder -= payload; 137268e8e04eSSam Leffler off += payload; 137368e8e04eSSam Leffler } while (remainder != 0); 137468e8e04eSSam Leffler whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; 137568e8e04eSSam Leffler 137668e8e04eSSam Leffler /* strip first mbuf now that everything has been copied */ 137768e8e04eSSam Leffler m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); 137868e8e04eSSam Leffler m0->m_flags |= M_FIRSTFRAG | M_FRAG; 137968e8e04eSSam Leffler 1380b032f27cSSam Leffler vap->iv_stats.is_tx_fragframes++; 1381b032f27cSSam Leffler vap->iv_stats.is_tx_frags += fragno-1; 138268e8e04eSSam Leffler 138368e8e04eSSam Leffler return 1; 138468e8e04eSSam Leffler bad: 138568e8e04eSSam Leffler /* reclaim fragments but leave original frame for caller to free */ 138668e8e04eSSam Leffler for (m = m0->m_nextpkt; m != NULL; m = next) { 138768e8e04eSSam Leffler next = m->m_nextpkt; 138868e8e04eSSam Leffler m->m_nextpkt = NULL; /* XXX paranoid */ 138968e8e04eSSam Leffler m_freem(m); 139068e8e04eSSam Leffler } 139168e8e04eSSam Leffler m0->m_nextpkt = NULL; 139268e8e04eSSam Leffler return 0; 139368e8e04eSSam Leffler } 139468e8e04eSSam Leffler 139568e8e04eSSam Leffler /* 13961a1e1d21SSam Leffler * Add a supported rates element id to a frame. 13971a1e1d21SSam Leffler */ 139868e8e04eSSam Leffler static uint8_t * 139968e8e04eSSam Leffler ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 14001a1e1d21SSam Leffler { 14011a1e1d21SSam Leffler int nrates; 14021a1e1d21SSam Leffler 14031a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_RATES; 14041a1e1d21SSam Leffler nrates = rs->rs_nrates; 14051a1e1d21SSam Leffler if (nrates > IEEE80211_RATE_SIZE) 14061a1e1d21SSam Leffler nrates = IEEE80211_RATE_SIZE; 14071a1e1d21SSam Leffler *frm++ = nrates; 14081a1e1d21SSam Leffler memcpy(frm, rs->rs_rates, nrates); 14091a1e1d21SSam Leffler return frm + nrates; 14101a1e1d21SSam Leffler } 14111a1e1d21SSam Leffler 14121a1e1d21SSam Leffler /* 14131a1e1d21SSam Leffler * Add an extended supported rates element id to a frame. 14141a1e1d21SSam Leffler */ 141568e8e04eSSam Leffler static uint8_t * 141668e8e04eSSam Leffler ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 14171a1e1d21SSam Leffler { 14181a1e1d21SSam Leffler /* 14191a1e1d21SSam Leffler * Add an extended supported rates element if operating in 11g mode. 14201a1e1d21SSam Leffler */ 14211a1e1d21SSam Leffler if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 14221a1e1d21SSam Leffler int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 14231a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_XRATES; 14241a1e1d21SSam Leffler *frm++ = nrates; 14251a1e1d21SSam Leffler memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 14261a1e1d21SSam Leffler frm += nrates; 14271a1e1d21SSam Leffler } 14281a1e1d21SSam Leffler return frm; 14291a1e1d21SSam Leffler } 14301a1e1d21SSam Leffler 14311a1e1d21SSam Leffler /* 1432b032f27cSSam Leffler * Add an ssid element to a frame. 14331a1e1d21SSam Leffler */ 143468e8e04eSSam Leffler static uint8_t * 143568e8e04eSSam Leffler ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) 14361a1e1d21SSam Leffler { 14371a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 14381a1e1d21SSam Leffler *frm++ = len; 14391a1e1d21SSam Leffler memcpy(frm, ssid, len); 14401a1e1d21SSam Leffler return frm + len; 14411a1e1d21SSam Leffler } 14421a1e1d21SSam Leffler 14438a1b9b6aSSam Leffler /* 14448a1b9b6aSSam Leffler * Add an erp element to a frame. 14458a1b9b6aSSam Leffler */ 144668e8e04eSSam Leffler static uint8_t * 144768e8e04eSSam Leffler ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) 14481a1e1d21SSam Leffler { 144968e8e04eSSam Leffler uint8_t erp; 14501a1e1d21SSam Leffler 14518a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_ERP; 14528a1b9b6aSSam Leffler *frm++ = 1; 14538a1b9b6aSSam Leffler erp = 0; 14548a1b9b6aSSam Leffler if (ic->ic_nonerpsta != 0) 14558a1b9b6aSSam Leffler erp |= IEEE80211_ERP_NON_ERP_PRESENT; 14568a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEPROT) 14578a1b9b6aSSam Leffler erp |= IEEE80211_ERP_USE_PROTECTION; 14588a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEBARKER) 14598a1b9b6aSSam Leffler erp |= IEEE80211_ERP_LONG_PREAMBLE; 14608a1b9b6aSSam Leffler *frm++ = erp; 14618a1b9b6aSSam Leffler return frm; 14621a1e1d21SSam Leffler } 14631a1e1d21SSam Leffler 14648a1b9b6aSSam Leffler /* 1465b032f27cSSam Leffler * Add a CFParams element to a frame. 14668a1b9b6aSSam Leffler */ 146768e8e04eSSam Leffler static uint8_t * 1468b032f27cSSam Leffler ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) 14698a1b9b6aSSam Leffler { 1470b032f27cSSam Leffler #define ADDSHORT(frm, v) do { \ 1471b032f27cSSam Leffler frm[0] = (v) & 0xff; \ 1472b032f27cSSam Leffler frm[1] = (v) >> 8; \ 1473b032f27cSSam Leffler frm += 2; \ 1474b032f27cSSam Leffler } while (0) 1475b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_CFPARMS; 1476b032f27cSSam Leffler *frm++ = 6; 1477b032f27cSSam Leffler *frm++ = 0; /* CFP count */ 1478b032f27cSSam Leffler *frm++ = 2; /* CFP period */ 1479b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ 1480b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ 14818a1b9b6aSSam Leffler return frm; 1482b032f27cSSam Leffler #undef ADDSHORT 1483b032f27cSSam Leffler } 1484b032f27cSSam Leffler 1485b032f27cSSam Leffler static __inline uint8_t * 1486b032f27cSSam Leffler add_appie(uint8_t *frm, const struct ieee80211_appie *ie) 1487b032f27cSSam Leffler { 1488b032f27cSSam Leffler memcpy(frm, ie->ie_data, ie->ie_len); 1489b032f27cSSam Leffler return frm + ie->ie_len; 1490b032f27cSSam Leffler } 1491b032f27cSSam Leffler 1492b032f27cSSam Leffler static __inline uint8_t * 1493b032f27cSSam Leffler add_ie(uint8_t *frm, const uint8_t *ie) 1494b032f27cSSam Leffler { 1495b032f27cSSam Leffler memcpy(frm, ie, 2 + ie[1]); 1496b032f27cSSam Leffler return frm + 2 + ie[1]; 14978a1b9b6aSSam Leffler } 14988a1b9b6aSSam Leffler 14998a1b9b6aSSam Leffler #define WME_OUI_BYTES 0x00, 0x50, 0xf2 15008a1b9b6aSSam Leffler /* 15018a1b9b6aSSam Leffler * Add a WME information element to a frame. 15028a1b9b6aSSam Leffler */ 150368e8e04eSSam Leffler static uint8_t * 150468e8e04eSSam Leffler ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 15058a1b9b6aSSam Leffler { 15068a1b9b6aSSam Leffler static const struct ieee80211_wme_info info = { 15078a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 15088a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_info) - 2, 15098a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 15108a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 15118a1b9b6aSSam Leffler .wme_subtype = WME_INFO_OUI_SUBTYPE, 15128a1b9b6aSSam Leffler .wme_version = WME_VERSION, 15138a1b9b6aSSam Leffler .wme_info = 0, 15148a1b9b6aSSam Leffler }; 15158a1b9b6aSSam Leffler memcpy(frm, &info, sizeof(info)); 15168a1b9b6aSSam Leffler return frm + sizeof(info); 15178a1b9b6aSSam Leffler } 15188a1b9b6aSSam Leffler 15198a1b9b6aSSam Leffler /* 15208a1b9b6aSSam Leffler * Add a WME parameters element to a frame. 15218a1b9b6aSSam Leffler */ 152268e8e04eSSam Leffler static uint8_t * 152368e8e04eSSam Leffler ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 15248a1b9b6aSSam Leffler { 15258a1b9b6aSSam Leffler #define SM(_v, _f) (((_v) << _f##_S) & _f) 15268a1b9b6aSSam Leffler #define ADDSHORT(frm, v) do { \ 15278a1b9b6aSSam Leffler frm[0] = (v) & 0xff; \ 15288a1b9b6aSSam Leffler frm[1] = (v) >> 8; \ 15298a1b9b6aSSam Leffler frm += 2; \ 15308a1b9b6aSSam Leffler } while (0) 15318a1b9b6aSSam Leffler /* NB: this works 'cuz a param has an info at the front */ 15328a1b9b6aSSam Leffler static const struct ieee80211_wme_info param = { 15338a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 15348a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_param) - 2, 15358a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 15368a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 15378a1b9b6aSSam Leffler .wme_subtype = WME_PARAM_OUI_SUBTYPE, 15388a1b9b6aSSam Leffler .wme_version = WME_VERSION, 15398a1b9b6aSSam Leffler }; 15408a1b9b6aSSam Leffler int i; 15418a1b9b6aSSam Leffler 15428a1b9b6aSSam Leffler memcpy(frm, ¶m, sizeof(param)); 15438a1b9b6aSSam Leffler frm += __offsetof(struct ieee80211_wme_info, wme_info); 15448a1b9b6aSSam Leffler *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 15458a1b9b6aSSam Leffler *frm++ = 0; /* reserved field */ 15468a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 15478a1b9b6aSSam Leffler const struct wmeParams *ac = 15488a1b9b6aSSam Leffler &wme->wme_bssChanParams.cap_wmeParams[i]; 15498a1b9b6aSSam Leffler *frm++ = SM(i, WME_PARAM_ACI) 15508a1b9b6aSSam Leffler | SM(ac->wmep_acm, WME_PARAM_ACM) 15518a1b9b6aSSam Leffler | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) 15528a1b9b6aSSam Leffler ; 15538a1b9b6aSSam Leffler *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 15548a1b9b6aSSam Leffler | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) 15558a1b9b6aSSam Leffler ; 15568a1b9b6aSSam Leffler ADDSHORT(frm, ac->wmep_txopLimit); 15578a1b9b6aSSam Leffler } 15588a1b9b6aSSam Leffler return frm; 15598a1b9b6aSSam Leffler #undef SM 15608a1b9b6aSSam Leffler #undef ADDSHORT 15618a1b9b6aSSam Leffler } 15628a1b9b6aSSam Leffler #undef WME_OUI_BYTES 15638a1b9b6aSSam Leffler 156468e8e04eSSam Leffler #define ATH_OUI_BYTES 0x00, 0x03, 0x7f 156568e8e04eSSam Leffler /* 156668e8e04eSSam Leffler * Add a WME information element to a frame. 156768e8e04eSSam Leffler */ 156868e8e04eSSam Leffler static uint8_t * 156968e8e04eSSam Leffler ieee80211_add_ath(uint8_t *frm, uint8_t caps, uint16_t defkeyix) 157068e8e04eSSam Leffler { 157168e8e04eSSam Leffler static const struct ieee80211_ath_ie info = { 157268e8e04eSSam Leffler .ath_id = IEEE80211_ELEMID_VENDOR, 157368e8e04eSSam Leffler .ath_len = sizeof(struct ieee80211_ath_ie) - 2, 157468e8e04eSSam Leffler .ath_oui = { ATH_OUI_BYTES }, 157568e8e04eSSam Leffler .ath_oui_type = ATH_OUI_TYPE, 157668e8e04eSSam Leffler .ath_oui_subtype= ATH_OUI_SUBTYPE, 157768e8e04eSSam Leffler .ath_version = ATH_OUI_VERSION, 157868e8e04eSSam Leffler }; 157968e8e04eSSam Leffler struct ieee80211_ath_ie *ath = (struct ieee80211_ath_ie *) frm; 158068e8e04eSSam Leffler 158168e8e04eSSam Leffler memcpy(frm, &info, sizeof(info)); 158268e8e04eSSam Leffler ath->ath_capability = caps; 158368e8e04eSSam Leffler ath->ath_defkeyix[0] = (defkeyix & 0xff); 158468e8e04eSSam Leffler ath->ath_defkeyix[1] = ((defkeyix >> 8) & 0xff); 158568e8e04eSSam Leffler return frm + sizeof(info); 158668e8e04eSSam Leffler } 158768e8e04eSSam Leffler #undef ATH_OUI_BYTES 158868e8e04eSSam Leffler 15890a915fadSSam Leffler /* 1590b032f27cSSam Leffler * Add an 11h Power Constraint element to a frame. 1591b032f27cSSam Leffler */ 1592b032f27cSSam Leffler static uint8_t * 1593b032f27cSSam Leffler ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) 1594b032f27cSSam Leffler { 1595b032f27cSSam Leffler const struct ieee80211_channel *c = vap->iv_bss->ni_chan; 1596b032f27cSSam Leffler /* XXX per-vap tx power limit? */ 1597b032f27cSSam Leffler int8_t limit = vap->iv_ic->ic_txpowlimit / 2; 1598b032f27cSSam Leffler 1599b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCNSTR; 1600b032f27cSSam Leffler frm[1] = 1; 1601b032f27cSSam Leffler frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; 1602b032f27cSSam Leffler return frm + 3; 1603b032f27cSSam Leffler } 1604b032f27cSSam Leffler 1605b032f27cSSam Leffler /* 1606b032f27cSSam Leffler * Add an 11h Power Capability element to a frame. 1607b032f27cSSam Leffler */ 1608b032f27cSSam Leffler static uint8_t * 1609b032f27cSSam Leffler ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) 1610b032f27cSSam Leffler { 1611b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCAP; 1612b032f27cSSam Leffler frm[1] = 2; 1613b032f27cSSam Leffler frm[2] = c->ic_minpower; 1614b032f27cSSam Leffler frm[3] = c->ic_maxpower; 1615b032f27cSSam Leffler return frm + 4; 1616b032f27cSSam Leffler } 1617b032f27cSSam Leffler 1618b032f27cSSam Leffler /* 1619b032f27cSSam Leffler * Add an 11h Supported Channels element to a frame. 1620b032f27cSSam Leffler */ 1621b032f27cSSam Leffler static uint8_t * 1622b032f27cSSam Leffler ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) 1623b032f27cSSam Leffler { 1624b032f27cSSam Leffler static const int ielen = 26; 1625b032f27cSSam Leffler 1626b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_SUPPCHAN; 1627b032f27cSSam Leffler frm[1] = ielen; 1628b032f27cSSam Leffler /* XXX not correct */ 1629b032f27cSSam Leffler memcpy(frm+2, ic->ic_chan_avail, ielen); 1630b032f27cSSam Leffler return frm + 2 + ielen; 1631b032f27cSSam Leffler } 1632b032f27cSSam Leffler 1633b032f27cSSam Leffler /* 1634b032f27cSSam Leffler * Add an 11h Channel Switch Announcement element to a frame. 1635b032f27cSSam Leffler * Note that we use the per-vap CSA count to adjust the global 1636b032f27cSSam Leffler * counter so we can use this routine to form probe response 1637b032f27cSSam Leffler * frames and get the current count. 1638b032f27cSSam Leffler */ 1639b032f27cSSam Leffler static uint8_t * 1640b032f27cSSam Leffler ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) 1641b032f27cSSam Leffler { 1642b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 1643b032f27cSSam Leffler struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; 1644b032f27cSSam Leffler 1645b032f27cSSam Leffler csa->csa_ie = IEEE80211_ELEMID_CHANSWITCHANN; 1646b032f27cSSam Leffler csa->csa_len = 3; 1647b032f27cSSam Leffler csa->csa_mode = 1; /* XXX force quiet on channel */ 1648b032f27cSSam Leffler csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); 1649b032f27cSSam Leffler csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; 1650b032f27cSSam Leffler return frm + sizeof(*csa); 1651b032f27cSSam Leffler } 1652b032f27cSSam Leffler 1653b032f27cSSam Leffler /* 1654b032f27cSSam Leffler * Add an 11h country information element to a frame. 1655b032f27cSSam Leffler */ 1656b032f27cSSam Leffler static uint8_t * 1657b032f27cSSam Leffler ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) 1658b032f27cSSam Leffler { 1659b032f27cSSam Leffler 1660b032f27cSSam Leffler if (ic->ic_countryie == NULL || 1661b032f27cSSam Leffler ic->ic_countryie_chan != ic->ic_bsschan) { 1662b032f27cSSam Leffler /* 1663b032f27cSSam Leffler * Handle lazy construction of ie. This is done on 1664b032f27cSSam Leffler * first use and after a channel change that requires 1665b032f27cSSam Leffler * re-calculation. 1666b032f27cSSam Leffler */ 1667b032f27cSSam Leffler if (ic->ic_countryie != NULL) 1668b032f27cSSam Leffler free(ic->ic_countryie, M_80211_NODE_IE); 1669b032f27cSSam Leffler ic->ic_countryie = ieee80211_alloc_countryie(ic); 1670b032f27cSSam Leffler if (ic->ic_countryie == NULL) 1671b032f27cSSam Leffler return frm; 1672b032f27cSSam Leffler ic->ic_countryie_chan = ic->ic_bsschan; 1673b032f27cSSam Leffler } 1674b032f27cSSam Leffler return add_appie(frm, ic->ic_countryie); 1675b032f27cSSam Leffler } 1676b032f27cSSam Leffler 1677b032f27cSSam Leffler /* 1678af8418dcSSam Leffler * Send a probe request frame with the specified ssid 1679af8418dcSSam Leffler * and any optional information element data. 1680af8418dcSSam Leffler */ 1681af8418dcSSam Leffler int 1682af8418dcSSam Leffler ieee80211_send_probereq(struct ieee80211_node *ni, 168368e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 168468e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 168568e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN], 1686b032f27cSSam Leffler const uint8_t *ssid, size_t ssidlen) 1687af8418dcSSam Leffler { 1688b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1689af8418dcSSam Leffler struct ieee80211com *ic = ni->ni_ic; 169016d7cbb1SSam Leffler const struct ieee80211_txparam *tp; 169116d7cbb1SSam Leffler struct ieee80211_bpf_params params; 1692af8418dcSSam Leffler struct ieee80211_frame *wh; 169341b3c790SSam Leffler const struct ieee80211_rateset *rs; 1694af8418dcSSam Leffler struct mbuf *m; 169568e8e04eSSam Leffler uint8_t *frm; 1696af8418dcSSam Leffler 1697b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 1698b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 1699b032f27cSSam Leffler "block %s frame in CAC state", "probe request"); 1700b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 1701b032f27cSSam Leffler return EIO; /* XXX */ 1702b032f27cSSam Leffler } 1703b032f27cSSam Leffler 1704af8418dcSSam Leffler /* 1705af8418dcSSam Leffler * Hold a reference on the node so it doesn't go away until after 1706af8418dcSSam Leffler * the xmit is complete all the way in the driver. On error we 1707af8418dcSSam Leffler * will remove our reference. 1708af8418dcSSam Leffler */ 1709b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1710af8418dcSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 1711af8418dcSSam Leffler __func__, __LINE__, 1712af8418dcSSam Leffler ni, ether_sprintf(ni->ni_macaddr), 1713af8418dcSSam Leffler ieee80211_node_refcnt(ni)+1); 1714af8418dcSSam Leffler ieee80211_ref_node(ni); 1715af8418dcSSam Leffler 1716af8418dcSSam Leffler /* 1717af8418dcSSam Leffler * prreq frame format 1718af8418dcSSam Leffler * [tlv] ssid 1719af8418dcSSam Leffler * [tlv] supported rates 1720b032f27cSSam Leffler * [tlv] RSN (optional) 1721af8418dcSSam Leffler * [tlv] extended supported rates 1722b032f27cSSam Leffler * [tlv] WPA (optional) 1723af8418dcSSam Leffler * [tlv] user-specified ie's 1724af8418dcSSam Leffler */ 1725af8418dcSSam Leffler m = ieee80211_getmgtframe(&frm, 172668e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 1727af8418dcSSam Leffler 2 + IEEE80211_NWID_LEN 1728af8418dcSSam Leffler + 2 + IEEE80211_RATE_SIZE 1729b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 1730af8418dcSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1731b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 1732b032f27cSSam Leffler + (vap->iv_appie_probereq != NULL ? 1733b032f27cSSam Leffler vap->iv_appie_probereq->ie_len : 0) 1734af8418dcSSam Leffler ); 1735af8418dcSSam Leffler if (m == NULL) { 1736b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 1737af8418dcSSam Leffler ieee80211_free_node(ni); 1738af8418dcSSam Leffler return ENOMEM; 1739af8418dcSSam Leffler } 1740af8418dcSSam Leffler 1741af8418dcSSam Leffler frm = ieee80211_add_ssid(frm, ssid, ssidlen); 174241b3c790SSam Leffler rs = ieee80211_get_suprates(ic, ic->ic_curchan); 174341b3c790SSam Leffler frm = ieee80211_add_rates(frm, rs); 1744b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 1745b032f27cSSam Leffler if (vap->iv_rsn_ie != NULL) 1746b032f27cSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 1747b032f27cSSam Leffler /* XXX else complain? */ 1748af8418dcSSam Leffler } 1749b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 1750b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 1751b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 1752b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 1753b032f27cSSam Leffler /* XXX else complain? */ 1754b032f27cSSam Leffler } 1755b032f27cSSam Leffler if (vap->iv_appie_probereq != NULL) 1756b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_probereq); 175768e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 1758af8418dcSSam Leffler 175916d7cbb1SSam Leffler KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), 176016d7cbb1SSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 1761af8418dcSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 176216d7cbb1SSam Leffler if (m == NULL) { 176316d7cbb1SSam Leffler /* NB: cannot happen */ 176416d7cbb1SSam Leffler ieee80211_free_node(ni); 1765af8418dcSSam Leffler return ENOMEM; 176616d7cbb1SSam Leffler } 1767af8418dcSSam Leffler 1768af8418dcSSam Leffler wh = mtod(m, struct ieee80211_frame *); 1769b032f27cSSam Leffler ieee80211_send_setup(ni, wh, 1770af8418dcSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 17718ac160cdSSam Leffler IEEE80211_NONQOS_TID, sa, da, bssid); 1772af8418dcSSam Leffler /* XXX power management? */ 1773af8418dcSSam Leffler 1774b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 1775b032f27cSSam Leffler 1776af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_probereq); 1777af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 1778af8418dcSSam Leffler 1779b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 1780b032f27cSSam Leffler "send probe req on channel %u bssid %s ssid \"%.*s\"\n", 1781b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid), 1782b032f27cSSam Leffler ssidlen, ssid); 1783af8418dcSSam Leffler 178416d7cbb1SSam Leffler memset(¶ms, 0, sizeof(params)); 178516d7cbb1SSam Leffler params.ibp_pri = M_WME_GETAC(m); 178616d7cbb1SSam Leffler tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 178716d7cbb1SSam Leffler params.ibp_rate0 = tp->mgmtrate; 178816d7cbb1SSam Leffler if (IEEE80211_IS_MULTICAST(da)) { 178916d7cbb1SSam Leffler params.ibp_flags |= IEEE80211_BPF_NOACK; 179016d7cbb1SSam Leffler params.ibp_try0 = 1; 179116d7cbb1SSam Leffler } else 179216d7cbb1SSam Leffler params.ibp_try0 = tp->maxretry; 179316d7cbb1SSam Leffler params.ibp_power = ni->ni_txpower; 179416d7cbb1SSam Leffler return ic->ic_raw_xmit(ni, m, ¶ms); 1795af8418dcSSam Leffler } 1796af8418dcSSam Leffler 1797af8418dcSSam Leffler /* 1798667dad55SSam Leffler * Calculate capability information for mgt frames. 1799667dad55SSam Leffler */ 180068e8e04eSSam Leffler static uint16_t 1801b032f27cSSam Leffler getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) 1802667dad55SSam Leffler { 1803b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 180468e8e04eSSam Leffler uint16_t capinfo; 1805667dad55SSam Leffler 1806b032f27cSSam Leffler KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); 1807667dad55SSam Leffler 1808b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) 1809667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 1810b032f27cSSam Leffler else if (vap->iv_opmode == IEEE80211_M_IBSS) 1811667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_IBSS; 1812667dad55SSam Leffler else 1813667dad55SSam Leffler capinfo = 0; 1814b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 1815667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 1816667dad55SSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 1817667dad55SSam Leffler IEEE80211_IS_CHAN_2GHZ(chan)) 1818667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 1819667dad55SSam Leffler if (ic->ic_flags & IEEE80211_F_SHSLOT) 1820667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 1821b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) 1822b032f27cSSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 1823667dad55SSam Leffler return capinfo; 1824667dad55SSam Leffler } 1825667dad55SSam Leffler 1826667dad55SSam Leffler /* 18270a915fadSSam Leffler * Send a management frame. The node is for the destination (or ic_bss 18280a915fadSSam Leffler * when in station mode). Nodes other than ic_bss have their reference 18290a915fadSSam Leffler * count bumped to reflect our use for an indeterminant time. 18300a915fadSSam Leffler */ 18311a1e1d21SSam Leffler int 1832b032f27cSSam Leffler ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) 18331a1e1d21SSam Leffler { 18341b6167d2SSam Leffler #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) 1835b032f27cSSam Leffler #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) 1836b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1837b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 1838b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 18398ac160cdSSam Leffler struct ieee80211_bpf_params params; 18401a1e1d21SSam Leffler struct mbuf *m; 184168e8e04eSSam Leffler uint8_t *frm; 184268e8e04eSSam Leffler uint16_t capinfo; 184368e8e04eSSam Leffler int has_challenge, is_shared_key, ret, status; 18441a1e1d21SSam Leffler 18450a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 18460a915fadSSam Leffler 18470a915fadSSam Leffler /* 18480a915fadSSam Leffler * Hold a reference on the node so it doesn't go away until after 18490a915fadSSam Leffler * the xmit is complete all the way in the driver. On error we 18500a915fadSSam Leffler * will remove our reference. 18510a915fadSSam Leffler */ 1852b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 185349a15236SSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 18548a1b9b6aSSam Leffler __func__, __LINE__, 185549a15236SSam Leffler ni, ether_sprintf(ni->ni_macaddr), 18568a1b9b6aSSam Leffler ieee80211_node_refcnt(ni)+1); 18570a915fadSSam Leffler ieee80211_ref_node(ni); 18588a1b9b6aSSam Leffler 18598ac160cdSSam Leffler memset(¶ms, 0, sizeof(params)); 18601a1e1d21SSam Leffler switch (type) { 18611a1e1d21SSam Leffler 18621a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 18638a1b9b6aSSam Leffler status = arg >> 16; 18648a1b9b6aSSam Leffler arg &= 0xffff; 18658a1b9b6aSSam Leffler has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 18668a1b9b6aSSam Leffler arg == IEEE80211_AUTH_SHARED_RESPONSE) && 18678a1b9b6aSSam Leffler ni->ni_challenge != NULL); 18688a1b9b6aSSam Leffler 18698a1b9b6aSSam Leffler /* 18708a1b9b6aSSam Leffler * Deduce whether we're doing open authentication or 18718a1b9b6aSSam Leffler * shared key authentication. We do the latter if 18728a1b9b6aSSam Leffler * we're in the middle of a shared key authentication 18738a1b9b6aSSam Leffler * handshake or if we're initiating an authentication 18748a1b9b6aSSam Leffler * request and configured to use shared key. 18758a1b9b6aSSam Leffler */ 18768a1b9b6aSSam Leffler is_shared_key = has_challenge || 18778a1b9b6aSSam Leffler arg >= IEEE80211_AUTH_SHARED_RESPONSE || 18788a1b9b6aSSam Leffler (arg == IEEE80211_AUTH_SHARED_REQUEST && 1879b032f27cSSam Leffler bss->ni_authmode == IEEE80211_AUTH_SHARED); 18808a1b9b6aSSam Leffler 18818a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 188268e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 188368e8e04eSSam Leffler 3 * sizeof(uint16_t) 18848a1b9b6aSSam Leffler + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 188568e8e04eSSam Leffler sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) 18868a1b9b6aSSam Leffler ); 18871a1e1d21SSam Leffler if (m == NULL) 18888a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 18898a1b9b6aSSam Leffler 189068e8e04eSSam Leffler ((uint16_t *)frm)[0] = 18918a1b9b6aSSam Leffler (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) 18928a1b9b6aSSam Leffler : htole16(IEEE80211_AUTH_ALG_OPEN); 189368e8e04eSSam Leffler ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ 189468e8e04eSSam Leffler ((uint16_t *)frm)[2] = htole16(status);/* status */ 18958a1b9b6aSSam Leffler 18968a1b9b6aSSam Leffler if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 189768e8e04eSSam Leffler ((uint16_t *)frm)[3] = 18988a1b9b6aSSam Leffler htole16((IEEE80211_CHALLENGE_LEN << 8) | 18998a1b9b6aSSam Leffler IEEE80211_ELEMID_CHALLENGE); 190068e8e04eSSam Leffler memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, 19018a1b9b6aSSam Leffler IEEE80211_CHALLENGE_LEN); 19028a1b9b6aSSam Leffler m->m_pkthdr.len = m->m_len = 190368e8e04eSSam Leffler 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; 19048a1b9b6aSSam Leffler if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { 1905b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1906b032f27cSSam Leffler "request encrypt frame (%s)", __func__); 19078ac160cdSSam Leffler /* mark frame for encryption */ 19088ac160cdSSam Leffler params.ibp_flags |= IEEE80211_BPF_CRYPTO; 19098a1b9b6aSSam Leffler } 19108a1b9b6aSSam Leffler } else 191168e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); 19128a1b9b6aSSam Leffler 19138a1b9b6aSSam Leffler /* XXX not right for shared key */ 19148a1b9b6aSSam Leffler if (status == IEEE80211_STATUS_SUCCESS) 19158a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth); 19168a1b9b6aSSam Leffler else 19178a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth_fail); 19188a1b9b6aSSam Leffler 1919b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA) 192068e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 1921b032f27cSSam Leffler (void *) vap->iv_state); 19221a1e1d21SSam Leffler break; 19231a1e1d21SSam Leffler 19241a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 1925b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1926b032f27cSSam Leffler "send station deauthenticate (reason %d)", arg); 192768e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 192868e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 192968e8e04eSSam Leffler sizeof(uint16_t)); 19301a1e1d21SSam Leffler if (m == NULL) 19318a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 193268e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 193368e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 19348a1b9b6aSSam Leffler 19358a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_deauth); 19368a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); 19378a1b9b6aSSam Leffler 1938e4918ecdSSam Leffler ieee80211_node_unauthorize(ni); /* port closed */ 19391a1e1d21SSam Leffler break; 19401a1e1d21SSam Leffler 19411a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 19421a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 19431a1e1d21SSam Leffler /* 19441a1e1d21SSam Leffler * asreq frame format 19451a1e1d21SSam Leffler * [2] capability information 19461a1e1d21SSam Leffler * [2] listen interval 19471a1e1d21SSam Leffler * [6*] current AP address (reassoc only) 19481a1e1d21SSam Leffler * [tlv] ssid 19491a1e1d21SSam Leffler * [tlv] supported rates 19501a1e1d21SSam Leffler * [tlv] extended supported rates 1951b032f27cSSam Leffler * [4] power capability (optional) 1952b032f27cSSam Leffler * [28] supported channels (optional) 195368e8e04eSSam Leffler * [tlv] HT capabilities 1954b032f27cSSam Leffler * [tlv] WME (optional) 195568e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 195668e8e04eSSam Leffler * [tlv] Atheros capabilities (if negotiated) 1957b032f27cSSam Leffler * [tlv] AppIE's (optional) 19581a1e1d21SSam Leffler */ 19598a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 196068e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 196168e8e04eSSam Leffler sizeof(uint16_t) 196268e8e04eSSam Leffler + sizeof(uint16_t) 19631a1e1d21SSam Leffler + IEEE80211_ADDR_LEN 19648a1b9b6aSSam Leffler + 2 + IEEE80211_NWID_LEN 19651a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 19668a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1967b032f27cSSam Leffler + 4 1968b032f27cSSam Leffler + 2 + 26 19698a1b9b6aSSam Leffler + sizeof(struct ieee80211_wme_info) 1970b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 1971b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 197268e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 1973b032f27cSSam Leffler + (vap->iv_appie_wpa != NULL ? 1974b032f27cSSam Leffler vap->iv_appie_wpa->ie_len : 0) 1975b032f27cSSam Leffler + (vap->iv_appie_assocreq != NULL ? 1976b032f27cSSam Leffler vap->iv_appie_assocreq->ie_len : 0) 19778a1b9b6aSSam Leffler ); 19781a1e1d21SSam Leffler if (m == NULL) 19798a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 19801a1e1d21SSam Leffler 1981b032f27cSSam Leffler KASSERT(vap->iv_opmode == IEEE80211_M_STA, 1982b032f27cSSam Leffler ("wrong mode %u", vap->iv_opmode)); 1983667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 1984b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 19851a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 19864f2e09c4SSam Leffler /* 19874f2e09c4SSam Leffler * NB: Some 11a AP's reject the request when 19884f2e09c4SSam Leffler * short premable is set. 19894f2e09c4SSam Leffler */ 19904f2e09c4SSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 1991b5c99415SSam Leffler IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 19921a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 199368e8e04eSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 19948a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHSLOT)) 19951a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 19961b6167d2SSam Leffler if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && 1997b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_DOTH)) 19981b6167d2SSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 199968e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 20001a1e1d21SSam Leffler frm += 2; 20011a1e1d21SSam Leffler 2002b032f27cSSam Leffler KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); 200368e8e04eSSam Leffler *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, 2004b032f27cSSam Leffler bss->ni_intval)); 20051a1e1d21SSam Leffler frm += 2; 20061a1e1d21SSam Leffler 20071a1e1d21SSam Leffler if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 2008b032f27cSSam Leffler IEEE80211_ADDR_COPY(frm, bss->ni_bssid); 20091a1e1d21SSam Leffler frm += IEEE80211_ADDR_LEN; 20101a1e1d21SSam Leffler } 20111a1e1d21SSam Leffler 20121a1e1d21SSam Leffler frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 20131a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 2014b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2015b032f27cSSam Leffler if (vap->iv_rsn_ie != NULL) 2016b032f27cSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2017b032f27cSSam Leffler /* XXX else complain? */ 20188a1b9b6aSSam Leffler } 2019b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 2020b032f27cSSam Leffler if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { 2021b032f27cSSam Leffler frm = ieee80211_add_powercapability(frm, 2022b032f27cSSam Leffler ic->ic_curchan); 2023b032f27cSSam Leffler frm = ieee80211_add_supportedchannels(frm, ic); 2024b032f27cSSam Leffler } 2025b032f27cSSam Leffler if ((vap->iv_flags_ext & IEEE80211_FEXT_HT) && 2026b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2027b032f27cSSam Leffler ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 2028b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, ni); 2029b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2030b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2031b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2032b032f27cSSam Leffler /* XXX else complain */ 2033b032f27cSSam Leffler } 2034b032f27cSSam Leffler if ((ic->ic_flags & IEEE80211_F_WME) && 2035b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 2036b032f27cSSam Leffler frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 2037b032f27cSSam Leffler if ((vap->iv_flags_ext & IEEE80211_FEXT_HT) && 2038b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2039b032f27cSSam Leffler ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 2040b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 2041b032f27cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 2042b032f27cSSam Leffler frm = ieee80211_add_ath(frm, 2043b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 2044b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_WPA) == 0 && 2045b032f27cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X && 2046b032f27cSSam Leffler vap->iv_def_txkey != IEEE80211_KEYIX_NONE ? 2047b032f27cSSam Leffler vap->iv_def_txkey : 0x7fff); 2048b032f27cSSam Leffler if (vap->iv_appie_assocreq != NULL) 2049b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocreq); 205068e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 20511a1e1d21SSam Leffler 205268e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 2053b032f27cSSam Leffler (void *) vap->iv_state); 20541a1e1d21SSam Leffler break; 20551a1e1d21SSam Leffler 20561a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 20571a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 20581a1e1d21SSam Leffler /* 205968e8e04eSSam Leffler * asresp frame format 20601a1e1d21SSam Leffler * [2] capability information 20611a1e1d21SSam Leffler * [2] status 20621a1e1d21SSam Leffler * [2] association ID 20631a1e1d21SSam Leffler * [tlv] supported rates 20641a1e1d21SSam Leffler * [tlv] extended supported rates 2065b032f27cSSam Leffler * [tlv] HT capabilities (standard, if STA enabled) 2066b032f27cSSam Leffler * [tlv] HT information (standard, if STA enabled) 2067b032f27cSSam Leffler * [tlv] WME (if configured and STA enabled) 2068b032f27cSSam Leffler * [tlv] HT capabilities (vendor OUI, if STA enabled) 2069b032f27cSSam Leffler * [tlv] HT information (vendor OUI, if STA enabled) 2070b032f27cSSam Leffler * [tlv] Atheros capabilities (if STA enabled) 2071b032f27cSSam Leffler * [tlv] AppIE's (optional) 20721a1e1d21SSam Leffler */ 20738a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 207468e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 207568e8e04eSSam Leffler sizeof(uint16_t) 207668e8e04eSSam Leffler + sizeof(uint16_t) 207768e8e04eSSam Leffler + sizeof(uint16_t) 20781a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 20798a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 208068e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htcap) + 4 208168e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htinfo) + 4 2082b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 208368e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2084b032f27cSSam Leffler + (vap->iv_appie_assocresp != NULL ? 2085b032f27cSSam Leffler vap->iv_appie_assocresp->ie_len : 0) 20868a1b9b6aSSam Leffler ); 20871a1e1d21SSam Leffler if (m == NULL) 20888a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 20891a1e1d21SSam Leffler 2090b032f27cSSam Leffler capinfo = getcapinfo(vap, bss->ni_chan); 209168e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 20921a1e1d21SSam Leffler frm += 2; 20931a1e1d21SSam Leffler 209468e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* status */ 20951a1e1d21SSam Leffler frm += 2; 20961a1e1d21SSam Leffler 20978a1b9b6aSSam Leffler if (arg == IEEE80211_STATUS_SUCCESS) { 209868e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_associd); 20998a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc); 21008a1b9b6aSSam Leffler } else 21018a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc_fail); 21021a1e1d21SSam Leffler frm += 2; 21031a1e1d21SSam Leffler 21041a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 21051a1e1d21SSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 210668e8e04eSSam Leffler /* NB: respond according to what we received */ 21071b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { 210868e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 210968e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 211068e8e04eSSam Leffler } 2111b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_WME) && 2112b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 21131b6167d2SSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 21141b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { 21151b6167d2SSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 21161b6167d2SSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 211768e8e04eSSam Leffler } 2118b032f27cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 211968e8e04eSSam Leffler frm = ieee80211_add_ath(frm, 2120b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 212168e8e04eSSam Leffler ni->ni_ath_defkeyix); 2122b032f27cSSam Leffler if (vap->iv_appie_assocresp != NULL) 2123b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocresp); 212468e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 21251a1e1d21SSam Leffler break; 21261a1e1d21SSam Leffler 21271a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DISASSOC: 2128b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 2129b032f27cSSam Leffler "send station disassociate (reason %d)", arg); 213068e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 213168e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 213268e8e04eSSam Leffler sizeof(uint16_t)); 21331a1e1d21SSam Leffler if (m == NULL) 21348a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 213568e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 213668e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 21378a1b9b6aSSam Leffler 21388a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_disassoc); 21398a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); 21401a1e1d21SSam Leffler break; 21411a1e1d21SSam Leffler 21421a1e1d21SSam Leffler default: 2143b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 2144b032f27cSSam Leffler "invalid mgmt frame type %u", type); 21451be50176SSam Leffler senderr(EINVAL, is_tx_unknownmgt); 21460a915fadSSam Leffler /* NOTREACHED */ 21471a1e1d21SSam Leffler } 214868e8e04eSSam Leffler 21498ac160cdSSam Leffler /* NB: force non-ProbeResp frames to the highest queue */ 21508ac160cdSSam Leffler params.ibp_pri = WME_AC_VO; 21518ac160cdSSam Leffler params.ibp_rate0 = bss->ni_txparms->mgmtrate; 21528ac160cdSSam Leffler /* NB: we know all frames are unicast */ 21538ac160cdSSam Leffler params.ibp_try0 = bss->ni_txparms->maxretry; 21548ac160cdSSam Leffler params.ibp_power = bss->ni_txpower; 21558ac160cdSSam Leffler return ieee80211_mgmt_output(ni, m, type, ¶ms); 21560a915fadSSam Leffler bad: 21578a1b9b6aSSam Leffler ieee80211_free_node(ni); 21581a1e1d21SSam Leffler return ret; 21590a915fadSSam Leffler #undef senderr 21601b6167d2SSam Leffler #undef HTFLAGS 21611a1e1d21SSam Leffler } 21628a1b9b6aSSam Leffler 2163b032f27cSSam Leffler /* 2164b032f27cSSam Leffler * Return an mbuf with a probe response frame in it. 2165b032f27cSSam Leffler * Space is left to prepend and 802.11 header at the 2166b032f27cSSam Leffler * front but it's left to the caller to fill in. 2167b032f27cSSam Leffler */ 2168b032f27cSSam Leffler struct mbuf * 2169b032f27cSSam Leffler ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) 2170b032f27cSSam Leffler { 2171b032f27cSSam Leffler struct ieee80211vap *vap = bss->ni_vap; 2172b032f27cSSam Leffler struct ieee80211com *ic = bss->ni_ic; 2173b032f27cSSam Leffler const struct ieee80211_rateset *rs; 2174b032f27cSSam Leffler struct mbuf *m; 2175b032f27cSSam Leffler uint16_t capinfo; 2176b032f27cSSam Leffler uint8_t *frm; 2177b032f27cSSam Leffler 2178b032f27cSSam Leffler /* 2179b032f27cSSam Leffler * probe response frame format 2180b032f27cSSam Leffler * [8] time stamp 2181b032f27cSSam Leffler * [2] beacon interval 2182b032f27cSSam Leffler * [2] cabability information 2183b032f27cSSam Leffler * [tlv] ssid 2184b032f27cSSam Leffler * [tlv] supported rates 2185b032f27cSSam Leffler * [tlv] parameter set (FH/DS) 2186b032f27cSSam Leffler * [tlv] parameter set (IBSS) 2187b032f27cSSam Leffler * [tlv] country (optional) 2188b032f27cSSam Leffler * [3] power control (optional) 2189b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 2190b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 2191b032f27cSSam Leffler * [tlv] extended supported rates 2192688fe74dSSam Leffler * [tlv] RSN (optional) 2193b032f27cSSam Leffler * [tlv] HT capabilities 2194b032f27cSSam Leffler * [tlv] HT information 2195b032f27cSSam Leffler * [tlv] WPA (optional) 2196b032f27cSSam Leffler * [tlv] WME (optional) 2197b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 2198b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 2199b032f27cSSam Leffler * [tlv] Atheros capabilities 2200b032f27cSSam Leffler * [tlv] AppIE's (optional) 2201b032f27cSSam Leffler */ 2202b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 2203b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 2204b032f27cSSam Leffler 8 2205b032f27cSSam Leffler + sizeof(uint16_t) 2206b032f27cSSam Leffler + sizeof(uint16_t) 2207b032f27cSSam Leffler + 2 + IEEE80211_NWID_LEN 2208b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE 2209b032f27cSSam Leffler + 7 /* max(7,3) */ 2210b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE 2211b032f27cSSam Leffler + 3 2212b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) 2213b032f27cSSam Leffler + 3 2214b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2215688fe74dSSam Leffler + sizeof(struct ieee80211_ie_wpa) 2216b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 2217b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htinfo) 2218b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 2219b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 2220b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 2221b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htinfo) 2222b032f27cSSam Leffler + sizeof(struct ieee80211_ath_ie) 2223b032f27cSSam Leffler + (vap->iv_appie_proberesp != NULL ? 2224b032f27cSSam Leffler vap->iv_appie_proberesp->ie_len : 0) 2225b032f27cSSam Leffler ); 2226b032f27cSSam Leffler if (m == NULL) { 2227b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 2228b032f27cSSam Leffler return NULL; 2229b032f27cSSam Leffler } 2230b032f27cSSam Leffler 2231b032f27cSSam Leffler memset(frm, 0, 8); /* timestamp should be filled later */ 2232b032f27cSSam Leffler frm += 8; 2233b032f27cSSam Leffler *(uint16_t *)frm = htole16(bss->ni_intval); 2234b032f27cSSam Leffler frm += 2; 2235b032f27cSSam Leffler capinfo = getcapinfo(vap, bss->ni_chan); 2236b032f27cSSam Leffler *(uint16_t *)frm = htole16(capinfo); 2237b032f27cSSam Leffler frm += 2; 2238b032f27cSSam Leffler 2239b032f27cSSam Leffler frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); 2240b032f27cSSam Leffler rs = ieee80211_get_suprates(ic, bss->ni_chan); 2241b032f27cSSam Leffler frm = ieee80211_add_rates(frm, rs); 2242b032f27cSSam Leffler 2243b032f27cSSam Leffler if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { 2244b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_FHPARMS; 2245b032f27cSSam Leffler *frm++ = 5; 2246b032f27cSSam Leffler *frm++ = bss->ni_fhdwell & 0x00ff; 2247b032f27cSSam Leffler *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; 2248b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANSET( 2249b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 2250b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANPAT( 2251b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 2252b032f27cSSam Leffler *frm++ = bss->ni_fhindex; 2253b032f27cSSam Leffler } else { 2254b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 2255b032f27cSSam Leffler *frm++ = 1; 2256b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); 2257b032f27cSSam Leffler } 2258b032f27cSSam Leffler 2259b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 2260b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 2261b032f27cSSam Leffler *frm++ = 2; 2262b032f27cSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 2263b032f27cSSam Leffler } 2264b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 2265b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2266b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 2267b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 2268b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) 2269b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 2270b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2271b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 2272b032f27cSSam Leffler } 2273b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) 2274b032f27cSSam Leffler frm = ieee80211_add_erp(frm, ic); 2275b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2276688fe74dSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2277688fe74dSSam Leffler if (vap->iv_rsn_ie != NULL) 2278688fe74dSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2279688fe74dSSam Leffler /* XXX else complain? */ 2280688fe74dSSam Leffler } 2281b032f27cSSam Leffler /* 2282b032f27cSSam Leffler * NB: legacy 11b clients do not get certain ie's. 2283b032f27cSSam Leffler * The caller identifies such clients by passing 2284b032f27cSSam Leffler * a token in legacy to us. Could expand this to be 2285b032f27cSSam Leffler * any legacy client for stuff like HT ie's. 2286b032f27cSSam Leffler */ 2287b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 2288b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 2289b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, bss); 2290b032f27cSSam Leffler frm = ieee80211_add_htinfo(frm, bss); 2291b032f27cSSam Leffler } 2292b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2293b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2294b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2295b032f27cSSam Leffler /* XXX else complain? */ 2296b032f27cSSam Leffler } 2297b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) 2298b032f27cSSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 2299b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 2300b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_HTCOMPAT) && 2301b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 2302b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, bss); 2303b032f27cSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, bss); 2304b032f27cSSam Leffler } 2305b032f27cSSam Leffler if (bss->ni_ies.ath_ie != NULL && legacy != IEEE80211_SEND_LEGACY_11B) 2306b032f27cSSam Leffler frm = ieee80211_add_ath(frm, bss->ni_ath_flags, 2307b032f27cSSam Leffler bss->ni_ath_defkeyix); 2308b032f27cSSam Leffler if (vap->iv_appie_proberesp != NULL) 2309b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_proberesp); 2310b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2311b032f27cSSam Leffler 2312b032f27cSSam Leffler return m; 2313b032f27cSSam Leffler } 2314b032f27cSSam Leffler 2315b032f27cSSam Leffler /* 2316b032f27cSSam Leffler * Send a probe response frame to the specified mac address. 2317b032f27cSSam Leffler * This does not go through the normal mgt frame api so we 2318b032f27cSSam Leffler * can specify the destination address and re-use the bss node 2319b032f27cSSam Leffler * for the sta reference. 2320b032f27cSSam Leffler */ 2321b032f27cSSam Leffler int 2322b032f27cSSam Leffler ieee80211_send_proberesp(struct ieee80211vap *vap, 2323b032f27cSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], int legacy) 2324b032f27cSSam Leffler { 2325b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 2326b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 2327b032f27cSSam Leffler struct ieee80211_frame *wh; 2328b032f27cSSam Leffler struct mbuf *m; 2329b032f27cSSam Leffler 2330b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 2331b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, 2332b032f27cSSam Leffler "block %s frame in CAC state", "probe response"); 2333b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 2334b032f27cSSam Leffler return EIO; /* XXX */ 2335b032f27cSSam Leffler } 2336b032f27cSSam Leffler 2337b032f27cSSam Leffler /* 2338b032f27cSSam Leffler * Hold a reference on the node so it doesn't go away until after 2339b032f27cSSam Leffler * the xmit is complete all the way in the driver. On error we 2340b032f27cSSam Leffler * will remove our reference. 2341b032f27cSSam Leffler */ 2342b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 2343b032f27cSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2344b032f27cSSam Leffler __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), 2345b032f27cSSam Leffler ieee80211_node_refcnt(bss)+1); 2346b032f27cSSam Leffler ieee80211_ref_node(bss); 2347b032f27cSSam Leffler 2348b032f27cSSam Leffler m = ieee80211_alloc_proberesp(bss, legacy); 2349b032f27cSSam Leffler if (m == NULL) { 2350b032f27cSSam Leffler ieee80211_free_node(bss); 2351b032f27cSSam Leffler return ENOMEM; 2352b032f27cSSam Leffler } 2353b032f27cSSam Leffler 2354b032f27cSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 2355b032f27cSSam Leffler KASSERT(m != NULL, ("no room for header")); 2356b032f27cSSam Leffler 2357b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 2358b032f27cSSam Leffler ieee80211_send_setup(bss, wh, 2359b032f27cSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, 23608ac160cdSSam Leffler IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); 2361b032f27cSSam Leffler /* XXX power management? */ 2362b032f27cSSam Leffler 2363b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 2364b032f27cSSam Leffler 2365b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 2366b032f27cSSam Leffler "send probe resp on channel %u to %s%s\n", 2367b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), 2368b032f27cSSam Leffler legacy ? " <legacy>" : ""); 2369b032f27cSSam Leffler IEEE80211_NODE_STAT(bss, tx_mgmt); 2370b032f27cSSam Leffler 2371b032f27cSSam Leffler return ic->ic_raw_xmit(bss, m, NULL); 2372b032f27cSSam Leffler } 2373b032f27cSSam Leffler 2374b032f27cSSam Leffler /* 2375b032f27cSSam Leffler * Allocate and build a RTS (Request To Send) control frame. 2376b032f27cSSam Leffler */ 2377b032f27cSSam Leffler struct mbuf * 2378b032f27cSSam Leffler ieee80211_alloc_rts(struct ieee80211com *ic, 2379b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], 2380b032f27cSSam Leffler const uint8_t ta[IEEE80211_ADDR_LEN], 2381b032f27cSSam Leffler uint16_t dur) 2382b032f27cSSam Leffler { 2383b032f27cSSam Leffler struct ieee80211_frame_rts *rts; 2384b032f27cSSam Leffler struct mbuf *m; 2385b032f27cSSam Leffler 2386b032f27cSSam Leffler /* XXX honor ic_headroom */ 2387b032f27cSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 2388b032f27cSSam Leffler if (m != NULL) { 2389b032f27cSSam Leffler rts = mtod(m, struct ieee80211_frame_rts *); 2390b032f27cSSam Leffler rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2391b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; 2392b032f27cSSam Leffler rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2393b032f27cSSam Leffler *(u_int16_t *)rts->i_dur = htole16(dur); 2394b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ra, ra); 2395b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ta, ta); 2396b032f27cSSam Leffler 2397b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); 2398b032f27cSSam Leffler } 2399b032f27cSSam Leffler return m; 2400b032f27cSSam Leffler } 2401b032f27cSSam Leffler 2402b032f27cSSam Leffler /* 2403b032f27cSSam Leffler * Allocate and build a CTS (Clear To Send) control frame. 2404b032f27cSSam Leffler */ 2405b032f27cSSam Leffler struct mbuf * 2406b032f27cSSam Leffler ieee80211_alloc_cts(struct ieee80211com *ic, 2407b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) 2408b032f27cSSam Leffler { 2409b032f27cSSam Leffler struct ieee80211_frame_cts *cts; 2410b032f27cSSam Leffler struct mbuf *m; 2411b032f27cSSam Leffler 2412b032f27cSSam Leffler /* XXX honor ic_headroom */ 2413b032f27cSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 2414b032f27cSSam Leffler if (m != NULL) { 2415b032f27cSSam Leffler cts = mtod(m, struct ieee80211_frame_cts *); 2416b032f27cSSam Leffler cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2417b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; 2418b032f27cSSam Leffler cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2419b032f27cSSam Leffler *(u_int16_t *)cts->i_dur = htole16(dur); 2420b032f27cSSam Leffler IEEE80211_ADDR_COPY(cts->i_ra, ra); 2421b032f27cSSam Leffler 2422b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); 2423b032f27cSSam Leffler } 2424b032f27cSSam Leffler return m; 2425b032f27cSSam Leffler } 2426b032f27cSSam Leffler 242768e8e04eSSam Leffler static void 242868e8e04eSSam Leffler ieee80211_tx_mgt_timeout(void *arg) 242968e8e04eSSam Leffler { 243068e8e04eSSam Leffler struct ieee80211_node *ni = arg; 2431b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 243268e8e04eSSam Leffler 2433b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_INIT && 2434b032f27cSSam Leffler (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { 243568e8e04eSSam Leffler /* 243668e8e04eSSam Leffler * NB: it's safe to specify a timeout as the reason here; 243768e8e04eSSam Leffler * it'll only be used in the right state. 243868e8e04eSSam Leffler */ 2439b032f27cSSam Leffler ieee80211_new_state(vap, IEEE80211_S_SCAN, 244068e8e04eSSam Leffler IEEE80211_SCAN_FAIL_TIMEOUT); 244168e8e04eSSam Leffler } 244268e8e04eSSam Leffler } 244368e8e04eSSam Leffler 244468e8e04eSSam Leffler static void 244568e8e04eSSam Leffler ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) 244668e8e04eSSam Leffler { 2447b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 244868e8e04eSSam Leffler enum ieee80211_state ostate = (enum ieee80211_state) arg; 244968e8e04eSSam Leffler 245068e8e04eSSam Leffler /* 245168e8e04eSSam Leffler * Frame transmit completed; arrange timer callback. If 245268e8e04eSSam Leffler * transmit was successfuly we wait for response. Otherwise 245368e8e04eSSam Leffler * we arrange an immediate callback instead of doing the 245468e8e04eSSam Leffler * callback directly since we don't know what state the driver 245568e8e04eSSam Leffler * is in (e.g. what locks it is holding). This work should 245668e8e04eSSam Leffler * not be too time-critical and not happen too often so the 245768e8e04eSSam Leffler * added overhead is acceptable. 245868e8e04eSSam Leffler * 245968e8e04eSSam Leffler * XXX what happens if !acked but response shows up before callback? 246068e8e04eSSam Leffler */ 2461b032f27cSSam Leffler if (vap->iv_state == ostate) 2462b032f27cSSam Leffler callout_reset(&vap->iv_mgtsend, 246368e8e04eSSam Leffler status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, 246468e8e04eSSam Leffler ieee80211_tx_mgt_timeout, ni); 246568e8e04eSSam Leffler } 246668e8e04eSSam Leffler 2467b032f27cSSam Leffler static void 2468b032f27cSSam Leffler ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, 2469b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni) 24708a1b9b6aSSam Leffler { 2471b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2472b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 2473b032f27cSSam Leffler struct ieee80211_rateset *rs = &ni->ni_rates; 247468e8e04eSSam Leffler uint16_t capinfo; 24758a1b9b6aSSam Leffler 24768a1b9b6aSSam Leffler /* 24778a1b9b6aSSam Leffler * beacon frame format 24788a1b9b6aSSam Leffler * [8] time stamp 24798a1b9b6aSSam Leffler * [2] beacon interval 24808a1b9b6aSSam Leffler * [2] cabability information 24818a1b9b6aSSam Leffler * [tlv] ssid 24828a1b9b6aSSam Leffler * [tlv] supported rates 24838a1b9b6aSSam Leffler * [3] parameter set (DS) 2484b032f27cSSam Leffler * [8] CF parameter set (optional) 24858a1b9b6aSSam Leffler * [tlv] parameter set (IBSS/TIM) 2486b032f27cSSam Leffler * [tlv] country (optional) 2487b032f27cSSam Leffler * [3] power control (optional) 2488b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 24898a1b9b6aSSam Leffler * [tlv] extended rate phy (ERP) 24908a1b9b6aSSam Leffler * [tlv] extended supported rates 2491688fe74dSSam Leffler * [tlv] RSN parameters 249268e8e04eSSam Leffler * [tlv] HT capabilities 249368e8e04eSSam Leffler * [tlv] HT information 2494b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 2495b032f27cSSam Leffler * [tlv] WPA parameters 2496b032f27cSSam Leffler * [tlv] WME parameters 249768e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 249868e8e04eSSam Leffler * [tlv] Vendor OUI HT information (optional) 2499b032f27cSSam Leffler * [tlv] application data (optional) 25008a1b9b6aSSam Leffler */ 25018a1b9b6aSSam Leffler 25021b6167d2SSam Leffler memset(bo, 0, sizeof(*bo)); 25031b6167d2SSam Leffler 25048a1b9b6aSSam Leffler memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ 25058a1b9b6aSSam Leffler frm += 8; 250668e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_intval); 25078a1b9b6aSSam Leffler frm += 2; 2508b032f27cSSam Leffler capinfo = getcapinfo(vap, ni->ni_chan); 250968e8e04eSSam Leffler bo->bo_caps = (uint16_t *)frm; 251068e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 25118a1b9b6aSSam Leffler frm += 2; 25128a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 2513b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { 25148a1b9b6aSSam Leffler *frm++ = ni->ni_esslen; 25158a1b9b6aSSam Leffler memcpy(frm, ni->ni_essid, ni->ni_esslen); 25168a1b9b6aSSam Leffler frm += ni->ni_esslen; 25178a1b9b6aSSam Leffler } else 25188a1b9b6aSSam Leffler *frm++ = 0; 25198a1b9b6aSSam Leffler frm = ieee80211_add_rates(frm, rs); 2520b032f27cSSam Leffler if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { 25218a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 25228a1b9b6aSSam Leffler *frm++ = 1; 2523b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); 2524b032f27cSSam Leffler } 2525b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_PCF) { 2526b032f27cSSam Leffler bo->bo_cfp = frm; 2527b032f27cSSam Leffler frm = ieee80211_add_cfparms(frm, ic); 25288a1b9b6aSSam Leffler } 25298a1b9b6aSSam Leffler bo->bo_tim = frm; 2530b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 25318a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 25328a1b9b6aSSam Leffler *frm++ = 2; 25338a1b9b6aSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 25348a1b9b6aSSam Leffler bo->bo_tim_len = 0; 2535b032f27cSSam Leffler } else if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 25368a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; 25378a1b9b6aSSam Leffler 25388a1b9b6aSSam Leffler tie->tim_ie = IEEE80211_ELEMID_TIM; 25398a1b9b6aSSam Leffler tie->tim_len = 4; /* length */ 25408a1b9b6aSSam Leffler tie->tim_count = 0; /* DTIM count */ 2541b032f27cSSam Leffler tie->tim_period = vap->iv_dtim_period; /* DTIM period */ 25428a1b9b6aSSam Leffler tie->tim_bitctl = 0; /* bitmap control */ 25438a1b9b6aSSam Leffler tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 25448a1b9b6aSSam Leffler frm += sizeof(struct ieee80211_tim_ie); 25458a1b9b6aSSam Leffler bo->bo_tim_len = 1; 25468a1b9b6aSSam Leffler } 2547b105a069SSam Leffler bo->bo_tim_trailer = frm; 2548b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 2549b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2550b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 2551b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 2552b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 2553b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 2554b032f27cSSam Leffler bo->bo_csa = frm; 2555b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2556b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 2557b032f27cSSam Leffler } else 2558b032f27cSSam Leffler bo->bo_csa = frm; 2559b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { 25600912bac9SSam Leffler bo->bo_erp = frm; 25618a1b9b6aSSam Leffler frm = ieee80211_add_erp(frm, ic); 25621b6167d2SSam Leffler } 256368e8e04eSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2564688fe74dSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2565688fe74dSSam Leffler if (vap->iv_rsn_ie != NULL) 2566688fe74dSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2567688fe74dSSam Leffler /* XXX else complain */ 2568688fe74dSSam Leffler } 2569b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { 257068e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 257168e8e04eSSam Leffler bo->bo_htinfo = frm; 257268e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 25731b6167d2SSam Leffler } 2574b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2575b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2576b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2577b032f27cSSam Leffler /* XXX else complain */ 2578b032f27cSSam Leffler } 2579b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 25801b6167d2SSam Leffler bo->bo_wme = frm; 25811b6167d2SSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 25821b6167d2SSam Leffler } 2583b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && 2584b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_HTCOMPAT)) { 258568e8e04eSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 258668e8e04eSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 25870912bac9SSam Leffler } 2588b032f27cSSam Leffler if (vap->iv_appie_beacon != NULL) { 2589b032f27cSSam Leffler bo->bo_appie = frm; 2590b032f27cSSam Leffler bo->bo_appie_len = vap->iv_appie_beacon->ie_len; 2591b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_beacon); 2592b032f27cSSam Leffler } 2593b105a069SSam Leffler bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; 2594b032f27cSSam Leffler bo->bo_csa_trailer_len = frm - bo->bo_csa; 259568e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2596b032f27cSSam Leffler } 2597b032f27cSSam Leffler 2598b032f27cSSam Leffler /* 2599b032f27cSSam Leffler * Allocate a beacon frame and fillin the appropriate bits. 2600b032f27cSSam Leffler */ 2601b032f27cSSam Leffler struct mbuf * 2602b032f27cSSam Leffler ieee80211_beacon_alloc(struct ieee80211_node *ni, 2603b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo) 2604b032f27cSSam Leffler { 2605b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2606b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2607b032f27cSSam Leffler struct ifnet *ifp = vap->iv_ifp; 2608b032f27cSSam Leffler struct ieee80211_frame *wh; 2609b032f27cSSam Leffler struct mbuf *m; 2610b032f27cSSam Leffler int pktlen; 2611b032f27cSSam Leffler uint8_t *frm; 2612b032f27cSSam Leffler 2613b032f27cSSam Leffler /* 2614b032f27cSSam Leffler * beacon frame format 2615b032f27cSSam Leffler * [8] time stamp 2616b032f27cSSam Leffler * [2] beacon interval 2617b032f27cSSam Leffler * [2] cabability information 2618b032f27cSSam Leffler * [tlv] ssid 2619b032f27cSSam Leffler * [tlv] supported rates 2620b032f27cSSam Leffler * [3] parameter set (DS) 2621b032f27cSSam Leffler * [8] CF parameter set (optional) 2622b032f27cSSam Leffler * [tlv] parameter set (IBSS/TIM) 2623b032f27cSSam Leffler * [tlv] country (optional) 2624b032f27cSSam Leffler * [3] power control (optional) 2625b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 2626b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 2627b032f27cSSam Leffler * [tlv] extended supported rates 2628b032f27cSSam Leffler * [tlv] RSN parameters 2629b032f27cSSam Leffler * [tlv] HT capabilities 2630b032f27cSSam Leffler * [tlv] HT information 2631b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 2632b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 2633b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 2634b032f27cSSam Leffler * [tlv] WPA parameters 2635b032f27cSSam Leffler * [tlv] WME parameters 2636b032f27cSSam Leffler * [tlv] application data (optional) 2637b032f27cSSam Leffler * NB: we allocate the max space required for the TIM bitmap. 2638b032f27cSSam Leffler * XXX how big is this? 2639b032f27cSSam Leffler */ 2640b032f27cSSam Leffler pktlen = 8 /* time stamp */ 2641b032f27cSSam Leffler + sizeof(uint16_t) /* beacon interval */ 2642b032f27cSSam Leffler + sizeof(uint16_t) /* capabilities */ 2643b032f27cSSam Leffler + 2 + ni->ni_esslen /* ssid */ 2644b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE /* supported rates */ 2645b032f27cSSam Leffler + 2 + 1 /* DS parameters */ 2646b032f27cSSam Leffler + 2 + 6 /* CF parameters */ 2647b032f27cSSam Leffler + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ 2648b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE /* country */ 2649b032f27cSSam Leffler + 2 + 1 /* power control */ 2650b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) /* CSA */ 2651b032f27cSSam Leffler + 2 + 1 /* ERP */ 2652b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2653b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2654b032f27cSSam Leffler 2*sizeof(struct ieee80211_ie_wpa) : 0) 2655b032f27cSSam Leffler /* XXX conditional? */ 2656b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ 2657b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ 2658b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ 2659b032f27cSSam Leffler sizeof(struct ieee80211_wme_param) : 0) 2660b032f27cSSam Leffler + IEEE80211_MAX_APPIE 2661b032f27cSSam Leffler ; 2662b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 2663b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); 2664b032f27cSSam Leffler if (m == NULL) { 2665b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 2666b032f27cSSam Leffler "%s: cannot get buf; size %u\n", __func__, pktlen); 2667b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 2668b032f27cSSam Leffler return NULL; 2669b032f27cSSam Leffler } 2670b032f27cSSam Leffler ieee80211_beacon_construct(m, frm, bo, ni); 26718a1b9b6aSSam Leffler 26728a1b9b6aSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 26738a1b9b6aSSam Leffler KASSERT(m != NULL, ("no space for 802.11 header?")); 26748a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 26758a1b9b6aSSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 26768a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_BEACON; 26778a1b9b6aSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 267868e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 26798a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 2680b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 26818a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 268268e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 0; 26838a1b9b6aSSam Leffler 26848a1b9b6aSSam Leffler return m; 26858a1b9b6aSSam Leffler } 26868a1b9b6aSSam Leffler 26878a1b9b6aSSam Leffler /* 26888a1b9b6aSSam Leffler * Update the dynamic parts of a beacon frame based on the current state. 26898a1b9b6aSSam Leffler */ 26908a1b9b6aSSam Leffler int 2691b105a069SSam Leffler ieee80211_beacon_update(struct ieee80211_node *ni, 26928a1b9b6aSSam Leffler struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) 26938a1b9b6aSSam Leffler { 2694b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2695b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 26968a1b9b6aSSam Leffler int len_changed = 0; 269768e8e04eSSam Leffler uint16_t capinfo; 26988a1b9b6aSSam Leffler 2699b032f27cSSam Leffler IEEE80211_LOCK(ic); 2700b032f27cSSam Leffler /* 2701b032f27cSSam Leffler * Handle 11h channel change when we've reached the count. 2702b032f27cSSam Leffler * We must recalculate the beacon frame contents to account 2703b032f27cSSam Leffler * for the new channel. Note we do this only for the first 2704b032f27cSSam Leffler * vap that reaches this point; subsequent vaps just update 2705b032f27cSSam Leffler * their beacon state to reflect the recalculated channel. 2706b032f27cSSam Leffler */ 2707b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && 2708b032f27cSSam Leffler vap->iv_csa_count == ic->ic_csa_count) { 2709b032f27cSSam Leffler vap->iv_csa_count = 0; 2710b032f27cSSam Leffler /* 2711b032f27cSSam Leffler * Effect channel change before reconstructing the beacon 2712b032f27cSSam Leffler * frame contents as many places reference ni_chan. 2713b032f27cSSam Leffler */ 2714b032f27cSSam Leffler if (ic->ic_csa_newchan != NULL) 2715b032f27cSSam Leffler ieee80211_csa_completeswitch(ic); 2716b032f27cSSam Leffler /* 2717b032f27cSSam Leffler * NB: ieee80211_beacon_construct clears all pending 2718b032f27cSSam Leffler * updates in bo_flags so we don't need to explicitly 2719b032f27cSSam Leffler * clear IEEE80211_BEACON_CSA. 2720b032f27cSSam Leffler */ 2721b032f27cSSam Leffler ieee80211_beacon_construct(m, 2722b032f27cSSam Leffler mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni); 2723b032f27cSSam Leffler 2724b032f27cSSam Leffler /* XXX do WME aggressive mode processing? */ 2725b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 2726b032f27cSSam Leffler return 1; /* just assume length changed */ 2727b032f27cSSam Leffler } 2728b032f27cSSam Leffler 27298a1b9b6aSSam Leffler /* XXX faster to recalculate entirely or just changes? */ 2730b032f27cSSam Leffler capinfo = getcapinfo(vap, ni->ni_chan); 27318a1b9b6aSSam Leffler *bo->bo_caps = htole16(capinfo); 27328a1b9b6aSSam Leffler 2733b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 27348a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 27358a1b9b6aSSam Leffler 27368a1b9b6aSSam Leffler /* 27378a1b9b6aSSam Leffler * Check for agressive mode change. When there is 27388a1b9b6aSSam Leffler * significant high priority traffic in the BSS 27398a1b9b6aSSam Leffler * throttle back BE traffic by using conservative 27408a1b9b6aSSam Leffler * parameters. Otherwise BE uses agressive params 27418a1b9b6aSSam Leffler * to optimize performance of legacy/non-QoS traffic. 27428a1b9b6aSSam Leffler */ 27438a1b9b6aSSam Leffler if (wme->wme_flags & WME_F_AGGRMODE) { 27448a1b9b6aSSam Leffler if (wme->wme_hipri_traffic > 27458a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 2746b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 27478a1b9b6aSSam Leffler "%s: traffic %u, disable aggressive mode\n", 27488a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 27498a1b9b6aSSam Leffler wme->wme_flags &= ~WME_F_AGGRMODE; 2750b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 27518a1b9b6aSSam Leffler wme->wme_hipri_traffic = 27528a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 27538a1b9b6aSSam Leffler } else 27548a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 27558a1b9b6aSSam Leffler } else { 27568a1b9b6aSSam Leffler if (wme->wme_hipri_traffic <= 27578a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 2758b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 27598a1b9b6aSSam Leffler "%s: traffic %u, enable aggressive mode\n", 27608a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 27618a1b9b6aSSam Leffler wme->wme_flags |= WME_F_AGGRMODE; 2762b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 27638a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 27648a1b9b6aSSam Leffler } else 27658a1b9b6aSSam Leffler wme->wme_hipri_traffic = 27668a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 27678a1b9b6aSSam Leffler } 2768b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { 27698a1b9b6aSSam Leffler (void) ieee80211_add_wme_param(bo->bo_wme, wme); 2770b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_WME); 27718a1b9b6aSSam Leffler } 27728a1b9b6aSSam Leffler } 27738a1b9b6aSSam Leffler 2774b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { 2775b032f27cSSam Leffler ieee80211_ht_update_beacon(vap, bo); 2776b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); 277768e8e04eSSam Leffler } 277868e8e04eSSam Leffler 2779b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) { /* NB: no IBSS support*/ 27808a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = 27818a1b9b6aSSam Leffler (struct ieee80211_tim_ie *) bo->bo_tim; 2782b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { 27838a1b9b6aSSam Leffler u_int timlen, timoff, i; 27848a1b9b6aSSam Leffler /* 27858a1b9b6aSSam Leffler * ATIM/DTIM needs updating. If it fits in the 27868a1b9b6aSSam Leffler * current space allocated then just copy in the 27878a1b9b6aSSam Leffler * new bits. Otherwise we need to move any trailing 27888a1b9b6aSSam Leffler * data to make room. Note that we know there is 27898a1b9b6aSSam Leffler * contiguous space because ieee80211_beacon_allocate 27908a1b9b6aSSam Leffler * insures there is space in the mbuf to write a 2791b032f27cSSam Leffler * maximal-size virtual bitmap (based on iv_max_aid). 27928a1b9b6aSSam Leffler */ 27938a1b9b6aSSam Leffler /* 27948a1b9b6aSSam Leffler * Calculate the bitmap size and offset, copy any 27958a1b9b6aSSam Leffler * trailer out of the way, and then copy in the 27968a1b9b6aSSam Leffler * new bitmap and update the information element. 27978a1b9b6aSSam Leffler * Note that the tim bitmap must contain at least 27988a1b9b6aSSam Leffler * one byte and any offset must be even. 27998a1b9b6aSSam Leffler */ 2800b032f27cSSam Leffler if (vap->iv_ps_pending != 0) { 28018a1b9b6aSSam Leffler timoff = 128; /* impossibly large */ 2802b032f27cSSam Leffler for (i = 0; i < vap->iv_tim_len; i++) 2803b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) { 28048a1b9b6aSSam Leffler timoff = i &~ 1; 28058a1b9b6aSSam Leffler break; 28068a1b9b6aSSam Leffler } 28078a1b9b6aSSam Leffler KASSERT(timoff != 128, ("tim bitmap empty!")); 2808b032f27cSSam Leffler for (i = vap->iv_tim_len-1; i >= timoff; i--) 2809b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) 28108a1b9b6aSSam Leffler break; 28118a1b9b6aSSam Leffler timlen = 1 + (i - timoff); 28128a1b9b6aSSam Leffler } else { 28138a1b9b6aSSam Leffler timoff = 0; 28148a1b9b6aSSam Leffler timlen = 1; 28158a1b9b6aSSam Leffler } 28168a1b9b6aSSam Leffler if (timlen != bo->bo_tim_len) { 28178a1b9b6aSSam Leffler /* copy up/down trailer */ 28180912bac9SSam Leffler int adjust = tie->tim_bitmap+timlen 2819b105a069SSam Leffler - bo->bo_tim_trailer; 2820b105a069SSam Leffler ovbcopy(bo->bo_tim_trailer, 2821b105a069SSam Leffler bo->bo_tim_trailer+adjust, 2822b105a069SSam Leffler bo->bo_tim_trailer_len); 2823b105a069SSam Leffler bo->bo_tim_trailer += adjust; 28240912bac9SSam Leffler bo->bo_erp += adjust; 282568e8e04eSSam Leffler bo->bo_htinfo += adjust; 2826b032f27cSSam Leffler bo->bo_appie += adjust; 2827b032f27cSSam Leffler bo->bo_wme += adjust; 2828b032f27cSSam Leffler bo->bo_csa += adjust; 28298a1b9b6aSSam Leffler bo->bo_tim_len = timlen; 28308a1b9b6aSSam Leffler 28318a1b9b6aSSam Leffler /* update information element */ 28328a1b9b6aSSam Leffler tie->tim_len = 3 + timlen; 28338a1b9b6aSSam Leffler tie->tim_bitctl = timoff; 28348a1b9b6aSSam Leffler len_changed = 1; 28358a1b9b6aSSam Leffler } 2836b032f27cSSam Leffler memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, 28378a1b9b6aSSam Leffler bo->bo_tim_len); 28388a1b9b6aSSam Leffler 2839b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); 28408a1b9b6aSSam Leffler 2841b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 28428a1b9b6aSSam Leffler "%s: TIM updated, pending %u, off %u, len %u\n", 2843b032f27cSSam Leffler __func__, vap->iv_ps_pending, timoff, timlen); 28448a1b9b6aSSam Leffler } 28458a1b9b6aSSam Leffler /* count down DTIM period */ 28468a1b9b6aSSam Leffler if (tie->tim_count == 0) 28478a1b9b6aSSam Leffler tie->tim_count = tie->tim_period - 1; 28488a1b9b6aSSam Leffler else 28498a1b9b6aSSam Leffler tie->tim_count--; 28508a1b9b6aSSam Leffler /* update state for buffered multicast frames on DTIM */ 2851a196b35fSSam Leffler if (mcast && tie->tim_count == 0) 28528a1b9b6aSSam Leffler tie->tim_bitctl |= 1; 28538a1b9b6aSSam Leffler else 28548a1b9b6aSSam Leffler tie->tim_bitctl &= ~1; 2855b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { 2856b032f27cSSam Leffler struct ieee80211_csa_ie *csa = 2857b032f27cSSam Leffler (struct ieee80211_csa_ie *) bo->bo_csa; 2858b032f27cSSam Leffler 2859b032f27cSSam Leffler /* 2860b032f27cSSam Leffler * Insert or update CSA ie. If we're just starting 2861b032f27cSSam Leffler * to count down to the channel switch then we need 2862b032f27cSSam Leffler * to insert the CSA ie. Otherwise we just need to 2863b032f27cSSam Leffler * drop the count. The actual change happens above 2864b032f27cSSam Leffler * when the vap's count reaches the target count. 2865b032f27cSSam Leffler */ 2866b032f27cSSam Leffler if (vap->iv_csa_count == 0) { 2867b032f27cSSam Leffler memmove(&csa[1], csa, bo->bo_csa_trailer_len); 2868b032f27cSSam Leffler bo->bo_erp += sizeof(*csa); 2869b032f27cSSam Leffler bo->bo_wme += sizeof(*csa); 2870b032f27cSSam Leffler bo->bo_appie += sizeof(*csa); 2871b032f27cSSam Leffler bo->bo_csa_trailer_len += sizeof(*csa); 2872b032f27cSSam Leffler bo->bo_tim_trailer_len += sizeof(*csa); 2873b032f27cSSam Leffler m->m_len += sizeof(*csa); 2874b032f27cSSam Leffler m->m_pkthdr.len += sizeof(*csa); 2875b032f27cSSam Leffler 2876b032f27cSSam Leffler ieee80211_add_csa(bo->bo_csa, vap); 2877b032f27cSSam Leffler } else 2878b032f27cSSam Leffler csa->csa_count--; 2879b032f27cSSam Leffler vap->iv_csa_count++; 2880b032f27cSSam Leffler /* NB: don't clear IEEE80211_BEACON_CSA */ 2881b032f27cSSam Leffler } 2882b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { 28830912bac9SSam Leffler /* 28840912bac9SSam Leffler * ERP element needs updating. 28850912bac9SSam Leffler */ 28860912bac9SSam Leffler (void) ieee80211_add_erp(bo->bo_erp, ic); 2887b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); 28880912bac9SSam Leffler } 28898a1b9b6aSSam Leffler } 2890b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { 2891b032f27cSSam Leffler const struct ieee80211_appie *aie = vap->iv_appie_beacon; 2892b032f27cSSam Leffler int aielen; 2893b032f27cSSam Leffler uint8_t *frm; 2894b032f27cSSam Leffler 2895b032f27cSSam Leffler aielen = 0; 2896b032f27cSSam Leffler if (aie != NULL) 2897b032f27cSSam Leffler aielen += aie->ie_len; 2898b032f27cSSam Leffler if (aielen != bo->bo_appie_len) { 2899b032f27cSSam Leffler /* copy up/down trailer */ 2900b032f27cSSam Leffler int adjust = aielen - bo->bo_appie_len; 2901b032f27cSSam Leffler ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, 2902b032f27cSSam Leffler bo->bo_tim_trailer_len); 2903b032f27cSSam Leffler bo->bo_tim_trailer += adjust; 2904b032f27cSSam Leffler bo->bo_appie += adjust; 2905b032f27cSSam Leffler bo->bo_appie_len = aielen; 2906b032f27cSSam Leffler 2907b032f27cSSam Leffler len_changed = 1; 2908b032f27cSSam Leffler } 2909b032f27cSSam Leffler frm = bo->bo_appie; 2910b032f27cSSam Leffler if (aie != NULL) 2911b032f27cSSam Leffler frm = add_appie(frm, aie); 2912b032f27cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); 2913b032f27cSSam Leffler } 2914b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 29158a1b9b6aSSam Leffler 29168a1b9b6aSSam Leffler return len_changed; 29178a1b9b6aSSam Leffler } 2918