11a1e1d21SSam Leffler /*- 2fe267a55SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3fe267a55SPedro F. Giffuni * 47535e66aSSam Leffler * Copyright (c) 2001 Atsushi Onoe 510ad9a77SSam Leffler * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 61a1e1d21SSam Leffler * All rights reserved. 71a1e1d21SSam Leffler * 81a1e1d21SSam Leffler * Redistribution and use in source and binary forms, with or without 91a1e1d21SSam Leffler * modification, are permitted provided that the following conditions 101a1e1d21SSam Leffler * are met: 111a1e1d21SSam Leffler * 1. Redistributions of source code must retain the above copyright 127535e66aSSam Leffler * notice, this list of conditions and the following disclaimer. 137535e66aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 147535e66aSSam Leffler * notice, this list of conditions and the following disclaimer in the 157535e66aSSam Leffler * documentation and/or other materials provided with the distribution. 161a1e1d21SSam Leffler * 177535e66aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 187535e66aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 197535e66aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 207535e66aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 217535e66aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 227535e66aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237535e66aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247535e66aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257535e66aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 267535e66aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 271a1e1d21SSam Leffler */ 281a1e1d21SSam Leffler 291a1e1d21SSam Leffler #include <sys/cdefs.h> 301a1e1d21SSam Leffler __FBSDID("$FreeBSD$"); 311a1e1d21SSam Leffler 321a1e1d21SSam Leffler #include "opt_inet.h" 33e755a73dSSam Leffler #include "opt_inet6.h" 34b032f27cSSam Leffler #include "opt_wlan.h" 351a1e1d21SSam Leffler 361a1e1d21SSam Leffler #include <sys/param.h> 371a1e1d21SSam Leffler #include <sys/systm.h> 381a1e1d21SSam Leffler #include <sys/kernel.h> 398ec07310SGleb Smirnoff #include <sys/malloc.h> 408ec07310SGleb Smirnoff #include <sys/mbuf.h> 411a1e1d21SSam Leffler #include <sys/endian.h> 421a1e1d21SSam Leffler 438a1b9b6aSSam Leffler #include <sys/socket.h> 441a1e1d21SSam Leffler 451a1e1d21SSam Leffler #include <net/bpf.h> 468a1b9b6aSSam Leffler #include <net/ethernet.h> 478a1b9b6aSSam Leffler #include <net/if.h> 4876039bc8SGleb Smirnoff #include <net/if_var.h> 498a1b9b6aSSam Leffler #include <net/if_llc.h> 508a1b9b6aSSam Leffler #include <net/if_media.h> 518a1b9b6aSSam Leffler #include <net/if_vlan_var.h> 528a1b9b6aSSam Leffler 538a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h> 5468e8e04eSSam Leffler #include <net80211/ieee80211_regdomain.h> 55616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 56616190d0SSam Leffler #include <net80211/ieee80211_superg.h> 57616190d0SSam Leffler #endif 5810ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 5910ad9a77SSam Leffler #include <net80211/ieee80211_tdma.h> 6010ad9a77SSam Leffler #endif 61b032f27cSSam Leffler #include <net80211/ieee80211_wds.h> 6259aa14a9SRui Paulo #include <net80211/ieee80211_mesh.h> 6351172f62SAdrian Chadd #include <net80211/ieee80211_vht.h> 641a1e1d21SSam Leffler 658355d59dSBjoern A. Zeeb #if defined(INET) || defined(INET6) 661a1e1d21SSam Leffler #include <netinet/in.h> 678355d59dSBjoern A. Zeeb #endif 688355d59dSBjoern A. Zeeb 698355d59dSBjoern A. Zeeb #ifdef INET 701a1e1d21SSam Leffler #include <netinet/if_ether.h> 718a1b9b6aSSam Leffler #include <netinet/in_systm.h> 728a1b9b6aSSam Leffler #include <netinet/ip.h> 738a1b9b6aSSam Leffler #endif 74e755a73dSSam Leffler #ifdef INET6 75e755a73dSSam Leffler #include <netinet/ip6.h> 76e755a73dSSam Leffler #endif 778a1b9b6aSSam Leffler 78c27b9cdbSRobert Watson #include <security/mac/mac_framework.h> 79c27b9cdbSRobert Watson 8068e8e04eSSam Leffler #define ETHER_HEADER_COPY(dst, src) \ 8168e8e04eSSam Leffler memcpy(dst, src, sizeof(struct ether_header)) 8268e8e04eSSam Leffler 83b032f27cSSam Leffler static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *, 8468e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu); 8568e8e04eSSam Leffler static void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int); 8668e8e04eSSam Leffler 878a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 888a1b9b6aSSam Leffler /* 898a1b9b6aSSam Leffler * Decide if an outbound management frame should be 908a1b9b6aSSam Leffler * printed when debugging is enabled. This filters some 918a1b9b6aSSam Leffler * of the less interesting frames that come frequently 928a1b9b6aSSam Leffler * (e.g. beacons). 938a1b9b6aSSam Leffler */ 948a1b9b6aSSam Leffler static __inline int 95b032f27cSSam Leffler doprint(struct ieee80211vap *vap, int subtype) 968a1b9b6aSSam Leffler { 978a1b9b6aSSam Leffler switch (subtype) { 988a1b9b6aSSam Leffler case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 99b032f27cSSam Leffler return (vap->iv_opmode == IEEE80211_M_IBSS); 1008a1b9b6aSSam Leffler } 1018a1b9b6aSSam Leffler return 1; 1028a1b9b6aSSam Leffler } 1031a1e1d21SSam Leffler #endif 1041a1e1d21SSam Leffler 1050a915fadSSam Leffler /* 106363a2c3cSAdrian Chadd * Transmit a frame to the given destination on the given VAP. 107363a2c3cSAdrian Chadd * 108363a2c3cSAdrian Chadd * It's up to the caller to figure out the details of who this 109363a2c3cSAdrian Chadd * is going to and resolving the node. 110363a2c3cSAdrian Chadd * 111363a2c3cSAdrian Chadd * This routine takes care of queuing it for power save, 112363a2c3cSAdrian Chadd * A-MPDU state stuff, fast-frames state stuff, encapsulation 113363a2c3cSAdrian Chadd * if required, then passing it up to the driver layer. 114363a2c3cSAdrian Chadd * 115363a2c3cSAdrian Chadd * This routine (for now) consumes the mbuf and frees the node 116363a2c3cSAdrian Chadd * reference; it ideally will return a TX status which reflects 117363a2c3cSAdrian Chadd * whether the mbuf was consumed or not, so the caller can 118363a2c3cSAdrian Chadd * free the mbuf (if appropriate) and the node reference (again, 119363a2c3cSAdrian Chadd * if appropriate.) 120363a2c3cSAdrian Chadd */ 121363a2c3cSAdrian Chadd int 122363a2c3cSAdrian Chadd ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m, 123363a2c3cSAdrian Chadd struct ieee80211_node *ni) 124363a2c3cSAdrian Chadd { 125363a2c3cSAdrian Chadd struct ieee80211com *ic = vap->iv_ic; 126363a2c3cSAdrian Chadd struct ifnet *ifp = vap->iv_ifp; 1272e9090dfSBjoern A. Zeeb int mcast; 128b3d0e274SAdrian Chadd int do_ampdu = 0; 12905ea7a3eSBjoern A. Zeeb #ifdef IEEE80211_SUPPORT_SUPERG 130b3d0e274SAdrian Chadd int do_amsdu = 0; 131b3d0e274SAdrian Chadd int do_ampdu_amsdu = 0; 132b3d0e274SAdrian Chadd int no_ampdu = 1; /* Will be set to 0 if ampdu is active */ 133b3d0e274SAdrian Chadd int do_ff = 0; 13405ea7a3eSBjoern A. Zeeb #endif 135363a2c3cSAdrian Chadd 136363a2c3cSAdrian Chadd if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 137363a2c3cSAdrian Chadd (m->m_flags & M_PWR_SAV) == 0) { 138363a2c3cSAdrian Chadd /* 139363a2c3cSAdrian Chadd * Station in power save mode; pass the frame 140363a2c3cSAdrian Chadd * to the 802.11 layer and continue. We'll get 141363a2c3cSAdrian Chadd * the frame back when the time is right. 142363a2c3cSAdrian Chadd * XXX lose WDS vap linkage? 143363a2c3cSAdrian Chadd */ 14479077edcSAndrey V. Elsukov if (ieee80211_pwrsave(ni, m) != 0) 14579077edcSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 146363a2c3cSAdrian Chadd ieee80211_free_node(ni); 147c6d5b600SAdrian Chadd 148c6d5b600SAdrian Chadd /* 149c6d5b600SAdrian Chadd * We queued it fine, so tell the upper layer 150c6d5b600SAdrian Chadd * that we consumed it. 151c6d5b600SAdrian Chadd */ 152c6d5b600SAdrian Chadd return (0); 153363a2c3cSAdrian Chadd } 154363a2c3cSAdrian Chadd /* calculate priority so drivers can find the tx queue */ 155363a2c3cSAdrian Chadd if (ieee80211_classify(ni, m)) { 156363a2c3cSAdrian Chadd IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 157363a2c3cSAdrian Chadd ni->ni_macaddr, NULL, 158363a2c3cSAdrian Chadd "%s", "classification failure"); 159363a2c3cSAdrian Chadd vap->iv_stats.is_tx_classify++; 160dea45121SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 161363a2c3cSAdrian Chadd m_freem(m); 162363a2c3cSAdrian Chadd ieee80211_free_node(ni); 163c6d5b600SAdrian Chadd 164363a2c3cSAdrian Chadd /* XXX better status? */ 165c6d5b600SAdrian Chadd return (0); 166363a2c3cSAdrian Chadd } 167363a2c3cSAdrian Chadd /* 168363a2c3cSAdrian Chadd * Stash the node pointer. Note that we do this after 169363a2c3cSAdrian Chadd * any call to ieee80211_dwds_mcast because that code 170363a2c3cSAdrian Chadd * uses any existing value for rcvif to identify the 171363a2c3cSAdrian Chadd * interface it (might have been) received on. 172363a2c3cSAdrian Chadd */ 173fb3bc596SJohn Baldwin MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0); 174363a2c3cSAdrian Chadd m->m_pkthdr.rcvif = (void *)ni; 1752e9090dfSBjoern A. Zeeb mcast = (m->m_flags & (M_MCAST | M_BCAST)) ? 1: 0; 176363a2c3cSAdrian Chadd 177363a2c3cSAdrian Chadd BPF_MTAP(ifp, m); /* 802.3 tx */ 178363a2c3cSAdrian Chadd 179b3d0e274SAdrian Chadd /* 180b3d0e274SAdrian Chadd * Figure out if we can do A-MPDU, A-MSDU or FF. 181b3d0e274SAdrian Chadd * 182b3d0e274SAdrian Chadd * A-MPDU depends upon vap/node config. 183b3d0e274SAdrian Chadd * A-MSDU depends upon vap/node config. 184b3d0e274SAdrian Chadd * FF depends upon vap config, IE and whether 185b3d0e274SAdrian Chadd * it's 11abg (and not 11n/11ac/etc.) 186b3d0e274SAdrian Chadd * 187b3d0e274SAdrian Chadd * Note that these flags indiciate whether we can do 188b3d0e274SAdrian Chadd * it at all, rather than the situation (eg traffic type.) 189b3d0e274SAdrian Chadd */ 190b3d0e274SAdrian Chadd do_ampdu = ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && 191b3d0e274SAdrian Chadd (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX)); 19205ea7a3eSBjoern A. Zeeb #ifdef IEEE80211_SUPPORT_SUPERG 193b3d0e274SAdrian Chadd do_amsdu = ((ni->ni_flags & IEEE80211_NODE_AMSDU_TX) && 194b3d0e274SAdrian Chadd (vap->iv_flags_ht & IEEE80211_FHT_AMSDU_TX)); 195b3d0e274SAdrian Chadd do_ff = 196b3d0e274SAdrian Chadd ((ni->ni_flags & IEEE80211_NODE_HT) == 0) && 197b3d0e274SAdrian Chadd ((ni->ni_flags & IEEE80211_NODE_VHT) == 0) && 198b3d0e274SAdrian Chadd (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)); 19905ea7a3eSBjoern A. Zeeb #endif 200b3d0e274SAdrian Chadd 201363a2c3cSAdrian Chadd /* 202363a2c3cSAdrian Chadd * Check if A-MPDU tx aggregation is setup or if we 203363a2c3cSAdrian Chadd * should try to enable it. The sta must be associated 204363a2c3cSAdrian Chadd * with HT and A-MPDU enabled for use. When the policy 205363a2c3cSAdrian Chadd * routine decides we should enable A-MPDU we issue an 206363a2c3cSAdrian Chadd * ADDBA request and wait for a reply. The frame being 207363a2c3cSAdrian Chadd * encapsulated will go out w/o using A-MPDU, or possibly 208363a2c3cSAdrian Chadd * it might be collected by the driver and held/retransmit. 209363a2c3cSAdrian Chadd * The default ic_ampdu_enable routine handles staggering 210363a2c3cSAdrian Chadd * ADDBA requests in case the receiver NAK's us or we are 211363a2c3cSAdrian Chadd * otherwise unable to establish a BA stream. 2129764ef21SAdrian Chadd * 2139764ef21SAdrian Chadd * Don't treat group-addressed frames as candidates for aggregation; 2149764ef21SAdrian Chadd * net80211 doesn't support 802.11aa-2012 and so group addressed 2159764ef21SAdrian Chadd * frames will always have sequence numbers allocated from the NON_QOS 2169764ef21SAdrian Chadd * TID. 217363a2c3cSAdrian Chadd */ 218b3d0e274SAdrian Chadd if (do_ampdu) { 2199764ef21SAdrian Chadd if ((m->m_flags & M_EAPOL) == 0 && (! mcast)) { 220363a2c3cSAdrian Chadd int tid = WME_AC_TO_TID(M_WME_GETAC(m)); 221363a2c3cSAdrian Chadd struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; 222363a2c3cSAdrian Chadd 223363a2c3cSAdrian Chadd ieee80211_txampdu_count_packet(tap); 224363a2c3cSAdrian Chadd if (IEEE80211_AMPDU_RUNNING(tap)) { 225363a2c3cSAdrian Chadd /* 226363a2c3cSAdrian Chadd * Operational, mark frame for aggregation. 227363a2c3cSAdrian Chadd * 228363a2c3cSAdrian Chadd * XXX do tx aggregation here 229363a2c3cSAdrian Chadd */ 230363a2c3cSAdrian Chadd m->m_flags |= M_AMPDU_MPDU; 231363a2c3cSAdrian Chadd } else if (!IEEE80211_AMPDU_REQUESTED(tap) && 232363a2c3cSAdrian Chadd ic->ic_ampdu_enable(ni, tap)) { 233363a2c3cSAdrian Chadd /* 234363a2c3cSAdrian Chadd * Not negotiated yet, request service. 235363a2c3cSAdrian Chadd */ 236363a2c3cSAdrian Chadd ieee80211_ampdu_request(ni, tap); 237363a2c3cSAdrian Chadd /* XXX hold frame for reply? */ 238363a2c3cSAdrian Chadd } 239b3d0e274SAdrian Chadd /* 240b3d0e274SAdrian Chadd * Now update the no-ampdu flag. A-MPDU may have been 241b3d0e274SAdrian Chadd * started or administratively disabled above; so now we 242b3d0e274SAdrian Chadd * know whether we're running yet or not. 243b3d0e274SAdrian Chadd * 244b3d0e274SAdrian Chadd * This will let us know whether we should be doing A-MSDU 245b3d0e274SAdrian Chadd * at this point. We only do A-MSDU if we're either not 246b3d0e274SAdrian Chadd * doing A-MPDU, or A-MPDU is NACKed, or A-MPDU + A-MSDU 247b3d0e274SAdrian Chadd * is available. 248b3d0e274SAdrian Chadd * 249b3d0e274SAdrian Chadd * Whilst here, update the amsdu-ampdu flag. The above may 250b3d0e274SAdrian Chadd * have also set or cleared the amsdu-in-ampdu txa_flags 251b3d0e274SAdrian Chadd * combination so we can correctly do A-MPDU + A-MSDU. 252b3d0e274SAdrian Chadd */ 25305ea7a3eSBjoern A. Zeeb #ifdef IEEE80211_SUPPORT_SUPERG 254b3d0e274SAdrian Chadd no_ampdu = (! IEEE80211_AMPDU_RUNNING(tap) 255b3d0e274SAdrian Chadd || (IEEE80211_AMPDU_NACKED(tap))); 256b3d0e274SAdrian Chadd do_ampdu_amsdu = IEEE80211_AMPDU_RUNNING_AMSDU(tap); 25705ea7a3eSBjoern A. Zeeb #endif 258363a2c3cSAdrian Chadd } 2591c7b0c84SAdrian Chadd } 260363a2c3cSAdrian Chadd 261363a2c3cSAdrian Chadd #ifdef IEEE80211_SUPPORT_SUPERG 2621c7b0c84SAdrian Chadd /* 2631c7b0c84SAdrian Chadd * Check for AMSDU/FF; queue for aggregation 2641c7b0c84SAdrian Chadd * 2651c7b0c84SAdrian Chadd * Note: we don't bother trying to do fast frames or 2661c7b0c84SAdrian Chadd * A-MSDU encapsulation for 802.3 drivers. Now, we 2671c7b0c84SAdrian Chadd * likely could do it for FF (because it's a magic 2681c7b0c84SAdrian Chadd * atheros tunnel LLC type) but I don't think we're going 2691c7b0c84SAdrian Chadd * to really need to. For A-MSDU we'd have to set the 2701c7b0c84SAdrian Chadd * A-MSDU QoS bit in the wifi header, so we just plain 2711c7b0c84SAdrian Chadd * can't do it. 2721c7b0c84SAdrian Chadd */ 273b3d0e274SAdrian Chadd if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { 274b3d0e274SAdrian Chadd if ((! mcast) && 275b3d0e274SAdrian Chadd (do_ampdu_amsdu || (no_ampdu && do_amsdu)) && 276b3d0e274SAdrian Chadd ieee80211_amsdu_tx_ok(ni)) { 2771c7b0c84SAdrian Chadd m = ieee80211_amsdu_check(ni, m); 2781c7b0c84SAdrian Chadd if (m == NULL) { 2791c7b0c84SAdrian Chadd /* NB: any ni ref held on stageq */ 2801c7b0c84SAdrian Chadd IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 2811c7b0c84SAdrian Chadd "%s: amsdu_check queued frame\n", 2821c7b0c84SAdrian Chadd __func__); 2831c7b0c84SAdrian Chadd return (0); 2841c7b0c84SAdrian Chadd } 285b3d0e274SAdrian Chadd } else if ((! mcast) && do_ff) { 286363a2c3cSAdrian Chadd m = ieee80211_ff_check(ni, m); 287363a2c3cSAdrian Chadd if (m == NULL) { 288363a2c3cSAdrian Chadd /* NB: any ni ref held on stageq */ 2891c7b0c84SAdrian Chadd IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 2901c7b0c84SAdrian Chadd "%s: ff_check queued frame\n", 2911c7b0c84SAdrian Chadd __func__); 29211e0ddb1SAdrian Chadd return (0); 293363a2c3cSAdrian Chadd } 294363a2c3cSAdrian Chadd } 2951c7b0c84SAdrian Chadd } 296363a2c3cSAdrian Chadd #endif /* IEEE80211_SUPPORT_SUPERG */ 297363a2c3cSAdrian Chadd 298363a2c3cSAdrian Chadd /* 299363a2c3cSAdrian Chadd * Grab the TX lock - serialise the TX process from this 300363a2c3cSAdrian Chadd * point (where TX state is being checked/modified) 301363a2c3cSAdrian Chadd * through to driver queue. 302363a2c3cSAdrian Chadd */ 303363a2c3cSAdrian Chadd IEEE80211_TX_LOCK(ic); 304363a2c3cSAdrian Chadd 305f9128a1bSAdrian Chadd /* 306f9128a1bSAdrian Chadd * XXX make the encap and transmit code a separate function 307f9128a1bSAdrian Chadd * so things like the FF (and later A-MSDU) path can just call 308f9128a1bSAdrian Chadd * it for flushed frames. 309f9128a1bSAdrian Chadd */ 310363a2c3cSAdrian Chadd if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { 311363a2c3cSAdrian Chadd /* 312363a2c3cSAdrian Chadd * Encapsulate the packet in prep for transmission. 313363a2c3cSAdrian Chadd */ 314363a2c3cSAdrian Chadd m = ieee80211_encap(vap, ni, m); 315363a2c3cSAdrian Chadd if (m == NULL) { 316363a2c3cSAdrian Chadd /* NB: stat+msg handled in ieee80211_encap */ 317363a2c3cSAdrian Chadd IEEE80211_TX_UNLOCK(ic); 318363a2c3cSAdrian Chadd ieee80211_free_node(ni); 31979077edcSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 320363a2c3cSAdrian Chadd return (ENOBUFS); 321363a2c3cSAdrian Chadd } 322363a2c3cSAdrian Chadd } 323d3a4ade3SAdrian Chadd (void) ieee80211_parent_xmitpkt(ic, m); 324363a2c3cSAdrian Chadd 325363a2c3cSAdrian Chadd /* 326363a2c3cSAdrian Chadd * Unlock at this point - no need to hold it across 327363a2c3cSAdrian Chadd * ieee80211_free_node() (ie, the comlock) 328363a2c3cSAdrian Chadd */ 329363a2c3cSAdrian Chadd IEEE80211_TX_UNLOCK(ic); 330363a2c3cSAdrian Chadd ic->ic_lastdata = ticks; 331363a2c3cSAdrian Chadd 332363a2c3cSAdrian Chadd return (0); 333363a2c3cSAdrian Chadd } 334363a2c3cSAdrian Chadd 335363a2c3cSAdrian Chadd /* 3365cda6006SAdrian Chadd * Send the given mbuf through the given vap. 3375cda6006SAdrian Chadd * 3385cda6006SAdrian Chadd * This consumes the mbuf regardless of whether the transmit 3395cda6006SAdrian Chadd * was successful or not. 3405cda6006SAdrian Chadd * 3415cda6006SAdrian Chadd * This does none of the initial checks that ieee80211_start() 3425cda6006SAdrian Chadd * does (eg CAC timeout, interface wakeup) - the caller must 3435cda6006SAdrian Chadd * do this first. 3445cda6006SAdrian Chadd */ 3455cda6006SAdrian Chadd static int 3465cda6006SAdrian Chadd ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m) 3475cda6006SAdrian Chadd { 3485cda6006SAdrian Chadd #define IS_DWDS(vap) \ 3495cda6006SAdrian Chadd (vap->iv_opmode == IEEE80211_M_WDS && \ 3505cda6006SAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0) 3515cda6006SAdrian Chadd struct ieee80211com *ic = vap->iv_ic; 3525cda6006SAdrian Chadd struct ifnet *ifp = vap->iv_ifp; 3535cda6006SAdrian Chadd struct ieee80211_node *ni; 3545cda6006SAdrian Chadd struct ether_header *eh; 3555cda6006SAdrian Chadd 3565cda6006SAdrian Chadd /* 3575cda6006SAdrian Chadd * Cancel any background scan. 3585cda6006SAdrian Chadd */ 3595cda6006SAdrian Chadd if (ic->ic_flags & IEEE80211_F_SCAN) 3605cda6006SAdrian Chadd ieee80211_cancel_anyscan(vap); 3615cda6006SAdrian Chadd /* 3625cda6006SAdrian Chadd * Find the node for the destination so we can do 3635cda6006SAdrian Chadd * things like power save and fast frames aggregation. 3645cda6006SAdrian Chadd * 3655cda6006SAdrian Chadd * NB: past this point various code assumes the first 3665cda6006SAdrian Chadd * mbuf has the 802.3 header present (and contiguous). 3675cda6006SAdrian Chadd */ 3685cda6006SAdrian Chadd ni = NULL; 3695cda6006SAdrian Chadd if (m->m_len < sizeof(struct ether_header) && 3705cda6006SAdrian Chadd (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 3715cda6006SAdrian Chadd IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 3725cda6006SAdrian Chadd "discard frame, %s\n", "m_pullup failed"); 3735cda6006SAdrian Chadd vap->iv_stats.is_tx_nobuf++; /* XXX */ 374dea45121SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3755cda6006SAdrian Chadd return (ENOBUFS); 3765cda6006SAdrian Chadd } 3775cda6006SAdrian Chadd eh = mtod(m, struct ether_header *); 3785cda6006SAdrian Chadd if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 3795cda6006SAdrian Chadd if (IS_DWDS(vap)) { 3805cda6006SAdrian Chadd /* 3815cda6006SAdrian Chadd * Only unicast frames from the above go out 3825cda6006SAdrian Chadd * DWDS vaps; multicast frames are handled by 3835cda6006SAdrian Chadd * dispatching the frame as it comes through 3845cda6006SAdrian Chadd * the AP vap (see below). 3855cda6006SAdrian Chadd */ 3865cda6006SAdrian Chadd IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS, 3875cda6006SAdrian Chadd eh->ether_dhost, "mcast", "%s", "on DWDS"); 3885cda6006SAdrian Chadd vap->iv_stats.is_dwds_mcast++; 3895cda6006SAdrian Chadd m_freem(m); 39079077edcSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 3915cda6006SAdrian Chadd /* XXX better status? */ 3925cda6006SAdrian Chadd return (ENOBUFS); 3935cda6006SAdrian Chadd } 3945cda6006SAdrian Chadd if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 3955cda6006SAdrian Chadd /* 3965cda6006SAdrian Chadd * Spam DWDS vap's w/ multicast traffic. 3975cda6006SAdrian Chadd */ 3985cda6006SAdrian Chadd /* XXX only if dwds in use? */ 3995cda6006SAdrian Chadd ieee80211_dwds_mcast(vap, m); 4005cda6006SAdrian Chadd } 4015cda6006SAdrian Chadd } 4025cda6006SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH 4035cda6006SAdrian Chadd if (vap->iv_opmode != IEEE80211_M_MBSS) { 4045cda6006SAdrian Chadd #endif 4055cda6006SAdrian Chadd ni = ieee80211_find_txnode(vap, eh->ether_dhost); 4065cda6006SAdrian Chadd if (ni == NULL) { 4075cda6006SAdrian Chadd /* NB: ieee80211_find_txnode does stat+msg */ 408dea45121SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4095cda6006SAdrian Chadd m_freem(m); 4105cda6006SAdrian Chadd /* XXX better status? */ 4115cda6006SAdrian Chadd return (ENOBUFS); 4125cda6006SAdrian Chadd } 4135cda6006SAdrian Chadd if (ni->ni_associd == 0 && 4145cda6006SAdrian Chadd (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { 4155cda6006SAdrian Chadd IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 4165cda6006SAdrian Chadd eh->ether_dhost, NULL, 4175cda6006SAdrian Chadd "sta not associated (type 0x%04x)", 4185cda6006SAdrian Chadd htons(eh->ether_type)); 4195cda6006SAdrian Chadd vap->iv_stats.is_tx_notassoc++; 420dea45121SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4215cda6006SAdrian Chadd m_freem(m); 4225cda6006SAdrian Chadd ieee80211_free_node(ni); 4235cda6006SAdrian Chadd /* XXX better status? */ 4245cda6006SAdrian Chadd return (ENOBUFS); 4255cda6006SAdrian Chadd } 4265cda6006SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH 4275cda6006SAdrian Chadd } else { 4285cda6006SAdrian Chadd if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) { 4295cda6006SAdrian Chadd /* 4305cda6006SAdrian Chadd * Proxy station only if configured. 4315cda6006SAdrian Chadd */ 4325cda6006SAdrian Chadd if (!ieee80211_mesh_isproxyena(vap)) { 4335cda6006SAdrian Chadd IEEE80211_DISCARD_MAC(vap, 4345cda6006SAdrian Chadd IEEE80211_MSG_OUTPUT | 4355cda6006SAdrian Chadd IEEE80211_MSG_MESH, 4365cda6006SAdrian Chadd eh->ether_dhost, NULL, 4375cda6006SAdrian Chadd "%s", "proxy not enabled"); 4385cda6006SAdrian Chadd vap->iv_stats.is_mesh_notproxy++; 439dea45121SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4405cda6006SAdrian Chadd m_freem(m); 4415cda6006SAdrian Chadd /* XXX better status? */ 4425cda6006SAdrian Chadd return (ENOBUFS); 4435cda6006SAdrian Chadd } 4445cda6006SAdrian Chadd IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 4455cda6006SAdrian Chadd "forward frame from DS SA(%6D), DA(%6D)\n", 4465cda6006SAdrian Chadd eh->ether_shost, ":", 4475cda6006SAdrian Chadd eh->ether_dhost, ":"); 4485cda6006SAdrian Chadd ieee80211_mesh_proxy_check(vap, eh->ether_shost); 4495cda6006SAdrian Chadd } 4505cda6006SAdrian Chadd ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m); 4515cda6006SAdrian Chadd if (ni == NULL) { 4525cda6006SAdrian Chadd /* 4535cda6006SAdrian Chadd * NB: ieee80211_mesh_discover holds/disposes 4545cda6006SAdrian Chadd * frame (e.g. queueing on path discovery). 4555cda6006SAdrian Chadd */ 456dea45121SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 4575cda6006SAdrian Chadd /* XXX better status? */ 4585cda6006SAdrian Chadd return (ENOBUFS); 4595cda6006SAdrian Chadd } 4605cda6006SAdrian Chadd } 4615cda6006SAdrian Chadd #endif 462363a2c3cSAdrian Chadd 4635cda6006SAdrian Chadd /* 464363a2c3cSAdrian Chadd * We've resolved the sender, so attempt to transmit it. 4655cda6006SAdrian Chadd */ 466ddd9ebbcSAdrian Chadd 467ddd9ebbcSAdrian Chadd if (vap->iv_state == IEEE80211_S_SLEEP) { 468ddd9ebbcSAdrian Chadd /* 469ddd9ebbcSAdrian Chadd * In power save; queue frame and then wakeup device 470ddd9ebbcSAdrian Chadd * for transmit. 471ddd9ebbcSAdrian Chadd */ 472ddd9ebbcSAdrian Chadd ic->ic_lastdata = ticks; 47379077edcSAndrey V. Elsukov if (ieee80211_pwrsave(ni, m) != 0) 47479077edcSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 475ddd9ebbcSAdrian Chadd ieee80211_free_node(ni); 476ddd9ebbcSAdrian Chadd ieee80211_new_state(vap, IEEE80211_S_RUN, 0); 477ddd9ebbcSAdrian Chadd return (0); 478ddd9ebbcSAdrian Chadd } 479ddd9ebbcSAdrian Chadd 480363a2c3cSAdrian Chadd if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0) 4815cda6006SAdrian Chadd return (ENOBUFS); 4825cda6006SAdrian Chadd return (0); 4835cda6006SAdrian Chadd #undef IS_DWDS 4845cda6006SAdrian Chadd } 4855cda6006SAdrian Chadd 4865cda6006SAdrian Chadd /* 487b032f27cSSam Leffler * Start method for vap's. All packets from the stack come 488b032f27cSSam Leffler * through here. We handle common processing of the packets 489b032f27cSSam Leffler * before dispatching them to the underlying device. 4901df885c8SAdrian Chadd * 4911df885c8SAdrian Chadd * if_transmit() requires that the mbuf be consumed by this call 4921df885c8SAdrian Chadd * regardless of the return condition. 493b032f27cSSam Leffler */ 494e7495198SAdrian Chadd int 495e7495198SAdrian Chadd ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m) 496b032f27cSSam Leffler { 497b032f27cSSam Leffler struct ieee80211vap *vap = ifp->if_softc; 498b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 499ddd9ebbcSAdrian Chadd 500b032f27cSSam Leffler /* 501b032f27cSSam Leffler * No data frames go out unless we're running. 502b032f27cSSam Leffler * Note in particular this covers CAC and CSA 503b032f27cSSam Leffler * states (though maybe we should check muting 504b032f27cSSam Leffler * for CSA). 505b032f27cSSam Leffler */ 506ddd9ebbcSAdrian Chadd if (vap->iv_state != IEEE80211_S_RUN && 507ddd9ebbcSAdrian Chadd vap->iv_state != IEEE80211_S_SLEEP) { 508b032f27cSSam Leffler IEEE80211_LOCK(ic); 509b032f27cSSam Leffler /* re-check under the com lock to avoid races */ 510ddd9ebbcSAdrian Chadd if (vap->iv_state != IEEE80211_S_RUN && 511ddd9ebbcSAdrian Chadd vap->iv_state != IEEE80211_S_SLEEP) { 512b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 513b032f27cSSam Leffler "%s: ignore queue, in %s state\n", 514b032f27cSSam Leffler __func__, ieee80211_state_name[vap->iv_state]); 515b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 516b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 51770e0b5acSAdrian Chadd ifp->if_drv_flags |= IFF_DRV_OACTIVE; 5181df885c8SAdrian Chadd m_freem(m); 51979077edcSAndrey V. Elsukov if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 52079077edcSAndrey V. Elsukov return (ENETDOWN); 521b032f27cSSam Leffler } 522b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 523b032f27cSSam Leffler } 5245cda6006SAdrian Chadd 525b032f27cSSam Leffler /* 526b032f27cSSam Leffler * Sanitize mbuf flags for net80211 use. We cannot 527927ef5ffSSam Leffler * clear M_PWR_SAV or M_MORE_DATA because these may 528927ef5ffSSam Leffler * be set for frames that are re-submitted from the 529927ef5ffSSam Leffler * power save queue. 530b032f27cSSam Leffler * 531b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 532b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 533b032f27cSSam Leffler */ 534927ef5ffSSam Leffler m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); 535e7495198SAdrian Chadd 536b032f27cSSam Leffler /* 5375cda6006SAdrian Chadd * Bump to the packet transmission path. 538e7495198SAdrian Chadd * The mbuf will be consumed here. 539b032f27cSSam Leffler */ 540e7495198SAdrian Chadd return (ieee80211_start_pkt(vap, m)); 541b032f27cSSam Leffler } 542e7495198SAdrian Chadd 543e7495198SAdrian Chadd void 544e7495198SAdrian Chadd ieee80211_vap_qflush(struct ifnet *ifp) 545e7495198SAdrian Chadd { 546e7495198SAdrian Chadd 547e7495198SAdrian Chadd /* Empty for now */ 548b032f27cSSam Leffler } 549b032f27cSSam Leffler 550168f582eSSam Leffler /* 5515cda6006SAdrian Chadd * 802.11 raw output routine. 552ddd9ebbcSAdrian Chadd * 553ddd9ebbcSAdrian Chadd * XXX TODO: this (and other send routines) should correctly 554ddd9ebbcSAdrian Chadd * XXX keep the pwr mgmt bit set if it decides to call into the 555ddd9ebbcSAdrian Chadd * XXX driver to send a frame whilst the state is SLEEP. 556ddd9ebbcSAdrian Chadd * 557ddd9ebbcSAdrian Chadd * Otherwise the peer may decide that we're awake and flood us 558ddd9ebbcSAdrian Chadd * with traffic we are still too asleep to receive! 559168f582eSSam Leffler */ 5605cda6006SAdrian Chadd int 5615cda6006SAdrian Chadd ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni, 5625cda6006SAdrian Chadd struct mbuf *m, const struct ieee80211_bpf_params *params) 5635cda6006SAdrian Chadd { 5645cda6006SAdrian Chadd struct ieee80211com *ic = vap->iv_ic; 5657a79cebfSGleb Smirnoff int error; 566168f582eSSam Leffler 567ff09e23fSAdrian Chadd /* 568ff09e23fSAdrian Chadd * Set node - the caller has taken a reference, so ensure 569ff09e23fSAdrian Chadd * that the mbuf has the same node value that 570ff09e23fSAdrian Chadd * it would if it were going via the normal path. 571ff09e23fSAdrian Chadd */ 572fb3bc596SJohn Baldwin MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0); 573ff09e23fSAdrian Chadd m->m_pkthdr.rcvif = (void *)ni; 574ff09e23fSAdrian Chadd 575ff09e23fSAdrian Chadd /* 576ff09e23fSAdrian Chadd * Attempt to add bpf transmit parameters. 577ff09e23fSAdrian Chadd * 578ff09e23fSAdrian Chadd * For now it's ok to fail; the raw_xmit api still takes 579ff09e23fSAdrian Chadd * them as an option. 580ff09e23fSAdrian Chadd * 581ff09e23fSAdrian Chadd * Later on when ic_raw_xmit() has params removed, 582ff09e23fSAdrian Chadd * they'll have to be added - so fail the transmit if 583ff09e23fSAdrian Chadd * they can't be. 584ff09e23fSAdrian Chadd */ 5853a1da00bSAdrian Chadd if (params) 586ff09e23fSAdrian Chadd (void) ieee80211_add_xmit_params(m, params); 587ff09e23fSAdrian Chadd 5887a79cebfSGleb Smirnoff error = ic->ic_raw_xmit(ni, m, params); 589d957a93aSAdrian Chadd if (error) { 5907a79cebfSGleb Smirnoff if_inc_counter(vap->iv_ifp, IFCOUNTER_OERRORS, 1); 591d957a93aSAdrian Chadd ieee80211_free_node(ni); 592d957a93aSAdrian Chadd } 5937a79cebfSGleb Smirnoff return (error); 594b032f27cSSam Leffler } 595b032f27cSSam Leffler 596bcabc908SAndriy Voskoboinyk static int 597bcabc908SAndriy Voskoboinyk ieee80211_validate_frame(struct mbuf *m, 598bcabc908SAndriy Voskoboinyk const struct ieee80211_bpf_params *params) 599bcabc908SAndriy Voskoboinyk { 600bcabc908SAndriy Voskoboinyk struct ieee80211_frame *wh; 601bcabc908SAndriy Voskoboinyk int type; 602bcabc908SAndriy Voskoboinyk 603bcabc908SAndriy Voskoboinyk if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) 604bcabc908SAndriy Voskoboinyk return (EINVAL); 605bcabc908SAndriy Voskoboinyk 606bcabc908SAndriy Voskoboinyk wh = mtod(m, struct ieee80211_frame *); 607bcabc908SAndriy Voskoboinyk if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 608bcabc908SAndriy Voskoboinyk IEEE80211_FC0_VERSION_0) 609bcabc908SAndriy Voskoboinyk return (EINVAL); 610bcabc908SAndriy Voskoboinyk 611bcabc908SAndriy Voskoboinyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; 612bcabc908SAndriy Voskoboinyk if (type != IEEE80211_FC0_TYPE_DATA) { 613bcabc908SAndriy Voskoboinyk if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) != 614bcabc908SAndriy Voskoboinyk IEEE80211_FC1_DIR_NODS) 615bcabc908SAndriy Voskoboinyk return (EINVAL); 616bcabc908SAndriy Voskoboinyk 617bcabc908SAndriy Voskoboinyk if (type != IEEE80211_FC0_TYPE_MGT && 618bcabc908SAndriy Voskoboinyk (wh->i_fc[1] & IEEE80211_FC1_MORE_FRAG) != 0) 619bcabc908SAndriy Voskoboinyk return (EINVAL); 620bcabc908SAndriy Voskoboinyk 621bcabc908SAndriy Voskoboinyk /* XXX skip other field checks? */ 622bcabc908SAndriy Voskoboinyk } 623bcabc908SAndriy Voskoboinyk 624bcabc908SAndriy Voskoboinyk if ((params && (params->ibp_flags & IEEE80211_BPF_CRYPTO) != 0) || 625bcabc908SAndriy Voskoboinyk (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) != 0) { 626bcabc908SAndriy Voskoboinyk int subtype; 627bcabc908SAndriy Voskoboinyk 628bcabc908SAndriy Voskoboinyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 629bcabc908SAndriy Voskoboinyk 630bcabc908SAndriy Voskoboinyk /* 631bcabc908SAndriy Voskoboinyk * See IEEE Std 802.11-2012, 632bcabc908SAndriy Voskoboinyk * 8.2.4.1.9 'Protected Frame field' 633bcabc908SAndriy Voskoboinyk */ 634bcabc908SAndriy Voskoboinyk /* XXX no support for robust management frames yet. */ 635bcabc908SAndriy Voskoboinyk if (!(type == IEEE80211_FC0_TYPE_DATA || 636bcabc908SAndriy Voskoboinyk (type == IEEE80211_FC0_TYPE_MGT && 637bcabc908SAndriy Voskoboinyk subtype == IEEE80211_FC0_SUBTYPE_AUTH))) 638bcabc908SAndriy Voskoboinyk return (EINVAL); 639bcabc908SAndriy Voskoboinyk 640bcabc908SAndriy Voskoboinyk wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; 641bcabc908SAndriy Voskoboinyk } 642bcabc908SAndriy Voskoboinyk 643bcabc908SAndriy Voskoboinyk if (m->m_pkthdr.len < ieee80211_anyhdrsize(wh)) 644bcabc908SAndriy Voskoboinyk return (EINVAL); 645bcabc908SAndriy Voskoboinyk 646bcabc908SAndriy Voskoboinyk return (0); 647bcabc908SAndriy Voskoboinyk } 648bcabc908SAndriy Voskoboinyk 649e42e878bSAndriy Voskoboinyk static int 650e42e878bSAndriy Voskoboinyk ieee80211_validate_rate(struct ieee80211_node *ni, uint8_t rate) 651e42e878bSAndriy Voskoboinyk { 652e42e878bSAndriy Voskoboinyk struct ieee80211com *ic = ni->ni_ic; 653e42e878bSAndriy Voskoboinyk 654e42e878bSAndriy Voskoboinyk if (IEEE80211_IS_HT_RATE(rate)) { 655e42e878bSAndriy Voskoboinyk if ((ic->ic_htcaps & IEEE80211_HTC_HT) == 0) 656e42e878bSAndriy Voskoboinyk return (EINVAL); 657e42e878bSAndriy Voskoboinyk 658e42e878bSAndriy Voskoboinyk rate = IEEE80211_RV(rate); 659e42e878bSAndriy Voskoboinyk if (rate <= 31) { 660e42e878bSAndriy Voskoboinyk if (rate > ic->ic_txstream * 8 - 1) 661e42e878bSAndriy Voskoboinyk return (EINVAL); 662e42e878bSAndriy Voskoboinyk 663e42e878bSAndriy Voskoboinyk return (0); 664e42e878bSAndriy Voskoboinyk } 665e42e878bSAndriy Voskoboinyk 666e42e878bSAndriy Voskoboinyk if (rate == 32) { 667e42e878bSAndriy Voskoboinyk if ((ic->ic_htcaps & IEEE80211_HTC_TXMCS32) == 0) 668e42e878bSAndriy Voskoboinyk return (EINVAL); 669e42e878bSAndriy Voskoboinyk 670e42e878bSAndriy Voskoboinyk return (0); 671e42e878bSAndriy Voskoboinyk } 672e42e878bSAndriy Voskoboinyk 673e42e878bSAndriy Voskoboinyk if ((ic->ic_htcaps & IEEE80211_HTC_TXUNEQUAL) == 0) 674e42e878bSAndriy Voskoboinyk return (EINVAL); 675e42e878bSAndriy Voskoboinyk 676e42e878bSAndriy Voskoboinyk switch (ic->ic_txstream) { 677e42e878bSAndriy Voskoboinyk case 0: 678e42e878bSAndriy Voskoboinyk case 1: 679e42e878bSAndriy Voskoboinyk return (EINVAL); 680e42e878bSAndriy Voskoboinyk case 2: 681e42e878bSAndriy Voskoboinyk if (rate > 38) 682e42e878bSAndriy Voskoboinyk return (EINVAL); 683e42e878bSAndriy Voskoboinyk 684e42e878bSAndriy Voskoboinyk return (0); 685e42e878bSAndriy Voskoboinyk case 3: 686e42e878bSAndriy Voskoboinyk if (rate > 52) 687e42e878bSAndriy Voskoboinyk return (EINVAL); 688e42e878bSAndriy Voskoboinyk 689e42e878bSAndriy Voskoboinyk return (0); 690e42e878bSAndriy Voskoboinyk case 4: 691e42e878bSAndriy Voskoboinyk default: 692e42e878bSAndriy Voskoboinyk if (rate > 76) 693e42e878bSAndriy Voskoboinyk return (EINVAL); 694e42e878bSAndriy Voskoboinyk 695e42e878bSAndriy Voskoboinyk return (0); 696e42e878bSAndriy Voskoboinyk } 697e42e878bSAndriy Voskoboinyk } 698e42e878bSAndriy Voskoboinyk 699e42e878bSAndriy Voskoboinyk if (!ieee80211_isratevalid(ic->ic_rt, rate)) 700e42e878bSAndriy Voskoboinyk return (EINVAL); 701e42e878bSAndriy Voskoboinyk 702e42e878bSAndriy Voskoboinyk return (0); 703e42e878bSAndriy Voskoboinyk } 704e42e878bSAndriy Voskoboinyk 705e42e878bSAndriy Voskoboinyk static int 706e42e878bSAndriy Voskoboinyk ieee80211_sanitize_rates(struct ieee80211_node *ni, struct mbuf *m, 707e42e878bSAndriy Voskoboinyk const struct ieee80211_bpf_params *params) 708e42e878bSAndriy Voskoboinyk { 709e42e878bSAndriy Voskoboinyk int error; 710e42e878bSAndriy Voskoboinyk 711e42e878bSAndriy Voskoboinyk if (!params) 712e42e878bSAndriy Voskoboinyk return (0); /* nothing to do */ 713e42e878bSAndriy Voskoboinyk 714e42e878bSAndriy Voskoboinyk /* NB: most drivers assume that ibp_rate0 is set (!= 0). */ 715e42e878bSAndriy Voskoboinyk if (params->ibp_rate0 != 0) { 716e42e878bSAndriy Voskoboinyk error = ieee80211_validate_rate(ni, params->ibp_rate0); 717e42e878bSAndriy Voskoboinyk if (error != 0) 718e42e878bSAndriy Voskoboinyk return (error); 719e42e878bSAndriy Voskoboinyk } else { 720e42e878bSAndriy Voskoboinyk /* XXX pre-setup some default (e.g., mgmt / mcast) rate */ 721e42e878bSAndriy Voskoboinyk /* XXX __DECONST? */ 722e42e878bSAndriy Voskoboinyk (void) m; 723e42e878bSAndriy Voskoboinyk } 724e42e878bSAndriy Voskoboinyk 725e42e878bSAndriy Voskoboinyk if (params->ibp_rate1 != 0 && 726e42e878bSAndriy Voskoboinyk (error = ieee80211_validate_rate(ni, params->ibp_rate1)) != 0) 727e42e878bSAndriy Voskoboinyk return (error); 728e42e878bSAndriy Voskoboinyk 729e42e878bSAndriy Voskoboinyk if (params->ibp_rate2 != 0 && 730e42e878bSAndriy Voskoboinyk (error = ieee80211_validate_rate(ni, params->ibp_rate2)) != 0) 731e42e878bSAndriy Voskoboinyk return (error); 732e42e878bSAndriy Voskoboinyk 733e42e878bSAndriy Voskoboinyk if (params->ibp_rate3 != 0 && 734e42e878bSAndriy Voskoboinyk (error = ieee80211_validate_rate(ni, params->ibp_rate3)) != 0) 735e42e878bSAndriy Voskoboinyk return (error); 736e42e878bSAndriy Voskoboinyk 737e42e878bSAndriy Voskoboinyk return (0); 738e42e878bSAndriy Voskoboinyk } 739e42e878bSAndriy Voskoboinyk 740b032f27cSSam Leffler /* 741b032f27cSSam Leffler * 802.11 output routine. This is (currently) used only to 742b032f27cSSam Leffler * connect bpf write calls to the 802.11 layer for injecting 743fad788b1SSam Leffler * raw 802.11 frames. 744b032f27cSSam Leffler */ 745b032f27cSSam Leffler int 746b032f27cSSam Leffler ieee80211_output(struct ifnet *ifp, struct mbuf *m, 74747e8d432SGleb Smirnoff const struct sockaddr *dst, struct route *ro) 748b032f27cSSam Leffler { 749b032f27cSSam Leffler #define senderr(e) do { error = (e); goto bad;} while (0) 750bcabc908SAndriy Voskoboinyk const struct ieee80211_bpf_params *params = NULL; 751b032f27cSSam Leffler struct ieee80211_node *ni = NULL; 7528ed1835dSSam Leffler struct ieee80211vap *vap; 753b032f27cSSam Leffler struct ieee80211_frame *wh; 7545cda6006SAdrian Chadd struct ieee80211com *ic = NULL; 755b032f27cSSam Leffler int error; 7565cda6006SAdrian Chadd int ret; 757b032f27cSSam Leffler 7588ed1835dSSam Leffler if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 7598ed1835dSSam Leffler /* 7608ed1835dSSam Leffler * Short-circuit requests if the vap is marked OACTIVE 7618ed1835dSSam Leffler * as this can happen because a packet came down through 7628ed1835dSSam Leffler * ieee80211_start before the vap entered RUN state in 7638ed1835dSSam Leffler * which case it's ok to just drop the frame. This 7648ed1835dSSam Leffler * should not be necessary but callers of if_output don't 7658ed1835dSSam Leffler * check OACTIVE. 7668ed1835dSSam Leffler */ 7678ed1835dSSam Leffler senderr(ENETDOWN); 7688ed1835dSSam Leffler } 7698ed1835dSSam Leffler vap = ifp->if_softc; 7705cda6006SAdrian Chadd ic = vap->iv_ic; 771b032f27cSSam Leffler /* 772b032f27cSSam Leffler * Hand to the 802.3 code if not tagged as 773b032f27cSSam Leffler * a raw 802.11 frame. 774b032f27cSSam Leffler */ 775b032f27cSSam Leffler if (dst->sa_family != AF_IEEE80211) 776279aa3d4SKip Macy return vap->iv_output(ifp, m, dst, ro); 777b032f27cSSam Leffler #ifdef MAC 778c27b9cdbSRobert Watson error = mac_ifnet_check_transmit(ifp, m); 779b032f27cSSam Leffler if (error) 780b032f27cSSam Leffler senderr(error); 781b032f27cSSam Leffler #endif 782b032f27cSSam Leffler if (ifp->if_flags & IFF_MONITOR) 783b032f27cSSam Leffler senderr(ENETDOWN); 784b032f27cSSam Leffler if (!IFNET_IS_UP_RUNNING(ifp)) 785b032f27cSSam Leffler senderr(ENETDOWN); 786b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 787b032f27cSSam Leffler IEEE80211_DPRINTF(vap, 788b032f27cSSam Leffler IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 789b032f27cSSam Leffler "block %s frame in CAC state\n", "raw data"); 790b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 791b032f27cSSam Leffler senderr(EIO); /* XXX */ 7920d9aed8aSBernhard Schmidt } else if (vap->iv_state == IEEE80211_S_SCAN) 7930d9aed8aSBernhard Schmidt senderr(EIO); 794b032f27cSSam Leffler /* XXX bypass bridge, pfil, carp, etc. */ 795b032f27cSSam Leffler 796bcabc908SAndriy Voskoboinyk /* 797bcabc908SAndriy Voskoboinyk * NB: DLT_IEEE802_11_RADIO identifies the parameters are 798bcabc908SAndriy Voskoboinyk * present by setting the sa_len field of the sockaddr (yes, 799bcabc908SAndriy Voskoboinyk * this is a hack). 800bcabc908SAndriy Voskoboinyk * NB: we assume sa_data is suitably aligned to cast. 801bcabc908SAndriy Voskoboinyk */ 802bcabc908SAndriy Voskoboinyk if (dst->sa_len != 0) 803bcabc908SAndriy Voskoboinyk params = (const struct ieee80211_bpf_params *)dst->sa_data; 804bcabc908SAndriy Voskoboinyk 805bcabc908SAndriy Voskoboinyk error = ieee80211_validate_frame(m, params); 806bcabc908SAndriy Voskoboinyk if (error != 0) 807bcabc908SAndriy Voskoboinyk senderr(error); 808bcabc908SAndriy Voskoboinyk 809b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 810b032f27cSSam Leffler 811b032f27cSSam Leffler /* locate destination node */ 812b032f27cSSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 813b032f27cSSam Leffler case IEEE80211_FC1_DIR_NODS: 814b032f27cSSam Leffler case IEEE80211_FC1_DIR_FROMDS: 815b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr1); 816b032f27cSSam Leffler break; 817b032f27cSSam Leffler case IEEE80211_FC1_DIR_TODS: 818b032f27cSSam Leffler case IEEE80211_FC1_DIR_DSTODS: 819b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr3); 820b032f27cSSam Leffler break; 821b032f27cSSam Leffler default: 822bcabc908SAndriy Voskoboinyk senderr(EDOOFUS); 823b032f27cSSam Leffler } 824b032f27cSSam Leffler if (ni == NULL) { 825b032f27cSSam Leffler /* 826b032f27cSSam Leffler * Permit packets w/ bpf params through regardless 827b032f27cSSam Leffler * (see below about sa_len). 828b032f27cSSam Leffler */ 829b032f27cSSam Leffler if (dst->sa_len == 0) 830b032f27cSSam Leffler senderr(EHOSTUNREACH); 831b032f27cSSam Leffler ni = ieee80211_ref_node(vap->iv_bss); 832b032f27cSSam Leffler } 833b032f27cSSam Leffler 834b032f27cSSam Leffler /* 835b032f27cSSam Leffler * Sanitize mbuf for net80211 flags leaked from above. 836b032f27cSSam Leffler * 837b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 838b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 839b032f27cSSam Leffler */ 840b032f27cSSam Leffler m->m_flags &= ~M_80211_TX; 841bcabc908SAndriy Voskoboinyk m->m_flags |= M_ENCAP; /* mark encapsulated */ 842b032f27cSSam Leffler 843bcabc908SAndriy Voskoboinyk if (IEEE80211_IS_DATA(wh)) { 844b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 845b032f27cSSam Leffler if (ieee80211_classify(ni, m)) 846b032f27cSSam Leffler senderr(EIO); /* XXX */ 847b032f27cSSam Leffler 848bcabc908SAndriy Voskoboinyk /* NB: ieee80211_encap does not include 802.11 header */ 849bcabc908SAndriy Voskoboinyk IEEE80211_NODE_STAT_ADD(ni, tx_bytes, 850bcabc908SAndriy Voskoboinyk m->m_pkthdr.len - ieee80211_hdrsize(wh)); 851bcabc908SAndriy Voskoboinyk } else 852bcabc908SAndriy Voskoboinyk M_WME_SETAC(m, WME_AC_BE); 853bcabc908SAndriy Voskoboinyk 854e42e878bSAndriy Voskoboinyk error = ieee80211_sanitize_rates(ni, m, params); 855e42e878bSAndriy Voskoboinyk if (error != 0) 856e42e878bSAndriy Voskoboinyk senderr(error); 857e42e878bSAndriy Voskoboinyk 8580e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 8590e910c94SSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 8600e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 8610e910c94SSam Leffler m->m_flags |= M_MCAST; 8620e910c94SSam Leffler } else 8630e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 864b032f27cSSam Leffler 8655cda6006SAdrian Chadd IEEE80211_TX_LOCK(ic); 866bcabc908SAndriy Voskoboinyk ret = ieee80211_raw_output(vap, ni, m, params); 8675cda6006SAdrian Chadd IEEE80211_TX_UNLOCK(ic); 8685cda6006SAdrian Chadd return (ret); 869b032f27cSSam Leffler bad: 870b032f27cSSam Leffler if (m != NULL) 871b032f27cSSam Leffler m_freem(m); 872b032f27cSSam Leffler if (ni != NULL) 873b032f27cSSam Leffler ieee80211_free_node(ni); 874dea45121SGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 875b032f27cSSam Leffler return error; 876b032f27cSSam Leffler #undef senderr 877b032f27cSSam Leffler } 878b032f27cSSam Leffler 879b032f27cSSam Leffler /* 880add59d08SSam Leffler * Set the direction field and address fields of an outgoing 8810e66722dSSam Leffler * frame. Note this should be called early on in constructing 8820e66722dSSam Leffler * a frame as it sets i_fc[1]; other bits can then be or'd in. 883add59d08SSam Leffler */ 88459aa14a9SRui Paulo void 885b032f27cSSam Leffler ieee80211_send_setup( 886add59d08SSam Leffler struct ieee80211_node *ni, 8879e80b1dfSSam Leffler struct mbuf *m, 8888ac160cdSSam Leffler int type, int tid, 88968e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 89068e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 89168e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN]) 892add59d08SSam Leffler { 893add59d08SSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) 89459aa14a9SRui Paulo struct ieee80211vap *vap = ni->ni_vap; 89550cfec0eSBernhard Schmidt struct ieee80211_tx_ampdu *tap; 8969e80b1dfSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 8979e80b1dfSSam Leffler ieee80211_seq seqno; 898add59d08SSam Leffler 8996ce4aeb8SAdrian Chadd IEEE80211_TX_LOCK_ASSERT(ni->ni_ic); 9005cda6006SAdrian Chadd 901add59d08SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; 902add59d08SSam Leffler if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 903b032f27cSSam Leffler switch (vap->iv_opmode) { 904add59d08SSam Leffler case IEEE80211_M_STA: 905add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 906add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 907add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 908add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 909add59d08SSam Leffler break; 910add59d08SSam Leffler case IEEE80211_M_IBSS: 911add59d08SSam Leffler case IEEE80211_M_AHDEMO: 912add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 913add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 914add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 915add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 916add59d08SSam Leffler break; 917add59d08SSam Leffler case IEEE80211_M_HOSTAP: 918add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 919add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 920add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, bssid); 921add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, sa); 922add59d08SSam Leffler break; 92368e8e04eSSam Leffler case IEEE80211_M_WDS: 92468e8e04eSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 925b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 926b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 92768e8e04eSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 92868e8e04eSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 92968e8e04eSSam Leffler break; 93059aa14a9SRui Paulo case IEEE80211_M_MBSS: 93159aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 93259aa14a9SRui Paulo if (IEEE80211_IS_MULTICAST(da)) { 93359aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 93459aa14a9SRui Paulo /* XXX next hop */ 93559aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 93659aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 93759aa14a9SRui Paulo vap->iv_myaddr); 93859aa14a9SRui Paulo } else { 93959aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 94059aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 94159aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 94259aa14a9SRui Paulo vap->iv_myaddr); 94359aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, da); 94459aa14a9SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 94559aa14a9SRui Paulo } 94659aa14a9SRui Paulo #endif 94759aa14a9SRui Paulo break; 948add59d08SSam Leffler case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ 949add59d08SSam Leffler break; 950add59d08SSam Leffler } 951add59d08SSam Leffler } else { 952add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 953add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 954add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 95559aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 95659aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 95759aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, sa); 95859aa14a9SRui Paulo else 95959aa14a9SRui Paulo #endif 960add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 961add59d08SSam Leffler } 96268e8e04eSSam Leffler *(uint16_t *)&wh->i_dur[0] = 0; 9639e80b1dfSSam Leffler 96451172f62SAdrian Chadd /* 96551172f62SAdrian Chadd * XXX TODO: this is what the TX lock is for. 96651172f62SAdrian Chadd * Here we're incrementing sequence numbers, and they 96751172f62SAdrian Chadd * need to be in lock-step with what the driver is doing 96851172f62SAdrian Chadd * both in TX ordering and crypto encap (IV increment.) 96951172f62SAdrian Chadd * 97051172f62SAdrian Chadd * If the driver does seqno itself, then we can skip 97151172f62SAdrian Chadd * assigning sequence numbers here, and we can avoid 97251172f62SAdrian Chadd * requiring the TX lock. 97351172f62SAdrian Chadd */ 9742aa563dfSAdrian Chadd tap = &ni->ni_tx_ampdu[tid]; 9759764ef21SAdrian Chadd if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) { 97650cfec0eSBernhard Schmidt m->m_flags |= M_AMPDU_MPDU; 9772db223f9SAndriy Voskoboinyk 9782db223f9SAndriy Voskoboinyk /* NB: zero out i_seq field (for s/w encryption etc) */ 9792db223f9SAndriy Voskoboinyk *(uint16_t *)&wh->i_seq[0] = 0; 9809764ef21SAdrian Chadd } else { 981c3ebe019SAdrian Chadd if (IEEE80211_HAS_SEQ(type & IEEE80211_FC0_TYPE_MASK, 982c3ebe019SAdrian Chadd type & IEEE80211_FC0_SUBTYPE_MASK)) 9839764ef21SAdrian Chadd /* 9849764ef21SAdrian Chadd * 802.11-2012 9.3.2.10 - QoS multicast frames 9859764ef21SAdrian Chadd * come out of a different seqno space. 9869764ef21SAdrian Chadd */ 9879764ef21SAdrian Chadd if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 9889764ef21SAdrian Chadd seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 9899764ef21SAdrian Chadd } else { 9909e80b1dfSSam Leffler seqno = ni->ni_txseqs[tid]++; 9919764ef21SAdrian Chadd } 992c3ebe019SAdrian Chadd else 993c3ebe019SAdrian Chadd seqno = 0; 994c3ebe019SAdrian Chadd 99550cfec0eSBernhard Schmidt *(uint16_t *)&wh->i_seq[0] = 99650cfec0eSBernhard Schmidt htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 9979a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 99850cfec0eSBernhard Schmidt } 9999e80b1dfSSam Leffler 10009e80b1dfSSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 10019e80b1dfSSam Leffler m->m_flags |= M_MCAST; 1002add59d08SSam Leffler #undef WH4 1003add59d08SSam Leffler } 1004add59d08SSam Leffler 1005add59d08SSam Leffler /* 10060a915fadSSam Leffler * Send a management frame to the specified node. The node pointer 10070a915fadSSam Leffler * must have a reference as the pointer will be passed to the driver 10080a915fadSSam Leffler * and potentially held for a long time. If the frame is successfully 10090a915fadSSam Leffler * dispatched to the driver, then it is responsible for freeing the 1010b032f27cSSam Leffler * reference (and potentially free'ing up any associated storage); 1011b032f27cSSam Leffler * otherwise deal with reclaiming any reference (on error). 10120a915fadSSam Leffler */ 101368e8e04eSSam Leffler int 10148ac160cdSSam Leffler ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, 10158ac160cdSSam Leffler struct ieee80211_bpf_params *params) 10161a1e1d21SSam Leffler { 1017b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1018b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 10191a1e1d21SSam Leffler struct ieee80211_frame *wh; 10205cda6006SAdrian Chadd int ret; 10211a1e1d21SSam Leffler 10220a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 10231a1e1d21SSam Leffler 1024b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 1025b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 1026b032f27cSSam Leffler ni, "block %s frame in CAC state", 10274357a5d1SAndriy Voskoboinyk ieee80211_mgt_subtype_name(type)); 1028b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 1029b032f27cSSam Leffler ieee80211_free_node(ni); 1030b032f27cSSam Leffler m_freem(m); 1031b032f27cSSam Leffler return EIO; /* XXX */ 1032b032f27cSSam Leffler } 1033b032f27cSSam Leffler 1034eb1b1807SGleb Smirnoff M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 1035b032f27cSSam Leffler if (m == NULL) { 1036b032f27cSSam Leffler ieee80211_free_node(ni); 10371a1e1d21SSam Leffler return ENOMEM; 1038b032f27cSSam Leffler } 10390a915fadSSam Leffler 10405cda6006SAdrian Chadd IEEE80211_TX_LOCK(ic); 10415cda6006SAdrian Chadd 10421a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 10439e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 10448ac160cdSSam Leffler IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, 1045b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 10468ac160cdSSam Leffler if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 1047b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, 1048b032f27cSSam Leffler "encrypting frame (%s)", __func__); 10495945b5f5SKevin Lo wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; 10508a1b9b6aSSam Leffler } 1051c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 10528ac160cdSSam Leffler 10538ac160cdSSam Leffler KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); 10548ac160cdSSam Leffler M_WME_SETAC(m, params->ibp_pri); 10558ac160cdSSam Leffler 10568a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 10578a1b9b6aSSam Leffler /* avoid printing too many frames */ 1058b032f27cSSam Leffler if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || 1059b032f27cSSam Leffler ieee80211_msg_dumppkts(vap)) { 1060*2e59c9c7SBjoern A. Zeeb ieee80211_note(vap, "[%s] send %s on channel %u\n", 10618a1b9b6aSSam Leffler ether_sprintf(wh->i_addr1), 10624357a5d1SAndriy Voskoboinyk ieee80211_mgt_subtype_name(type), 1063b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan)); 10648a1b9b6aSSam Leffler } 10658a1b9b6aSSam Leffler #endif 10668a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 106768e8e04eSSam Leffler 10685cda6006SAdrian Chadd ret = ieee80211_raw_output(vap, ni, m, params); 10695cda6006SAdrian Chadd IEEE80211_TX_UNLOCK(ic); 10705cda6006SAdrian Chadd return (ret); 1071246b5467SSam Leffler } 1072246b5467SSam Leffler 10739f82bedaSAndriy Voskoboinyk static void 10749f82bedaSAndriy Voskoboinyk ieee80211_nulldata_transmitted(struct ieee80211_node *ni, void *arg, 10759f82bedaSAndriy Voskoboinyk int status) 10769f82bedaSAndriy Voskoboinyk { 10779f82bedaSAndriy Voskoboinyk struct ieee80211vap *vap = ni->ni_vap; 10789f82bedaSAndriy Voskoboinyk 10799f82bedaSAndriy Voskoboinyk wakeup(vap); 10809f82bedaSAndriy Voskoboinyk } 10819f82bedaSAndriy Voskoboinyk 1082246b5467SSam Leffler /* 10836683931eSSam Leffler * Send a null data frame to the specified node. If the station 10846683931eSSam Leffler * is setup for QoS then a QoS Null Data frame is constructed. 10856683931eSSam Leffler * If this is a WDS station then a 4-address frame is constructed. 108619ad2dd7SSam Leffler * 108719ad2dd7SSam Leffler * NB: the caller is assumed to have setup a node reference 108819ad2dd7SSam Leffler * for use; this is necessary to deal with a race condition 1089b032f27cSSam Leffler * when probing for inactive stations. Like ieee80211_mgmt_output 1090b032f27cSSam Leffler * we must cleanup any node reference on error; however we 1091b032f27cSSam Leffler * can safely just unref it as we know it will never be the 1092b032f27cSSam Leffler * last reference to the node. 10938a1b9b6aSSam Leffler */ 10948a1b9b6aSSam Leffler int 1095f62121ceSSam Leffler ieee80211_send_nulldata(struct ieee80211_node *ni) 10968a1b9b6aSSam Leffler { 1097b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1098f62121ceSSam Leffler struct ieee80211com *ic = ni->ni_ic; 10998a1b9b6aSSam Leffler struct mbuf *m; 11008a1b9b6aSSam Leffler struct ieee80211_frame *wh; 11016683931eSSam Leffler int hdrlen; 11026683931eSSam Leffler uint8_t *frm; 11035cda6006SAdrian Chadd int ret; 11048a1b9b6aSSam Leffler 1105b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 1106b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 1107b032f27cSSam Leffler ni, "block %s frame in CAC state", "null data"); 1108b032f27cSSam Leffler ieee80211_unref_node(&ni); 1109b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 1110b032f27cSSam Leffler return EIO; /* XXX */ 1111b032f27cSSam Leffler } 1112b032f27cSSam Leffler 11136683931eSSam Leffler if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) 11146683931eSSam Leffler hdrlen = sizeof(struct ieee80211_qosframe); 11156683931eSSam Leffler else 11166683931eSSam Leffler hdrlen = sizeof(struct ieee80211_frame); 11176683931eSSam Leffler /* NB: only WDS vap's get 4-address frames */ 11186683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 11196683931eSSam Leffler hdrlen += IEEE80211_ADDR_LEN; 11206683931eSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 11216683931eSSam Leffler hdrlen = roundup(hdrlen, sizeof(uint32_t)); 11226683931eSSam Leffler 11236683931eSSam Leffler m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); 11248a1b9b6aSSam Leffler if (m == NULL) { 11258a1b9b6aSSam Leffler /* XXX debug msg */ 112619ad2dd7SSam Leffler ieee80211_unref_node(&ni); 1127b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 11288a1b9b6aSSam Leffler return ENOMEM; 11298a1b9b6aSSam Leffler } 11306683931eSSam Leffler KASSERT(M_LEADINGSPACE(m) >= hdrlen, 11316683931eSSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 1132eb1b1807SGleb Smirnoff M_PREPEND(m, hdrlen, M_NOWAIT); 11336683931eSSam Leffler if (m == NULL) { 11346683931eSSam Leffler /* NB: cannot happen */ 11356683931eSSam Leffler ieee80211_free_node(ni); 11366683931eSSam Leffler return ENOMEM; 11376683931eSSam Leffler } 11388a1b9b6aSSam Leffler 11395cda6006SAdrian Chadd IEEE80211_TX_LOCK(ic); 11405cda6006SAdrian Chadd 11416683931eSSam Leffler wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ 11426683931eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 11436683931eSSam Leffler const int tid = WME_AC_TO_TID(WME_AC_BE); 11446683931eSSam Leffler uint8_t *qos; 11456683931eSSam Leffler 11469e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 11476683931eSSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, 11486683931eSSam Leffler tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 11496683931eSSam Leffler 11506683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 11516683931eSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 11526683931eSSam Leffler else 11536683931eSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 11546683931eSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 11556683931eSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) 11566683931eSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 11576683931eSSam Leffler qos[1] = 0; 11586683931eSSam Leffler } else { 11599e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 1160add59d08SSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 11618ac160cdSSam Leffler IEEE80211_NONQOS_TID, 1162b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 11636683931eSSam Leffler } 1164b032f27cSSam Leffler if (vap->iv_opmode != IEEE80211_M_WDS) { 1165add59d08SSam Leffler /* NB: power management bit is never sent by an AP */ 1166add59d08SSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 1167b032f27cSSam Leffler vap->iv_opmode != IEEE80211_M_HOSTAP) 1168add59d08SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 1169b032f27cSSam Leffler } 11709f82bedaSAndriy Voskoboinyk if ((ic->ic_flags & IEEE80211_F_SCAN) && 11719f82bedaSAndriy Voskoboinyk (ni->ni_flags & IEEE80211_NODE_PWR_MGT)) { 11729f82bedaSAndriy Voskoboinyk ieee80211_add_callback(m, ieee80211_nulldata_transmitted, 11739f82bedaSAndriy Voskoboinyk NULL); 11749f82bedaSAndriy Voskoboinyk } 11756683931eSSam Leffler m->m_len = m->m_pkthdr.len = hdrlen; 1176c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 11776683931eSSam Leffler 1178bb239ce9SSam Leffler M_WME_SETAC(m, WME_AC_BE); 11798a1b9b6aSSam Leffler 11808a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 11818a1b9b6aSSam Leffler 1182b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, 11836683931eSSam Leffler "send %snull data frame on channel %u, pwr mgt %s", 11846683931eSSam Leffler ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", 1185b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), 1186add59d08SSam Leffler wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 1187add59d08SSam Leffler 11885cda6006SAdrian Chadd ret = ieee80211_raw_output(vap, ni, m, NULL); 11895cda6006SAdrian Chadd IEEE80211_TX_UNLOCK(ic); 11905cda6006SAdrian Chadd return (ret); 11918a1b9b6aSSam Leffler } 11928a1b9b6aSSam Leffler 11938a1b9b6aSSam Leffler /* 11948a1b9b6aSSam Leffler * Assign priority to a frame based on any vlan tag assigned 11958a1b9b6aSSam Leffler * to the station and/or any Diffserv setting in an IP header. 11968a1b9b6aSSam Leffler * Finally, if an ACM policy is setup (in station mode) it's 11978a1b9b6aSSam Leffler * applied. 11988a1b9b6aSSam Leffler */ 11998a1b9b6aSSam Leffler int 1200b032f27cSSam Leffler ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) 12018a1b9b6aSSam Leffler { 1202bcabc908SAndriy Voskoboinyk const struct ether_header *eh = NULL; 1203bcabc908SAndriy Voskoboinyk uint16_t ether_type; 12048a1b9b6aSSam Leffler int v_wme_ac, d_wme_ac, ac; 12058a1b9b6aSSam Leffler 1206bcabc908SAndriy Voskoboinyk if (__predict_false(m->m_flags & M_ENCAP)) { 1207bcabc908SAndriy Voskoboinyk struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 1208bcabc908SAndriy Voskoboinyk struct llc *llc; 1209bcabc908SAndriy Voskoboinyk int hdrlen, subtype; 1210bcabc908SAndriy Voskoboinyk 1211bcabc908SAndriy Voskoboinyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; 1212bcabc908SAndriy Voskoboinyk if (subtype & IEEE80211_FC0_SUBTYPE_NODATA) { 1213bcabc908SAndriy Voskoboinyk ac = WME_AC_BE; 1214bcabc908SAndriy Voskoboinyk goto done; 1215bcabc908SAndriy Voskoboinyk } 1216bcabc908SAndriy Voskoboinyk 1217bcabc908SAndriy Voskoboinyk hdrlen = ieee80211_hdrsize(wh); 1218bcabc908SAndriy Voskoboinyk if (m->m_pkthdr.len < hdrlen + sizeof(*llc)) 1219bcabc908SAndriy Voskoboinyk return 1; 1220bcabc908SAndriy Voskoboinyk 1221bcabc908SAndriy Voskoboinyk llc = (struct llc *)mtodo(m, hdrlen); 1222bcabc908SAndriy Voskoboinyk if (llc->llc_dsap != LLC_SNAP_LSAP || 1223bcabc908SAndriy Voskoboinyk llc->llc_ssap != LLC_SNAP_LSAP || 1224bcabc908SAndriy Voskoboinyk llc->llc_control != LLC_UI || 1225bcabc908SAndriy Voskoboinyk llc->llc_snap.org_code[0] != 0 || 1226bcabc908SAndriy Voskoboinyk llc->llc_snap.org_code[1] != 0 || 1227bcabc908SAndriy Voskoboinyk llc->llc_snap.org_code[2] != 0) 1228bcabc908SAndriy Voskoboinyk return 1; 1229bcabc908SAndriy Voskoboinyk 1230bcabc908SAndriy Voskoboinyk ether_type = llc->llc_snap.ether_type; 1231bcabc908SAndriy Voskoboinyk } else { 1232bcabc908SAndriy Voskoboinyk eh = mtod(m, struct ether_header *); 1233bcabc908SAndriy Voskoboinyk ether_type = eh->ether_type; 1234bcabc908SAndriy Voskoboinyk } 1235bcabc908SAndriy Voskoboinyk 1236b032f27cSSam Leffler /* 1237b032f27cSSam Leffler * Always promote PAE/EAPOL frames to high priority. 1238b032f27cSSam Leffler */ 1239bcabc908SAndriy Voskoboinyk if (ether_type == htons(ETHERTYPE_PAE)) { 1240b032f27cSSam Leffler /* NB: mark so others don't need to check header */ 1241b032f27cSSam Leffler m->m_flags |= M_EAPOL; 1242b032f27cSSam Leffler ac = WME_AC_VO; 1243b032f27cSSam Leffler goto done; 1244b032f27cSSam Leffler } 1245b032f27cSSam Leffler /* 1246b032f27cSSam Leffler * Non-qos traffic goes to BE. 1247b032f27cSSam Leffler */ 12488a1b9b6aSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { 12498a1b9b6aSSam Leffler ac = WME_AC_BE; 12508a1b9b6aSSam Leffler goto done; 12518a1b9b6aSSam Leffler } 12528a1b9b6aSSam Leffler 12538a1b9b6aSSam Leffler /* 12548a1b9b6aSSam Leffler * If node has a vlan tag then all traffic 12558a1b9b6aSSam Leffler * to it must have a matching tag. 12568a1b9b6aSSam Leffler */ 12578a1b9b6aSSam Leffler v_wme_ac = 0; 12588a1b9b6aSSam Leffler if (ni->ni_vlan != 0) { 125978ba57b9SAndre Oppermann if ((m->m_flags & M_VLANTAG) == 0) { 12608a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_novlantag); 12618a1b9b6aSSam Leffler return 1; 12628a1b9b6aSSam Leffler } 126378ba57b9SAndre Oppermann if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 12648a1b9b6aSSam Leffler EVL_VLANOFTAG(ni->ni_vlan)) { 12658a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 12668a1b9b6aSSam Leffler return 1; 12678a1b9b6aSSam Leffler } 12688a1b9b6aSSam Leffler /* map vlan priority to AC */ 1269f4558c9aSSam Leffler v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); 12708a1b9b6aSSam Leffler } 12718a1b9b6aSSam Leffler 1272e755a73dSSam Leffler /* XXX m_copydata may be too slow for fast path */ 12738a1b9b6aSSam Leffler #ifdef INET 1274bcabc908SAndriy Voskoboinyk if (eh && eh->ether_type == htons(ETHERTYPE_IP)) { 1275f4558c9aSSam Leffler uint8_t tos; 12768a1b9b6aSSam Leffler /* 1277f4558c9aSSam Leffler * IP frame, map the DSCP bits from the TOS field. 12788a1b9b6aSSam Leffler */ 1279f4558c9aSSam Leffler /* NB: ip header may not be in first mbuf */ 1280f4558c9aSSam Leffler m_copydata(m, sizeof(struct ether_header) + 1281f4558c9aSSam Leffler offsetof(struct ip, ip_tos), sizeof(tos), &tos); 1282f4558c9aSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 1283f4558c9aSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 12848a1b9b6aSSam Leffler } else { 12858a1b9b6aSSam Leffler #endif /* INET */ 1286e755a73dSSam Leffler #ifdef INET6 1287bcabc908SAndriy Voskoboinyk if (eh && eh->ether_type == htons(ETHERTYPE_IPV6)) { 1288e755a73dSSam Leffler uint32_t flow; 1289e755a73dSSam Leffler uint8_t tos; 1290e755a73dSSam Leffler /* 12916ffd0ca9SBjoern A. Zeeb * IPv6 frame, map the DSCP bits from the traffic class field. 1292e755a73dSSam Leffler */ 1293e755a73dSSam Leffler m_copydata(m, sizeof(struct ether_header) + 1294e755a73dSSam Leffler offsetof(struct ip6_hdr, ip6_flow), sizeof(flow), 1295e755a73dSSam Leffler (caddr_t) &flow); 1296e755a73dSSam Leffler tos = (uint8_t)(ntohl(flow) >> 20); 1297e755a73dSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 1298e755a73dSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 1299e755a73dSSam Leffler } else { 1300e755a73dSSam Leffler #endif /* INET6 */ 13018a1b9b6aSSam Leffler d_wme_ac = WME_AC_BE; 1302e755a73dSSam Leffler #ifdef INET6 1303e755a73dSSam Leffler } 1304e755a73dSSam Leffler #endif 13058a1b9b6aSSam Leffler #ifdef INET 13068a1b9b6aSSam Leffler } 13078a1b9b6aSSam Leffler #endif 13088a1b9b6aSSam Leffler /* 13098a1b9b6aSSam Leffler * Use highest priority AC. 13108a1b9b6aSSam Leffler */ 13118a1b9b6aSSam Leffler if (v_wme_ac > d_wme_ac) 13128a1b9b6aSSam Leffler ac = v_wme_ac; 13138a1b9b6aSSam Leffler else 13148a1b9b6aSSam Leffler ac = d_wme_ac; 13158a1b9b6aSSam Leffler 13168a1b9b6aSSam Leffler /* 13178a1b9b6aSSam Leffler * Apply ACM policy. 13188a1b9b6aSSam Leffler */ 1319b032f27cSSam Leffler if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { 13208a1b9b6aSSam Leffler static const int acmap[4] = { 13218a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BE */ 13228a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BK */ 13238a1b9b6aSSam Leffler WME_AC_BE, /* WME_AC_VI */ 13248a1b9b6aSSam Leffler WME_AC_VI, /* WME_AC_VO */ 13258a1b9b6aSSam Leffler }; 1326b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 1327b032f27cSSam Leffler 13288a1b9b6aSSam Leffler while (ac != WME_AC_BK && 13298a1b9b6aSSam Leffler ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) 13308a1b9b6aSSam Leffler ac = acmap[ac]; 13318a1b9b6aSSam Leffler } 13328a1b9b6aSSam Leffler done: 13338a1b9b6aSSam Leffler M_WME_SETAC(m, ac); 13348a1b9b6aSSam Leffler return 0; 13358a1b9b6aSSam Leffler } 13368a1b9b6aSSam Leffler 13378a1b9b6aSSam Leffler /* 13385e923d2eSSam Leffler * Insure there is sufficient contiguous space to encapsulate the 13395e923d2eSSam Leffler * 802.11 data frame. If room isn't already there, arrange for it. 13405e923d2eSSam Leffler * Drivers and cipher modules assume we have done the necessary work 13415e923d2eSSam Leffler * and fail rudely if they don't find the space they need. 13425e923d2eSSam Leffler */ 1343616190d0SSam Leffler struct mbuf * 1344b032f27cSSam Leffler ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, 13455e923d2eSSam Leffler struct ieee80211_key *key, struct mbuf *m) 13465e923d2eSSam Leffler { 1347ab96db10SSam Leffler #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) 1348b032f27cSSam Leffler int needed_space = vap->iv_ic->ic_headroom + hdrsize; 13495e923d2eSSam Leffler 13505e923d2eSSam Leffler if (key != NULL) { 13515e923d2eSSam Leffler /* XXX belongs in crypto code? */ 13525e923d2eSSam Leffler needed_space += key->wk_cipher->ic_header; 13535e923d2eSSam Leffler /* XXX frags */ 135483a244dbSSam Leffler /* 135583a244dbSSam Leffler * When crypto is being done in the host we must insure 135683a244dbSSam Leffler * the data are writable for the cipher routines; clone 135783a244dbSSam Leffler * a writable mbuf chain. 135883a244dbSSam Leffler * XXX handle SWMIC specially 135983a244dbSSam Leffler */ 13605c1f7f19SSam Leffler if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { 136183a244dbSSam Leffler m = m_unshare(m, M_NOWAIT); 136283a244dbSSam Leffler if (m == NULL) { 1363b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 136483a244dbSSam Leffler "%s: cannot get writable mbuf\n", __func__); 1365b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ 136683a244dbSSam Leffler return NULL; 136783a244dbSSam Leffler } 136883a244dbSSam Leffler } 13695e923d2eSSam Leffler } 13705e923d2eSSam Leffler /* 13715e923d2eSSam Leffler * We know we are called just before stripping an Ethernet 13725e923d2eSSam Leffler * header and prepending an LLC header. This means we know 13735e923d2eSSam Leffler * there will be 1374ab96db10SSam Leffler * sizeof(struct ether_header) - sizeof(struct llc) 13755e923d2eSSam Leffler * bytes recovered to which we need additional space for the 13765e923d2eSSam Leffler * 802.11 header and any crypto header. 13775e923d2eSSam Leffler */ 13785e923d2eSSam Leffler /* XXX check trailing space and copy instead? */ 13795e923d2eSSam Leffler if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { 13805e923d2eSSam Leffler struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); 13815e923d2eSSam Leffler if (n == NULL) { 1382b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 13835e923d2eSSam Leffler "%s: cannot expand storage\n", __func__); 1384b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 13855e923d2eSSam Leffler m_freem(m); 13865e923d2eSSam Leffler return NULL; 13875e923d2eSSam Leffler } 13885e923d2eSSam Leffler KASSERT(needed_space <= MHLEN, 1389d7b5c50bSAlfred Perlstein ("not enough room, need %u got %d\n", needed_space, MHLEN)); 13905e923d2eSSam Leffler /* 13915e923d2eSSam Leffler * Setup new mbuf to have leading space to prepend the 13925e923d2eSSam Leffler * 802.11 header and any crypto header bits that are 13935e923d2eSSam Leffler * required (the latter are added when the driver calls 13945e923d2eSSam Leffler * back to ieee80211_crypto_encap to do crypto encapsulation). 13955e923d2eSSam Leffler */ 13965e923d2eSSam Leffler /* NB: must be first 'cuz it clobbers m_data */ 13975e923d2eSSam Leffler m_move_pkthdr(n, m); 13985e923d2eSSam Leffler n->m_len = 0; /* NB: m_gethdr does not set */ 13995e923d2eSSam Leffler n->m_data += needed_space; 14005e923d2eSSam Leffler /* 14015e923d2eSSam Leffler * Pull up Ethernet header to create the expected layout. 14025e923d2eSSam Leffler * We could use m_pullup but that's overkill (i.e. we don't 14035e923d2eSSam Leffler * need the actual data) and it cannot fail so do it inline 14045e923d2eSSam Leffler * for speed. 14055e923d2eSSam Leffler */ 14065e923d2eSSam Leffler /* NB: struct ether_header is known to be contiguous */ 14075e923d2eSSam Leffler n->m_len += sizeof(struct ether_header); 14085e923d2eSSam Leffler m->m_len -= sizeof(struct ether_header); 14095e923d2eSSam Leffler m->m_data += sizeof(struct ether_header); 14105e923d2eSSam Leffler /* 14115e923d2eSSam Leffler * Replace the head of the chain. 14125e923d2eSSam Leffler */ 14135e923d2eSSam Leffler n->m_next = m; 14145e923d2eSSam Leffler m = n; 14155e923d2eSSam Leffler } 14165e923d2eSSam Leffler return m; 14175e923d2eSSam Leffler #undef TO_BE_RECLAIMED 14185e923d2eSSam Leffler } 14195e923d2eSSam Leffler 14205e923d2eSSam Leffler /* 14215e923d2eSSam Leffler * Return the transmit key to use in sending a unicast frame. 14225e923d2eSSam Leffler * If a unicast key is set we use that. When no unicast key is set 14235e923d2eSSam Leffler * we fall back to the default transmit key. 14248a1b9b6aSSam Leffler */ 14258a1b9b6aSSam Leffler static __inline struct ieee80211_key * 1426b032f27cSSam Leffler ieee80211_crypto_getucastkey(struct ieee80211vap *vap, 1427b032f27cSSam Leffler struct ieee80211_node *ni) 14288a1b9b6aSSam Leffler { 1429cda15ce1SSam Leffler if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { 1430b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 1431b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 14328a1b9b6aSSam Leffler return NULL; 1433b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 14348a1b9b6aSSam Leffler } else { 14358a1b9b6aSSam Leffler return &ni->ni_ucastkey; 14368a1b9b6aSSam Leffler } 14375e923d2eSSam Leffler } 14385e923d2eSSam Leffler 14395e923d2eSSam Leffler /* 14405e923d2eSSam Leffler * Return the transmit key to use in sending a multicast frame. 14415e923d2eSSam Leffler * Multicast traffic always uses the group key which is installed as 14425e923d2eSSam Leffler * the default tx key. 14435e923d2eSSam Leffler */ 14445e923d2eSSam Leffler static __inline struct ieee80211_key * 1445b032f27cSSam Leffler ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, 1446b032f27cSSam Leffler struct ieee80211_node *ni) 14475e923d2eSSam Leffler { 1448b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 1449b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 14505e923d2eSSam Leffler return NULL; 1451b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 14528a1b9b6aSSam Leffler } 14538a1b9b6aSSam Leffler 14548a1b9b6aSSam Leffler /* 14558a1b9b6aSSam Leffler * Encapsulate an outbound data frame. The mbuf chain is updated. 14568a1b9b6aSSam Leffler * If an error is encountered NULL is returned. The caller is required 14578a1b9b6aSSam Leffler * to provide a node reference and pullup the ethernet header in the 14588a1b9b6aSSam Leffler * first mbuf. 1459b032f27cSSam Leffler * 1460b032f27cSSam Leffler * NB: Packet is assumed to be processed by ieee80211_classify which 1461b032f27cSSam Leffler * marked EAPOL frames w/ M_EAPOL. 14620a915fadSSam Leffler */ 14631a1e1d21SSam Leffler struct mbuf * 1464339ccfb3SSam Leffler ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni, 1465339ccfb3SSam Leffler struct mbuf *m) 14661a1e1d21SSam Leffler { 1467b032f27cSSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) 14683c314f6dSMonthadar Al Jaberi #define MC01(mc) ((struct ieee80211_meshcntl_ae01 *)mc) 1469b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 147059aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 147159aa14a9SRui Paulo struct ieee80211_mesh_state *ms = vap->iv_mesh; 1472c104cff2SRui Paulo struct ieee80211_meshcntl_ae10 *mc; 14733c314f6dSMonthadar Al Jaberi struct ieee80211_mesh_route *rt = NULL; 14743c314f6dSMonthadar Al Jaberi int dir = -1; 147559aa14a9SRui Paulo #endif 14761a1e1d21SSam Leffler struct ether_header eh; 14771a1e1d21SSam Leffler struct ieee80211_frame *wh; 14788a1b9b6aSSam Leffler struct ieee80211_key *key; 14791a1e1d21SSam Leffler struct llc *llc; 14809764ef21SAdrian Chadd int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr, is_mcast; 14819e80b1dfSSam Leffler ieee80211_seq seqno; 148259aa14a9SRui Paulo int meshhdrsize, meshae; 148359aa14a9SRui Paulo uint8_t *qos; 14841c7b0c84SAdrian Chadd int is_amsdu = 0; 14851a1e1d21SSam Leffler 14865cda6006SAdrian Chadd IEEE80211_TX_LOCK_ASSERT(ic); 14875cda6006SAdrian Chadd 14889764ef21SAdrian Chadd is_mcast = !! (m->m_flags & (M_MCAST | M_BCAST)); 14899764ef21SAdrian Chadd 149068e8e04eSSam Leffler /* 149168e8e04eSSam Leffler * Copy existing Ethernet header to a safe place. The 149268e8e04eSSam Leffler * rest of the code assumes it's ok to strip it when 149368e8e04eSSam Leffler * reorganizing state for the final encapsulation. 149468e8e04eSSam Leffler */ 14958a1b9b6aSSam Leffler KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); 1496b032f27cSSam Leffler ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); 14971a1e1d21SSam Leffler 14988a1b9b6aSSam Leffler /* 14998a1b9b6aSSam Leffler * Insure space for additional headers. First identify 15008a1b9b6aSSam Leffler * transmit key to use in calculating any buffer adjustments 15018a1b9b6aSSam Leffler * required. This is also used below to do privacy 15028a1b9b6aSSam Leffler * encapsulation work. Then calculate the 802.11 header 15038a1b9b6aSSam Leffler * size and any padding required by the driver. 15048a1b9b6aSSam Leffler * 15058a1b9b6aSSam Leffler * Note key may be NULL if we fall back to the default 15068a1b9b6aSSam Leffler * transmit key and that is not set. In that case the 15078a1b9b6aSSam Leffler * buffer may not be expanded as needed by the cipher 15088a1b9b6aSSam Leffler * routines, but they will/should discard it. 15098a1b9b6aSSam Leffler */ 1510b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) { 1511b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA || 1512b032f27cSSam Leffler !IEEE80211_IS_MULTICAST(eh.ether_dhost) || 1513b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_WDS && 15142172664cSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) { 1515b032f27cSSam Leffler key = ieee80211_crypto_getucastkey(vap, ni); 15162172664cSAdrian Chadd } else if ((vap->iv_opmode == IEEE80211_M_WDS) && 15172172664cSAdrian Chadd (! (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) { 15182172664cSAdrian Chadd /* 15192172664cSAdrian Chadd * Use ucastkey for DWDS transmit nodes, multicast 15202172664cSAdrian Chadd * or otherwise. 15212172664cSAdrian Chadd * 15222172664cSAdrian Chadd * This is required to ensure that multicast frames 15232172664cSAdrian Chadd * from a DWDS AP to a DWDS STA is encrypted with 15242172664cSAdrian Chadd * a key that can actually work. 15252172664cSAdrian Chadd * 15262172664cSAdrian Chadd * There's no default key for multicast traffic 15272172664cSAdrian Chadd * on a DWDS WDS VAP node (note NOT the DWDS enabled 15282172664cSAdrian Chadd * AP VAP, the dynamically created per-STA WDS node) 15292172664cSAdrian Chadd * so encap fails and transmit fails. 15302172664cSAdrian Chadd */ 15312172664cSAdrian Chadd key = ieee80211_crypto_getucastkey(vap, ni); 15322172664cSAdrian Chadd } else { 1533b032f27cSSam Leffler key = ieee80211_crypto_getmcastkey(vap, ni); 15342172664cSAdrian Chadd } 1535b032f27cSSam Leffler if (key == NULL && (m->m_flags & M_EAPOL) == 0) { 1536b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, 1537b032f27cSSam Leffler eh.ether_dhost, 1538b032f27cSSam Leffler "no default transmit key (%s) deftxkey %u", 1539b032f27cSSam Leffler __func__, vap->iv_def_txkey); 1540b032f27cSSam Leffler vap->iv_stats.is_tx_nodefkey++; 1541d72c7253SSam Leffler goto bad; 15428a1b9b6aSSam Leffler } 15438a1b9b6aSSam Leffler } else 15448a1b9b6aSSam Leffler key = NULL; 15455e923d2eSSam Leffler /* 15465e923d2eSSam Leffler * XXX Some ap's don't handle QoS-encapsulated EAPOL 15475e923d2eSSam Leffler * frames so suppress use. This may be an issue if other 15485e923d2eSSam Leffler * ap's require all data frames to be QoS-encapsulated 15495e923d2eSSam Leffler * once negotiated in which case we'll need to make this 15505e923d2eSSam Leffler * configurable. 15519764ef21SAdrian Chadd * 15529764ef21SAdrian Chadd * Don't send multicast QoS frames. 15539764ef21SAdrian Chadd * Technically multicast frames can be QoS if all stations in the 15549764ef21SAdrian Chadd * BSS are also QoS. 15559764ef21SAdrian Chadd * 15569764ef21SAdrian Chadd * NB: mesh data frames are QoS, including multicast frames. 15575e923d2eSSam Leffler */ 15589764ef21SAdrian Chadd addqos = 15599764ef21SAdrian Chadd (((is_mcast == 0) && (ni->ni_flags & 15609764ef21SAdrian Chadd (IEEE80211_NODE_QOS|IEEE80211_NODE_HT))) || 156191216c71SAdrian Chadd (vap->iv_opmode == IEEE80211_M_MBSS)) && 1562b032f27cSSam Leffler (m->m_flags & M_EAPOL) == 0; 15639764ef21SAdrian Chadd 15645e923d2eSSam Leffler if (addqos) 15658a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_qosframe); 15668a1b9b6aSSam Leffler else 15678a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_frame); 156859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 156959aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 157059aa14a9SRui Paulo /* 157159aa14a9SRui Paulo * Mesh data frames are encapsulated according to the 157259aa14a9SRui Paulo * rules of Section 11B.8.5 (p.139 of D3.0 spec). 157359aa14a9SRui Paulo * o Group Addressed data (aka multicast) originating 157459aa14a9SRui Paulo * at the local sta are sent w/ 3-address format and 157559aa14a9SRui Paulo * address extension mode 00 157659aa14a9SRui Paulo * o Individually Addressed data (aka unicast) originating 157759aa14a9SRui Paulo * at the local sta are sent w/ 4-address format and 157859aa14a9SRui Paulo * address extension mode 00 157959aa14a9SRui Paulo * o Group Addressed data forwarded from a non-mesh sta are 158059aa14a9SRui Paulo * sent w/ 3-address format and address extension mode 01 158159aa14a9SRui Paulo * o Individually Address data from another sta are sent 158259aa14a9SRui Paulo * w/ 4-address format and address extension mode 10 158359aa14a9SRui Paulo */ 158459aa14a9SRui Paulo is4addr = 0; /* NB: don't use, disable */ 15853c314f6dSMonthadar Al Jaberi if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) { 15863c314f6dSMonthadar Al Jaberi rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost); 15873c314f6dSMonthadar Al Jaberi KASSERT(rt != NULL, ("route is NULL")); 15883c314f6dSMonthadar Al Jaberi dir = IEEE80211_FC1_DIR_DSTODS; 15893c314f6dSMonthadar Al Jaberi hdrsize += IEEE80211_ADDR_LEN; 15903c314f6dSMonthadar Al Jaberi if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) { 15913c314f6dSMonthadar Al Jaberi if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate, 15923c314f6dSMonthadar Al Jaberi vap->iv_myaddr)) { 15933c314f6dSMonthadar Al Jaberi IEEE80211_NOTE_MAC(vap, 15943c314f6dSMonthadar Al Jaberi IEEE80211_MSG_MESH, 15953c314f6dSMonthadar Al Jaberi eh.ether_dhost, 15963c314f6dSMonthadar Al Jaberi "%s", "trying to send to ourself"); 15973c314f6dSMonthadar Al Jaberi goto bad; 15983c314f6dSMonthadar Al Jaberi } 15993c314f6dSMonthadar Al Jaberi meshae = IEEE80211_MESH_AE_10; 16003c314f6dSMonthadar Al Jaberi meshhdrsize = 16013c314f6dSMonthadar Al Jaberi sizeof(struct ieee80211_meshcntl_ae10); 160259aa14a9SRui Paulo } else { 16033c314f6dSMonthadar Al Jaberi meshae = IEEE80211_MESH_AE_00; 16043c314f6dSMonthadar Al Jaberi meshhdrsize = 16053c314f6dSMonthadar Al Jaberi sizeof(struct ieee80211_meshcntl); 16063c314f6dSMonthadar Al Jaberi } 16073c314f6dSMonthadar Al Jaberi } else { 16083c314f6dSMonthadar Al Jaberi dir = IEEE80211_FC1_DIR_FROMDS; 16093c314f6dSMonthadar Al Jaberi if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { 16103c314f6dSMonthadar Al Jaberi /* proxy group */ 16113c314f6dSMonthadar Al Jaberi meshae = IEEE80211_MESH_AE_01; 16123c314f6dSMonthadar Al Jaberi meshhdrsize = 16133c314f6dSMonthadar Al Jaberi sizeof(struct ieee80211_meshcntl_ae01); 16143c314f6dSMonthadar Al Jaberi } else { 16153c314f6dSMonthadar Al Jaberi /* group */ 16163c314f6dSMonthadar Al Jaberi meshae = IEEE80211_MESH_AE_00; 16173c314f6dSMonthadar Al Jaberi meshhdrsize = sizeof(struct ieee80211_meshcntl); 16183c314f6dSMonthadar Al Jaberi } 161959aa14a9SRui Paulo } 162059aa14a9SRui Paulo } else { 162159aa14a9SRui Paulo #endif 1622b032f27cSSam Leffler /* 1623b032f27cSSam Leffler * 4-address frames need to be generated for: 16246437e6daSSam Leffler * o packets sent through a WDS vap (IEEE80211_M_WDS) 1625f2a6a13cSSam Leffler * o packets sent through a vap marked for relaying 1626f2a6a13cSSam Leffler * (e.g. a station operating with dynamic WDS) 1627b032f27cSSam Leffler */ 16286437e6daSSam Leffler is4addr = vap->iv_opmode == IEEE80211_M_WDS || 1629f2a6a13cSSam Leffler ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) && 1630b032f27cSSam Leffler !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); 1631b032f27cSSam Leffler if (is4addr) 1632b032f27cSSam Leffler hdrsize += IEEE80211_ADDR_LEN; 163359aa14a9SRui Paulo meshhdrsize = meshae = 0; 163459aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 163559aa14a9SRui Paulo } 163659aa14a9SRui Paulo #endif 1637b032f27cSSam Leffler /* 1638b032f27cSSam Leffler * Honor driver DATAPAD requirement. 1639b032f27cSSam Leffler */ 16408a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 1641b032f27cSSam Leffler hdrspace = roundup(hdrsize, sizeof(uint32_t)); 1642b032f27cSSam Leffler else 1643b032f27cSSam Leffler hdrspace = hdrsize; 164468e8e04eSSam Leffler 1645616190d0SSam Leffler if (__predict_true((m->m_flags & M_FF) == 0)) { 164668e8e04eSSam Leffler /* 164768e8e04eSSam Leffler * Normal frame. 164868e8e04eSSam Leffler */ 164959aa14a9SRui Paulo m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m); 16508a1b9b6aSSam Leffler if (m == NULL) { 16518a1b9b6aSSam Leffler /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 16520a915fadSSam Leffler goto bad; 16530a915fadSSam Leffler } 165468e8e04eSSam Leffler /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ 1655ab96db10SSam Leffler m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 16561a1e1d21SSam Leffler llc = mtod(m, struct llc *); 16571a1e1d21SSam Leffler llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 16581a1e1d21SSam Leffler llc->llc_control = LLC_UI; 16591a1e1d21SSam Leffler llc->llc_snap.org_code[0] = 0; 16601a1e1d21SSam Leffler llc->llc_snap.org_code[1] = 0; 16611a1e1d21SSam Leffler llc->llc_snap.org_code[2] = 0; 16621a1e1d21SSam Leffler llc->llc_snap.ether_type = eh.ether_type; 1663616190d0SSam Leffler } else { 1664616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 1665339ccfb3SSam Leffler /* 16661c7b0c84SAdrian Chadd * Aggregated frame. Check if it's for AMSDU or FF. 16671c7b0c84SAdrian Chadd * 16681c7b0c84SAdrian Chadd * XXX TODO: IEEE80211_NODE_AMSDU* isn't implemented 16691c7b0c84SAdrian Chadd * anywhere for some reason. But, since 11n requires 16701c7b0c84SAdrian Chadd * AMSDU RX, we can just assume "11n" == "AMSDU". 1671339ccfb3SSam Leffler */ 16721c7b0c84SAdrian Chadd IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, "%s: called; M_FF\n", __func__); 16731c7b0c84SAdrian Chadd if (ieee80211_amsdu_tx_ok(ni)) { 16741c7b0c84SAdrian Chadd m = ieee80211_amsdu_encap(vap, m, hdrspace + meshhdrsize, key); 16751c7b0c84SAdrian Chadd is_amsdu = 1; 16761c7b0c84SAdrian Chadd } else { 167759aa14a9SRui Paulo m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key); 16781c7b0c84SAdrian Chadd } 1679616190d0SSam Leffler if (m == NULL) 1680616190d0SSam Leffler #endif 1681616190d0SSam Leffler goto bad; 168268e8e04eSSam Leffler } 16838a1b9b6aSSam Leffler datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ 16848a1b9b6aSSam Leffler 1685eb1b1807SGleb Smirnoff M_PREPEND(m, hdrspace + meshhdrsize, M_NOWAIT); 16861be50176SSam Leffler if (m == NULL) { 1687b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 16880a915fadSSam Leffler goto bad; 16891be50176SSam Leffler } 16901a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 16911a1e1d21SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 169268e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 169359aa14a9SRui Paulo qos = NULL; /* NB: quiet compiler */ 1694b032f27cSSam Leffler if (is4addr) { 1695b032f27cSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 1696b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 1697b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1698b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1699b032f27cSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 1700b032f27cSSam Leffler } else switch (vap->iv_opmode) { 17011a1e1d21SSam Leffler case IEEE80211_M_STA: 17021a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 17031a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 17041a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 17051a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 17061a1e1d21SSam Leffler break; 17071a1e1d21SSam Leffler case IEEE80211_M_IBSS: 17081a1e1d21SSam Leffler case IEEE80211_M_AHDEMO: 17091a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 17101a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 17111a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1712a8b16e87SSam Leffler /* 1713b032f27cSSam Leffler * NB: always use the bssid from iv_bss as the 1714a8b16e87SSam Leffler * neighbor's may be stale after an ibss merge 1715a8b16e87SSam Leffler */ 1716b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); 17171a1e1d21SSam Leffler break; 17181a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 17191a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 17201a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 17211a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 17221a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 17231a1e1d21SSam Leffler break; 172459aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 172559aa14a9SRui Paulo case IEEE80211_M_MBSS: 172659aa14a9SRui Paulo /* NB: offset by hdrspace to deal with DATAPAD */ 1727c104cff2SRui Paulo mc = (struct ieee80211_meshcntl_ae10 *) 172859aa14a9SRui Paulo (mtod(m, uint8_t *) + hdrspace); 17293c314f6dSMonthadar Al Jaberi wh->i_fc[1] = dir; 173059aa14a9SRui Paulo switch (meshae) { 17313c314f6dSMonthadar Al Jaberi case IEEE80211_MESH_AE_00: /* no proxy */ 173259aa14a9SRui Paulo mc->mc_flags = 0; 17333c314f6dSMonthadar Al Jaberi if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */ 17343c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(wh->i_addr1, 17353c314f6dSMonthadar Al Jaberi ni->ni_macaddr); 17363c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(wh->i_addr2, 17373c314f6dSMonthadar Al Jaberi vap->iv_myaddr); 17383c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(wh->i_addr3, 17393c314f6dSMonthadar Al Jaberi eh.ether_dhost); 17403c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, 17413c314f6dSMonthadar Al Jaberi eh.ether_shost); 17423c314f6dSMonthadar Al Jaberi qos =((struct ieee80211_qosframe_addr4 *) 17433c314f6dSMonthadar Al Jaberi wh)->i_qos; 17443c314f6dSMonthadar Al Jaberi } else if (dir == IEEE80211_FC1_DIR_FROMDS) { 17453c314f6dSMonthadar Al Jaberi /* mcast */ 17463c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(wh->i_addr1, 17473c314f6dSMonthadar Al Jaberi eh.ether_dhost); 17483c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(wh->i_addr2, 17493c314f6dSMonthadar Al Jaberi vap->iv_myaddr); 17503c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(wh->i_addr3, 17513c314f6dSMonthadar Al Jaberi eh.ether_shost); 17523c314f6dSMonthadar Al Jaberi qos = ((struct ieee80211_qosframe *) 17533c314f6dSMonthadar Al Jaberi wh)->i_qos; 17543c314f6dSMonthadar Al Jaberi } 175559aa14a9SRui Paulo break; 17563c314f6dSMonthadar Al Jaberi case IEEE80211_MESH_AE_01: /* mcast, proxy */ 175759aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 175859aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 175959aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1760c104cff2SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr); 176159aa14a9SRui Paulo mc->mc_flags = 1; 17623c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4, 17633c314f6dSMonthadar Al Jaberi eh.ether_shost); 176459aa14a9SRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 176559aa14a9SRui Paulo break; 17663c314f6dSMonthadar Al Jaberi case IEEE80211_MESH_AE_10: /* ucast, proxy */ 17673c314f6dSMonthadar Al Jaberi KASSERT(rt != NULL, ("route is NULL")); 17683c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop); 176959aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 17703c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate); 1771c104cff2SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr); 17723c314f6dSMonthadar Al Jaberi mc->mc_flags = IEEE80211_MESH_AE_10; 17733c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost); 17743c314f6dSMonthadar Al Jaberi IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost); 177559aa14a9SRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 177659aa14a9SRui Paulo break; 177759aa14a9SRui Paulo default: 177859aa14a9SRui Paulo KASSERT(0, ("meshae %d", meshae)); 177959aa14a9SRui Paulo break; 178059aa14a9SRui Paulo } 178159aa14a9SRui Paulo mc->mc_ttl = ms->ms_ttl; 178259aa14a9SRui Paulo ms->ms_seq++; 178331021a2bSAndriy Voskoboinyk le32enc(mc->mc_seq, ms->ms_seq); 178459aa14a9SRui Paulo break; 178559aa14a9SRui Paulo #endif 1786b032f27cSSam Leffler case IEEE80211_M_WDS: /* NB: is4addr should always be true */ 178759aa14a9SRui Paulo default: 17880a915fadSSam Leffler goto bad; 17891a1e1d21SSam Leffler } 1790bc5627d9SSam Leffler if (m->m_flags & M_MORE_DATA) 1791bc5627d9SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 17925e923d2eSSam Leffler if (addqos) { 17938a1b9b6aSSam Leffler int ac, tid; 17948a1b9b6aSSam Leffler 1795b032f27cSSam Leffler if (is4addr) { 1796b032f27cSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 179759aa14a9SRui Paulo /* NB: mesh case handled earlier */ 179859aa14a9SRui Paulo } else if (vap->iv_opmode != IEEE80211_M_MBSS) 1799b032f27cSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 18008a1b9b6aSSam Leffler ac = M_WME_GETAC(m); 18018a1b9b6aSSam Leffler /* map from access class/queue to 11e header priorty value */ 18028a1b9b6aSSam Leffler tid = WME_AC_TO_TID(ac); 1803b032f27cSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 18048a1b9b6aSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) 1805b032f27cSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 180691216c71SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH 1807d566999aSMonthadar Al Jaberi if (vap->iv_opmode == IEEE80211_M_MBSS) 1808d566999aSMonthadar Al Jaberi qos[1] = IEEE80211_QOS_MC; 1809d566999aSMonthadar Al Jaberi else 181091216c71SAdrian Chadd #endif 1811b032f27cSSam Leffler qos[1] = 0; 1812b032f27cSSam Leffler wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; 18138a1b9b6aSSam Leffler 18141c7b0c84SAdrian Chadd /* 18151c7b0c84SAdrian Chadd * If this is an A-MSDU then ensure we set the 18161c7b0c84SAdrian Chadd * relevant field. 18171c7b0c84SAdrian Chadd */ 18181c7b0c84SAdrian Chadd if (is_amsdu) 18191c7b0c84SAdrian Chadd qos[0] |= IEEE80211_QOS_AMSDU; 18201c7b0c84SAdrian Chadd 182151172f62SAdrian Chadd /* 182251172f62SAdrian Chadd * XXX TODO TX lock is needed for atomic updates of sequence 182351172f62SAdrian Chadd * numbers. If the driver does it, then don't do it here; 182451172f62SAdrian Chadd * and we don't need the TX lock held. 182551172f62SAdrian Chadd */ 182645f856e3SSam Leffler if ((m->m_flags & M_AMPDU_MPDU) == 0) { 182745f856e3SSam Leffler /* 18289764ef21SAdrian Chadd * 802.11-2012 9.3.2.10 - 18299764ef21SAdrian Chadd * 18309764ef21SAdrian Chadd * If this is a multicast frame then we need 18319764ef21SAdrian Chadd * to ensure that the sequence number comes from 18329764ef21SAdrian Chadd * a separate seqno space and not the TID space. 18339764ef21SAdrian Chadd * 18349764ef21SAdrian Chadd * Otherwise multicast frames may actually cause 18359764ef21SAdrian Chadd * holes in the TX blockack window space and 18369764ef21SAdrian Chadd * upset various things. 18379764ef21SAdrian Chadd */ 18389764ef21SAdrian Chadd if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 18399764ef21SAdrian Chadd seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 18409764ef21SAdrian Chadd else 18419764ef21SAdrian Chadd seqno = ni->ni_txseqs[tid]++; 18429764ef21SAdrian Chadd 18439764ef21SAdrian Chadd /* 184445f856e3SSam Leffler * NB: don't assign a sequence # to potential 184545f856e3SSam Leffler * aggregates; we expect this happens at the 184645f856e3SSam Leffler * point the frame comes off any aggregation q 184745f856e3SSam Leffler * as otherwise we may introduce holes in the 184845f856e3SSam Leffler * BA sequence space and/or make window accouting 184945f856e3SSam Leffler * more difficult. 185045f856e3SSam Leffler * 185145f856e3SSam Leffler * XXX may want to control this with a driver 185245f856e3SSam Leffler * capability; this may also change when we pull 185345f856e3SSam Leffler * aggregation up into net80211 185445f856e3SSam Leffler */ 185568e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 18569e80b1dfSSam Leffler htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 18579a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 18582db223f9SAndriy Voskoboinyk } else { 18592db223f9SAndriy Voskoboinyk /* NB: zero out i_seq field (for s/w encryption etc) */ 18602db223f9SAndriy Voskoboinyk *(uint16_t *)wh->i_seq = 0; 186145f856e3SSam Leffler } 18628a1b9b6aSSam Leffler } else { 186351172f62SAdrian Chadd /* 186451172f62SAdrian Chadd * XXX TODO TX lock is needed for atomic updates of sequence 186551172f62SAdrian Chadd * numbers. If the driver does it, then don't do it here; 186651172f62SAdrian Chadd * and we don't need the TX lock held. 186751172f62SAdrian Chadd */ 18689e80b1dfSSam Leffler seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 186968e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 18709e80b1dfSSam Leffler htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 18719a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 18721c7b0c84SAdrian Chadd 18731c7b0c84SAdrian Chadd /* 18741c7b0c84SAdrian Chadd * XXX TODO: we shouldn't allow EAPOL, etc that would 18751c7b0c84SAdrian Chadd * be forced to be non-QoS traffic to be A-MSDU encapsulated. 18761c7b0c84SAdrian Chadd */ 18771c7b0c84SAdrian Chadd if (is_amsdu) 18781c7b0c84SAdrian Chadd printf("%s: XXX ERROR: is_amsdu set; not QoS!\n", 18791c7b0c84SAdrian Chadd __func__); 18808a1b9b6aSSam Leffler } 18819a841c7fSSam Leffler 188243eafd0dSAdrian Chadd /* 188343eafd0dSAdrian Chadd * Check if xmit fragmentation is required. 188443eafd0dSAdrian Chadd * 188543eafd0dSAdrian Chadd * If the hardware does fragmentation offload, then don't bother 188643eafd0dSAdrian Chadd * doing it here. 188743eafd0dSAdrian Chadd */ 188843eafd0dSAdrian Chadd if (IEEE80211_CONF_FRAG_OFFLOAD(ic)) 188943eafd0dSAdrian Chadd txfrag = 0; 189043eafd0dSAdrian Chadd else 1891b032f27cSSam Leffler txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && 189268e8e04eSSam Leffler !IEEE80211_IS_MULTICAST(wh->i_addr1) && 1893b032f27cSSam Leffler (vap->iv_caps & IEEE80211_C_TXFRAG) && 1894e9cfc1f5SSam Leffler (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0); 189543eafd0dSAdrian Chadd 18965e923d2eSSam Leffler if (key != NULL) { 18975e923d2eSSam Leffler /* 18985e923d2eSSam Leffler * IEEE 802.1X: send EAPOL frames always in the clear. 18995e923d2eSSam Leffler * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 19005e923d2eSSam Leffler */ 1901b032f27cSSam Leffler if ((m->m_flags & M_EAPOL) == 0 || 1902b032f27cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) && 1903b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_STA ? 1904cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(key) : 1905cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { 19065945b5f5SKevin Lo wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; 1907b032f27cSSam Leffler if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { 1908b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, 1909b032f27cSSam Leffler eh.ether_dhost, 1910b032f27cSSam Leffler "%s", "enmic failed, discard frame"); 1911b032f27cSSam Leffler vap->iv_stats.is_crypto_enmicfail++; 19125e923d2eSSam Leffler goto bad; 19135e923d2eSSam Leffler } 19145e923d2eSSam Leffler } 19155e923d2eSSam Leffler } 1916b032f27cSSam Leffler if (txfrag && !ieee80211_fragment(vap, m, hdrsize, 1917b032f27cSSam Leffler key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) 191868e8e04eSSam Leffler goto bad; 19198a1b9b6aSSam Leffler 1920c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 1921c1af44bdSSam Leffler 19228a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 19239e80b1dfSSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1924b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 19259e80b1dfSSam Leffler m->m_flags |= M_MCAST; 19269e80b1dfSSam Leffler } else 1927b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 19288a1b9b6aSSam Leffler IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); 19298a1b9b6aSSam Leffler 19301a1e1d21SSam Leffler return m; 19310a915fadSSam Leffler bad: 19320a915fadSSam Leffler if (m != NULL) 19330a915fadSSam Leffler m_freem(m); 19340a915fadSSam Leffler return NULL; 1935b032f27cSSam Leffler #undef WH4 19363c314f6dSMonthadar Al Jaberi #undef MC01 19371a1e1d21SSam Leffler } 19381a1e1d21SSam Leffler 1939d07be335SAdrian Chadd void 1940d07be335SAdrian Chadd ieee80211_free_mbuf(struct mbuf *m) 1941d07be335SAdrian Chadd { 1942d07be335SAdrian Chadd struct mbuf *next; 1943d07be335SAdrian Chadd 1944d07be335SAdrian Chadd if (m == NULL) 1945d07be335SAdrian Chadd return; 1946d07be335SAdrian Chadd 1947d07be335SAdrian Chadd do { 1948d07be335SAdrian Chadd next = m->m_nextpkt; 1949d07be335SAdrian Chadd m->m_nextpkt = NULL; 1950d07be335SAdrian Chadd m_freem(m); 1951d07be335SAdrian Chadd } while ((m = next) != NULL); 1952d07be335SAdrian Chadd } 1953d07be335SAdrian Chadd 19541a1e1d21SSam Leffler /* 195568e8e04eSSam Leffler * Fragment the frame according to the specified mtu. 195668e8e04eSSam Leffler * The size of the 802.11 header (w/o padding) is provided 195768e8e04eSSam Leffler * so we don't need to recalculate it. We create a new 195868e8e04eSSam Leffler * mbuf for each fragment and chain it through m_nextpkt; 195968e8e04eSSam Leffler * we might be able to optimize this by reusing the original 196068e8e04eSSam Leffler * packet's mbufs but that is significantly more complicated. 196168e8e04eSSam Leffler */ 196268e8e04eSSam Leffler static int 1963b032f27cSSam Leffler ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, 196468e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu) 196568e8e04eSSam Leffler { 19668d46c25dSAdrian Chadd struct ieee80211com *ic = vap->iv_ic; 196768e8e04eSSam Leffler struct ieee80211_frame *wh, *whf; 1968d07be335SAdrian Chadd struct mbuf *m, *prev; 196968e8e04eSSam Leffler u_int totalhdrsize, fragno, fragsize, off, remainder, payload; 19708d46c25dSAdrian Chadd u_int hdrspace; 197168e8e04eSSam Leffler 197268e8e04eSSam Leffler KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); 197368e8e04eSSam Leffler KASSERT(m0->m_pkthdr.len > mtu, 197468e8e04eSSam Leffler ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); 197568e8e04eSSam Leffler 19768d46c25dSAdrian Chadd /* 19778d46c25dSAdrian Chadd * Honor driver DATAPAD requirement. 19788d46c25dSAdrian Chadd */ 19798d46c25dSAdrian Chadd if (ic->ic_flags & IEEE80211_F_DATAPAD) 19808d46c25dSAdrian Chadd hdrspace = roundup(hdrsize, sizeof(uint32_t)); 19818d46c25dSAdrian Chadd else 19828d46c25dSAdrian Chadd hdrspace = hdrsize; 19838d46c25dSAdrian Chadd 198468e8e04eSSam Leffler wh = mtod(m0, struct ieee80211_frame *); 198568e8e04eSSam Leffler /* NB: mark the first frag; it will be propagated below */ 198668e8e04eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; 19878d46c25dSAdrian Chadd totalhdrsize = hdrspace + ciphdrsize; 198868e8e04eSSam Leffler fragno = 1; 198968e8e04eSSam Leffler off = mtu - ciphdrsize; 199068e8e04eSSam Leffler remainder = m0->m_pkthdr.len - off; 199168e8e04eSSam Leffler prev = m0; 199268e8e04eSSam Leffler do { 199318d20be0SAndriy Voskoboinyk fragsize = MIN(totalhdrsize + remainder, mtu); 199418d20be0SAndriy Voskoboinyk m = m_get2(fragsize, M_NOWAIT, MT_DATA, M_PKTHDR); 199568e8e04eSSam Leffler if (m == NULL) 199668e8e04eSSam Leffler goto bad; 199768e8e04eSSam Leffler /* leave room to prepend any cipher header */ 199868e8e04eSSam Leffler m_align(m, fragsize - ciphdrsize); 199968e8e04eSSam Leffler 200068e8e04eSSam Leffler /* 200168e8e04eSSam Leffler * Form the header in the fragment. Note that since 200268e8e04eSSam Leffler * we mark the first fragment with the MORE_FRAG bit 200368e8e04eSSam Leffler * it automatically is propagated to each fragment; we 200468e8e04eSSam Leffler * need only clear it on the last fragment (done below). 200591216c71SAdrian Chadd * NB: frag 1+ dont have Mesh Control field present. 200668e8e04eSSam Leffler */ 200768e8e04eSSam Leffler whf = mtod(m, struct ieee80211_frame *); 200868e8e04eSSam Leffler memcpy(whf, wh, hdrsize); 200991216c71SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH 2010f3f08e16SAndriy Voskoboinyk if (vap->iv_opmode == IEEE80211_M_MBSS) 2011f3f08e16SAndriy Voskoboinyk ieee80211_getqos(wh)[1] &= ~IEEE80211_QOS_MC; 201291216c71SAdrian Chadd #endif 201368e8e04eSSam Leffler *(uint16_t *)&whf->i_seq[0] |= htole16( 201468e8e04eSSam Leffler (fragno & IEEE80211_SEQ_FRAG_MASK) << 201568e8e04eSSam Leffler IEEE80211_SEQ_FRAG_SHIFT); 201668e8e04eSSam Leffler fragno++; 201768e8e04eSSam Leffler 201868e8e04eSSam Leffler payload = fragsize - totalhdrsize; 201968e8e04eSSam Leffler /* NB: destination is known to be contiguous */ 20208d46c25dSAdrian Chadd 20218d46c25dSAdrian Chadd m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrspace); 20228d46c25dSAdrian Chadd m->m_len = hdrspace + payload; 20238d46c25dSAdrian Chadd m->m_pkthdr.len = hdrspace + payload; 202468e8e04eSSam Leffler m->m_flags |= M_FRAG; 202568e8e04eSSam Leffler 202668e8e04eSSam Leffler /* chain up the fragment */ 202768e8e04eSSam Leffler prev->m_nextpkt = m; 202868e8e04eSSam Leffler prev = m; 202968e8e04eSSam Leffler 203068e8e04eSSam Leffler /* deduct fragment just formed */ 203168e8e04eSSam Leffler remainder -= payload; 203268e8e04eSSam Leffler off += payload; 203368e8e04eSSam Leffler } while (remainder != 0); 203451cec121SWeongyo Jeong 203551cec121SWeongyo Jeong /* set the last fragment */ 203651cec121SWeongyo Jeong m->m_flags |= M_LASTFRAG; 203768e8e04eSSam Leffler whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; 203868e8e04eSSam Leffler 203968e8e04eSSam Leffler /* strip first mbuf now that everything has been copied */ 204068e8e04eSSam Leffler m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); 204168e8e04eSSam Leffler m0->m_flags |= M_FIRSTFRAG | M_FRAG; 204268e8e04eSSam Leffler 2043b032f27cSSam Leffler vap->iv_stats.is_tx_fragframes++; 2044b032f27cSSam Leffler vap->iv_stats.is_tx_frags += fragno-1; 204568e8e04eSSam Leffler 204668e8e04eSSam Leffler return 1; 204768e8e04eSSam Leffler bad: 204868e8e04eSSam Leffler /* reclaim fragments but leave original frame for caller to free */ 2049d07be335SAdrian Chadd ieee80211_free_mbuf(m0->m_nextpkt); 205068e8e04eSSam Leffler m0->m_nextpkt = NULL; 205168e8e04eSSam Leffler return 0; 205268e8e04eSSam Leffler } 205368e8e04eSSam Leffler 205468e8e04eSSam Leffler /* 20551a1e1d21SSam Leffler * Add a supported rates element id to a frame. 20561a1e1d21SSam Leffler */ 205759aa14a9SRui Paulo uint8_t * 205868e8e04eSSam Leffler ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 20591a1e1d21SSam Leffler { 20601a1e1d21SSam Leffler int nrates; 20611a1e1d21SSam Leffler 20621a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_RATES; 20631a1e1d21SSam Leffler nrates = rs->rs_nrates; 20641a1e1d21SSam Leffler if (nrates > IEEE80211_RATE_SIZE) 20651a1e1d21SSam Leffler nrates = IEEE80211_RATE_SIZE; 20661a1e1d21SSam Leffler *frm++ = nrates; 20671a1e1d21SSam Leffler memcpy(frm, rs->rs_rates, nrates); 20681a1e1d21SSam Leffler return frm + nrates; 20691a1e1d21SSam Leffler } 20701a1e1d21SSam Leffler 20711a1e1d21SSam Leffler /* 20721a1e1d21SSam Leffler * Add an extended supported rates element id to a frame. 20731a1e1d21SSam Leffler */ 207459aa14a9SRui Paulo uint8_t * 207568e8e04eSSam Leffler ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 20761a1e1d21SSam Leffler { 20771a1e1d21SSam Leffler /* 20781a1e1d21SSam Leffler * Add an extended supported rates element if operating in 11g mode. 20791a1e1d21SSam Leffler */ 20801a1e1d21SSam Leffler if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 20811a1e1d21SSam Leffler int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 20821a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_XRATES; 20831a1e1d21SSam Leffler *frm++ = nrates; 20841a1e1d21SSam Leffler memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 20851a1e1d21SSam Leffler frm += nrates; 20861a1e1d21SSam Leffler } 20871a1e1d21SSam Leffler return frm; 20881a1e1d21SSam Leffler } 20891a1e1d21SSam Leffler 20901a1e1d21SSam Leffler /* 2091b032f27cSSam Leffler * Add an ssid element to a frame. 20921a1e1d21SSam Leffler */ 2093de981aecSAdrian Chadd uint8_t * 209468e8e04eSSam Leffler ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) 20951a1e1d21SSam Leffler { 20961a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 20971a1e1d21SSam Leffler *frm++ = len; 20981a1e1d21SSam Leffler memcpy(frm, ssid, len); 20991a1e1d21SSam Leffler return frm + len; 21001a1e1d21SSam Leffler } 21011a1e1d21SSam Leffler 21028a1b9b6aSSam Leffler /* 21038a1b9b6aSSam Leffler * Add an erp element to a frame. 21048a1b9b6aSSam Leffler */ 210568e8e04eSSam Leffler static uint8_t * 2106f1481c8dSAdrian Chadd ieee80211_add_erp(uint8_t *frm, struct ieee80211vap *vap) 21071a1e1d21SSam Leffler { 2108f1481c8dSAdrian Chadd struct ieee80211com *ic = vap->iv_ic; 210968e8e04eSSam Leffler uint8_t erp; 21101a1e1d21SSam Leffler 21118a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_ERP; 21128a1b9b6aSSam Leffler *frm++ = 1; 21138a1b9b6aSSam Leffler erp = 0; 2114f1481c8dSAdrian Chadd 2115f1481c8dSAdrian Chadd /* 2116f1481c8dSAdrian Chadd * TODO: This uses the global flags for now because 2117f1481c8dSAdrian Chadd * the per-VAP flags are fine for per-VAP, but don't 2118f1481c8dSAdrian Chadd * take into account which VAPs share the same channel 2119f1481c8dSAdrian Chadd * and which are on different channels. 2120f1481c8dSAdrian Chadd * 2121f1481c8dSAdrian Chadd * ERP and HT/VHT protection mode is a function of 2122f1481c8dSAdrian Chadd * how many stations are on a channel, not specifically 2123f1481c8dSAdrian Chadd * the VAP or global. But, until we grow that status, 2124f1481c8dSAdrian Chadd * the global flag will have to do. 2125f1481c8dSAdrian Chadd */ 2126f1481c8dSAdrian Chadd if (ic->ic_flags_ext & IEEE80211_FEXT_NONERP_PR) 21278a1b9b6aSSam Leffler erp |= IEEE80211_ERP_NON_ERP_PRESENT; 2128f1481c8dSAdrian Chadd 2129f1481c8dSAdrian Chadd /* 2130f1481c8dSAdrian Chadd * TODO: same as above; these should be based not 2131f1481c8dSAdrian Chadd * on the vap or ic flags, but instead on a combination 2132f1481c8dSAdrian Chadd * of per-VAP and channels. 2133f1481c8dSAdrian Chadd */ 21348a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEPROT) 21358a1b9b6aSSam Leffler erp |= IEEE80211_ERP_USE_PROTECTION; 21368a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEBARKER) 21378a1b9b6aSSam Leffler erp |= IEEE80211_ERP_LONG_PREAMBLE; 21388a1b9b6aSSam Leffler *frm++ = erp; 21398a1b9b6aSSam Leffler return frm; 21401a1e1d21SSam Leffler } 21411a1e1d21SSam Leffler 21428a1b9b6aSSam Leffler /* 2143b032f27cSSam Leffler * Add a CFParams element to a frame. 21448a1b9b6aSSam Leffler */ 214568e8e04eSSam Leffler static uint8_t * 2146b032f27cSSam Leffler ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) 21478a1b9b6aSSam Leffler { 2148b032f27cSSam Leffler #define ADDSHORT(frm, v) do { \ 214931021a2bSAndriy Voskoboinyk le16enc(frm, v); \ 2150b032f27cSSam Leffler frm += 2; \ 2151b032f27cSSam Leffler } while (0) 2152b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_CFPARMS; 2153b032f27cSSam Leffler *frm++ = 6; 2154b032f27cSSam Leffler *frm++ = 0; /* CFP count */ 2155b032f27cSSam Leffler *frm++ = 2; /* CFP period */ 2156b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ 2157b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ 21588a1b9b6aSSam Leffler return frm; 2159b032f27cSSam Leffler #undef ADDSHORT 2160b032f27cSSam Leffler } 2161b032f27cSSam Leffler 2162b032f27cSSam Leffler static __inline uint8_t * 2163b032f27cSSam Leffler add_appie(uint8_t *frm, const struct ieee80211_appie *ie) 2164b032f27cSSam Leffler { 2165b032f27cSSam Leffler memcpy(frm, ie->ie_data, ie->ie_len); 2166b032f27cSSam Leffler return frm + ie->ie_len; 2167b032f27cSSam Leffler } 2168b032f27cSSam Leffler 2169b032f27cSSam Leffler static __inline uint8_t * 2170b032f27cSSam Leffler add_ie(uint8_t *frm, const uint8_t *ie) 2171b032f27cSSam Leffler { 2172b032f27cSSam Leffler memcpy(frm, ie, 2 + ie[1]); 2173b032f27cSSam Leffler return frm + 2 + ie[1]; 21748a1b9b6aSSam Leffler } 21758a1b9b6aSSam Leffler 21768a1b9b6aSSam Leffler #define WME_OUI_BYTES 0x00, 0x50, 0xf2 21778a1b9b6aSSam Leffler /* 21788a1b9b6aSSam Leffler * Add a WME information element to a frame. 21798a1b9b6aSSam Leffler */ 21804eadefc2SAdrian Chadd uint8_t * 21818379e8dbSAdrian Chadd ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme, 21828379e8dbSAdrian Chadd struct ieee80211_node *ni) 21838a1b9b6aSSam Leffler { 21848379e8dbSAdrian Chadd static const uint8_t oui[4] = { WME_OUI_BYTES, WME_OUI_TYPE }; 21858379e8dbSAdrian Chadd struct ieee80211vap *vap = ni->ni_vap; 21868379e8dbSAdrian Chadd 21878379e8dbSAdrian Chadd *frm++ = IEEE80211_ELEMID_VENDOR; 21888379e8dbSAdrian Chadd *frm++ = sizeof(struct ieee80211_wme_info) - 2; 21898379e8dbSAdrian Chadd memcpy(frm, oui, sizeof(oui)); 21908379e8dbSAdrian Chadd frm += sizeof(oui); 21918379e8dbSAdrian Chadd *frm++ = WME_INFO_OUI_SUBTYPE; 21928379e8dbSAdrian Chadd *frm++ = WME_VERSION; 21938379e8dbSAdrian Chadd 21948379e8dbSAdrian Chadd /* QoS info field depends upon operating mode */ 21958379e8dbSAdrian Chadd switch (vap->iv_opmode) { 21968379e8dbSAdrian Chadd case IEEE80211_M_HOSTAP: 21978379e8dbSAdrian Chadd *frm = wme->wme_bssChanParams.cap_info; 21988379e8dbSAdrian Chadd if (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD) 21998379e8dbSAdrian Chadd *frm |= WME_CAPINFO_UAPSD_EN; 22008379e8dbSAdrian Chadd frm++; 22018379e8dbSAdrian Chadd break; 22028379e8dbSAdrian Chadd case IEEE80211_M_STA: 22038379e8dbSAdrian Chadd /* 22048379e8dbSAdrian Chadd * NB: UAPSD drivers must set this up in their 22058379e8dbSAdrian Chadd * VAP creation method. 22068379e8dbSAdrian Chadd */ 22078379e8dbSAdrian Chadd *frm++ = vap->iv_uapsdinfo; 22088379e8dbSAdrian Chadd break; 22098379e8dbSAdrian Chadd default: 22108379e8dbSAdrian Chadd *frm++ = 0; 22118379e8dbSAdrian Chadd break; 22128379e8dbSAdrian Chadd } 22138379e8dbSAdrian Chadd 22148379e8dbSAdrian Chadd return frm; 22158a1b9b6aSSam Leffler } 22168a1b9b6aSSam Leffler 22178a1b9b6aSSam Leffler /* 22188a1b9b6aSSam Leffler * Add a WME parameters element to a frame. 22198a1b9b6aSSam Leffler */ 222068e8e04eSSam Leffler static uint8_t * 22218379e8dbSAdrian Chadd ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme, 22228379e8dbSAdrian Chadd int uapsd_enable) 22238a1b9b6aSSam Leffler { 22248a1b9b6aSSam Leffler #define ADDSHORT(frm, v) do { \ 222531021a2bSAndriy Voskoboinyk le16enc(frm, v); \ 22268a1b9b6aSSam Leffler frm += 2; \ 22278a1b9b6aSSam Leffler } while (0) 22288a1b9b6aSSam Leffler /* NB: this works 'cuz a param has an info at the front */ 22298a1b9b6aSSam Leffler static const struct ieee80211_wme_info param = { 22308a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 22318a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_param) - 2, 22328a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 22338a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 22348a1b9b6aSSam Leffler .wme_subtype = WME_PARAM_OUI_SUBTYPE, 22358a1b9b6aSSam Leffler .wme_version = WME_VERSION, 22368a1b9b6aSSam Leffler }; 22378a1b9b6aSSam Leffler int i; 22388a1b9b6aSSam Leffler 22398a1b9b6aSSam Leffler memcpy(frm, ¶m, sizeof(param)); 22408a1b9b6aSSam Leffler frm += __offsetof(struct ieee80211_wme_info, wme_info); 22418379e8dbSAdrian Chadd *frm = wme->wme_bssChanParams.cap_info; /* AC info */ 22428379e8dbSAdrian Chadd if (uapsd_enable) 22438379e8dbSAdrian Chadd *frm |= WME_CAPINFO_UAPSD_EN; 22448379e8dbSAdrian Chadd frm++; 22458a1b9b6aSSam Leffler *frm++ = 0; /* reserved field */ 22468379e8dbSAdrian Chadd /* XXX TODO - U-APSD bits - SP, flags below */ 22478a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 22488a1b9b6aSSam Leffler const struct wmeParams *ac = 22498a1b9b6aSSam Leffler &wme->wme_bssChanParams.cap_wmeParams[i]; 2250fe5ebb23SBjoern A. Zeeb *frm++ = _IEEE80211_SHIFTMASK(i, WME_PARAM_ACI) 2251fe5ebb23SBjoern A. Zeeb | _IEEE80211_SHIFTMASK(ac->wmep_acm, WME_PARAM_ACM) 2252fe5ebb23SBjoern A. Zeeb | _IEEE80211_SHIFTMASK(ac->wmep_aifsn, WME_PARAM_AIFSN) 22538a1b9b6aSSam Leffler ; 2254fe5ebb23SBjoern A. Zeeb *frm++ = _IEEE80211_SHIFTMASK(ac->wmep_logcwmax, 2255fe5ebb23SBjoern A. Zeeb WME_PARAM_LOGCWMAX) 2256fe5ebb23SBjoern A. Zeeb | _IEEE80211_SHIFTMASK(ac->wmep_logcwmin, 2257fe5ebb23SBjoern A. Zeeb WME_PARAM_LOGCWMIN) 22588a1b9b6aSSam Leffler ; 22598a1b9b6aSSam Leffler ADDSHORT(frm, ac->wmep_txopLimit); 22608a1b9b6aSSam Leffler } 22618a1b9b6aSSam Leffler return frm; 22628a1b9b6aSSam Leffler #undef ADDSHORT 22638a1b9b6aSSam Leffler } 22648a1b9b6aSSam Leffler #undef WME_OUI_BYTES 22658a1b9b6aSSam Leffler 22660a915fadSSam Leffler /* 2267b032f27cSSam Leffler * Add an 11h Power Constraint element to a frame. 2268b032f27cSSam Leffler */ 2269b032f27cSSam Leffler static uint8_t * 2270b032f27cSSam Leffler ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) 2271b032f27cSSam Leffler { 2272b032f27cSSam Leffler const struct ieee80211_channel *c = vap->iv_bss->ni_chan; 2273b032f27cSSam Leffler /* XXX per-vap tx power limit? */ 2274b032f27cSSam Leffler int8_t limit = vap->iv_ic->ic_txpowlimit / 2; 2275b032f27cSSam Leffler 2276b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCNSTR; 2277b032f27cSSam Leffler frm[1] = 1; 2278b032f27cSSam Leffler frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; 2279b032f27cSSam Leffler return frm + 3; 2280b032f27cSSam Leffler } 2281b032f27cSSam Leffler 2282b032f27cSSam Leffler /* 2283b032f27cSSam Leffler * Add an 11h Power Capability element to a frame. 2284b032f27cSSam Leffler */ 2285b032f27cSSam Leffler static uint8_t * 2286b032f27cSSam Leffler ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) 2287b032f27cSSam Leffler { 2288b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCAP; 2289b032f27cSSam Leffler frm[1] = 2; 2290b032f27cSSam Leffler frm[2] = c->ic_minpower; 2291b032f27cSSam Leffler frm[3] = c->ic_maxpower; 2292b032f27cSSam Leffler return frm + 4; 2293b032f27cSSam Leffler } 2294b032f27cSSam Leffler 2295b032f27cSSam Leffler /* 2296b032f27cSSam Leffler * Add an 11h Supported Channels element to a frame. 2297b032f27cSSam Leffler */ 2298b032f27cSSam Leffler static uint8_t * 2299b032f27cSSam Leffler ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) 2300b032f27cSSam Leffler { 2301b032f27cSSam Leffler static const int ielen = 26; 2302b032f27cSSam Leffler 2303b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_SUPPCHAN; 2304b032f27cSSam Leffler frm[1] = ielen; 2305b032f27cSSam Leffler /* XXX not correct */ 2306b032f27cSSam Leffler memcpy(frm+2, ic->ic_chan_avail, ielen); 2307b032f27cSSam Leffler return frm + 2 + ielen; 2308b032f27cSSam Leffler } 2309b032f27cSSam Leffler 2310b032f27cSSam Leffler /* 231132b0e64bSAdrian Chadd * Add an 11h Quiet time element to a frame. 231232b0e64bSAdrian Chadd */ 231332b0e64bSAdrian Chadd static uint8_t * 2314ce4552cdSAdrian Chadd ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap, int update) 231532b0e64bSAdrian Chadd { 231632b0e64bSAdrian Chadd struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm; 231732b0e64bSAdrian Chadd 231832b0e64bSAdrian Chadd quiet->quiet_ie = IEEE80211_ELEMID_QUIET; 231932b0e64bSAdrian Chadd quiet->len = 6; 2320ce4552cdSAdrian Chadd 2321ce4552cdSAdrian Chadd /* 2322ce4552cdSAdrian Chadd * Only update every beacon interval - otherwise probe responses 2323ce4552cdSAdrian Chadd * would update the quiet count value. 2324ce4552cdSAdrian Chadd */ 2325ce4552cdSAdrian Chadd if (update) { 232632b0e64bSAdrian Chadd if (vap->iv_quiet_count_value == 1) 232732b0e64bSAdrian Chadd vap->iv_quiet_count_value = vap->iv_quiet_count; 232832b0e64bSAdrian Chadd else if (vap->iv_quiet_count_value > 1) 232932b0e64bSAdrian Chadd vap->iv_quiet_count_value--; 2330ce4552cdSAdrian Chadd } 233132b0e64bSAdrian Chadd 233232b0e64bSAdrian Chadd if (vap->iv_quiet_count_value == 0) { 233332b0e64bSAdrian Chadd /* value 0 is reserved as per 802.11h standerd */ 233432b0e64bSAdrian Chadd vap->iv_quiet_count_value = 1; 233532b0e64bSAdrian Chadd } 233632b0e64bSAdrian Chadd 233732b0e64bSAdrian Chadd quiet->tbttcount = vap->iv_quiet_count_value; 233832b0e64bSAdrian Chadd quiet->period = vap->iv_quiet_period; 233932b0e64bSAdrian Chadd quiet->duration = htole16(vap->iv_quiet_duration); 234032b0e64bSAdrian Chadd quiet->offset = htole16(vap->iv_quiet_offset); 234132b0e64bSAdrian Chadd return frm + sizeof(*quiet); 234232b0e64bSAdrian Chadd } 234332b0e64bSAdrian Chadd 234432b0e64bSAdrian Chadd /* 2345b032f27cSSam Leffler * Add an 11h Channel Switch Announcement element to a frame. 2346b032f27cSSam Leffler * Note that we use the per-vap CSA count to adjust the global 2347b032f27cSSam Leffler * counter so we can use this routine to form probe response 2348b032f27cSSam Leffler * frames and get the current count. 2349b032f27cSSam Leffler */ 2350b032f27cSSam Leffler static uint8_t * 2351b032f27cSSam Leffler ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) 2352b032f27cSSam Leffler { 2353b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 2354b032f27cSSam Leffler struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; 2355b032f27cSSam Leffler 2356c70761e6SSam Leffler csa->csa_ie = IEEE80211_ELEMID_CSA; 2357b032f27cSSam Leffler csa->csa_len = 3; 2358b032f27cSSam Leffler csa->csa_mode = 1; /* XXX force quiet on channel */ 2359b032f27cSSam Leffler csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); 2360b032f27cSSam Leffler csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; 2361b032f27cSSam Leffler return frm + sizeof(*csa); 2362b032f27cSSam Leffler } 2363b032f27cSSam Leffler 2364b032f27cSSam Leffler /* 2365b032f27cSSam Leffler * Add an 11h country information element to a frame. 2366b032f27cSSam Leffler */ 2367b032f27cSSam Leffler static uint8_t * 2368b032f27cSSam Leffler ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) 2369b032f27cSSam Leffler { 2370b032f27cSSam Leffler 2371b032f27cSSam Leffler if (ic->ic_countryie == NULL || 2372b032f27cSSam Leffler ic->ic_countryie_chan != ic->ic_bsschan) { 2373b032f27cSSam Leffler /* 2374b032f27cSSam Leffler * Handle lazy construction of ie. This is done on 2375b032f27cSSam Leffler * first use and after a channel change that requires 2376b032f27cSSam Leffler * re-calculation. 2377b032f27cSSam Leffler */ 2378b032f27cSSam Leffler if (ic->ic_countryie != NULL) 2379b9b53389SAdrian Chadd IEEE80211_FREE(ic->ic_countryie, M_80211_NODE_IE); 2380b032f27cSSam Leffler ic->ic_countryie = ieee80211_alloc_countryie(ic); 2381b032f27cSSam Leffler if (ic->ic_countryie == NULL) 2382b032f27cSSam Leffler return frm; 2383b032f27cSSam Leffler ic->ic_countryie_chan = ic->ic_bsschan; 2384b032f27cSSam Leffler } 2385b032f27cSSam Leffler return add_appie(frm, ic->ic_countryie); 2386b032f27cSSam Leffler } 2387b032f27cSSam Leffler 2388d8df5f3dSRui Paulo uint8_t * 2389d8df5f3dSRui Paulo ieee80211_add_wpa(uint8_t *frm, const struct ieee80211vap *vap) 2390d8df5f3dSRui Paulo { 2391d8df5f3dSRui Paulo if (vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL) 2392d8df5f3dSRui Paulo return (add_ie(frm, vap->iv_wpa_ie)); 2393d8df5f3dSRui Paulo else { 2394d8df5f3dSRui Paulo /* XXX else complain? */ 2395d8df5f3dSRui Paulo return (frm); 2396d8df5f3dSRui Paulo } 2397d8df5f3dSRui Paulo } 2398d8df5f3dSRui Paulo 2399d8df5f3dSRui Paulo uint8_t * 2400d8df5f3dSRui Paulo ieee80211_add_rsn(uint8_t *frm, const struct ieee80211vap *vap) 2401d8df5f3dSRui Paulo { 2402d8df5f3dSRui Paulo if (vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL) 2403d8df5f3dSRui Paulo return (add_ie(frm, vap->iv_rsn_ie)); 2404d8df5f3dSRui Paulo else { 2405d8df5f3dSRui Paulo /* XXX else complain? */ 2406d8df5f3dSRui Paulo return (frm); 2407d8df5f3dSRui Paulo } 2408d8df5f3dSRui Paulo } 2409d8df5f3dSRui Paulo 2410d8df5f3dSRui Paulo uint8_t * 2411d8df5f3dSRui Paulo ieee80211_add_qos(uint8_t *frm, const struct ieee80211_node *ni) 2412d8df5f3dSRui Paulo { 2413d8df5f3dSRui Paulo if (ni->ni_flags & IEEE80211_NODE_QOS) { 2414d8df5f3dSRui Paulo *frm++ = IEEE80211_ELEMID_QOS; 2415d8df5f3dSRui Paulo *frm++ = 1; 2416d8df5f3dSRui Paulo *frm++ = 0; 2417d8df5f3dSRui Paulo } 2418d8df5f3dSRui Paulo 2419d8df5f3dSRui Paulo return (frm); 2420d8df5f3dSRui Paulo } 2421d8df5f3dSRui Paulo 2422b032f27cSSam Leffler /* 2423c338cf2cSBjoern A. Zeeb * ieee80211_send_probereq(): send a probe request frame with the specified ssid 2424c338cf2cSBjoern A. Zeeb * and any optional information element data; some helper functions as FW based 2425c338cf2cSBjoern A. Zeeb * HW scans need some of that information passed too. 2426af8418dcSSam Leffler */ 2427c338cf2cSBjoern A. Zeeb static uint32_t 2428c338cf2cSBjoern A. Zeeb ieee80211_probereq_ie_len(struct ieee80211vap *vap, struct ieee80211com *ic) 2429af8418dcSSam Leffler { 243041b3c790SSam Leffler const struct ieee80211_rateset *rs; 2431af8418dcSSam Leffler 2432c338cf2cSBjoern A. Zeeb rs = ieee80211_get_suprates(ic, ic->ic_curchan); 2433af8418dcSSam Leffler 2434af8418dcSSam Leffler /* 2435af8418dcSSam Leffler * prreq frame format 2436af8418dcSSam Leffler * [tlv] ssid 2437af8418dcSSam Leffler * [tlv] supported rates 2438b032f27cSSam Leffler * [tlv] RSN (optional) 2439c338cf2cSBjoern A. Zeeb * [tlv] extended supported rates (if needed) 2440f8a67728SAdrian Chadd * [tlv] HT cap (optional) 244151172f62SAdrian Chadd * [tlv] VHT cap (optional) 2442b032f27cSSam Leffler * [tlv] WPA (optional) 2443af8418dcSSam Leffler * [tlv] user-specified ie's 2444af8418dcSSam Leffler */ 2445c338cf2cSBjoern A. Zeeb return ( 2 + IEEE80211_NWID_LEN 2446af8418dcSSam Leffler + 2 + IEEE80211_RATE_SIZE 2447c338cf2cSBjoern A. Zeeb + ((vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL) ? 2448c338cf2cSBjoern A. Zeeb vap->iv_rsn_ie[1] : 0) 2449c338cf2cSBjoern A. Zeeb + ((rs->rs_nrates > IEEE80211_RATE_SIZE) ? 2450c338cf2cSBjoern A. Zeeb 2 + (rs->rs_nrates - IEEE80211_RATE_SIZE) : 0) 2451c338cf2cSBjoern A. Zeeb + (((vap->iv_opmode == IEEE80211_M_IBSS) && 2452c338cf2cSBjoern A. Zeeb (vap->iv_flags_ht & IEEE80211_FHT_HT)) ? 2453c338cf2cSBjoern A. Zeeb sizeof(struct ieee80211_ie_htcap) : 0) 2454c338cf2cSBjoern A. Zeeb #ifdef notyet 245551172f62SAdrian Chadd + sizeof(struct ieee80211_ie_htinfo) /* XXX not needed? */ 2456c338cf2cSBjoern A. Zeeb + sizeof(struct ieee80211_ie_vhtcap) 2457c338cf2cSBjoern A. Zeeb #endif 2458c338cf2cSBjoern A. Zeeb + ((vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL) ? 2459c338cf2cSBjoern A. Zeeb vap->iv_wpa_ie[1] : 0) 2460b032f27cSSam Leffler + (vap->iv_appie_probereq != NULL ? 2461b032f27cSSam Leffler vap->iv_appie_probereq->ie_len : 0) 2462af8418dcSSam Leffler ); 2463af8418dcSSam Leffler } 2464af8418dcSSam Leffler 2465c338cf2cSBjoern A. Zeeb int 2466c338cf2cSBjoern A. Zeeb ieee80211_probereq_ie(struct ieee80211vap *vap, struct ieee80211com *ic, 2467c338cf2cSBjoern A. Zeeb uint8_t **frmp, uint32_t *frmlen, const uint8_t *ssid, size_t ssidlen, 2468c338cf2cSBjoern A. Zeeb bool alloc) 2469c338cf2cSBjoern A. Zeeb { 2470c338cf2cSBjoern A. Zeeb const struct ieee80211_rateset *rs; 2471c338cf2cSBjoern A. Zeeb uint8_t *frm; 2472c338cf2cSBjoern A. Zeeb uint32_t len; 2473c338cf2cSBjoern A. Zeeb 2474c338cf2cSBjoern A. Zeeb if (!alloc && (frmp == NULL || frmlen == NULL)) 2475c338cf2cSBjoern A. Zeeb return (EINVAL); 2476c338cf2cSBjoern A. Zeeb 2477c338cf2cSBjoern A. Zeeb len = ieee80211_probereq_ie_len(vap, ic); 2478c338cf2cSBjoern A. Zeeb if (!alloc && len > *frmlen) 2479c338cf2cSBjoern A. Zeeb return (ENOBUFS); 2480c338cf2cSBjoern A. Zeeb 2481243b9597SBjoern A. Zeeb /* For HW scans we usually do not pass in the SSID as IE. */ 2482243b9597SBjoern A. Zeeb if (ssidlen == -1) 2483243b9597SBjoern A. Zeeb len -= (2 + IEEE80211_NWID_LEN); 2484243b9597SBjoern A. Zeeb 2485c338cf2cSBjoern A. Zeeb if (alloc) { 2486c338cf2cSBjoern A. Zeeb frm = malloc(len, M_80211_VAP, M_WAITOK | M_ZERO); 2487c338cf2cSBjoern A. Zeeb *frmp = frm; 2488c338cf2cSBjoern A. Zeeb *frmlen = len; 2489c338cf2cSBjoern A. Zeeb } else 2490c338cf2cSBjoern A. Zeeb frm = *frmp; 2491c338cf2cSBjoern A. Zeeb 2492243b9597SBjoern A. Zeeb if (ssidlen != -1) 2493af8418dcSSam Leffler frm = ieee80211_add_ssid(frm, ssid, ssidlen); 249441b3c790SSam Leffler rs = ieee80211_get_suprates(ic, ic->ic_curchan); 249541b3c790SSam Leffler frm = ieee80211_add_rates(frm, rs); 2496d8df5f3dSRui Paulo frm = ieee80211_add_rsn(frm, vap); 2497b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2498f8a67728SAdrian Chadd 2499f8a67728SAdrian Chadd /* 2500f8a67728SAdrian Chadd * Note: we can't use bss; we don't have one yet. 2501f8a67728SAdrian Chadd * 2502f8a67728SAdrian Chadd * So, we should announce our capabilities 2503f8a67728SAdrian Chadd * in this channel mode (2g/5g), not the 2504f8a67728SAdrian Chadd * channel details itself. 2505f8a67728SAdrian Chadd */ 2506f8a67728SAdrian Chadd if ((vap->iv_opmode == IEEE80211_M_IBSS) && 2507f8a67728SAdrian Chadd (vap->iv_flags_ht & IEEE80211_FHT_HT)) { 2508f8a67728SAdrian Chadd struct ieee80211_channel *c; 2509f8a67728SAdrian Chadd 2510f8a67728SAdrian Chadd /* 2511f8a67728SAdrian Chadd * Get the HT channel that we should try upgrading to. 2512f8a67728SAdrian Chadd * If we can do 40MHz then this'll upgrade it appropriately. 2513f8a67728SAdrian Chadd */ 2514f8a67728SAdrian Chadd c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, 2515f8a67728SAdrian Chadd vap->iv_flags_ht); 2516f8a67728SAdrian Chadd frm = ieee80211_add_htcap_ch(frm, vap, c); 2517f8a67728SAdrian Chadd } 2518f8a67728SAdrian Chadd 251951172f62SAdrian Chadd /* 252051172f62SAdrian Chadd * XXX TODO: need to figure out what/how to update the 252151172f62SAdrian Chadd * VHT channel. 252251172f62SAdrian Chadd */ 2523c338cf2cSBjoern A. Zeeb #ifdef notyet 2524c338cf2cSBjoern A. Zeeb if (vap->iv_flags_vht & IEEE80211_FVHT_VHT) { 252551172f62SAdrian Chadd struct ieee80211_channel *c; 252651172f62SAdrian Chadd 252751172f62SAdrian Chadd c = ieee80211_ht_adjust_channel(ic, ic->ic_curchan, 252851172f62SAdrian Chadd vap->iv_flags_ht); 252951172f62SAdrian Chadd c = ieee80211_vht_adjust_channel(ic, c, vap->iv_flags_vht); 253051172f62SAdrian Chadd frm = ieee80211_add_vhtcap_ch(frm, vap, c); 253151172f62SAdrian Chadd } 253251172f62SAdrian Chadd #endif 253351172f62SAdrian Chadd 2534d8df5f3dSRui Paulo frm = ieee80211_add_wpa(frm, vap); 2535b032f27cSSam Leffler if (vap->iv_appie_probereq != NULL) 2536b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_probereq); 2537af8418dcSSam Leffler 2538c338cf2cSBjoern A. Zeeb if (!alloc) { 2539c338cf2cSBjoern A. Zeeb *frmp = frm; 2540c338cf2cSBjoern A. Zeeb *frmlen = len; 2541c338cf2cSBjoern A. Zeeb } 2542c338cf2cSBjoern A. Zeeb 2543c338cf2cSBjoern A. Zeeb return (0); 2544c338cf2cSBjoern A. Zeeb } 2545c338cf2cSBjoern A. Zeeb 2546c338cf2cSBjoern A. Zeeb int 2547c338cf2cSBjoern A. Zeeb ieee80211_send_probereq(struct ieee80211_node *ni, 2548c338cf2cSBjoern A. Zeeb const uint8_t sa[IEEE80211_ADDR_LEN], 2549c338cf2cSBjoern A. Zeeb const uint8_t da[IEEE80211_ADDR_LEN], 2550c338cf2cSBjoern A. Zeeb const uint8_t bssid[IEEE80211_ADDR_LEN], 2551c338cf2cSBjoern A. Zeeb const uint8_t *ssid, size_t ssidlen) 2552c338cf2cSBjoern A. Zeeb { 2553c338cf2cSBjoern A. Zeeb struct ieee80211vap *vap = ni->ni_vap; 2554c338cf2cSBjoern A. Zeeb struct ieee80211com *ic = ni->ni_ic; 2555c338cf2cSBjoern A. Zeeb struct ieee80211_node *bss; 2556c338cf2cSBjoern A. Zeeb const struct ieee80211_txparam *tp; 2557c338cf2cSBjoern A. Zeeb struct ieee80211_bpf_params params; 2558c338cf2cSBjoern A. Zeeb struct mbuf *m; 2559c338cf2cSBjoern A. Zeeb uint8_t *frm; 2560c338cf2cSBjoern A. Zeeb uint32_t frmlen; 2561c338cf2cSBjoern A. Zeeb int ret; 2562c338cf2cSBjoern A. Zeeb 2563c338cf2cSBjoern A. Zeeb bss = ieee80211_ref_node(vap->iv_bss); 2564c338cf2cSBjoern A. Zeeb 2565c338cf2cSBjoern A. Zeeb if (vap->iv_state == IEEE80211_S_CAC) { 2566c338cf2cSBjoern A. Zeeb IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 2567c338cf2cSBjoern A. Zeeb "block %s frame in CAC state", "probe request"); 2568c338cf2cSBjoern A. Zeeb vap->iv_stats.is_tx_badstate++; 2569c338cf2cSBjoern A. Zeeb ieee80211_free_node(bss); 2570c338cf2cSBjoern A. Zeeb return EIO; /* XXX */ 2571c338cf2cSBjoern A. Zeeb } 2572c338cf2cSBjoern A. Zeeb 2573c338cf2cSBjoern A. Zeeb /* 2574c338cf2cSBjoern A. Zeeb * Hold a reference on the node so it doesn't go away until after 2575c338cf2cSBjoern A. Zeeb * the xmit is complete all the way in the driver. On error we 2576c338cf2cSBjoern A. Zeeb * will remove our reference. 2577c338cf2cSBjoern A. Zeeb */ 2578c338cf2cSBjoern A. Zeeb IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 2579c338cf2cSBjoern A. Zeeb "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2580c338cf2cSBjoern A. Zeeb __func__, __LINE__, 2581c338cf2cSBjoern A. Zeeb ni, ether_sprintf(ni->ni_macaddr), 2582c338cf2cSBjoern A. Zeeb ieee80211_node_refcnt(ni)+1); 2583c338cf2cSBjoern A. Zeeb ieee80211_ref_node(ni); 2584c338cf2cSBjoern A. Zeeb 2585c338cf2cSBjoern A. Zeeb /* See comments above for entire frame format. */ 2586c338cf2cSBjoern A. Zeeb frmlen = ieee80211_probereq_ie_len(vap, ic); 2587c338cf2cSBjoern A. Zeeb m = ieee80211_getmgtframe(&frm, 2588c338cf2cSBjoern A. Zeeb ic->ic_headroom + sizeof(struct ieee80211_frame), frmlen); 2589c338cf2cSBjoern A. Zeeb if (m == NULL) { 2590c338cf2cSBjoern A. Zeeb vap->iv_stats.is_tx_nobuf++; 2591c338cf2cSBjoern A. Zeeb ieee80211_free_node(ni); 2592c338cf2cSBjoern A. Zeeb ieee80211_free_node(bss); 2593c338cf2cSBjoern A. Zeeb return ENOMEM; 2594c338cf2cSBjoern A. Zeeb } 2595c338cf2cSBjoern A. Zeeb 2596c338cf2cSBjoern A. Zeeb ret = ieee80211_probereq_ie(vap, ic, &frm, &frmlen, ssid, ssidlen, 2597c338cf2cSBjoern A. Zeeb false); 2598c338cf2cSBjoern A. Zeeb KASSERT(ret == 0, 259949c220b0SBjoern A. Zeeb ("%s: ieee80211_probereq_ie failed: %d\n", __func__, ret)); 2600c338cf2cSBjoern A. Zeeb 2601c338cf2cSBjoern A. Zeeb m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 260216d7cbb1SSam Leffler KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), 260316d7cbb1SSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 2604eb1b1807SGleb Smirnoff M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 260516d7cbb1SSam Leffler if (m == NULL) { 260616d7cbb1SSam Leffler /* NB: cannot happen */ 260716d7cbb1SSam Leffler ieee80211_free_node(ni); 2608f8a67728SAdrian Chadd ieee80211_free_node(bss); 2609af8418dcSSam Leffler return ENOMEM; 261016d7cbb1SSam Leffler } 2611af8418dcSSam Leffler 26125cda6006SAdrian Chadd IEEE80211_TX_LOCK(ic); 26139e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 2614af8418dcSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 26158ac160cdSSam Leffler IEEE80211_NONQOS_TID, sa, da, bssid); 2616af8418dcSSam Leffler /* XXX power management? */ 2617c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 2618af8418dcSSam Leffler 2619b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 2620b032f27cSSam Leffler 2621af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_probereq); 2622af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 2623af8418dcSSam Leffler 2624b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 2625f8a67728SAdrian Chadd "send probe req on channel %u bssid %s sa %6D da %6D ssid \"%.*s\"\n", 2626f8a67728SAdrian Chadd ieee80211_chan2ieee(ic, ic->ic_curchan), 2627f8a67728SAdrian Chadd ether_sprintf(bssid), 2628f8a67728SAdrian Chadd sa, ":", 2629f8a67728SAdrian Chadd da, ":", 2630b032f27cSSam Leffler ssidlen, ssid); 2631af8418dcSSam Leffler 263216d7cbb1SSam Leffler memset(¶ms, 0, sizeof(params)); 263316d7cbb1SSam Leffler params.ibp_pri = M_WME_GETAC(m); 263416d7cbb1SSam Leffler tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 263516d7cbb1SSam Leffler params.ibp_rate0 = tp->mgmtrate; 263616d7cbb1SSam Leffler if (IEEE80211_IS_MULTICAST(da)) { 263716d7cbb1SSam Leffler params.ibp_flags |= IEEE80211_BPF_NOACK; 263816d7cbb1SSam Leffler params.ibp_try0 = 1; 263916d7cbb1SSam Leffler } else 264016d7cbb1SSam Leffler params.ibp_try0 = tp->maxretry; 264116d7cbb1SSam Leffler params.ibp_power = ni->ni_txpower; 26425cda6006SAdrian Chadd ret = ieee80211_raw_output(vap, ni, m, ¶ms); 26435cda6006SAdrian Chadd IEEE80211_TX_UNLOCK(ic); 2644f8a67728SAdrian Chadd ieee80211_free_node(bss); 26455cda6006SAdrian Chadd return (ret); 2646af8418dcSSam Leffler } 2647af8418dcSSam Leffler 2648af8418dcSSam Leffler /* 2649667dad55SSam Leffler * Calculate capability information for mgt frames. 2650667dad55SSam Leffler */ 265159aa14a9SRui Paulo uint16_t 265259aa14a9SRui Paulo ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) 2653667dad55SSam Leffler { 265468e8e04eSSam Leffler uint16_t capinfo; 2655667dad55SSam Leffler 2656b032f27cSSam Leffler KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); 2657667dad55SSam Leffler 2658b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2659667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 2660b032f27cSSam Leffler else if (vap->iv_opmode == IEEE80211_M_IBSS) 2661667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_IBSS; 2662667dad55SSam Leffler else 2663667dad55SSam Leffler capinfo = 0; 2664b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 2665667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 2666f1481c8dSAdrian Chadd if ((vap->iv_flags & IEEE80211_F_SHPREAMBLE) && 2667667dad55SSam Leffler IEEE80211_IS_CHAN_2GHZ(chan)) 2668667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 2669d20ff6e6SAdrian Chadd if (vap->iv_flags & IEEE80211_F_SHSLOT) 2670667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 2671b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) 2672b032f27cSSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 2673667dad55SSam Leffler return capinfo; 2674667dad55SSam Leffler } 2675667dad55SSam Leffler 2676667dad55SSam Leffler /* 26770a915fadSSam Leffler * Send a management frame. The node is for the destination (or ic_bss 26780a915fadSSam Leffler * when in station mode). Nodes other than ic_bss have their reference 26790a915fadSSam Leffler * count bumped to reflect our use for an indeterminant time. 26800a915fadSSam Leffler */ 26811a1e1d21SSam Leffler int 2682b032f27cSSam Leffler ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) 26831a1e1d21SSam Leffler { 26841b6167d2SSam Leffler #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) 2685b032f27cSSam Leffler #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) 2686b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2687b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2688b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 26898ac160cdSSam Leffler struct ieee80211_bpf_params params; 26901a1e1d21SSam Leffler struct mbuf *m; 269168e8e04eSSam Leffler uint8_t *frm; 269268e8e04eSSam Leffler uint16_t capinfo; 269368e8e04eSSam Leffler int has_challenge, is_shared_key, ret, status; 26941a1e1d21SSam Leffler 26950a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 26960a915fadSSam Leffler 26970a915fadSSam Leffler /* 26980a915fadSSam Leffler * Hold a reference on the node so it doesn't go away until after 26990a915fadSSam Leffler * the xmit is complete all the way in the driver. On error we 27000a915fadSSam Leffler * will remove our reference. 27010a915fadSSam Leffler */ 2702b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 270349a15236SSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 27048a1b9b6aSSam Leffler __func__, __LINE__, 270549a15236SSam Leffler ni, ether_sprintf(ni->ni_macaddr), 27068a1b9b6aSSam Leffler ieee80211_node_refcnt(ni)+1); 27070a915fadSSam Leffler ieee80211_ref_node(ni); 27088a1b9b6aSSam Leffler 27098ac160cdSSam Leffler memset(¶ms, 0, sizeof(params)); 27101a1e1d21SSam Leffler switch (type) { 27111a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 27128a1b9b6aSSam Leffler status = arg >> 16; 27138a1b9b6aSSam Leffler arg &= 0xffff; 27148a1b9b6aSSam Leffler has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 27158a1b9b6aSSam Leffler arg == IEEE80211_AUTH_SHARED_RESPONSE) && 27168a1b9b6aSSam Leffler ni->ni_challenge != NULL); 27178a1b9b6aSSam Leffler 27188a1b9b6aSSam Leffler /* 27198a1b9b6aSSam Leffler * Deduce whether we're doing open authentication or 27208a1b9b6aSSam Leffler * shared key authentication. We do the latter if 27218a1b9b6aSSam Leffler * we're in the middle of a shared key authentication 27228a1b9b6aSSam Leffler * handshake or if we're initiating an authentication 27238a1b9b6aSSam Leffler * request and configured to use shared key. 27248a1b9b6aSSam Leffler */ 27258a1b9b6aSSam Leffler is_shared_key = has_challenge || 27268a1b9b6aSSam Leffler arg >= IEEE80211_AUTH_SHARED_RESPONSE || 27278a1b9b6aSSam Leffler (arg == IEEE80211_AUTH_SHARED_REQUEST && 2728b032f27cSSam Leffler bss->ni_authmode == IEEE80211_AUTH_SHARED); 27298a1b9b6aSSam Leffler 27308a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 273168e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 273268e8e04eSSam Leffler 3 * sizeof(uint16_t) 27338a1b9b6aSSam Leffler + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 273449c220b0SBjoern A. Zeeb sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0)); 27351a1e1d21SSam Leffler if (m == NULL) 27368a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 27378a1b9b6aSSam Leffler 273868e8e04eSSam Leffler ((uint16_t *)frm)[0] = 27398a1b9b6aSSam Leffler (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) 27408a1b9b6aSSam Leffler : htole16(IEEE80211_AUTH_ALG_OPEN); 274168e8e04eSSam Leffler ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ 274268e8e04eSSam Leffler ((uint16_t *)frm)[2] = htole16(status);/* status */ 27438a1b9b6aSSam Leffler 27448a1b9b6aSSam Leffler if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 274568e8e04eSSam Leffler ((uint16_t *)frm)[3] = 27468a1b9b6aSSam Leffler htole16((IEEE80211_CHALLENGE_LEN << 8) | 27478a1b9b6aSSam Leffler IEEE80211_ELEMID_CHALLENGE); 274868e8e04eSSam Leffler memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, 27498a1b9b6aSSam Leffler IEEE80211_CHALLENGE_LEN); 27508a1b9b6aSSam Leffler m->m_pkthdr.len = m->m_len = 275168e8e04eSSam Leffler 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; 27528a1b9b6aSSam Leffler if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { 2753b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 2754b032f27cSSam Leffler "request encrypt frame (%s)", __func__); 27558ac160cdSSam Leffler /* mark frame for encryption */ 27568ac160cdSSam Leffler params.ibp_flags |= IEEE80211_BPF_CRYPTO; 27578a1b9b6aSSam Leffler } 27588a1b9b6aSSam Leffler } else 275968e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); 27608a1b9b6aSSam Leffler 27618a1b9b6aSSam Leffler /* XXX not right for shared key */ 27628a1b9b6aSSam Leffler if (status == IEEE80211_STATUS_SUCCESS) 27638a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth); 27648a1b9b6aSSam Leffler else 27658a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth_fail); 27668a1b9b6aSSam Leffler 2767b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA) 276868e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 2769b032f27cSSam Leffler (void *) vap->iv_state); 27701a1e1d21SSam Leffler break; 27711a1e1d21SSam Leffler 27721a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 2773b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 2774d72d72d3SAndriy Voskoboinyk "send station deauthenticate (reason: %d (%s))", arg, 2775d72d72d3SAndriy Voskoboinyk ieee80211_reason_to_string(arg)); 277668e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 277768e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 277868e8e04eSSam Leffler sizeof(uint16_t)); 27791a1e1d21SSam Leffler if (m == NULL) 27808a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 278168e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 278268e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 27838a1b9b6aSSam Leffler 27848a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_deauth); 27858a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); 27868a1b9b6aSSam Leffler 2787e4918ecdSSam Leffler ieee80211_node_unauthorize(ni); /* port closed */ 27881a1e1d21SSam Leffler break; 27891a1e1d21SSam Leffler 27901a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 27911a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 27921a1e1d21SSam Leffler /* 27931a1e1d21SSam Leffler * asreq frame format 27941a1e1d21SSam Leffler * [2] capability information 27951a1e1d21SSam Leffler * [2] listen interval 27961a1e1d21SSam Leffler * [6*] current AP address (reassoc only) 27971a1e1d21SSam Leffler * [tlv] ssid 27981a1e1d21SSam Leffler * [tlv] supported rates 27991a1e1d21SSam Leffler * [tlv] extended supported rates 2800b032f27cSSam Leffler * [4] power capability (optional) 2801b032f27cSSam Leffler * [28] supported channels (optional) 280268e8e04eSSam Leffler * [tlv] HT capabilities 280351172f62SAdrian Chadd * [tlv] VHT capabilities 2804b032f27cSSam Leffler * [tlv] WME (optional) 280568e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 280668e8e04eSSam Leffler * [tlv] Atheros capabilities (if negotiated) 2807b032f27cSSam Leffler * [tlv] AppIE's (optional) 28081a1e1d21SSam Leffler */ 28098a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 281068e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 281168e8e04eSSam Leffler sizeof(uint16_t) 281268e8e04eSSam Leffler + sizeof(uint16_t) 28131a1e1d21SSam Leffler + IEEE80211_ADDR_LEN 28148a1b9b6aSSam Leffler + 2 + IEEE80211_NWID_LEN 28151a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 28168a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2817b032f27cSSam Leffler + 4 2818b032f27cSSam Leffler + 2 + 26 28198a1b9b6aSSam Leffler + sizeof(struct ieee80211_wme_info) 2820b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 282151172f62SAdrian Chadd + sizeof(struct ieee80211_ie_vhtcap) 2822b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 2823616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 282468e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2825616190d0SSam Leffler #endif 2826b032f27cSSam Leffler + (vap->iv_appie_wpa != NULL ? 2827b032f27cSSam Leffler vap->iv_appie_wpa->ie_len : 0) 2828b032f27cSSam Leffler + (vap->iv_appie_assocreq != NULL ? 2829b032f27cSSam Leffler vap->iv_appie_assocreq->ie_len : 0) 28308a1b9b6aSSam Leffler ); 28311a1e1d21SSam Leffler if (m == NULL) 28328a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 28331a1e1d21SSam Leffler 2834b032f27cSSam Leffler KASSERT(vap->iv_opmode == IEEE80211_M_STA, 2835b032f27cSSam Leffler ("wrong mode %u", vap->iv_opmode)); 2836667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 2837b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 28381a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 28394f2e09c4SSam Leffler /* 28404f2e09c4SSam Leffler * NB: Some 11a AP's reject the request when 2841191ccdf5SAndriy Voskoboinyk * short preamble is set. 28424f2e09c4SSam Leffler */ 2843f1481c8dSAdrian Chadd if ((vap->iv_flags & IEEE80211_F_SHPREAMBLE) && 2844b5c99415SSam Leffler IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 28451a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 284668e8e04eSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 28478a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHSLOT)) 28481a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 28491b6167d2SSam Leffler if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && 2850b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_DOTH)) 28511b6167d2SSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 285268e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 28531a1e1d21SSam Leffler frm += 2; 28541a1e1d21SSam Leffler 2855b032f27cSSam Leffler KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); 285668e8e04eSSam Leffler *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, 2857b032f27cSSam Leffler bss->ni_intval)); 28581a1e1d21SSam Leffler frm += 2; 28591a1e1d21SSam Leffler 28601a1e1d21SSam Leffler if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 2861b032f27cSSam Leffler IEEE80211_ADDR_COPY(frm, bss->ni_bssid); 28621a1e1d21SSam Leffler frm += IEEE80211_ADDR_LEN; 28631a1e1d21SSam Leffler } 28641a1e1d21SSam Leffler 28651a1e1d21SSam Leffler frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 28661a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 2867d8df5f3dSRui Paulo frm = ieee80211_add_rsn(frm, vap); 2868b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 2869b032f27cSSam Leffler if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { 2870b032f27cSSam Leffler frm = ieee80211_add_powercapability(frm, 2871b032f27cSSam Leffler ic->ic_curchan); 2872b032f27cSSam Leffler frm = ieee80211_add_supportedchannels(frm, ic); 2873b032f27cSSam Leffler } 2874b83391bfSAdrian Chadd 2875b83391bfSAdrian Chadd /* 2876b83391bfSAdrian Chadd * Check the channel - we may be using an 11n NIC with an 2877b83391bfSAdrian Chadd * 11n capable station, but we're configured to be an 11b 2878b83391bfSAdrian Chadd * channel. 2879b83391bfSAdrian Chadd */ 28802bfc8a91SSam Leffler if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 2881b83391bfSAdrian Chadd IEEE80211_IS_CHAN_HT(ni->ni_chan) && 2882b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2883b83391bfSAdrian Chadd ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) { 2884b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, ni); 2885b83391bfSAdrian Chadd } 288651172f62SAdrian Chadd 288751172f62SAdrian Chadd if ((vap->iv_flags_vht & IEEE80211_FVHT_VHT) && 288851172f62SAdrian Chadd IEEE80211_IS_CHAN_VHT(ni->ni_chan) && 288951172f62SAdrian Chadd ni->ni_ies.vhtcap_ie != NULL && 289051172f62SAdrian Chadd ni->ni_ies.vhtcap_ie[0] == IEEE80211_ELEMID_VHT_CAP) { 289151172f62SAdrian Chadd frm = ieee80211_add_vhtcap(frm, ni); 289251172f62SAdrian Chadd } 289351172f62SAdrian Chadd 2894d8df5f3dSRui Paulo frm = ieee80211_add_wpa(frm, vap); 2895b032f27cSSam Leffler if ((ic->ic_flags & IEEE80211_F_WME) && 2896b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 28978379e8dbSAdrian Chadd frm = ieee80211_add_wme_info(frm, &ic->ic_wme, ni); 2898b83391bfSAdrian Chadd 2899b83391bfSAdrian Chadd /* 2900b83391bfSAdrian Chadd * Same deal - only send HT info if we're on an 11n 2901b83391bfSAdrian Chadd * capable channel. 2902b83391bfSAdrian Chadd */ 29032bfc8a91SSam Leffler if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 2904b83391bfSAdrian Chadd IEEE80211_IS_CHAN_HT(ni->ni_chan) && 2905b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2906b83391bfSAdrian Chadd ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) { 2907b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 2908b83391bfSAdrian Chadd } 2909616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 29104207227cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { 2911b032f27cSSam Leffler frm = ieee80211_add_ath(frm, 2912b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 29134207227cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 29144207227cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X) ? 29154207227cSSam Leffler vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 29164207227cSSam Leffler } 2917616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 2918b032f27cSSam Leffler if (vap->iv_appie_assocreq != NULL) 2919b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocreq); 292068e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 29211a1e1d21SSam Leffler 292268e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 2923b032f27cSSam Leffler (void *) vap->iv_state); 29241a1e1d21SSam Leffler break; 29251a1e1d21SSam Leffler 29261a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 29271a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 29281a1e1d21SSam Leffler /* 292968e8e04eSSam Leffler * asresp frame format 29301a1e1d21SSam Leffler * [2] capability information 29311a1e1d21SSam Leffler * [2] status 29321a1e1d21SSam Leffler * [2] association ID 29331a1e1d21SSam Leffler * [tlv] supported rates 29341a1e1d21SSam Leffler * [tlv] extended supported rates 2935b032f27cSSam Leffler * [tlv] HT capabilities (standard, if STA enabled) 2936b032f27cSSam Leffler * [tlv] HT information (standard, if STA enabled) 293751172f62SAdrian Chadd * [tlv] VHT capabilities (standard, if STA enabled) 293851172f62SAdrian Chadd * [tlv] VHT information (standard, if STA enabled) 2939b032f27cSSam Leffler * [tlv] WME (if configured and STA enabled) 2940b032f27cSSam Leffler * [tlv] HT capabilities (vendor OUI, if STA enabled) 2941b032f27cSSam Leffler * [tlv] HT information (vendor OUI, if STA enabled) 2942b032f27cSSam Leffler * [tlv] Atheros capabilities (if STA enabled) 2943b032f27cSSam Leffler * [tlv] AppIE's (optional) 29441a1e1d21SSam Leffler */ 29458a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 294668e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 294768e8e04eSSam Leffler sizeof(uint16_t) 294868e8e04eSSam Leffler + sizeof(uint16_t) 294968e8e04eSSam Leffler + sizeof(uint16_t) 29501a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 29518a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 295268e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htcap) + 4 295368e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htinfo) + 4 295451172f62SAdrian Chadd + sizeof(struct ieee80211_ie_vhtcap) 295551172f62SAdrian Chadd + sizeof(struct ieee80211_ie_vht_operation) 2956b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 2957616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 295868e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2959616190d0SSam Leffler #endif 2960b032f27cSSam Leffler + (vap->iv_appie_assocresp != NULL ? 2961b032f27cSSam Leffler vap->iv_appie_assocresp->ie_len : 0) 29628a1b9b6aSSam Leffler ); 29631a1e1d21SSam Leffler if (m == NULL) 29648a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 29651a1e1d21SSam Leffler 296659aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 296768e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 29681a1e1d21SSam Leffler frm += 2; 29691a1e1d21SSam Leffler 297068e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* status */ 29711a1e1d21SSam Leffler frm += 2; 29721a1e1d21SSam Leffler 29738a1b9b6aSSam Leffler if (arg == IEEE80211_STATUS_SUCCESS) { 297468e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_associd); 29758a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc); 29768a1b9b6aSSam Leffler } else 29778a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc_fail); 29781a1e1d21SSam Leffler frm += 2; 29791a1e1d21SSam Leffler 29801a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 29811a1e1d21SSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 298268e8e04eSSam Leffler /* NB: respond according to what we received */ 29831b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { 298468e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 298568e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 298668e8e04eSSam Leffler } 2987b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_WME) && 2988b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 29898379e8dbSAdrian Chadd frm = ieee80211_add_wme_param(frm, &ic->ic_wme, 29908379e8dbSAdrian Chadd !! (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD)); 29911b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { 29921b6167d2SSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 29931b6167d2SSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 299468e8e04eSSam Leffler } 299551172f62SAdrian Chadd if (ni->ni_flags & IEEE80211_NODE_VHT) { 299651172f62SAdrian Chadd frm = ieee80211_add_vhtcap(frm, ni); 299751172f62SAdrian Chadd frm = ieee80211_add_vhtinfo(frm, ni); 299851172f62SAdrian Chadd } 2999616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 3000b032f27cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 300168e8e04eSSam Leffler frm = ieee80211_add_ath(frm, 3002b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 30034207227cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 30044207227cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X) ? 30054207227cSSam Leffler vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 3006616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 3007b032f27cSSam Leffler if (vap->iv_appie_assocresp != NULL) 3008b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocresp); 300968e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 30101a1e1d21SSam Leffler break; 30111a1e1d21SSam Leffler 30121a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DISASSOC: 3013b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 3014d72d72d3SAndriy Voskoboinyk "send station disassociate (reason: %d (%s))", arg, 3015d72d72d3SAndriy Voskoboinyk ieee80211_reason_to_string(arg)); 301668e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 301768e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 301868e8e04eSSam Leffler sizeof(uint16_t)); 30191a1e1d21SSam Leffler if (m == NULL) 30208a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 302168e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 302268e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 30238a1b9b6aSSam Leffler 30248a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_disassoc); 30258a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); 30261a1e1d21SSam Leffler break; 30271a1e1d21SSam Leffler 30281a1e1d21SSam Leffler default: 3029b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 3030b032f27cSSam Leffler "invalid mgmt frame type %u", type); 30311be50176SSam Leffler senderr(EINVAL, is_tx_unknownmgt); 30320a915fadSSam Leffler /* NOTREACHED */ 30331a1e1d21SSam Leffler } 303468e8e04eSSam Leffler 30358ac160cdSSam Leffler /* NB: force non-ProbeResp frames to the highest queue */ 30368ac160cdSSam Leffler params.ibp_pri = WME_AC_VO; 30378ac160cdSSam Leffler params.ibp_rate0 = bss->ni_txparms->mgmtrate; 30388ac160cdSSam Leffler /* NB: we know all frames are unicast */ 30398ac160cdSSam Leffler params.ibp_try0 = bss->ni_txparms->maxretry; 30408ac160cdSSam Leffler params.ibp_power = bss->ni_txpower; 30418ac160cdSSam Leffler return ieee80211_mgmt_output(ni, m, type, ¶ms); 30420a915fadSSam Leffler bad: 30438a1b9b6aSSam Leffler ieee80211_free_node(ni); 30441a1e1d21SSam Leffler return ret; 30450a915fadSSam Leffler #undef senderr 30461b6167d2SSam Leffler #undef HTFLAGS 30471a1e1d21SSam Leffler } 30488a1b9b6aSSam Leffler 3049b032f27cSSam Leffler /* 3050b032f27cSSam Leffler * Return an mbuf with a probe response frame in it. 3051b032f27cSSam Leffler * Space is left to prepend and 802.11 header at the 3052b032f27cSSam Leffler * front but it's left to the caller to fill in. 3053b032f27cSSam Leffler */ 3054b032f27cSSam Leffler struct mbuf * 3055b032f27cSSam Leffler ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) 3056b032f27cSSam Leffler { 3057b032f27cSSam Leffler struct ieee80211vap *vap = bss->ni_vap; 3058b032f27cSSam Leffler struct ieee80211com *ic = bss->ni_ic; 3059b032f27cSSam Leffler const struct ieee80211_rateset *rs; 3060b032f27cSSam Leffler struct mbuf *m; 3061b032f27cSSam Leffler uint16_t capinfo; 3062b032f27cSSam Leffler uint8_t *frm; 3063b032f27cSSam Leffler 3064b032f27cSSam Leffler /* 3065b032f27cSSam Leffler * probe response frame format 3066b032f27cSSam Leffler * [8] time stamp 3067b032f27cSSam Leffler * [2] beacon interval 3068b032f27cSSam Leffler * [2] cabability information 3069b032f27cSSam Leffler * [tlv] ssid 3070b032f27cSSam Leffler * [tlv] supported rates 3071b032f27cSSam Leffler * [tlv] parameter set (FH/DS) 3072b032f27cSSam Leffler * [tlv] parameter set (IBSS) 3073b032f27cSSam Leffler * [tlv] country (optional) 3074b032f27cSSam Leffler * [3] power control (optional) 3075b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 3076b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 3077b032f27cSSam Leffler * [tlv] extended supported rates 3078688fe74dSSam Leffler * [tlv] RSN (optional) 3079b032f27cSSam Leffler * [tlv] HT capabilities 3080b032f27cSSam Leffler * [tlv] HT information 3081ac0b7d32SAdrian Chadd * [tlv] VHT capabilities 3082ac0b7d32SAdrian Chadd * [tlv] VHT information 3083b032f27cSSam Leffler * [tlv] WPA (optional) 3084b032f27cSSam Leffler * [tlv] WME (optional) 3085b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 3086b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 3087b032f27cSSam Leffler * [tlv] Atheros capabilities 3088b032f27cSSam Leffler * [tlv] AppIE's (optional) 308959aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 309059aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 3091b032f27cSSam Leffler */ 3092b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 3093b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 3094b032f27cSSam Leffler 8 3095b032f27cSSam Leffler + sizeof(uint16_t) 3096b032f27cSSam Leffler + sizeof(uint16_t) 3097b032f27cSSam Leffler + 2 + IEEE80211_NWID_LEN 3098b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE 3099b032f27cSSam Leffler + 7 /* max(7,3) */ 3100b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE 3101b032f27cSSam Leffler + 3 3102b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) 310332b0e64bSAdrian Chadd + sizeof(struct ieee80211_quiet_ie) 3104b032f27cSSam Leffler + 3 3105b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 3106688fe74dSSam Leffler + sizeof(struct ieee80211_ie_wpa) 3107b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 3108b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htinfo) 3109b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 3110b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 3111b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 3112b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htinfo) 3113ac0b7d32SAdrian Chadd + sizeof(struct ieee80211_ie_vhtcap) 3114ac0b7d32SAdrian Chadd + sizeof(struct ieee80211_ie_vht_operation) 3115616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 3116b032f27cSSam Leffler + sizeof(struct ieee80211_ath_ie) 3117616190d0SSam Leffler #endif 311859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 311959aa14a9SRui Paulo + 2 + IEEE80211_MESHID_LEN 312059aa14a9SRui Paulo + sizeof(struct ieee80211_meshconf_ie) 312159aa14a9SRui Paulo #endif 3122b032f27cSSam Leffler + (vap->iv_appie_proberesp != NULL ? 3123b032f27cSSam Leffler vap->iv_appie_proberesp->ie_len : 0) 3124b032f27cSSam Leffler ); 3125b032f27cSSam Leffler if (m == NULL) { 3126b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 3127b032f27cSSam Leffler return NULL; 3128b032f27cSSam Leffler } 3129b032f27cSSam Leffler 3130b032f27cSSam Leffler memset(frm, 0, 8); /* timestamp should be filled later */ 3131b032f27cSSam Leffler frm += 8; 3132b032f27cSSam Leffler *(uint16_t *)frm = htole16(bss->ni_intval); 3133b032f27cSSam Leffler frm += 2; 313459aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 3135b032f27cSSam Leffler *(uint16_t *)frm = htole16(capinfo); 3136b032f27cSSam Leffler frm += 2; 3137b032f27cSSam Leffler 3138b032f27cSSam Leffler frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); 3139b032f27cSSam Leffler rs = ieee80211_get_suprates(ic, bss->ni_chan); 3140b032f27cSSam Leffler frm = ieee80211_add_rates(frm, rs); 3141b032f27cSSam Leffler 3142b032f27cSSam Leffler if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { 3143b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_FHPARMS; 3144b032f27cSSam Leffler *frm++ = 5; 3145b032f27cSSam Leffler *frm++ = bss->ni_fhdwell & 0x00ff; 3146b032f27cSSam Leffler *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; 3147b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANSET( 3148b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 3149b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANPAT( 3150b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 3151b032f27cSSam Leffler *frm++ = bss->ni_fhindex; 3152b032f27cSSam Leffler } else { 3153b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 3154b032f27cSSam Leffler *frm++ = 1; 3155b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); 3156b032f27cSSam Leffler } 3157b032f27cSSam Leffler 3158b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 3159b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 3160b032f27cSSam Leffler *frm++ = 2; 3161b032f27cSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 3162b032f27cSSam Leffler } 3163b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 3164b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 3165b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 3166b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 3167b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) 3168b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 3169b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 3170b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 3171b032f27cSSam Leffler } 317232b0e64bSAdrian Chadd if (vap->iv_flags & IEEE80211_F_DOTH) { 317332b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 317432b0e64bSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 317532b0e64bSAdrian Chadd if (vap->iv_quiet) 3176ce4552cdSAdrian Chadd frm = ieee80211_add_quiet(frm, vap, 0); 317732b0e64bSAdrian Chadd } 317832b0e64bSAdrian Chadd } 3179b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) 3180f1481c8dSAdrian Chadd frm = ieee80211_add_erp(frm, vap); 3181b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 3182d8df5f3dSRui Paulo frm = ieee80211_add_rsn(frm, vap); 3183b032f27cSSam Leffler /* 3184b032f27cSSam Leffler * NB: legacy 11b clients do not get certain ie's. 3185b032f27cSSam Leffler * The caller identifies such clients by passing 3186b032f27cSSam Leffler * a token in legacy to us. Could expand this to be 3187b032f27cSSam Leffler * any legacy client for stuff like HT ie's. 3188b032f27cSSam Leffler */ 3189b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 3190b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 3191b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, bss); 3192b032f27cSSam Leffler frm = ieee80211_add_htinfo(frm, bss); 3193b032f27cSSam Leffler } 3194ac0b7d32SAdrian Chadd if (IEEE80211_IS_CHAN_VHT(bss->ni_chan) && 3195ac0b7d32SAdrian Chadd legacy != IEEE80211_SEND_LEGACY_11B) { 3196ac0b7d32SAdrian Chadd frm = ieee80211_add_vhtcap(frm, bss); 3197ac0b7d32SAdrian Chadd frm = ieee80211_add_vhtinfo(frm, bss); 3198ac0b7d32SAdrian Chadd } 3199d8df5f3dSRui Paulo frm = ieee80211_add_wpa(frm, vap); 3200b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) 32018379e8dbSAdrian Chadd frm = ieee80211_add_wme_param(frm, &ic->ic_wme, 32028379e8dbSAdrian Chadd !! (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD)); 3203b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 32042bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) && 3205b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 3206b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, bss); 3207b032f27cSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, bss); 3208b032f27cSSam Leffler } 3209616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 32104207227cSSam Leffler if ((vap->iv_flags & IEEE80211_F_ATHEROS) && 32114207227cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) 32124207227cSSam Leffler frm = ieee80211_add_athcaps(frm, bss); 3213616190d0SSam Leffler #endif 3214b032f27cSSam Leffler if (vap->iv_appie_proberesp != NULL) 3215b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_proberesp); 321659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 321759aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 321859aa14a9SRui Paulo frm = ieee80211_add_meshid(frm, vap); 321959aa14a9SRui Paulo frm = ieee80211_add_meshconf(frm, vap); 322059aa14a9SRui Paulo } 322159aa14a9SRui Paulo #endif 3222b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 3223b032f27cSSam Leffler 3224b032f27cSSam Leffler return m; 3225b032f27cSSam Leffler } 3226b032f27cSSam Leffler 3227b032f27cSSam Leffler /* 3228b032f27cSSam Leffler * Send a probe response frame to the specified mac address. 3229b032f27cSSam Leffler * This does not go through the normal mgt frame api so we 3230b032f27cSSam Leffler * can specify the destination address and re-use the bss node 3231b032f27cSSam Leffler * for the sta reference. 3232b032f27cSSam Leffler */ 3233b032f27cSSam Leffler int 3234b032f27cSSam Leffler ieee80211_send_proberesp(struct ieee80211vap *vap, 3235b032f27cSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], int legacy) 3236b032f27cSSam Leffler { 3237b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 3238b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 3239b032f27cSSam Leffler struct mbuf *m; 32405cda6006SAdrian Chadd int ret; 3241b032f27cSSam Leffler 3242b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 3243b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, 3244b032f27cSSam Leffler "block %s frame in CAC state", "probe response"); 3245b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 3246b032f27cSSam Leffler return EIO; /* XXX */ 3247b032f27cSSam Leffler } 3248b032f27cSSam Leffler 3249b032f27cSSam Leffler /* 3250b032f27cSSam Leffler * Hold a reference on the node so it doesn't go away until after 3251b032f27cSSam Leffler * the xmit is complete all the way in the driver. On error we 3252b032f27cSSam Leffler * will remove our reference. 3253b032f27cSSam Leffler */ 3254b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 3255b032f27cSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 3256b032f27cSSam Leffler __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), 3257b032f27cSSam Leffler ieee80211_node_refcnt(bss)+1); 3258b032f27cSSam Leffler ieee80211_ref_node(bss); 3259b032f27cSSam Leffler 3260b032f27cSSam Leffler m = ieee80211_alloc_proberesp(bss, legacy); 3261b032f27cSSam Leffler if (m == NULL) { 3262b032f27cSSam Leffler ieee80211_free_node(bss); 3263b032f27cSSam Leffler return ENOMEM; 3264b032f27cSSam Leffler } 3265b032f27cSSam Leffler 3266eb1b1807SGleb Smirnoff M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 3267b032f27cSSam Leffler KASSERT(m != NULL, ("no room for header")); 3268b032f27cSSam Leffler 32695cda6006SAdrian Chadd IEEE80211_TX_LOCK(ic); 32709e80b1dfSSam Leffler ieee80211_send_setup(bss, m, 3271b032f27cSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, 32728ac160cdSSam Leffler IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); 3273b032f27cSSam Leffler /* XXX power management? */ 3274c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 3275b032f27cSSam Leffler 3276b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 3277b032f27cSSam Leffler 3278b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 3279b032f27cSSam Leffler "send probe resp on channel %u to %s%s\n", 3280b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), 3281b032f27cSSam Leffler legacy ? " <legacy>" : ""); 3282b032f27cSSam Leffler IEEE80211_NODE_STAT(bss, tx_mgmt); 3283b032f27cSSam Leffler 32845cda6006SAdrian Chadd ret = ieee80211_raw_output(vap, bss, m, NULL); 32855cda6006SAdrian Chadd IEEE80211_TX_UNLOCK(ic); 32865cda6006SAdrian Chadd return (ret); 3287b032f27cSSam Leffler } 3288b032f27cSSam Leffler 3289b032f27cSSam Leffler /* 3290b032f27cSSam Leffler * Allocate and build a RTS (Request To Send) control frame. 3291b032f27cSSam Leffler */ 3292b032f27cSSam Leffler struct mbuf * 3293b032f27cSSam Leffler ieee80211_alloc_rts(struct ieee80211com *ic, 3294b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], 3295b032f27cSSam Leffler const uint8_t ta[IEEE80211_ADDR_LEN], 3296b032f27cSSam Leffler uint16_t dur) 3297b032f27cSSam Leffler { 3298b032f27cSSam Leffler struct ieee80211_frame_rts *rts; 3299b032f27cSSam Leffler struct mbuf *m; 3300b032f27cSSam Leffler 3301b032f27cSSam Leffler /* XXX honor ic_headroom */ 3302eb1b1807SGleb Smirnoff m = m_gethdr(M_NOWAIT, MT_DATA); 3303b032f27cSSam Leffler if (m != NULL) { 3304b032f27cSSam Leffler rts = mtod(m, struct ieee80211_frame_rts *); 3305b032f27cSSam Leffler rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 3306b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; 3307b032f27cSSam Leffler rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 3308b032f27cSSam Leffler *(u_int16_t *)rts->i_dur = htole16(dur); 3309b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ra, ra); 3310b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ta, ta); 3311b032f27cSSam Leffler 3312b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); 3313b032f27cSSam Leffler } 3314b032f27cSSam Leffler return m; 3315b032f27cSSam Leffler } 3316b032f27cSSam Leffler 3317b032f27cSSam Leffler /* 3318b032f27cSSam Leffler * Allocate and build a CTS (Clear To Send) control frame. 3319b032f27cSSam Leffler */ 3320b032f27cSSam Leffler struct mbuf * 3321b032f27cSSam Leffler ieee80211_alloc_cts(struct ieee80211com *ic, 3322b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) 3323b032f27cSSam Leffler { 3324b032f27cSSam Leffler struct ieee80211_frame_cts *cts; 3325b032f27cSSam Leffler struct mbuf *m; 3326b032f27cSSam Leffler 3327b032f27cSSam Leffler /* XXX honor ic_headroom */ 3328eb1b1807SGleb Smirnoff m = m_gethdr(M_NOWAIT, MT_DATA); 3329b032f27cSSam Leffler if (m != NULL) { 3330b032f27cSSam Leffler cts = mtod(m, struct ieee80211_frame_cts *); 3331b032f27cSSam Leffler cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 3332b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; 3333b032f27cSSam Leffler cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 3334b032f27cSSam Leffler *(u_int16_t *)cts->i_dur = htole16(dur); 3335b032f27cSSam Leffler IEEE80211_ADDR_COPY(cts->i_ra, ra); 3336b032f27cSSam Leffler 3337b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); 3338b032f27cSSam Leffler } 3339b032f27cSSam Leffler return m; 3340b032f27cSSam Leffler } 3341b032f27cSSam Leffler 3342d1b67106SAndriy Voskoboinyk /* 3343d1b67106SAndriy Voskoboinyk * Wrapper for CTS/RTS frame allocation. 3344d1b67106SAndriy Voskoboinyk */ 3345d1b67106SAndriy Voskoboinyk struct mbuf * 3346d1b67106SAndriy Voskoboinyk ieee80211_alloc_prot(struct ieee80211_node *ni, const struct mbuf *m, 3347d1b67106SAndriy Voskoboinyk uint8_t rate, int prot) 3348d1b67106SAndriy Voskoboinyk { 3349d1b67106SAndriy Voskoboinyk struct ieee80211com *ic = ni->ni_ic; 3350f1481c8dSAdrian Chadd struct ieee80211vap *vap = ni->ni_vap; 3351d1b67106SAndriy Voskoboinyk const struct ieee80211_frame *wh; 3352d1b67106SAndriy Voskoboinyk struct mbuf *mprot; 3353d1b67106SAndriy Voskoboinyk uint16_t dur; 3354d1b67106SAndriy Voskoboinyk int pktlen, isshort; 3355d1b67106SAndriy Voskoboinyk 3356d1b67106SAndriy Voskoboinyk KASSERT(prot == IEEE80211_PROT_RTSCTS || 3357d1b67106SAndriy Voskoboinyk prot == IEEE80211_PROT_CTSONLY, 3358d1b67106SAndriy Voskoboinyk ("wrong protection type %d", prot)); 3359d1b67106SAndriy Voskoboinyk 3360d1b67106SAndriy Voskoboinyk wh = mtod(m, const struct ieee80211_frame *); 3361d1b67106SAndriy Voskoboinyk pktlen = m->m_pkthdr.len + IEEE80211_CRC_LEN; 3362f1481c8dSAdrian Chadd isshort = (vap->iv_flags & IEEE80211_F_SHPREAMBLE) != 0; 3363d1b67106SAndriy Voskoboinyk dur = ieee80211_compute_duration(ic->ic_rt, pktlen, rate, isshort) 3364d1b67106SAndriy Voskoboinyk + ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3365d1b67106SAndriy Voskoboinyk 3366d1b67106SAndriy Voskoboinyk if (prot == IEEE80211_PROT_RTSCTS) { 3367d1b67106SAndriy Voskoboinyk /* NB: CTS is the same size as an ACK */ 3368d1b67106SAndriy Voskoboinyk dur += ieee80211_ack_duration(ic->ic_rt, rate, isshort); 3369d1b67106SAndriy Voskoboinyk mprot = ieee80211_alloc_rts(ic, wh->i_addr1, wh->i_addr2, dur); 3370d1b67106SAndriy Voskoboinyk } else 3371f1481c8dSAdrian Chadd mprot = ieee80211_alloc_cts(ic, vap->iv_myaddr, dur); 3372d1b67106SAndriy Voskoboinyk 3373d1b67106SAndriy Voskoboinyk return (mprot); 3374d1b67106SAndriy Voskoboinyk } 3375d1b67106SAndriy Voskoboinyk 337668e8e04eSSam Leffler static void 337768e8e04eSSam Leffler ieee80211_tx_mgt_timeout(void *arg) 337868e8e04eSSam Leffler { 3379e94527beSAdrian Chadd struct ieee80211vap *vap = arg; 338068e8e04eSSam Leffler 338104efa18fSBjoern A. Zeeb IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 338204efa18fSBjoern A. Zeeb "vap %p mode %s state %s flags %#x & %#x\n", vap, 338304efa18fSBjoern A. Zeeb ieee80211_opmode_name[vap->iv_opmode], 338404efa18fSBjoern A. Zeeb ieee80211_state_name[vap->iv_state], 338504efa18fSBjoern A. Zeeb vap->iv_ic->ic_flags, IEEE80211_F_SCAN); 338604efa18fSBjoern A. Zeeb 3387e94527beSAdrian Chadd IEEE80211_LOCK(vap->iv_ic); 3388b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_INIT && 3389b032f27cSSam Leffler (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { 339068e8e04eSSam Leffler /* 339168e8e04eSSam Leffler * NB: it's safe to specify a timeout as the reason here; 339268e8e04eSSam Leffler * it'll only be used in the right state. 339368e8e04eSSam Leffler */ 3394e94527beSAdrian Chadd ieee80211_new_state_locked(vap, IEEE80211_S_SCAN, 339568e8e04eSSam Leffler IEEE80211_SCAN_FAIL_TIMEOUT); 339668e8e04eSSam Leffler } 3397e94527beSAdrian Chadd IEEE80211_UNLOCK(vap->iv_ic); 339868e8e04eSSam Leffler } 339968e8e04eSSam Leffler 3400e94527beSAdrian Chadd /* 3401e94527beSAdrian Chadd * This is the callback set on net80211-sourced transmitted 3402e94527beSAdrian Chadd * authentication request frames. 3403e94527beSAdrian Chadd * 3404e94527beSAdrian Chadd * This does a couple of things: 3405e94527beSAdrian Chadd * 3406e94527beSAdrian Chadd * + If the frame transmitted was a success, it schedules a future 3407e94527beSAdrian Chadd * event which will transition the interface to scan. 3408e94527beSAdrian Chadd * If a state transition _then_ occurs before that event occurs, 3409e94527beSAdrian Chadd * said state transition will cancel this callout. 3410e94527beSAdrian Chadd * 3411e94527beSAdrian Chadd * + If the frame transmit was a failure, it immediately schedules 3412e94527beSAdrian Chadd * the transition back to scan. 3413e94527beSAdrian Chadd */ 341468e8e04eSSam Leffler static void 341568e8e04eSSam Leffler ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) 341668e8e04eSSam Leffler { 3417b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 34186671366aSBrooks Davis enum ieee80211_state ostate = (enum ieee80211_state)(uintptr_t)arg; 341968e8e04eSSam Leffler 342068e8e04eSSam Leffler /* 342168e8e04eSSam Leffler * Frame transmit completed; arrange timer callback. If 3422a4641f4eSPedro F. Giffuni * transmit was successfully we wait for response. Otherwise 342368e8e04eSSam Leffler * we arrange an immediate callback instead of doing the 342468e8e04eSSam Leffler * callback directly since we don't know what state the driver 342568e8e04eSSam Leffler * is in (e.g. what locks it is holding). This work should 342668e8e04eSSam Leffler * not be too time-critical and not happen too often so the 342768e8e04eSSam Leffler * added overhead is acceptable. 342868e8e04eSSam Leffler * 342968e8e04eSSam Leffler * XXX what happens if !acked but response shows up before callback? 343068e8e04eSSam Leffler */ 3431e94527beSAdrian Chadd if (vap->iv_state == ostate) { 343204efa18fSBjoern A. Zeeb IEEE80211_DPRINTF(vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 343304efa18fSBjoern A. Zeeb "ni %p mode %s state %s ostate %d arg %p status %d\n", ni, 343404efa18fSBjoern A. Zeeb ieee80211_opmode_name[vap->iv_opmode], 343504efa18fSBjoern A. Zeeb ieee80211_state_name[vap->iv_state], ostate, arg, status); 343604efa18fSBjoern A. Zeeb 3437b032f27cSSam Leffler callout_reset(&vap->iv_mgtsend, 343868e8e04eSSam Leffler status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, 3439e94527beSAdrian Chadd ieee80211_tx_mgt_timeout, vap); 3440e94527beSAdrian Chadd } 344168e8e04eSSam Leffler } 344268e8e04eSSam Leffler 3443b032f27cSSam Leffler static void 3444b032f27cSSam Leffler ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, 3445210ab3c2SAdrian Chadd struct ieee80211_node *ni) 34468a1b9b6aSSam Leffler { 3447b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 3448210ab3c2SAdrian Chadd struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 3449b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 3450b032f27cSSam Leffler struct ieee80211_rateset *rs = &ni->ni_rates; 345168e8e04eSSam Leffler uint16_t capinfo; 34528a1b9b6aSSam Leffler 34538a1b9b6aSSam Leffler /* 34548a1b9b6aSSam Leffler * beacon frame format 345551172f62SAdrian Chadd * 345651172f62SAdrian Chadd * TODO: update to 802.11-2012; a lot of stuff has changed; 345751172f62SAdrian Chadd * vendor extensions should be at the end, etc. 345851172f62SAdrian Chadd * 34598a1b9b6aSSam Leffler * [8] time stamp 34608a1b9b6aSSam Leffler * [2] beacon interval 34618a1b9b6aSSam Leffler * [2] cabability information 34628a1b9b6aSSam Leffler * [tlv] ssid 34638a1b9b6aSSam Leffler * [tlv] supported rates 34648a1b9b6aSSam Leffler * [3] parameter set (DS) 3465b032f27cSSam Leffler * [8] CF parameter set (optional) 34668a1b9b6aSSam Leffler * [tlv] parameter set (IBSS/TIM) 3467b032f27cSSam Leffler * [tlv] country (optional) 3468b032f27cSSam Leffler * [3] power control (optional) 3469b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 347051172f62SAdrian Chadd * XXX TODO: Quiet 347151172f62SAdrian Chadd * XXX TODO: IBSS DFS 347251172f62SAdrian Chadd * XXX TODO: TPC report 34738a1b9b6aSSam Leffler * [tlv] extended rate phy (ERP) 34748a1b9b6aSSam Leffler * [tlv] extended supported rates 3475688fe74dSSam Leffler * [tlv] RSN parameters 347651172f62SAdrian Chadd * XXX TODO: BSSLOAD 347751172f62SAdrian Chadd * (XXX EDCA parameter set, QoS capability?) 347851172f62SAdrian Chadd * XXX TODO: AP channel report 347951172f62SAdrian Chadd * 348068e8e04eSSam Leffler * [tlv] HT capabilities 348168e8e04eSSam Leffler * [tlv] HT information 348251172f62SAdrian Chadd * XXX TODO: 20/40 BSS coexistence 348351172f62SAdrian Chadd * Mesh: 348451172f62SAdrian Chadd * XXX TODO: Meshid 348551172f62SAdrian Chadd * XXX TODO: mesh config 348651172f62SAdrian Chadd * XXX TODO: mesh awake window 348751172f62SAdrian Chadd * XXX TODO: beacon timing (mesh, etc) 348851172f62SAdrian Chadd * XXX TODO: MCCAOP Advertisement Overview 348951172f62SAdrian Chadd * XXX TODO: MCCAOP Advertisement 349051172f62SAdrian Chadd * XXX TODO: Mesh channel switch parameters 349151172f62SAdrian Chadd * VHT: 349251172f62SAdrian Chadd * XXX TODO: VHT capabilities 349351172f62SAdrian Chadd * XXX TODO: VHT operation 349451172f62SAdrian Chadd * XXX TODO: VHT transmit power envelope 349551172f62SAdrian Chadd * XXX TODO: channel switch wrapper element 349651172f62SAdrian Chadd * XXX TODO: extended BSS load element 349751172f62SAdrian Chadd * 3498b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 3499b032f27cSSam Leffler * [tlv] WPA parameters 3500b032f27cSSam Leffler * [tlv] WME parameters 350168e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 350268e8e04eSSam Leffler * [tlv] Vendor OUI HT information (optional) 35034207227cSSam Leffler * [tlv] Atheros capabilities (optional) 350410ad9a77SSam Leffler * [tlv] TDMA parameters (optional) 350559aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 350659aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 3507b032f27cSSam Leffler * [tlv] application data (optional) 35088a1b9b6aSSam Leffler */ 35098a1b9b6aSSam Leffler 35101b6167d2SSam Leffler memset(bo, 0, sizeof(*bo)); 35111b6167d2SSam Leffler 35128a1b9b6aSSam Leffler memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ 35138a1b9b6aSSam Leffler frm += 8; 351468e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_intval); 35158a1b9b6aSSam Leffler frm += 2; 351659aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 351768e8e04eSSam Leffler bo->bo_caps = (uint16_t *)frm; 351868e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 35198a1b9b6aSSam Leffler frm += 2; 35208a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 3521b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { 35228a1b9b6aSSam Leffler *frm++ = ni->ni_esslen; 35238a1b9b6aSSam Leffler memcpy(frm, ni->ni_essid, ni->ni_esslen); 35248a1b9b6aSSam Leffler frm += ni->ni_esslen; 35258a1b9b6aSSam Leffler } else 35268a1b9b6aSSam Leffler *frm++ = 0; 35278a1b9b6aSSam Leffler frm = ieee80211_add_rates(frm, rs); 3528b032f27cSSam Leffler if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { 35298a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 35308a1b9b6aSSam Leffler *frm++ = 1; 3531b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); 3532b032f27cSSam Leffler } 3533b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_PCF) { 3534b032f27cSSam Leffler bo->bo_cfp = frm; 3535b032f27cSSam Leffler frm = ieee80211_add_cfparms(frm, ic); 35368a1b9b6aSSam Leffler } 35378a1b9b6aSSam Leffler bo->bo_tim = frm; 3538b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 35398a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 35408a1b9b6aSSam Leffler *frm++ = 2; 35418a1b9b6aSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 35428a1b9b6aSSam Leffler bo->bo_tim_len = 0; 354359aa14a9SRui Paulo } else if (vap->iv_opmode == IEEE80211_M_HOSTAP || 354459aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { 354559aa14a9SRui Paulo /* TIM IE is the same for Mesh and Hostap */ 35468a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; 35478a1b9b6aSSam Leffler 35488a1b9b6aSSam Leffler tie->tim_ie = IEEE80211_ELEMID_TIM; 35498a1b9b6aSSam Leffler tie->tim_len = 4; /* length */ 35508a1b9b6aSSam Leffler tie->tim_count = 0; /* DTIM count */ 3551b032f27cSSam Leffler tie->tim_period = vap->iv_dtim_period; /* DTIM period */ 35528a1b9b6aSSam Leffler tie->tim_bitctl = 0; /* bitmap control */ 35538a1b9b6aSSam Leffler tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 35548a1b9b6aSSam Leffler frm += sizeof(struct ieee80211_tim_ie); 35558a1b9b6aSSam Leffler bo->bo_tim_len = 1; 35568a1b9b6aSSam Leffler } 3557b105a069SSam Leffler bo->bo_tim_trailer = frm; 3558b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 3559b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 3560b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 3561b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 3562b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 3563b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 3564b032f27cSSam Leffler bo->bo_csa = frm; 3565b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 3566b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 3567b032f27cSSam Leffler } else 3568b032f27cSSam Leffler bo->bo_csa = frm; 356932b0e64bSAdrian Chadd 35704d3dcce5SAdrian Chadd bo->bo_quiet = NULL; 357132b0e64bSAdrian Chadd if (vap->iv_flags & IEEE80211_F_DOTH) { 357232b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 35734d3dcce5SAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS) && 35744d3dcce5SAdrian Chadd (vap->iv_quiet == 1)) { 35754d3dcce5SAdrian Chadd /* 35764d3dcce5SAdrian Chadd * We only insert the quiet IE offset if 35774d3dcce5SAdrian Chadd * the quiet IE is enabled. Otherwise don't 35784d3dcce5SAdrian Chadd * put it here or we'll just overwrite 35794d3dcce5SAdrian Chadd * some other beacon contents. 35804d3dcce5SAdrian Chadd */ 35814d3dcce5SAdrian Chadd if (vap->iv_quiet) { 35824d3dcce5SAdrian Chadd bo->bo_quiet = frm; 3583ce4552cdSAdrian Chadd frm = ieee80211_add_quiet(frm,vap, 0); 358432b0e64bSAdrian Chadd } 35854d3dcce5SAdrian Chadd } 35864d3dcce5SAdrian Chadd } 358732b0e64bSAdrian Chadd 3588b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { 35890912bac9SSam Leffler bo->bo_erp = frm; 3590f1481c8dSAdrian Chadd frm = ieee80211_add_erp(frm, vap); 35911b6167d2SSam Leffler } 359268e8e04eSSam Leffler frm = ieee80211_add_xrates(frm, rs); 3593d8df5f3dSRui Paulo frm = ieee80211_add_rsn(frm, vap); 3594b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { 359568e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 359668e8e04eSSam Leffler bo->bo_htinfo = frm; 359768e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 35981b6167d2SSam Leffler } 359951172f62SAdrian Chadd 360051172f62SAdrian Chadd if (IEEE80211_IS_CHAN_VHT(ni->ni_chan)) { 360151172f62SAdrian Chadd frm = ieee80211_add_vhtcap(frm, ni); 360251172f62SAdrian Chadd bo->bo_vhtinfo = frm; 360351172f62SAdrian Chadd frm = ieee80211_add_vhtinfo(frm, ni); 360451172f62SAdrian Chadd /* Transmit power envelope */ 360551172f62SAdrian Chadd /* Channel switch wrapper element */ 360651172f62SAdrian Chadd /* Extended bss load element */ 360751172f62SAdrian Chadd } 360851172f62SAdrian Chadd 3609d8df5f3dSRui Paulo frm = ieee80211_add_wpa(frm, vap); 3610b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 36111b6167d2SSam Leffler bo->bo_wme = frm; 36128379e8dbSAdrian Chadd frm = ieee80211_add_wme_param(frm, &ic->ic_wme, 36138379e8dbSAdrian Chadd !! (vap->iv_flags_ext & IEEE80211_FEXT_UAPSD)); 36141b6167d2SSam Leffler } 3615b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && 36162bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) { 361768e8e04eSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 361868e8e04eSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 36190912bac9SSam Leffler } 362051172f62SAdrian Chadd 36214207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 36224207227cSSam Leffler if (vap->iv_flags & IEEE80211_F_ATHEROS) { 36234207227cSSam Leffler bo->bo_ath = frm; 36244207227cSSam Leffler frm = ieee80211_add_athcaps(frm, ni); 36254207227cSSam Leffler } 36264207227cSSam Leffler #endif 362710ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 362810ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 362910ad9a77SSam Leffler bo->bo_tdma = frm; 363010ad9a77SSam Leffler frm = ieee80211_add_tdma(frm, vap); 363110ad9a77SSam Leffler } 363210ad9a77SSam Leffler #endif 3633b032f27cSSam Leffler if (vap->iv_appie_beacon != NULL) { 3634b032f27cSSam Leffler bo->bo_appie = frm; 3635b032f27cSSam Leffler bo->bo_appie_len = vap->iv_appie_beacon->ie_len; 3636b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_beacon); 3637b032f27cSSam Leffler } 363851172f62SAdrian Chadd 363951172f62SAdrian Chadd /* XXX TODO: move meshid/meshconf up to before vendor extensions? */ 364059aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 364159aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 364259aa14a9SRui Paulo frm = ieee80211_add_meshid(frm, vap); 3643d093681cSRui Paulo bo->bo_meshconf = frm; 364459aa14a9SRui Paulo frm = ieee80211_add_meshconf(frm, vap); 364559aa14a9SRui Paulo } 364659aa14a9SRui Paulo #endif 3647b105a069SSam Leffler bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; 3648b032f27cSSam Leffler bo->bo_csa_trailer_len = frm - bo->bo_csa; 364968e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 3650b032f27cSSam Leffler } 3651b032f27cSSam Leffler 3652b032f27cSSam Leffler /* 3653b032f27cSSam Leffler * Allocate a beacon frame and fillin the appropriate bits. 3654b032f27cSSam Leffler */ 3655b032f27cSSam Leffler struct mbuf * 3656210ab3c2SAdrian Chadd ieee80211_beacon_alloc(struct ieee80211_node *ni) 3657b032f27cSSam Leffler { 3658b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 3659b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 3660b032f27cSSam Leffler struct ifnet *ifp = vap->iv_ifp; 3661b032f27cSSam Leffler struct ieee80211_frame *wh; 3662b032f27cSSam Leffler struct mbuf *m; 3663b032f27cSSam Leffler int pktlen; 3664b032f27cSSam Leffler uint8_t *frm; 3665b032f27cSSam Leffler 3666b032f27cSSam Leffler /* 36674d3dcce5SAdrian Chadd * Update the "We're putting the quiet IE in the beacon" state. 36684d3dcce5SAdrian Chadd */ 36694d3dcce5SAdrian Chadd if (vap->iv_quiet == 1) 36704d3dcce5SAdrian Chadd vap->iv_flags_ext |= IEEE80211_FEXT_QUIET_IE; 36714d3dcce5SAdrian Chadd else if (vap->iv_quiet == 0) 36724d3dcce5SAdrian Chadd vap->iv_flags_ext &= ~IEEE80211_FEXT_QUIET_IE; 36734d3dcce5SAdrian Chadd 36744d3dcce5SAdrian Chadd /* 3675b032f27cSSam Leffler * beacon frame format 367651172f62SAdrian Chadd * 367751172f62SAdrian Chadd * Note: This needs updating for 802.11-2012. 367851172f62SAdrian Chadd * 3679b032f27cSSam Leffler * [8] time stamp 3680b032f27cSSam Leffler * [2] beacon interval 3681b032f27cSSam Leffler * [2] cabability information 3682b032f27cSSam Leffler * [tlv] ssid 3683b032f27cSSam Leffler * [tlv] supported rates 3684b032f27cSSam Leffler * [3] parameter set (DS) 3685b032f27cSSam Leffler * [8] CF parameter set (optional) 3686b032f27cSSam Leffler * [tlv] parameter set (IBSS/TIM) 3687b032f27cSSam Leffler * [tlv] country (optional) 3688b032f27cSSam Leffler * [3] power control (optional) 3689b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 3690b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 3691b032f27cSSam Leffler * [tlv] extended supported rates 3692b032f27cSSam Leffler * [tlv] RSN parameters 3693b032f27cSSam Leffler * [tlv] HT capabilities 3694b032f27cSSam Leffler * [tlv] HT information 369551172f62SAdrian Chadd * [tlv] VHT capabilities 369651172f62SAdrian Chadd * [tlv] VHT operation 3697b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 3698b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 3699b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 3700b032f27cSSam Leffler * [tlv] WPA parameters 3701b032f27cSSam Leffler * [tlv] WME parameters 370210ad9a77SSam Leffler * [tlv] TDMA parameters (optional) 370359aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 370459aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 3705b032f27cSSam Leffler * [tlv] application data (optional) 3706b032f27cSSam Leffler * NB: we allocate the max space required for the TIM bitmap. 3707b032f27cSSam Leffler * XXX how big is this? 3708b032f27cSSam Leffler */ 3709b032f27cSSam Leffler pktlen = 8 /* time stamp */ 3710b032f27cSSam Leffler + sizeof(uint16_t) /* beacon interval */ 3711b032f27cSSam Leffler + sizeof(uint16_t) /* capabilities */ 3712b032f27cSSam Leffler + 2 + ni->ni_esslen /* ssid */ 3713b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE /* supported rates */ 3714b032f27cSSam Leffler + 2 + 1 /* DS parameters */ 3715b032f27cSSam Leffler + 2 + 6 /* CF parameters */ 3716b032f27cSSam Leffler + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ 3717b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE /* country */ 3718b032f27cSSam Leffler + 2 + 1 /* power control */ 3719b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) /* CSA */ 372032b0e64bSAdrian Chadd + sizeof(struct ieee80211_quiet_ie) /* Quiet */ 3721b032f27cSSam Leffler + 2 + 1 /* ERP */ 3722b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 3723b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 3724b032f27cSSam Leffler 2*sizeof(struct ieee80211_ie_wpa) : 0) 3725b032f27cSSam Leffler /* XXX conditional? */ 3726b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ 3727b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ 372851172f62SAdrian Chadd + sizeof(struct ieee80211_ie_vhtcap)/* VHT caps */ 372951172f62SAdrian Chadd + sizeof(struct ieee80211_ie_vht_operation)/* VHT info */ 3730b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ 3731b032f27cSSam Leffler sizeof(struct ieee80211_wme_param) : 0) 37324207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 37334207227cSSam Leffler + sizeof(struct ieee80211_ath_ie) /* ATH */ 37344207227cSSam Leffler #endif 373510ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 373610ad9a77SSam Leffler + (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */ 373710ad9a77SSam Leffler sizeof(struct ieee80211_tdma_param) : 0) 373810ad9a77SSam Leffler #endif 373959aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 374059aa14a9SRui Paulo + 2 + ni->ni_meshidlen 374159aa14a9SRui Paulo + sizeof(struct ieee80211_meshconf_ie) 374259aa14a9SRui Paulo #endif 3743b032f27cSSam Leffler + IEEE80211_MAX_APPIE 3744b032f27cSSam Leffler ; 3745b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 3746b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); 3747b032f27cSSam Leffler if (m == NULL) { 3748b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 3749b032f27cSSam Leffler "%s: cannot get buf; size %u\n", __func__, pktlen); 3750b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 3751b032f27cSSam Leffler return NULL; 3752b032f27cSSam Leffler } 3753210ab3c2SAdrian Chadd ieee80211_beacon_construct(m, frm, ni); 37548a1b9b6aSSam Leffler 3755eb1b1807SGleb Smirnoff M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 37568a1b9b6aSSam Leffler KASSERT(m != NULL, ("no space for 802.11 header?")); 37578a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 37588a1b9b6aSSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 37598a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_BEACON; 37608a1b9b6aSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 376168e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 37628a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 3763b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 37648a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 376568e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 0; 37668a1b9b6aSSam Leffler 37678a1b9b6aSSam Leffler return m; 37688a1b9b6aSSam Leffler } 37698a1b9b6aSSam Leffler 37708a1b9b6aSSam Leffler /* 37718a1b9b6aSSam Leffler * Update the dynamic parts of a beacon frame based on the current state. 37728a1b9b6aSSam Leffler */ 37738a1b9b6aSSam Leffler int 3774210ab3c2SAdrian Chadd ieee80211_beacon_update(struct ieee80211_node *ni, struct mbuf *m, int mcast) 37758a1b9b6aSSam Leffler { 3776b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 3777210ab3c2SAdrian Chadd struct ieee80211_beacon_offsets *bo = &vap->iv_bcn_off; 3778b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 37798a1b9b6aSSam Leffler int len_changed = 0; 378068e8e04eSSam Leffler uint16_t capinfo; 3781fa3324c9SAdrian Chadd struct ieee80211_frame *wh; 3782fa3324c9SAdrian Chadd ieee80211_seq seqno; 37838a1b9b6aSSam Leffler 3784b032f27cSSam Leffler IEEE80211_LOCK(ic); 3785b032f27cSSam Leffler /* 3786b032f27cSSam Leffler * Handle 11h channel change when we've reached the count. 3787b032f27cSSam Leffler * We must recalculate the beacon frame contents to account 3788b032f27cSSam Leffler * for the new channel. Note we do this only for the first 3789b032f27cSSam Leffler * vap that reaches this point; subsequent vaps just update 3790b032f27cSSam Leffler * their beacon state to reflect the recalculated channel. 3791b032f27cSSam Leffler */ 3792b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && 3793b032f27cSSam Leffler vap->iv_csa_count == ic->ic_csa_count) { 3794b032f27cSSam Leffler vap->iv_csa_count = 0; 3795b032f27cSSam Leffler /* 3796b032f27cSSam Leffler * Effect channel change before reconstructing the beacon 3797b032f27cSSam Leffler * frame contents as many places reference ni_chan. 3798b032f27cSSam Leffler */ 3799b032f27cSSam Leffler if (ic->ic_csa_newchan != NULL) 3800b032f27cSSam Leffler ieee80211_csa_completeswitch(ic); 3801b032f27cSSam Leffler /* 3802b032f27cSSam Leffler * NB: ieee80211_beacon_construct clears all pending 3803b032f27cSSam Leffler * updates in bo_flags so we don't need to explicitly 3804b032f27cSSam Leffler * clear IEEE80211_BEACON_CSA. 3805b032f27cSSam Leffler */ 3806b032f27cSSam Leffler ieee80211_beacon_construct(m, 3807210ab3c2SAdrian Chadd mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni); 3808b032f27cSSam Leffler 3809b032f27cSSam Leffler /* XXX do WME aggressive mode processing? */ 3810b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 3811b032f27cSSam Leffler return 1; /* just assume length changed */ 3812b032f27cSSam Leffler } 3813b032f27cSSam Leffler 38144d3dcce5SAdrian Chadd /* 38154d3dcce5SAdrian Chadd * Handle the quiet time element being added and removed. 38164d3dcce5SAdrian Chadd * Again, for now we just cheat and reconstruct the whole 38174d3dcce5SAdrian Chadd * beacon - that way the gap is provided as appropriate. 38184d3dcce5SAdrian Chadd * 38194d3dcce5SAdrian Chadd * So, track whether we have already added the IE versus 38204d3dcce5SAdrian Chadd * whether we want to be adding the IE. 38214d3dcce5SAdrian Chadd */ 38224d3dcce5SAdrian Chadd if ((vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE) && 38234d3dcce5SAdrian Chadd (vap->iv_quiet == 0)) { 38244d3dcce5SAdrian Chadd /* 38254d3dcce5SAdrian Chadd * Quiet time beacon IE enabled, but it's disabled; 38264d3dcce5SAdrian Chadd * recalc 38274d3dcce5SAdrian Chadd */ 38284d3dcce5SAdrian Chadd vap->iv_flags_ext &= ~IEEE80211_FEXT_QUIET_IE; 38294d3dcce5SAdrian Chadd ieee80211_beacon_construct(m, 38304d3dcce5SAdrian Chadd mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni); 38314d3dcce5SAdrian Chadd /* XXX do WME aggressive mode processing? */ 38324d3dcce5SAdrian Chadd IEEE80211_UNLOCK(ic); 38334d3dcce5SAdrian Chadd return 1; /* just assume length changed */ 38344d3dcce5SAdrian Chadd } 38354d3dcce5SAdrian Chadd 38364d3dcce5SAdrian Chadd if (((vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE) == 0) && 38374d3dcce5SAdrian Chadd (vap->iv_quiet == 1)) { 38384d3dcce5SAdrian Chadd /* 38394d3dcce5SAdrian Chadd * Quiet time beacon IE disabled, but it's now enabled; 38404d3dcce5SAdrian Chadd * recalc 38414d3dcce5SAdrian Chadd */ 38424d3dcce5SAdrian Chadd vap->iv_flags_ext |= IEEE80211_FEXT_QUIET_IE; 38434d3dcce5SAdrian Chadd ieee80211_beacon_construct(m, 38444d3dcce5SAdrian Chadd mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), ni); 38454d3dcce5SAdrian Chadd /* XXX do WME aggressive mode processing? */ 38464d3dcce5SAdrian Chadd IEEE80211_UNLOCK(ic); 38474d3dcce5SAdrian Chadd return 1; /* just assume length changed */ 38484d3dcce5SAdrian Chadd } 38494d3dcce5SAdrian Chadd 3850fa3324c9SAdrian Chadd wh = mtod(m, struct ieee80211_frame *); 385151172f62SAdrian Chadd 385251172f62SAdrian Chadd /* 385351172f62SAdrian Chadd * XXX TODO Strictly speaking this should be incremented with the TX 385451172f62SAdrian Chadd * lock held so as to serialise access to the non-qos TID sequence 385551172f62SAdrian Chadd * number space. 385651172f62SAdrian Chadd * 385751172f62SAdrian Chadd * If the driver identifies it does its own TX seqno management then 385851172f62SAdrian Chadd * we can skip this (and still not do the TX seqno.) 385951172f62SAdrian Chadd */ 3860fa3324c9SAdrian Chadd seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 3861fa3324c9SAdrian Chadd *(uint16_t *)&wh->i_seq[0] = 3862fa3324c9SAdrian Chadd htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 3863fa3324c9SAdrian Chadd M_SEQNO_SET(m, seqno); 3864fa3324c9SAdrian Chadd 38658a1b9b6aSSam Leffler /* XXX faster to recalculate entirely or just changes? */ 386659aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 38678a1b9b6aSSam Leffler *bo->bo_caps = htole16(capinfo); 38688a1b9b6aSSam Leffler 3869b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 38708a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 38718a1b9b6aSSam Leffler 38728a1b9b6aSSam Leffler /* 3873a4641f4eSPedro F. Giffuni * Check for aggressive mode change. When there is 38748a1b9b6aSSam Leffler * significant high priority traffic in the BSS 38758a1b9b6aSSam Leffler * throttle back BE traffic by using conservative 3876a4641f4eSPedro F. Giffuni * parameters. Otherwise BE uses aggressive params 38778a1b9b6aSSam Leffler * to optimize performance of legacy/non-QoS traffic. 38788a1b9b6aSSam Leffler */ 38798a1b9b6aSSam Leffler if (wme->wme_flags & WME_F_AGGRMODE) { 38808a1b9b6aSSam Leffler if (wme->wme_hipri_traffic > 38818a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 3882b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 38838a1b9b6aSSam Leffler "%s: traffic %u, disable aggressive mode\n", 38848a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 38858a1b9b6aSSam Leffler wme->wme_flags &= ~WME_F_AGGRMODE; 3886b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 38878a1b9b6aSSam Leffler wme->wme_hipri_traffic = 38888a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 38898a1b9b6aSSam Leffler } else 38908a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 38918a1b9b6aSSam Leffler } else { 38928a1b9b6aSSam Leffler if (wme->wme_hipri_traffic <= 38938a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 3894b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 38958a1b9b6aSSam Leffler "%s: traffic %u, enable aggressive mode\n", 38968a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 38978a1b9b6aSSam Leffler wme->wme_flags |= WME_F_AGGRMODE; 3898b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 38998a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 39008a1b9b6aSSam Leffler } else 39018a1b9b6aSSam Leffler wme->wme_hipri_traffic = 39028a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 39038a1b9b6aSSam Leffler } 3904b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { 39058379e8dbSAdrian Chadd (void) ieee80211_add_wme_param(bo->bo_wme, wme, 39068379e8dbSAdrian Chadd vap->iv_flags_ext & IEEE80211_FEXT_UAPSD); 3907b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_WME); 39088a1b9b6aSSam Leffler } 39098a1b9b6aSSam Leffler } 39108a1b9b6aSSam Leffler 3911b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { 3912b032f27cSSam Leffler ieee80211_ht_update_beacon(vap, bo); 3913b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); 391468e8e04eSSam Leffler } 391510ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 391610ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 391710ad9a77SSam Leffler /* 391810ad9a77SSam Leffler * NB: the beacon is potentially updated every TBTT. 391910ad9a77SSam Leffler */ 392010ad9a77SSam Leffler ieee80211_tdma_update_beacon(vap, bo); 392110ad9a77SSam Leffler } 392210ad9a77SSam Leffler #endif 3923d093681cSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 3924d093681cSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 3925d093681cSRui Paulo ieee80211_mesh_update_beacon(vap, bo); 3926d093681cSRui Paulo #endif 3927d093681cSRui Paulo 392859aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP || 392959aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/ 39308a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = 39318a1b9b6aSSam Leffler (struct ieee80211_tim_ie *) bo->bo_tim; 3932b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { 39338a1b9b6aSSam Leffler u_int timlen, timoff, i; 39348a1b9b6aSSam Leffler /* 39358a1b9b6aSSam Leffler * ATIM/DTIM needs updating. If it fits in the 39368a1b9b6aSSam Leffler * current space allocated then just copy in the 39378a1b9b6aSSam Leffler * new bits. Otherwise we need to move any trailing 39388a1b9b6aSSam Leffler * data to make room. Note that we know there is 39398a1b9b6aSSam Leffler * contiguous space because ieee80211_beacon_allocate 39408a1b9b6aSSam Leffler * insures there is space in the mbuf to write a 3941b032f27cSSam Leffler * maximal-size virtual bitmap (based on iv_max_aid). 39428a1b9b6aSSam Leffler */ 39438a1b9b6aSSam Leffler /* 39448a1b9b6aSSam Leffler * Calculate the bitmap size and offset, copy any 39458a1b9b6aSSam Leffler * trailer out of the way, and then copy in the 39468a1b9b6aSSam Leffler * new bitmap and update the information element. 39478a1b9b6aSSam Leffler * Note that the tim bitmap must contain at least 39488a1b9b6aSSam Leffler * one byte and any offset must be even. 39498a1b9b6aSSam Leffler */ 3950b032f27cSSam Leffler if (vap->iv_ps_pending != 0) { 39518a1b9b6aSSam Leffler timoff = 128; /* impossibly large */ 3952b032f27cSSam Leffler for (i = 0; i < vap->iv_tim_len; i++) 3953b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) { 39548a1b9b6aSSam Leffler timoff = i &~ 1; 39558a1b9b6aSSam Leffler break; 39568a1b9b6aSSam Leffler } 39578a1b9b6aSSam Leffler KASSERT(timoff != 128, ("tim bitmap empty!")); 3958b032f27cSSam Leffler for (i = vap->iv_tim_len-1; i >= timoff; i--) 3959b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) 39608a1b9b6aSSam Leffler break; 39618a1b9b6aSSam Leffler timlen = 1 + (i - timoff); 39628a1b9b6aSSam Leffler } else { 39638a1b9b6aSSam Leffler timoff = 0; 39648a1b9b6aSSam Leffler timlen = 1; 39658a1b9b6aSSam Leffler } 396651172f62SAdrian Chadd 396751172f62SAdrian Chadd /* 396851172f62SAdrian Chadd * TODO: validate this! 396951172f62SAdrian Chadd */ 39708a1b9b6aSSam Leffler if (timlen != bo->bo_tim_len) { 39718a1b9b6aSSam Leffler /* copy up/down trailer */ 39720912bac9SSam Leffler int adjust = tie->tim_bitmap+timlen 3973b105a069SSam Leffler - bo->bo_tim_trailer; 3974b105a069SSam Leffler ovbcopy(bo->bo_tim_trailer, 3975b105a069SSam Leffler bo->bo_tim_trailer+adjust, 3976b105a069SSam Leffler bo->bo_tim_trailer_len); 3977b105a069SSam Leffler bo->bo_tim_trailer += adjust; 39780912bac9SSam Leffler bo->bo_erp += adjust; 397968e8e04eSSam Leffler bo->bo_htinfo += adjust; 398051172f62SAdrian Chadd bo->bo_vhtinfo += adjust; 398102e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG 39824207227cSSam Leffler bo->bo_ath += adjust; 39834207227cSSam Leffler #endif 398402e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA 398592e870edSSam Leffler bo->bo_tdma += adjust; 398692e870edSSam Leffler #endif 398702e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH 3988d093681cSRui Paulo bo->bo_meshconf += adjust; 3989d093681cSRui Paulo #endif 3990b032f27cSSam Leffler bo->bo_appie += adjust; 3991b032f27cSSam Leffler bo->bo_wme += adjust; 3992b032f27cSSam Leffler bo->bo_csa += adjust; 399332b0e64bSAdrian Chadd bo->bo_quiet += adjust; 39948a1b9b6aSSam Leffler bo->bo_tim_len = timlen; 39958a1b9b6aSSam Leffler 39968a1b9b6aSSam Leffler /* update information element */ 39978a1b9b6aSSam Leffler tie->tim_len = 3 + timlen; 39988a1b9b6aSSam Leffler tie->tim_bitctl = timoff; 39998a1b9b6aSSam Leffler len_changed = 1; 40008a1b9b6aSSam Leffler } 4001b032f27cSSam Leffler memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, 40028a1b9b6aSSam Leffler bo->bo_tim_len); 40038a1b9b6aSSam Leffler 4004b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); 40058a1b9b6aSSam Leffler 4006b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 40078a1b9b6aSSam Leffler "%s: TIM updated, pending %u, off %u, len %u\n", 4008b032f27cSSam Leffler __func__, vap->iv_ps_pending, timoff, timlen); 40098a1b9b6aSSam Leffler } 40108a1b9b6aSSam Leffler /* count down DTIM period */ 40118a1b9b6aSSam Leffler if (tie->tim_count == 0) 40128a1b9b6aSSam Leffler tie->tim_count = tie->tim_period - 1; 40138a1b9b6aSSam Leffler else 40148a1b9b6aSSam Leffler tie->tim_count--; 40158a1b9b6aSSam Leffler /* update state for buffered multicast frames on DTIM */ 4016a196b35fSSam Leffler if (mcast && tie->tim_count == 0) 40178a1b9b6aSSam Leffler tie->tim_bitctl |= 1; 40188a1b9b6aSSam Leffler else 40198a1b9b6aSSam Leffler tie->tim_bitctl &= ~1; 4020b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { 4021b032f27cSSam Leffler struct ieee80211_csa_ie *csa = 4022b032f27cSSam Leffler (struct ieee80211_csa_ie *) bo->bo_csa; 4023b032f27cSSam Leffler 4024b032f27cSSam Leffler /* 4025b032f27cSSam Leffler * Insert or update CSA ie. If we're just starting 4026b032f27cSSam Leffler * to count down to the channel switch then we need 4027b032f27cSSam Leffler * to insert the CSA ie. Otherwise we just need to 4028b032f27cSSam Leffler * drop the count. The actual change happens above 4029b032f27cSSam Leffler * when the vap's count reaches the target count. 4030b032f27cSSam Leffler */ 4031b032f27cSSam Leffler if (vap->iv_csa_count == 0) { 4032b032f27cSSam Leffler memmove(&csa[1], csa, bo->bo_csa_trailer_len); 4033b032f27cSSam Leffler bo->bo_erp += sizeof(*csa); 4034d01b3c26SSam Leffler bo->bo_htinfo += sizeof(*csa); 403551172f62SAdrian Chadd bo->bo_vhtinfo += sizeof(*csa); 4036b032f27cSSam Leffler bo->bo_wme += sizeof(*csa); 403702e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG 40384207227cSSam Leffler bo->bo_ath += sizeof(*csa); 40394207227cSSam Leffler #endif 404002e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA 404192e870edSSam Leffler bo->bo_tdma += sizeof(*csa); 404292e870edSSam Leffler #endif 404302e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH 4044d093681cSRui Paulo bo->bo_meshconf += sizeof(*csa); 4045d093681cSRui Paulo #endif 4046b032f27cSSam Leffler bo->bo_appie += sizeof(*csa); 4047b032f27cSSam Leffler bo->bo_csa_trailer_len += sizeof(*csa); 404832b0e64bSAdrian Chadd bo->bo_quiet += sizeof(*csa); 4049b032f27cSSam Leffler bo->bo_tim_trailer_len += sizeof(*csa); 4050b032f27cSSam Leffler m->m_len += sizeof(*csa); 4051b032f27cSSam Leffler m->m_pkthdr.len += sizeof(*csa); 4052b032f27cSSam Leffler 4053b032f27cSSam Leffler ieee80211_add_csa(bo->bo_csa, vap); 4054b032f27cSSam Leffler } else 4055b032f27cSSam Leffler csa->csa_count--; 4056b032f27cSSam Leffler vap->iv_csa_count++; 4057b032f27cSSam Leffler /* NB: don't clear IEEE80211_BEACON_CSA */ 4058b032f27cSSam Leffler } 40594d3dcce5SAdrian Chadd 40604d3dcce5SAdrian Chadd /* 40614d3dcce5SAdrian Chadd * Only add the quiet time IE if we've enabled it 40624d3dcce5SAdrian Chadd * as appropriate. 40634d3dcce5SAdrian Chadd */ 406432b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 406532b0e64bSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 40664d3dcce5SAdrian Chadd if (vap->iv_quiet && 40674d3dcce5SAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_QUIET_IE)) { 4068ce4552cdSAdrian Chadd ieee80211_add_quiet(bo->bo_quiet, vap, 1); 406932b0e64bSAdrian Chadd } 40704d3dcce5SAdrian Chadd } 4071b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { 40720912bac9SSam Leffler /* 40730912bac9SSam Leffler * ERP element needs updating. 40740912bac9SSam Leffler */ 4075f1481c8dSAdrian Chadd (void) ieee80211_add_erp(bo->bo_erp, vap); 4076b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); 40770912bac9SSam Leffler } 40784207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 40794207227cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ATH)) { 40804207227cSSam Leffler ieee80211_add_athcaps(bo->bo_ath, ni); 40814207227cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ATH); 40824207227cSSam Leffler } 40834207227cSSam Leffler #endif 40848a1b9b6aSSam Leffler } 4085b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { 4086b032f27cSSam Leffler const struct ieee80211_appie *aie = vap->iv_appie_beacon; 4087b032f27cSSam Leffler int aielen; 4088b032f27cSSam Leffler uint8_t *frm; 4089b032f27cSSam Leffler 4090b032f27cSSam Leffler aielen = 0; 4091b032f27cSSam Leffler if (aie != NULL) 4092b032f27cSSam Leffler aielen += aie->ie_len; 4093b032f27cSSam Leffler if (aielen != bo->bo_appie_len) { 4094b032f27cSSam Leffler /* copy up/down trailer */ 4095b032f27cSSam Leffler int adjust = aielen - bo->bo_appie_len; 4096b032f27cSSam Leffler ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, 4097b032f27cSSam Leffler bo->bo_tim_trailer_len); 4098b032f27cSSam Leffler bo->bo_tim_trailer += adjust; 4099b032f27cSSam Leffler bo->bo_appie += adjust; 4100b032f27cSSam Leffler bo->bo_appie_len = aielen; 4101b032f27cSSam Leffler 4102b032f27cSSam Leffler len_changed = 1; 4103b032f27cSSam Leffler } 4104b032f27cSSam Leffler frm = bo->bo_appie; 4105b032f27cSSam Leffler if (aie != NULL) 4106b032f27cSSam Leffler frm = add_appie(frm, aie); 4107b032f27cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); 4108b032f27cSSam Leffler } 4109b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 41108a1b9b6aSSam Leffler 41118a1b9b6aSSam Leffler return len_changed; 41128a1b9b6aSSam Leffler } 411374b4c76eSAdrian Chadd 411474b4c76eSAdrian Chadd /* 411574b4c76eSAdrian Chadd * Do Ethernet-LLC encapsulation for each payload in a fast frame 411674b4c76eSAdrian Chadd * tunnel encapsulation. The frame is assumed to have an Ethernet 411774b4c76eSAdrian Chadd * header at the front that must be stripped before prepending the 411874b4c76eSAdrian Chadd * LLC followed by the Ethernet header passed in (with an Ethernet 411974b4c76eSAdrian Chadd * type that specifies the payload size). 412074b4c76eSAdrian Chadd */ 412174b4c76eSAdrian Chadd struct mbuf * 412274b4c76eSAdrian Chadd ieee80211_ff_encap1(struct ieee80211vap *vap, struct mbuf *m, 412374b4c76eSAdrian Chadd const struct ether_header *eh) 412474b4c76eSAdrian Chadd { 412574b4c76eSAdrian Chadd struct llc *llc; 412674b4c76eSAdrian Chadd uint16_t payload; 412774b4c76eSAdrian Chadd 412874b4c76eSAdrian Chadd /* XXX optimize by combining m_adj+M_PREPEND */ 412974b4c76eSAdrian Chadd m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 413074b4c76eSAdrian Chadd llc = mtod(m, struct llc *); 413174b4c76eSAdrian Chadd llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 413274b4c76eSAdrian Chadd llc->llc_control = LLC_UI; 413374b4c76eSAdrian Chadd llc->llc_snap.org_code[0] = 0; 413474b4c76eSAdrian Chadd llc->llc_snap.org_code[1] = 0; 413574b4c76eSAdrian Chadd llc->llc_snap.org_code[2] = 0; 413674b4c76eSAdrian Chadd llc->llc_snap.ether_type = eh->ether_type; 413774b4c76eSAdrian Chadd payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */ 413874b4c76eSAdrian Chadd 413974b4c76eSAdrian Chadd M_PREPEND(m, sizeof(struct ether_header), M_NOWAIT); 414074b4c76eSAdrian Chadd if (m == NULL) { /* XXX cannot happen */ 414174b4c76eSAdrian Chadd IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 414274b4c76eSAdrian Chadd "%s: no space for ether_header\n", __func__); 414374b4c76eSAdrian Chadd vap->iv_stats.is_tx_nobuf++; 414474b4c76eSAdrian Chadd return NULL; 414574b4c76eSAdrian Chadd } 414674b4c76eSAdrian Chadd ETHER_HEADER_COPY(mtod(m, void *), eh); 414774b4c76eSAdrian Chadd mtod(m, struct ether_header *)->ether_type = htons(payload); 414874b4c76eSAdrian Chadd return m; 414974b4c76eSAdrian Chadd } 415036ee7775SAdrian Chadd 415136ee7775SAdrian Chadd /* 415236ee7775SAdrian Chadd * Complete an mbuf transmission. 415336ee7775SAdrian Chadd * 415436ee7775SAdrian Chadd * For now, this simply processes a completed frame after the 415536ee7775SAdrian Chadd * driver has completed it's transmission and/or retransmission. 415636ee7775SAdrian Chadd * It assumes the frame is an 802.11 encapsulated frame. 415736ee7775SAdrian Chadd * 415836ee7775SAdrian Chadd * Later on it will grow to become the exit path for a given frame 415936ee7775SAdrian Chadd * from the driver and, depending upon how it's been encapsulated 416036ee7775SAdrian Chadd * and already transmitted, it may end up doing A-MPDU retransmission, 416136ee7775SAdrian Chadd * power save requeuing, etc. 416236ee7775SAdrian Chadd * 416336ee7775SAdrian Chadd * In order for the above to work, the driver entry point to this 416436ee7775SAdrian Chadd * must not hold any driver locks. Thus, the driver needs to delay 416536ee7775SAdrian Chadd * any actual mbuf completion until it can release said locks. 416636ee7775SAdrian Chadd * 416736ee7775SAdrian Chadd * This frees the mbuf and if the mbuf has a node reference, 416836ee7775SAdrian Chadd * the node reference will be freed. 416936ee7775SAdrian Chadd */ 417036ee7775SAdrian Chadd void 417136ee7775SAdrian Chadd ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status) 417236ee7775SAdrian Chadd { 417336ee7775SAdrian Chadd 417436ee7775SAdrian Chadd if (ni != NULL) { 41757a79cebfSGleb Smirnoff struct ifnet *ifp = ni->ni_vap->iv_ifp; 41767a79cebfSGleb Smirnoff 41777a79cebfSGleb Smirnoff if (status == 0) { 41787a79cebfSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len); 41797a79cebfSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1); 41807a79cebfSGleb Smirnoff if (m->m_flags & M_MCAST) 41817a79cebfSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 41827a79cebfSGleb Smirnoff } else 41837a79cebfSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 418404efa18fSBjoern A. Zeeb if (m->m_flags & M_TXCB) { 418504efa18fSBjoern A. Zeeb IEEE80211_DPRINTF(ni->ni_vap, IEEE80211_MSG_STATE | IEEE80211_MSG_DEBUG, 418604efa18fSBjoern A. Zeeb "ni %p vap %p mode %s state %s m %p status %d\n", ni, ni->ni_vap, 418704efa18fSBjoern A. Zeeb ieee80211_opmode_name[ni->ni_vap->iv_opmode], 418804efa18fSBjoern A. Zeeb ieee80211_state_name[ni->ni_vap->iv_state], m, status); 418936ee7775SAdrian Chadd ieee80211_process_callback(ni, m, status); 419004efa18fSBjoern A. Zeeb } 419136ee7775SAdrian Chadd ieee80211_free_node(ni); 419236ee7775SAdrian Chadd } 419336ee7775SAdrian Chadd m_freem(m); 419436ee7775SAdrian Chadd } 4195