11a1e1d21SSam Leffler /*- 27535e66aSSam Leffler * Copyright (c) 2001 Atsushi Onoe 310ad9a77SSam Leffler * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 41a1e1d21SSam Leffler * All rights reserved. 51a1e1d21SSam Leffler * 61a1e1d21SSam Leffler * Redistribution and use in source and binary forms, with or without 71a1e1d21SSam Leffler * modification, are permitted provided that the following conditions 81a1e1d21SSam Leffler * are met: 91a1e1d21SSam Leffler * 1. Redistributions of source code must retain the above copyright 107535e66aSSam Leffler * notice, this list of conditions and the following disclaimer. 117535e66aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 127535e66aSSam Leffler * notice, this list of conditions and the following disclaimer in the 137535e66aSSam Leffler * documentation and/or other materials provided with the distribution. 141a1e1d21SSam Leffler * 157535e66aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 167535e66aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 177535e66aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 187535e66aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 197535e66aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 207535e66aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 217535e66aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 227535e66aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 237535e66aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 247535e66aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251a1e1d21SSam Leffler */ 261a1e1d21SSam Leffler 271a1e1d21SSam Leffler #include <sys/cdefs.h> 281a1e1d21SSam Leffler __FBSDID("$FreeBSD$"); 291a1e1d21SSam Leffler 301a1e1d21SSam Leffler #include "opt_inet.h" 31e755a73dSSam Leffler #include "opt_inet6.h" 32b032f27cSSam Leffler #include "opt_wlan.h" 331a1e1d21SSam Leffler 341a1e1d21SSam Leffler #include <sys/param.h> 351a1e1d21SSam Leffler #include <sys/systm.h> 361a1e1d21SSam Leffler #include <sys/mbuf.h> 371a1e1d21SSam Leffler #include <sys/kernel.h> 381a1e1d21SSam Leffler #include <sys/endian.h> 391a1e1d21SSam Leffler 408a1b9b6aSSam Leffler #include <sys/socket.h> 411a1e1d21SSam Leffler 421a1e1d21SSam Leffler #include <net/bpf.h> 438a1b9b6aSSam Leffler #include <net/ethernet.h> 448a1b9b6aSSam Leffler #include <net/if.h> 458a1b9b6aSSam Leffler #include <net/if_llc.h> 468a1b9b6aSSam Leffler #include <net/if_media.h> 478a1b9b6aSSam Leffler #include <net/if_vlan_var.h> 488a1b9b6aSSam Leffler 498a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h> 5068e8e04eSSam Leffler #include <net80211/ieee80211_regdomain.h> 51616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 52616190d0SSam Leffler #include <net80211/ieee80211_superg.h> 53616190d0SSam Leffler #endif 5410ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 5510ad9a77SSam Leffler #include <net80211/ieee80211_tdma.h> 5610ad9a77SSam Leffler #endif 57b032f27cSSam Leffler #include <net80211/ieee80211_wds.h> 5859aa14a9SRui Paulo #include <net80211/ieee80211_mesh.h> 591a1e1d21SSam Leffler 608355d59dSBjoern A. Zeeb #if defined(INET) || defined(INET6) 611a1e1d21SSam Leffler #include <netinet/in.h> 628355d59dSBjoern A. Zeeb #endif 638355d59dSBjoern A. Zeeb 648355d59dSBjoern A. Zeeb #ifdef INET 651a1e1d21SSam Leffler #include <netinet/if_ether.h> 668a1b9b6aSSam Leffler #include <netinet/in_systm.h> 678a1b9b6aSSam Leffler #include <netinet/ip.h> 688a1b9b6aSSam Leffler #endif 69e755a73dSSam Leffler #ifdef INET6 70e755a73dSSam Leffler #include <netinet/ip6.h> 71e755a73dSSam Leffler #endif 728a1b9b6aSSam Leffler 73c27b9cdbSRobert Watson #include <security/mac/mac_framework.h> 74c27b9cdbSRobert Watson 7568e8e04eSSam Leffler #define ETHER_HEADER_COPY(dst, src) \ 7668e8e04eSSam Leffler memcpy(dst, src, sizeof(struct ether_header)) 7768e8e04eSSam Leffler 7859aa14a9SRui Paulo /* unalligned little endian access */ 7959aa14a9SRui Paulo #define LE_WRITE_2(p, v) do { \ 8059aa14a9SRui Paulo ((uint8_t *)(p))[0] = (v) & 0xff; \ 8159aa14a9SRui Paulo ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 8259aa14a9SRui Paulo } while (0) 8359aa14a9SRui Paulo #define LE_WRITE_4(p, v) do { \ 8459aa14a9SRui Paulo ((uint8_t *)(p))[0] = (v) & 0xff; \ 8559aa14a9SRui Paulo ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 8659aa14a9SRui Paulo ((uint8_t *)(p))[2] = ((v) >> 16) & 0xff; \ 8759aa14a9SRui Paulo ((uint8_t *)(p))[3] = ((v) >> 24) & 0xff; \ 8859aa14a9SRui Paulo } while (0) 8959aa14a9SRui Paulo 90b032f27cSSam Leffler static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *, 9168e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu); 9268e8e04eSSam Leffler static void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int); 9368e8e04eSSam Leffler 948a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 958a1b9b6aSSam Leffler /* 968a1b9b6aSSam Leffler * Decide if an outbound management frame should be 978a1b9b6aSSam Leffler * printed when debugging is enabled. This filters some 988a1b9b6aSSam Leffler * of the less interesting frames that come frequently 998a1b9b6aSSam Leffler * (e.g. beacons). 1008a1b9b6aSSam Leffler */ 1018a1b9b6aSSam Leffler static __inline int 102b032f27cSSam Leffler doprint(struct ieee80211vap *vap, int subtype) 1038a1b9b6aSSam Leffler { 1048a1b9b6aSSam Leffler switch (subtype) { 1058a1b9b6aSSam Leffler case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 106b032f27cSSam Leffler return (vap->iv_opmode == IEEE80211_M_IBSS); 1078a1b9b6aSSam Leffler } 1088a1b9b6aSSam Leffler return 1; 1098a1b9b6aSSam Leffler } 1101a1e1d21SSam Leffler #endif 1111a1e1d21SSam Leffler 1120a915fadSSam Leffler /* 113b032f27cSSam Leffler * Start method for vap's. All packets from the stack come 114b032f27cSSam Leffler * through here. We handle common processing of the packets 115b032f27cSSam Leffler * before dispatching them to the underlying device. 116b032f27cSSam Leffler */ 117b032f27cSSam Leffler void 118b032f27cSSam Leffler ieee80211_start(struct ifnet *ifp) 119b032f27cSSam Leffler { 120b032f27cSSam Leffler #define IS_DWDS(vap) \ 121b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_WDS && \ 122b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0) 123b032f27cSSam Leffler struct ieee80211vap *vap = ifp->if_softc; 124b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 125b032f27cSSam Leffler struct ifnet *parent = ic->ic_ifp; 126b032f27cSSam Leffler struct ieee80211_node *ni; 127b032f27cSSam Leffler struct mbuf *m; 128b032f27cSSam Leffler struct ether_header *eh; 129b032f27cSSam Leffler int error; 130b032f27cSSam Leffler 131b032f27cSSam Leffler /* NB: parent must be up and running */ 132b032f27cSSam Leffler if (!IFNET_IS_UP_RUNNING(parent)) { 133b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 134b032f27cSSam Leffler "%s: ignore queue, parent %s not up+running\n", 135b032f27cSSam Leffler __func__, parent->if_xname); 136b032f27cSSam Leffler /* XXX stat */ 137b032f27cSSam Leffler return; 138b032f27cSSam Leffler } 139b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_SLEEP) { 140b032f27cSSam Leffler /* 141b032f27cSSam Leffler * In power save, wakeup device for transmit. 142b032f27cSSam Leffler */ 143b032f27cSSam Leffler ieee80211_new_state(vap, IEEE80211_S_RUN, 0); 144b032f27cSSam Leffler return; 145b032f27cSSam Leffler } 146b032f27cSSam Leffler /* 147b032f27cSSam Leffler * No data frames go out unless we're running. 148b032f27cSSam Leffler * Note in particular this covers CAC and CSA 149b032f27cSSam Leffler * states (though maybe we should check muting 150b032f27cSSam Leffler * for CSA). 151b032f27cSSam Leffler */ 152b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_RUN) { 153b032f27cSSam Leffler IEEE80211_LOCK(ic); 154b032f27cSSam Leffler /* re-check under the com lock to avoid races */ 155b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_RUN) { 156b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 157b032f27cSSam Leffler "%s: ignore queue, in %s state\n", 158b032f27cSSam Leffler __func__, ieee80211_state_name[vap->iv_state]); 159b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 160b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 161*70e0b5acSAdrian Chadd IFQ_LOCK(&ifp->if_snd); 162*70e0b5acSAdrian Chadd ifp->if_drv_flags |= IFF_DRV_OACTIVE; 163*70e0b5acSAdrian Chadd IFQ_UNLOCK(&ifp->if_snd); 164b032f27cSSam Leffler return; 165b032f27cSSam Leffler } 166b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 167b032f27cSSam Leffler } 168b032f27cSSam Leffler for (;;) { 169b032f27cSSam Leffler IFQ_DEQUEUE(&ifp->if_snd, m); 170b032f27cSSam Leffler if (m == NULL) 171b032f27cSSam Leffler break; 172b032f27cSSam Leffler /* 173b032f27cSSam Leffler * Sanitize mbuf flags for net80211 use. We cannot 174927ef5ffSSam Leffler * clear M_PWR_SAV or M_MORE_DATA because these may 175927ef5ffSSam Leffler * be set for frames that are re-submitted from the 176927ef5ffSSam Leffler * power save queue. 177b032f27cSSam Leffler * 178b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 179b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 180b032f27cSSam Leffler */ 181927ef5ffSSam Leffler m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); 182b032f27cSSam Leffler /* 183b032f27cSSam Leffler * Cancel any background scan. 184b032f27cSSam Leffler */ 185b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_SCAN) 186b032f27cSSam Leffler ieee80211_cancel_anyscan(vap); 187b032f27cSSam Leffler /* 188b032f27cSSam Leffler * Find the node for the destination so we can do 189b032f27cSSam Leffler * things like power save and fast frames aggregation. 190b032f27cSSam Leffler * 191b032f27cSSam Leffler * NB: past this point various code assumes the first 192b032f27cSSam Leffler * mbuf has the 802.3 header present (and contiguous). 193b032f27cSSam Leffler */ 194b032f27cSSam Leffler ni = NULL; 195b032f27cSSam Leffler if (m->m_len < sizeof(struct ether_header) && 196b032f27cSSam Leffler (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 197b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 198b032f27cSSam Leffler "discard frame, %s\n", "m_pullup failed"); 199b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX */ 200b032f27cSSam Leffler ifp->if_oerrors++; 201b032f27cSSam Leffler continue; 202b032f27cSSam Leffler } 203b032f27cSSam Leffler eh = mtod(m, struct ether_header *); 204b032f27cSSam Leffler if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 205b032f27cSSam Leffler if (IS_DWDS(vap)) { 206b032f27cSSam Leffler /* 207b032f27cSSam Leffler * Only unicast frames from the above go out 208b032f27cSSam Leffler * DWDS vaps; multicast frames are handled by 209b032f27cSSam Leffler * dispatching the frame as it comes through 210b032f27cSSam Leffler * the AP vap (see below). 211b032f27cSSam Leffler */ 212b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS, 213b032f27cSSam Leffler eh->ether_dhost, "mcast", "%s", "on DWDS"); 214b032f27cSSam Leffler vap->iv_stats.is_dwds_mcast++; 215b032f27cSSam Leffler m_freem(m); 216b032f27cSSam Leffler continue; 217b032f27cSSam Leffler } 218b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 219b032f27cSSam Leffler /* 220b032f27cSSam Leffler * Spam DWDS vap's w/ multicast traffic. 221b032f27cSSam Leffler */ 222b032f27cSSam Leffler /* XXX only if dwds in use? */ 223b032f27cSSam Leffler ieee80211_dwds_mcast(vap, m); 224b032f27cSSam Leffler } 225b032f27cSSam Leffler } 22659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 22759aa14a9SRui Paulo if (vap->iv_opmode != IEEE80211_M_MBSS) { 22859aa14a9SRui Paulo #endif 229b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, eh->ether_dhost); 230b032f27cSSam Leffler if (ni == NULL) { 231b032f27cSSam Leffler /* NB: ieee80211_find_txnode does stat+msg */ 232b032f27cSSam Leffler ifp->if_oerrors++; 233b032f27cSSam Leffler m_freem(m); 234b032f27cSSam Leffler continue; 235b032f27cSSam Leffler } 2366ff2e10aSSam Leffler if (ni->ni_associd == 0 && 2371b999d64SSam Leffler (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { 238b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 239b032f27cSSam Leffler eh->ether_dhost, NULL, 240b032f27cSSam Leffler "sta not associated (type 0x%04x)", 241b032f27cSSam Leffler htons(eh->ether_type)); 242b032f27cSSam Leffler vap->iv_stats.is_tx_notassoc++; 243b032f27cSSam Leffler ifp->if_oerrors++; 244b032f27cSSam Leffler m_freem(m); 245b032f27cSSam Leffler ieee80211_free_node(ni); 246b032f27cSSam Leffler continue; 247b032f27cSSam Leffler } 24859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 24959aa14a9SRui Paulo } else { 250c104cff2SRui Paulo if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) { 251c104cff2SRui Paulo /* 252c104cff2SRui Paulo * Proxy station only if configured. 253c104cff2SRui Paulo */ 254c104cff2SRui Paulo if (!ieee80211_mesh_isproxyena(vap)) { 255c104cff2SRui Paulo IEEE80211_DISCARD_MAC(vap, 256c104cff2SRui Paulo IEEE80211_MSG_OUTPUT | 257c104cff2SRui Paulo IEEE80211_MSG_MESH, 258c104cff2SRui Paulo eh->ether_dhost, NULL, 259c104cff2SRui Paulo "%s", "proxy not enabled"); 260c104cff2SRui Paulo vap->iv_stats.is_mesh_notproxy++; 261c104cff2SRui Paulo ifp->if_oerrors++; 262c104cff2SRui Paulo m_freem(m); 263c104cff2SRui Paulo continue; 264c104cff2SRui Paulo } 265c104cff2SRui Paulo ieee80211_mesh_proxy_check(vap, eh->ether_shost); 266c104cff2SRui Paulo } 26759aa14a9SRui Paulo ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m); 26859aa14a9SRui Paulo if (ni == NULL) { 26959aa14a9SRui Paulo /* 270c104cff2SRui Paulo * NB: ieee80211_mesh_discover holds/disposes 271c104cff2SRui Paulo * frame (e.g. queueing on path discovery). 27259aa14a9SRui Paulo */ 27359aa14a9SRui Paulo ifp->if_oerrors++; 27459aa14a9SRui Paulo continue; 27559aa14a9SRui Paulo } 27659aa14a9SRui Paulo } 27759aa14a9SRui Paulo #endif 278b032f27cSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 279b032f27cSSam Leffler (m->m_flags & M_PWR_SAV) == 0) { 280b032f27cSSam Leffler /* 281b032f27cSSam Leffler * Station in power save mode; pass the frame 282b032f27cSSam Leffler * to the 802.11 layer and continue. We'll get 283b032f27cSSam Leffler * the frame back when the time is right. 284b032f27cSSam Leffler * XXX lose WDS vap linkage? 285b032f27cSSam Leffler */ 28663092fceSSam Leffler (void) ieee80211_pwrsave(ni, m); 287b032f27cSSam Leffler ieee80211_free_node(ni); 288b032f27cSSam Leffler continue; 289b032f27cSSam Leffler } 290b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 291b032f27cSSam Leffler if (ieee80211_classify(ni, m)) { 292b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 293b032f27cSSam Leffler eh->ether_dhost, NULL, 294b032f27cSSam Leffler "%s", "classification failure"); 295b032f27cSSam Leffler vap->iv_stats.is_tx_classify++; 296b032f27cSSam Leffler ifp->if_oerrors++; 297b032f27cSSam Leffler m_freem(m); 298b032f27cSSam Leffler ieee80211_free_node(ni); 299b032f27cSSam Leffler continue; 300b032f27cSSam Leffler } 3017ebe9c0eSSam Leffler /* 3027ebe9c0eSSam Leffler * Stash the node pointer. Note that we do this after 3037ebe9c0eSSam Leffler * any call to ieee80211_dwds_mcast because that code 3047ebe9c0eSSam Leffler * uses any existing value for rcvif to identify the 3057ebe9c0eSSam Leffler * interface it (might have been) received on. 3067ebe9c0eSSam Leffler */ 3077ebe9c0eSSam Leffler m->m_pkthdr.rcvif = (void *)ni; 308b032f27cSSam Leffler 309339ccfb3SSam Leffler BPF_MTAP(ifp, m); /* 802.3 tx */ 310b032f27cSSam Leffler 311168f582eSSam Leffler /* 312168f582eSSam Leffler * Check if A-MPDU tx aggregation is setup or if we 313168f582eSSam Leffler * should try to enable it. The sta must be associated 314168f582eSSam Leffler * with HT and A-MPDU enabled for use. When the policy 315168f582eSSam Leffler * routine decides we should enable A-MPDU we issue an 316168f582eSSam Leffler * ADDBA request and wait for a reply. The frame being 317168f582eSSam Leffler * encapsulated will go out w/o using A-MPDU, or possibly 318168f582eSSam Leffler * it might be collected by the driver and held/retransmit. 319168f582eSSam Leffler * The default ic_ampdu_enable routine handles staggering 320168f582eSSam Leffler * ADDBA requests in case the receiver NAK's us or we are 321168f582eSSam Leffler * otherwise unable to establish a BA stream. 322168f582eSSam Leffler */ 323168f582eSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && 3242bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) && 325168f582eSSam Leffler (m->m_flags & M_EAPOL) == 0) { 326168f582eSSam Leffler const int ac = M_WME_GETAC(m); 327168f582eSSam Leffler struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; 328168f582eSSam Leffler 329168f582eSSam Leffler ieee80211_txampdu_count_packet(tap); 330168f582eSSam Leffler if (IEEE80211_AMPDU_RUNNING(tap)) { 331168f582eSSam Leffler /* 332168f582eSSam Leffler * Operational, mark frame for aggregation. 333168f582eSSam Leffler * 334168f582eSSam Leffler * XXX do tx aggregation here 335168f582eSSam Leffler */ 336168f582eSSam Leffler m->m_flags |= M_AMPDU_MPDU; 337168f582eSSam Leffler } else if (!IEEE80211_AMPDU_REQUESTED(tap) && 338168f582eSSam Leffler ic->ic_ampdu_enable(ni, tap)) { 339168f582eSSam Leffler /* 340168f582eSSam Leffler * Not negotiated yet, request service. 341168f582eSSam Leffler */ 342168f582eSSam Leffler ieee80211_ampdu_request(ni, tap); 343168f582eSSam Leffler /* XXX hold frame for reply? */ 344168f582eSSam Leffler } 345168f582eSSam Leffler } 346339ccfb3SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 347168f582eSSam Leffler else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { 348339ccfb3SSam Leffler m = ieee80211_ff_check(ni, m); 349339ccfb3SSam Leffler if (m == NULL) { 350339ccfb3SSam Leffler /* NB: any ni ref held on stageq */ 351339ccfb3SSam Leffler continue; 352339ccfb3SSam Leffler } 353339ccfb3SSam Leffler } 354339ccfb3SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 3559fb0fccbSSam Leffler if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { 356b032f27cSSam Leffler /* 357339ccfb3SSam Leffler * Encapsulate the packet in prep for transmission. 358b032f27cSSam Leffler */ 359339ccfb3SSam Leffler m = ieee80211_encap(vap, ni, m); 360339ccfb3SSam Leffler if (m == NULL) { 361339ccfb3SSam Leffler /* NB: stat+msg handled in ieee80211_encap */ 362339ccfb3SSam Leffler ieee80211_free_node(ni); 363339ccfb3SSam Leffler continue; 364339ccfb3SSam Leffler } 3659fb0fccbSSam Leffler } 366b032f27cSSam Leffler 36772fecb4dSSam Leffler error = parent->if_transmit(parent, m); 368b032f27cSSam Leffler if (error != 0) { 369b032f27cSSam Leffler /* NB: IFQ_HANDOFF reclaims mbuf */ 370b032f27cSSam Leffler ieee80211_free_node(ni); 371b032f27cSSam Leffler } else { 372b032f27cSSam Leffler ifp->if_opackets++; 373b032f27cSSam Leffler } 374b032f27cSSam Leffler ic->ic_lastdata = ticks; 375b032f27cSSam Leffler } 376b032f27cSSam Leffler #undef IS_DWDS 377b032f27cSSam Leffler } 378b032f27cSSam Leffler 379b032f27cSSam Leffler /* 380b032f27cSSam Leffler * 802.11 output routine. This is (currently) used only to 381b032f27cSSam Leffler * connect bpf write calls to the 802.11 layer for injecting 382fad788b1SSam Leffler * raw 802.11 frames. 383b032f27cSSam Leffler */ 384b032f27cSSam Leffler int 385b032f27cSSam Leffler ieee80211_output(struct ifnet *ifp, struct mbuf *m, 386279aa3d4SKip Macy struct sockaddr *dst, struct route *ro) 387b032f27cSSam Leffler { 388b032f27cSSam Leffler #define senderr(e) do { error = (e); goto bad;} while (0) 389b032f27cSSam Leffler struct ieee80211_node *ni = NULL; 3908ed1835dSSam Leffler struct ieee80211vap *vap; 391b032f27cSSam Leffler struct ieee80211_frame *wh; 392b032f27cSSam Leffler int error; 393b032f27cSSam Leffler 394*70e0b5acSAdrian Chadd IFQ_LOCK(&ifp->if_snd); 3958ed1835dSSam Leffler if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 396*70e0b5acSAdrian Chadd IFQ_UNLOCK(&ifp->if_snd); 3978ed1835dSSam Leffler /* 3988ed1835dSSam Leffler * Short-circuit requests if the vap is marked OACTIVE 3998ed1835dSSam Leffler * as this can happen because a packet came down through 4008ed1835dSSam Leffler * ieee80211_start before the vap entered RUN state in 4018ed1835dSSam Leffler * which case it's ok to just drop the frame. This 4028ed1835dSSam Leffler * should not be necessary but callers of if_output don't 4038ed1835dSSam Leffler * check OACTIVE. 4048ed1835dSSam Leffler */ 4058ed1835dSSam Leffler senderr(ENETDOWN); 4068ed1835dSSam Leffler } 407*70e0b5acSAdrian Chadd IFQ_UNLOCK(&ifp->if_snd); 4088ed1835dSSam Leffler vap = ifp->if_softc; 409b032f27cSSam Leffler /* 410b032f27cSSam Leffler * Hand to the 802.3 code if not tagged as 411b032f27cSSam Leffler * a raw 802.11 frame. 412b032f27cSSam Leffler */ 413b032f27cSSam Leffler if (dst->sa_family != AF_IEEE80211) 414279aa3d4SKip Macy return vap->iv_output(ifp, m, dst, ro); 415b032f27cSSam Leffler #ifdef MAC 416c27b9cdbSRobert Watson error = mac_ifnet_check_transmit(ifp, m); 417b032f27cSSam Leffler if (error) 418b032f27cSSam Leffler senderr(error); 419b032f27cSSam Leffler #endif 420b032f27cSSam Leffler if (ifp->if_flags & IFF_MONITOR) 421b032f27cSSam Leffler senderr(ENETDOWN); 422b032f27cSSam Leffler if (!IFNET_IS_UP_RUNNING(ifp)) 423b032f27cSSam Leffler senderr(ENETDOWN); 424b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 425b032f27cSSam Leffler IEEE80211_DPRINTF(vap, 426b032f27cSSam Leffler IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 427b032f27cSSam Leffler "block %s frame in CAC state\n", "raw data"); 428b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 429b032f27cSSam Leffler senderr(EIO); /* XXX */ 4300d9aed8aSBernhard Schmidt } else if (vap->iv_state == IEEE80211_S_SCAN) 4310d9aed8aSBernhard Schmidt senderr(EIO); 432b032f27cSSam Leffler /* XXX bypass bridge, pfil, carp, etc. */ 433b032f27cSSam Leffler 434b032f27cSSam Leffler if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) 435b032f27cSSam Leffler senderr(EIO); /* XXX */ 436b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 437b032f27cSSam Leffler if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 438b032f27cSSam Leffler IEEE80211_FC0_VERSION_0) 439b032f27cSSam Leffler senderr(EIO); /* XXX */ 440b032f27cSSam Leffler 441b032f27cSSam Leffler /* locate destination node */ 442b032f27cSSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 443b032f27cSSam Leffler case IEEE80211_FC1_DIR_NODS: 444b032f27cSSam Leffler case IEEE80211_FC1_DIR_FROMDS: 445b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr1); 446b032f27cSSam Leffler break; 447b032f27cSSam Leffler case IEEE80211_FC1_DIR_TODS: 448b032f27cSSam Leffler case IEEE80211_FC1_DIR_DSTODS: 449b032f27cSSam Leffler if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) 450b032f27cSSam Leffler senderr(EIO); /* XXX */ 451b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr3); 452b032f27cSSam Leffler break; 453b032f27cSSam Leffler default: 454b032f27cSSam Leffler senderr(EIO); /* XXX */ 455b032f27cSSam Leffler } 456b032f27cSSam Leffler if (ni == NULL) { 457b032f27cSSam Leffler /* 458b032f27cSSam Leffler * Permit packets w/ bpf params through regardless 459b032f27cSSam Leffler * (see below about sa_len). 460b032f27cSSam Leffler */ 461b032f27cSSam Leffler if (dst->sa_len == 0) 462b032f27cSSam Leffler senderr(EHOSTUNREACH); 463b032f27cSSam Leffler ni = ieee80211_ref_node(vap->iv_bss); 464b032f27cSSam Leffler } 465b032f27cSSam Leffler 466b032f27cSSam Leffler /* 467b032f27cSSam Leffler * Sanitize mbuf for net80211 flags leaked from above. 468b032f27cSSam Leffler * 469b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 470b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 471b032f27cSSam Leffler */ 472b032f27cSSam Leffler m->m_flags &= ~M_80211_TX; 473b032f27cSSam Leffler 474b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 475b032f27cSSam Leffler /* XXX assumes an 802.3 frame */ 476b032f27cSSam Leffler if (ieee80211_classify(ni, m)) 477b032f27cSSam Leffler senderr(EIO); /* XXX */ 478b032f27cSSam Leffler 479224881b4SSam Leffler ifp->if_opackets++; 4800e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 4810e910c94SSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 4820e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 4830e910c94SSam Leffler m->m_flags |= M_MCAST; 4840e910c94SSam Leffler } else 4850e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 4860e910c94SSam Leffler /* NB: ieee80211_encap does not include 802.11 header */ 4870e910c94SSam Leffler IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len); 488b032f27cSSam Leffler 489b032f27cSSam Leffler /* 490b032f27cSSam Leffler * NB: DLT_IEEE802_11_RADIO identifies the parameters are 491b032f27cSSam Leffler * present by setting the sa_len field of the sockaddr (yes, 492b032f27cSSam Leffler * this is a hack). 493b032f27cSSam Leffler * NB: we assume sa_data is suitably aligned to cast. 494b032f27cSSam Leffler */ 495b032f27cSSam Leffler return vap->iv_ic->ic_raw_xmit(ni, m, 496b032f27cSSam Leffler (const struct ieee80211_bpf_params *)(dst->sa_len ? 497b032f27cSSam Leffler dst->sa_data : NULL)); 498b032f27cSSam Leffler bad: 499b032f27cSSam Leffler if (m != NULL) 500b032f27cSSam Leffler m_freem(m); 501b032f27cSSam Leffler if (ni != NULL) 502b032f27cSSam Leffler ieee80211_free_node(ni); 503224881b4SSam Leffler ifp->if_oerrors++; 504b032f27cSSam Leffler return error; 505b032f27cSSam Leffler #undef senderr 506b032f27cSSam Leffler } 507b032f27cSSam Leffler 508b032f27cSSam Leffler /* 509add59d08SSam Leffler * Set the direction field and address fields of an outgoing 5100e66722dSSam Leffler * frame. Note this should be called early on in constructing 5110e66722dSSam Leffler * a frame as it sets i_fc[1]; other bits can then be or'd in. 512add59d08SSam Leffler */ 51359aa14a9SRui Paulo void 514b032f27cSSam Leffler ieee80211_send_setup( 515add59d08SSam Leffler struct ieee80211_node *ni, 5169e80b1dfSSam Leffler struct mbuf *m, 5178ac160cdSSam Leffler int type, int tid, 51868e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 51968e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 52068e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN]) 521add59d08SSam Leffler { 522add59d08SSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) 52359aa14a9SRui Paulo struct ieee80211vap *vap = ni->ni_vap; 52450cfec0eSBernhard Schmidt struct ieee80211_tx_ampdu *tap; 5259e80b1dfSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 5269e80b1dfSSam Leffler ieee80211_seq seqno; 527add59d08SSam Leffler 528add59d08SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; 529add59d08SSam Leffler if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 530b032f27cSSam Leffler switch (vap->iv_opmode) { 531add59d08SSam Leffler case IEEE80211_M_STA: 532add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 533add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 534add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 535add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 536add59d08SSam Leffler break; 537add59d08SSam Leffler case IEEE80211_M_IBSS: 538add59d08SSam Leffler case IEEE80211_M_AHDEMO: 539add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 540add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 541add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 542add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 543add59d08SSam Leffler break; 544add59d08SSam Leffler case IEEE80211_M_HOSTAP: 545add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 546add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 547add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, bssid); 548add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, sa); 549add59d08SSam Leffler break; 55068e8e04eSSam Leffler case IEEE80211_M_WDS: 55168e8e04eSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 552b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 553b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 55468e8e04eSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 55568e8e04eSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 55668e8e04eSSam Leffler break; 55759aa14a9SRui Paulo case IEEE80211_M_MBSS: 55859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 55959aa14a9SRui Paulo /* XXX add support for proxied addresses */ 56059aa14a9SRui Paulo if (IEEE80211_IS_MULTICAST(da)) { 56159aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 56259aa14a9SRui Paulo /* XXX next hop */ 56359aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 56459aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 56559aa14a9SRui Paulo vap->iv_myaddr); 56659aa14a9SRui Paulo } else { 56759aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 56859aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 56959aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 57059aa14a9SRui Paulo vap->iv_myaddr); 57159aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, da); 57259aa14a9SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 57359aa14a9SRui Paulo } 57459aa14a9SRui Paulo #endif 57559aa14a9SRui Paulo break; 576add59d08SSam Leffler case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ 577add59d08SSam Leffler break; 578add59d08SSam Leffler } 579add59d08SSam Leffler } else { 580add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 581add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 582add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 58359aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 58459aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 58559aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, sa); 58659aa14a9SRui Paulo else 58759aa14a9SRui Paulo #endif 588add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 589add59d08SSam Leffler } 59068e8e04eSSam Leffler *(uint16_t *)&wh->i_dur[0] = 0; 5919e80b1dfSSam Leffler 59250cfec0eSBernhard Schmidt tap = &ni->ni_tx_ampdu[TID_TO_WME_AC(tid)]; 59350cfec0eSBernhard Schmidt if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) 59450cfec0eSBernhard Schmidt m->m_flags |= M_AMPDU_MPDU; 59550cfec0eSBernhard Schmidt else { 5969e80b1dfSSam Leffler seqno = ni->ni_txseqs[tid]++; 59750cfec0eSBernhard Schmidt *(uint16_t *)&wh->i_seq[0] = 59850cfec0eSBernhard Schmidt htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 5999a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 60050cfec0eSBernhard Schmidt } 6019e80b1dfSSam Leffler 6029e80b1dfSSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 6039e80b1dfSSam Leffler m->m_flags |= M_MCAST; 604add59d08SSam Leffler #undef WH4 605add59d08SSam Leffler } 606add59d08SSam Leffler 607add59d08SSam Leffler /* 6080a915fadSSam Leffler * Send a management frame to the specified node. The node pointer 6090a915fadSSam Leffler * must have a reference as the pointer will be passed to the driver 6100a915fadSSam Leffler * and potentially held for a long time. If the frame is successfully 6110a915fadSSam Leffler * dispatched to the driver, then it is responsible for freeing the 612b032f27cSSam Leffler * reference (and potentially free'ing up any associated storage); 613b032f27cSSam Leffler * otherwise deal with reclaiming any reference (on error). 6140a915fadSSam Leffler */ 61568e8e04eSSam Leffler int 6168ac160cdSSam Leffler ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, 6178ac160cdSSam Leffler struct ieee80211_bpf_params *params) 6181a1e1d21SSam Leffler { 619b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 620b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 6211a1e1d21SSam Leffler struct ieee80211_frame *wh; 6221a1e1d21SSam Leffler 6230a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 6241a1e1d21SSam Leffler 625b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 626b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 627b032f27cSSam Leffler ni, "block %s frame in CAC state", 628b032f27cSSam Leffler ieee80211_mgt_subtype_name[ 629b032f27cSSam Leffler (type & IEEE80211_FC0_SUBTYPE_MASK) >> 630b032f27cSSam Leffler IEEE80211_FC0_SUBTYPE_SHIFT]); 631b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 632b032f27cSSam Leffler ieee80211_free_node(ni); 633b032f27cSSam Leffler m_freem(m); 634b032f27cSSam Leffler return EIO; /* XXX */ 635b032f27cSSam Leffler } 636b032f27cSSam Leffler 6371a1e1d21SSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 638b032f27cSSam Leffler if (m == NULL) { 639b032f27cSSam Leffler ieee80211_free_node(ni); 6401a1e1d21SSam Leffler return ENOMEM; 641b032f27cSSam Leffler } 6420a915fadSSam Leffler 6431a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 6449e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 6458ac160cdSSam Leffler IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, 646b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 6478ac160cdSSam Leffler if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 648b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, 649b032f27cSSam Leffler "encrypting frame (%s)", __func__); 6508a1b9b6aSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 6518a1b9b6aSSam Leffler } 652c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 6538ac160cdSSam Leffler 6548ac160cdSSam Leffler KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); 6558ac160cdSSam Leffler M_WME_SETAC(m, params->ibp_pri); 6568ac160cdSSam Leffler 6578a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 6588a1b9b6aSSam Leffler /* avoid printing too many frames */ 659b032f27cSSam Leffler if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || 660b032f27cSSam Leffler ieee80211_msg_dumppkts(vap)) { 6618a1b9b6aSSam Leffler printf("[%s] send %s on channel %u\n", 6628a1b9b6aSSam Leffler ether_sprintf(wh->i_addr1), 6638a1b9b6aSSam Leffler ieee80211_mgt_subtype_name[ 6648a1b9b6aSSam Leffler (type & IEEE80211_FC0_SUBTYPE_MASK) >> 6658a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_SHIFT], 666b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan)); 6678a1b9b6aSSam Leffler } 6688a1b9b6aSSam Leffler #endif 6698a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 67068e8e04eSSam Leffler 6718ac160cdSSam Leffler return ic->ic_raw_xmit(ni, m, params); 672246b5467SSam Leffler } 673246b5467SSam Leffler 674246b5467SSam Leffler /* 6756683931eSSam Leffler * Send a null data frame to the specified node. If the station 6766683931eSSam Leffler * is setup for QoS then a QoS Null Data frame is constructed. 6776683931eSSam Leffler * If this is a WDS station then a 4-address frame is constructed. 67819ad2dd7SSam Leffler * 67919ad2dd7SSam Leffler * NB: the caller is assumed to have setup a node reference 68019ad2dd7SSam Leffler * for use; this is necessary to deal with a race condition 681b032f27cSSam Leffler * when probing for inactive stations. Like ieee80211_mgmt_output 682b032f27cSSam Leffler * we must cleanup any node reference on error; however we 683b032f27cSSam Leffler * can safely just unref it as we know it will never be the 684b032f27cSSam Leffler * last reference to the node. 6858a1b9b6aSSam Leffler */ 6868a1b9b6aSSam Leffler int 687f62121ceSSam Leffler ieee80211_send_nulldata(struct ieee80211_node *ni) 6888a1b9b6aSSam Leffler { 689b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 690f62121ceSSam Leffler struct ieee80211com *ic = ni->ni_ic; 6918a1b9b6aSSam Leffler struct mbuf *m; 6928a1b9b6aSSam Leffler struct ieee80211_frame *wh; 6936683931eSSam Leffler int hdrlen; 6946683931eSSam Leffler uint8_t *frm; 6958a1b9b6aSSam Leffler 696b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 697b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 698b032f27cSSam Leffler ni, "block %s frame in CAC state", "null data"); 699b032f27cSSam Leffler ieee80211_unref_node(&ni); 700b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 701b032f27cSSam Leffler return EIO; /* XXX */ 702b032f27cSSam Leffler } 703b032f27cSSam Leffler 7046683931eSSam Leffler if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) 7056683931eSSam Leffler hdrlen = sizeof(struct ieee80211_qosframe); 7066683931eSSam Leffler else 7076683931eSSam Leffler hdrlen = sizeof(struct ieee80211_frame); 7086683931eSSam Leffler /* NB: only WDS vap's get 4-address frames */ 7096683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 7106683931eSSam Leffler hdrlen += IEEE80211_ADDR_LEN; 7116683931eSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 7126683931eSSam Leffler hdrlen = roundup(hdrlen, sizeof(uint32_t)); 7136683931eSSam Leffler 7146683931eSSam Leffler m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); 7158a1b9b6aSSam Leffler if (m == NULL) { 7168a1b9b6aSSam Leffler /* XXX debug msg */ 71719ad2dd7SSam Leffler ieee80211_unref_node(&ni); 718b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 7198a1b9b6aSSam Leffler return ENOMEM; 7208a1b9b6aSSam Leffler } 7216683931eSSam Leffler KASSERT(M_LEADINGSPACE(m) >= hdrlen, 7226683931eSSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 7236683931eSSam Leffler M_PREPEND(m, hdrlen, M_DONTWAIT); 7246683931eSSam Leffler if (m == NULL) { 7256683931eSSam Leffler /* NB: cannot happen */ 7266683931eSSam Leffler ieee80211_free_node(ni); 7276683931eSSam Leffler return ENOMEM; 7286683931eSSam Leffler } 7298a1b9b6aSSam Leffler 7306683931eSSam Leffler wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ 7316683931eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 7326683931eSSam Leffler const int tid = WME_AC_TO_TID(WME_AC_BE); 7336683931eSSam Leffler uint8_t *qos; 7346683931eSSam Leffler 7359e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 7366683931eSSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, 7376683931eSSam Leffler tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 7386683931eSSam Leffler 7396683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 7406683931eSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 7416683931eSSam Leffler else 7426683931eSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 7436683931eSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 7446683931eSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) 7456683931eSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 7466683931eSSam Leffler qos[1] = 0; 7476683931eSSam Leffler } else { 7489e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 749add59d08SSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 7508ac160cdSSam Leffler IEEE80211_NONQOS_TID, 751b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 7526683931eSSam Leffler } 753b032f27cSSam Leffler if (vap->iv_opmode != IEEE80211_M_WDS) { 754add59d08SSam Leffler /* NB: power management bit is never sent by an AP */ 755add59d08SSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 756b032f27cSSam Leffler vap->iv_opmode != IEEE80211_M_HOSTAP) 757add59d08SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 758b032f27cSSam Leffler } 7596683931eSSam Leffler m->m_len = m->m_pkthdr.len = hdrlen; 760c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 7616683931eSSam Leffler 762bb239ce9SSam Leffler M_WME_SETAC(m, WME_AC_BE); 7638a1b9b6aSSam Leffler 7648a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 7658a1b9b6aSSam Leffler 766b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, 7676683931eSSam Leffler "send %snull data frame on channel %u, pwr mgt %s", 7686683931eSSam Leffler ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", 769b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), 770add59d08SSam Leffler wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 771add59d08SSam Leffler 772b032f27cSSam Leffler return ic->ic_raw_xmit(ni, m, NULL); 7738a1b9b6aSSam Leffler } 7748a1b9b6aSSam Leffler 7758a1b9b6aSSam Leffler /* 7768a1b9b6aSSam Leffler * Assign priority to a frame based on any vlan tag assigned 7778a1b9b6aSSam Leffler * to the station and/or any Diffserv setting in an IP header. 7788a1b9b6aSSam Leffler * Finally, if an ACM policy is setup (in station mode) it's 7798a1b9b6aSSam Leffler * applied. 7808a1b9b6aSSam Leffler */ 7818a1b9b6aSSam Leffler int 782b032f27cSSam Leffler ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) 7838a1b9b6aSSam Leffler { 784b032f27cSSam Leffler const struct ether_header *eh = mtod(m, struct ether_header *); 7858a1b9b6aSSam Leffler int v_wme_ac, d_wme_ac, ac; 7868a1b9b6aSSam Leffler 787b032f27cSSam Leffler /* 788b032f27cSSam Leffler * Always promote PAE/EAPOL frames to high priority. 789b032f27cSSam Leffler */ 790b032f27cSSam Leffler if (eh->ether_type == htons(ETHERTYPE_PAE)) { 791b032f27cSSam Leffler /* NB: mark so others don't need to check header */ 792b032f27cSSam Leffler m->m_flags |= M_EAPOL; 793b032f27cSSam Leffler ac = WME_AC_VO; 794b032f27cSSam Leffler goto done; 795b032f27cSSam Leffler } 796b032f27cSSam Leffler /* 797b032f27cSSam Leffler * Non-qos traffic goes to BE. 798b032f27cSSam Leffler */ 7998a1b9b6aSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { 8008a1b9b6aSSam Leffler ac = WME_AC_BE; 8018a1b9b6aSSam Leffler goto done; 8028a1b9b6aSSam Leffler } 8038a1b9b6aSSam Leffler 8048a1b9b6aSSam Leffler /* 8058a1b9b6aSSam Leffler * If node has a vlan tag then all traffic 8068a1b9b6aSSam Leffler * to it must have a matching tag. 8078a1b9b6aSSam Leffler */ 8088a1b9b6aSSam Leffler v_wme_ac = 0; 8098a1b9b6aSSam Leffler if (ni->ni_vlan != 0) { 81078ba57b9SAndre Oppermann if ((m->m_flags & M_VLANTAG) == 0) { 8118a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_novlantag); 8128a1b9b6aSSam Leffler return 1; 8138a1b9b6aSSam Leffler } 81478ba57b9SAndre Oppermann if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 8158a1b9b6aSSam Leffler EVL_VLANOFTAG(ni->ni_vlan)) { 8168a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 8178a1b9b6aSSam Leffler return 1; 8188a1b9b6aSSam Leffler } 8198a1b9b6aSSam Leffler /* map vlan priority to AC */ 820f4558c9aSSam Leffler v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); 8218a1b9b6aSSam Leffler } 8228a1b9b6aSSam Leffler 823e755a73dSSam Leffler /* XXX m_copydata may be too slow for fast path */ 8248a1b9b6aSSam Leffler #ifdef INET 8258a1b9b6aSSam Leffler if (eh->ether_type == htons(ETHERTYPE_IP)) { 826f4558c9aSSam Leffler uint8_t tos; 8278a1b9b6aSSam Leffler /* 828f4558c9aSSam Leffler * IP frame, map the DSCP bits from the TOS field. 8298a1b9b6aSSam Leffler */ 830f4558c9aSSam Leffler /* NB: ip header may not be in first mbuf */ 831f4558c9aSSam Leffler m_copydata(m, sizeof(struct ether_header) + 832f4558c9aSSam Leffler offsetof(struct ip, ip_tos), sizeof(tos), &tos); 833f4558c9aSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 834f4558c9aSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 8358a1b9b6aSSam Leffler } else { 8368a1b9b6aSSam Leffler #endif /* INET */ 837e755a73dSSam Leffler #ifdef INET6 838e755a73dSSam Leffler if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 839e755a73dSSam Leffler uint32_t flow; 840e755a73dSSam Leffler uint8_t tos; 841e755a73dSSam Leffler /* 8426ffd0ca9SBjoern A. Zeeb * IPv6 frame, map the DSCP bits from the traffic class field. 843e755a73dSSam Leffler */ 844e755a73dSSam Leffler m_copydata(m, sizeof(struct ether_header) + 845e755a73dSSam Leffler offsetof(struct ip6_hdr, ip6_flow), sizeof(flow), 846e755a73dSSam Leffler (caddr_t) &flow); 847e755a73dSSam Leffler tos = (uint8_t)(ntohl(flow) >> 20); 848e755a73dSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 849e755a73dSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 850e755a73dSSam Leffler } else { 851e755a73dSSam Leffler #endif /* INET6 */ 8528a1b9b6aSSam Leffler d_wme_ac = WME_AC_BE; 853e755a73dSSam Leffler #ifdef INET6 854e755a73dSSam Leffler } 855e755a73dSSam Leffler #endif 8568a1b9b6aSSam Leffler #ifdef INET 8578a1b9b6aSSam Leffler } 8588a1b9b6aSSam Leffler #endif 8598a1b9b6aSSam Leffler /* 8608a1b9b6aSSam Leffler * Use highest priority AC. 8618a1b9b6aSSam Leffler */ 8628a1b9b6aSSam Leffler if (v_wme_ac > d_wme_ac) 8638a1b9b6aSSam Leffler ac = v_wme_ac; 8648a1b9b6aSSam Leffler else 8658a1b9b6aSSam Leffler ac = d_wme_ac; 8668a1b9b6aSSam Leffler 8678a1b9b6aSSam Leffler /* 8688a1b9b6aSSam Leffler * Apply ACM policy. 8698a1b9b6aSSam Leffler */ 870b032f27cSSam Leffler if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { 8718a1b9b6aSSam Leffler static const int acmap[4] = { 8728a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BE */ 8738a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BK */ 8748a1b9b6aSSam Leffler WME_AC_BE, /* WME_AC_VI */ 8758a1b9b6aSSam Leffler WME_AC_VI, /* WME_AC_VO */ 8768a1b9b6aSSam Leffler }; 877b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 878b032f27cSSam Leffler 8798a1b9b6aSSam Leffler while (ac != WME_AC_BK && 8808a1b9b6aSSam Leffler ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) 8818a1b9b6aSSam Leffler ac = acmap[ac]; 8828a1b9b6aSSam Leffler } 8838a1b9b6aSSam Leffler done: 8848a1b9b6aSSam Leffler M_WME_SETAC(m, ac); 8858a1b9b6aSSam Leffler return 0; 8868a1b9b6aSSam Leffler } 8878a1b9b6aSSam Leffler 8888a1b9b6aSSam Leffler /* 8895e923d2eSSam Leffler * Insure there is sufficient contiguous space to encapsulate the 8905e923d2eSSam Leffler * 802.11 data frame. If room isn't already there, arrange for it. 8915e923d2eSSam Leffler * Drivers and cipher modules assume we have done the necessary work 8925e923d2eSSam Leffler * and fail rudely if they don't find the space they need. 8935e923d2eSSam Leffler */ 894616190d0SSam Leffler struct mbuf * 895b032f27cSSam Leffler ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, 8965e923d2eSSam Leffler struct ieee80211_key *key, struct mbuf *m) 8975e923d2eSSam Leffler { 898ab96db10SSam Leffler #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) 899b032f27cSSam Leffler int needed_space = vap->iv_ic->ic_headroom + hdrsize; 9005e923d2eSSam Leffler 9015e923d2eSSam Leffler if (key != NULL) { 9025e923d2eSSam Leffler /* XXX belongs in crypto code? */ 9035e923d2eSSam Leffler needed_space += key->wk_cipher->ic_header; 9045e923d2eSSam Leffler /* XXX frags */ 90583a244dbSSam Leffler /* 90683a244dbSSam Leffler * When crypto is being done in the host we must insure 90783a244dbSSam Leffler * the data are writable for the cipher routines; clone 90883a244dbSSam Leffler * a writable mbuf chain. 90983a244dbSSam Leffler * XXX handle SWMIC specially 91083a244dbSSam Leffler */ 9115c1f7f19SSam Leffler if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { 91283a244dbSSam Leffler m = m_unshare(m, M_NOWAIT); 91383a244dbSSam Leffler if (m == NULL) { 914b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 91583a244dbSSam Leffler "%s: cannot get writable mbuf\n", __func__); 916b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ 91783a244dbSSam Leffler return NULL; 91883a244dbSSam Leffler } 91983a244dbSSam Leffler } 9205e923d2eSSam Leffler } 9215e923d2eSSam Leffler /* 9225e923d2eSSam Leffler * We know we are called just before stripping an Ethernet 9235e923d2eSSam Leffler * header and prepending an LLC header. This means we know 9245e923d2eSSam Leffler * there will be 925ab96db10SSam Leffler * sizeof(struct ether_header) - sizeof(struct llc) 9265e923d2eSSam Leffler * bytes recovered to which we need additional space for the 9275e923d2eSSam Leffler * 802.11 header and any crypto header. 9285e923d2eSSam Leffler */ 9295e923d2eSSam Leffler /* XXX check trailing space and copy instead? */ 9305e923d2eSSam Leffler if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { 9315e923d2eSSam Leffler struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); 9325e923d2eSSam Leffler if (n == NULL) { 933b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 9345e923d2eSSam Leffler "%s: cannot expand storage\n", __func__); 935b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 9365e923d2eSSam Leffler m_freem(m); 9375e923d2eSSam Leffler return NULL; 9385e923d2eSSam Leffler } 9395e923d2eSSam Leffler KASSERT(needed_space <= MHLEN, 9405e923d2eSSam Leffler ("not enough room, need %u got %zu\n", needed_space, MHLEN)); 9415e923d2eSSam Leffler /* 9425e923d2eSSam Leffler * Setup new mbuf to have leading space to prepend the 9435e923d2eSSam Leffler * 802.11 header and any crypto header bits that are 9445e923d2eSSam Leffler * required (the latter are added when the driver calls 9455e923d2eSSam Leffler * back to ieee80211_crypto_encap to do crypto encapsulation). 9465e923d2eSSam Leffler */ 9475e923d2eSSam Leffler /* NB: must be first 'cuz it clobbers m_data */ 9485e923d2eSSam Leffler m_move_pkthdr(n, m); 9495e923d2eSSam Leffler n->m_len = 0; /* NB: m_gethdr does not set */ 9505e923d2eSSam Leffler n->m_data += needed_space; 9515e923d2eSSam Leffler /* 9525e923d2eSSam Leffler * Pull up Ethernet header to create the expected layout. 9535e923d2eSSam Leffler * We could use m_pullup but that's overkill (i.e. we don't 9545e923d2eSSam Leffler * need the actual data) and it cannot fail so do it inline 9555e923d2eSSam Leffler * for speed. 9565e923d2eSSam Leffler */ 9575e923d2eSSam Leffler /* NB: struct ether_header is known to be contiguous */ 9585e923d2eSSam Leffler n->m_len += sizeof(struct ether_header); 9595e923d2eSSam Leffler m->m_len -= sizeof(struct ether_header); 9605e923d2eSSam Leffler m->m_data += sizeof(struct ether_header); 9615e923d2eSSam Leffler /* 9625e923d2eSSam Leffler * Replace the head of the chain. 9635e923d2eSSam Leffler */ 9645e923d2eSSam Leffler n->m_next = m; 9655e923d2eSSam Leffler m = n; 9665e923d2eSSam Leffler } 9675e923d2eSSam Leffler return m; 9685e923d2eSSam Leffler #undef TO_BE_RECLAIMED 9695e923d2eSSam Leffler } 9705e923d2eSSam Leffler 9715e923d2eSSam Leffler /* 9725e923d2eSSam Leffler * Return the transmit key to use in sending a unicast frame. 9735e923d2eSSam Leffler * If a unicast key is set we use that. When no unicast key is set 9745e923d2eSSam Leffler * we fall back to the default transmit key. 9758a1b9b6aSSam Leffler */ 9768a1b9b6aSSam Leffler static __inline struct ieee80211_key * 977b032f27cSSam Leffler ieee80211_crypto_getucastkey(struct ieee80211vap *vap, 978b032f27cSSam Leffler struct ieee80211_node *ni) 9798a1b9b6aSSam Leffler { 980cda15ce1SSam Leffler if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { 981b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 982b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 9838a1b9b6aSSam Leffler return NULL; 984b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 9858a1b9b6aSSam Leffler } else { 9868a1b9b6aSSam Leffler return &ni->ni_ucastkey; 9878a1b9b6aSSam Leffler } 9885e923d2eSSam Leffler } 9895e923d2eSSam Leffler 9905e923d2eSSam Leffler /* 9915e923d2eSSam Leffler * Return the transmit key to use in sending a multicast frame. 9925e923d2eSSam Leffler * Multicast traffic always uses the group key which is installed as 9935e923d2eSSam Leffler * the default tx key. 9945e923d2eSSam Leffler */ 9955e923d2eSSam Leffler static __inline struct ieee80211_key * 996b032f27cSSam Leffler ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, 997b032f27cSSam Leffler struct ieee80211_node *ni) 9985e923d2eSSam Leffler { 999b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 1000b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 10015e923d2eSSam Leffler return NULL; 1002b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 10038a1b9b6aSSam Leffler } 10048a1b9b6aSSam Leffler 10058a1b9b6aSSam Leffler /* 10068a1b9b6aSSam Leffler * Encapsulate an outbound data frame. The mbuf chain is updated. 10078a1b9b6aSSam Leffler * If an error is encountered NULL is returned. The caller is required 10088a1b9b6aSSam Leffler * to provide a node reference and pullup the ethernet header in the 10098a1b9b6aSSam Leffler * first mbuf. 1010b032f27cSSam Leffler * 1011b032f27cSSam Leffler * NB: Packet is assumed to be processed by ieee80211_classify which 1012b032f27cSSam Leffler * marked EAPOL frames w/ M_EAPOL. 10130a915fadSSam Leffler */ 10141a1e1d21SSam Leffler struct mbuf * 1015339ccfb3SSam Leffler ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni, 1016339ccfb3SSam Leffler struct mbuf *m) 10171a1e1d21SSam Leffler { 1018b032f27cSSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) 1019b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 102059aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 102159aa14a9SRui Paulo struct ieee80211_mesh_state *ms = vap->iv_mesh; 1022c104cff2SRui Paulo struct ieee80211_meshcntl_ae10 *mc; 102359aa14a9SRui Paulo #endif 10241a1e1d21SSam Leffler struct ether_header eh; 10251a1e1d21SSam Leffler struct ieee80211_frame *wh; 10268a1b9b6aSSam Leffler struct ieee80211_key *key; 10271a1e1d21SSam Leffler struct llc *llc; 1028616190d0SSam Leffler int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr; 10299e80b1dfSSam Leffler ieee80211_seq seqno; 103059aa14a9SRui Paulo int meshhdrsize, meshae; 103159aa14a9SRui Paulo uint8_t *qos; 10321a1e1d21SSam Leffler 103368e8e04eSSam Leffler /* 103468e8e04eSSam Leffler * Copy existing Ethernet header to a safe place. The 103568e8e04eSSam Leffler * rest of the code assumes it's ok to strip it when 103668e8e04eSSam Leffler * reorganizing state for the final encapsulation. 103768e8e04eSSam Leffler */ 10388a1b9b6aSSam Leffler KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); 1039b032f27cSSam Leffler ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); 10401a1e1d21SSam Leffler 10418a1b9b6aSSam Leffler /* 10428a1b9b6aSSam Leffler * Insure space for additional headers. First identify 10438a1b9b6aSSam Leffler * transmit key to use in calculating any buffer adjustments 10448a1b9b6aSSam Leffler * required. This is also used below to do privacy 10458a1b9b6aSSam Leffler * encapsulation work. Then calculate the 802.11 header 10468a1b9b6aSSam Leffler * size and any padding required by the driver. 10478a1b9b6aSSam Leffler * 10488a1b9b6aSSam Leffler * Note key may be NULL if we fall back to the default 10498a1b9b6aSSam Leffler * transmit key and that is not set. In that case the 10508a1b9b6aSSam Leffler * buffer may not be expanded as needed by the cipher 10518a1b9b6aSSam Leffler * routines, but they will/should discard it. 10528a1b9b6aSSam Leffler */ 1053b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) { 1054b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA || 1055b032f27cSSam Leffler !IEEE80211_IS_MULTICAST(eh.ether_dhost) || 1056b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_WDS && 1057b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) 1058b032f27cSSam Leffler key = ieee80211_crypto_getucastkey(vap, ni); 10595e923d2eSSam Leffler else 1060b032f27cSSam Leffler key = ieee80211_crypto_getmcastkey(vap, ni); 1061b032f27cSSam Leffler if (key == NULL && (m->m_flags & M_EAPOL) == 0) { 1062b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, 1063b032f27cSSam Leffler eh.ether_dhost, 1064b032f27cSSam Leffler "no default transmit key (%s) deftxkey %u", 1065b032f27cSSam Leffler __func__, vap->iv_def_txkey); 1066b032f27cSSam Leffler vap->iv_stats.is_tx_nodefkey++; 1067d72c7253SSam Leffler goto bad; 10688a1b9b6aSSam Leffler } 10698a1b9b6aSSam Leffler } else 10708a1b9b6aSSam Leffler key = NULL; 10715e923d2eSSam Leffler /* 10725e923d2eSSam Leffler * XXX Some ap's don't handle QoS-encapsulated EAPOL 10735e923d2eSSam Leffler * frames so suppress use. This may be an issue if other 10745e923d2eSSam Leffler * ap's require all data frames to be QoS-encapsulated 10755e923d2eSSam Leffler * once negotiated in which case we'll need to make this 10765e923d2eSSam Leffler * configurable. 10775e923d2eSSam Leffler */ 107868e8e04eSSam Leffler addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) && 1079b032f27cSSam Leffler (m->m_flags & M_EAPOL) == 0; 10805e923d2eSSam Leffler if (addqos) 10818a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_qosframe); 10828a1b9b6aSSam Leffler else 10838a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_frame); 108459aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 108559aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 108659aa14a9SRui Paulo /* 108759aa14a9SRui Paulo * Mesh data frames are encapsulated according to the 108859aa14a9SRui Paulo * rules of Section 11B.8.5 (p.139 of D3.0 spec). 108959aa14a9SRui Paulo * o Group Addressed data (aka multicast) originating 109059aa14a9SRui Paulo * at the local sta are sent w/ 3-address format and 109159aa14a9SRui Paulo * address extension mode 00 109259aa14a9SRui Paulo * o Individually Addressed data (aka unicast) originating 109359aa14a9SRui Paulo * at the local sta are sent w/ 4-address format and 109459aa14a9SRui Paulo * address extension mode 00 109559aa14a9SRui Paulo * o Group Addressed data forwarded from a non-mesh sta are 109659aa14a9SRui Paulo * sent w/ 3-address format and address extension mode 01 109759aa14a9SRui Paulo * o Individually Address data from another sta are sent 109859aa14a9SRui Paulo * w/ 4-address format and address extension mode 10 109959aa14a9SRui Paulo */ 110059aa14a9SRui Paulo is4addr = 0; /* NB: don't use, disable */ 1101c104cff2SRui Paulo if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) 1102c104cff2SRui Paulo hdrsize += IEEE80211_ADDR_LEN; /* unicast are 4-addr */ 110359aa14a9SRui Paulo meshhdrsize = sizeof(struct ieee80211_meshcntl); 110459aa14a9SRui Paulo /* XXX defines for AE modes */ 110559aa14a9SRui Paulo if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { 1106c104cff2SRui Paulo if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) 110759aa14a9SRui Paulo meshae = 0; 1108c104cff2SRui Paulo else 110959aa14a9SRui Paulo meshae = 4; /* NB: pseudo */ 111059aa14a9SRui Paulo } else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) { 111159aa14a9SRui Paulo meshae = 1; 1112c104cff2SRui Paulo meshhdrsize += 1*IEEE80211_ADDR_LEN; 111359aa14a9SRui Paulo } else { 111459aa14a9SRui Paulo meshae = 2; 1115c104cff2SRui Paulo meshhdrsize += 2*IEEE80211_ADDR_LEN; 111659aa14a9SRui Paulo } 111759aa14a9SRui Paulo } else { 111859aa14a9SRui Paulo #endif 1119b032f27cSSam Leffler /* 1120b032f27cSSam Leffler * 4-address frames need to be generated for: 11216437e6daSSam Leffler * o packets sent through a WDS vap (IEEE80211_M_WDS) 1122f2a6a13cSSam Leffler * o packets sent through a vap marked for relaying 1123f2a6a13cSSam Leffler * (e.g. a station operating with dynamic WDS) 1124b032f27cSSam Leffler */ 11256437e6daSSam Leffler is4addr = vap->iv_opmode == IEEE80211_M_WDS || 1126f2a6a13cSSam Leffler ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) && 1127b032f27cSSam Leffler !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); 1128b032f27cSSam Leffler if (is4addr) 1129b032f27cSSam Leffler hdrsize += IEEE80211_ADDR_LEN; 113059aa14a9SRui Paulo meshhdrsize = meshae = 0; 113159aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 113259aa14a9SRui Paulo } 113359aa14a9SRui Paulo #endif 1134b032f27cSSam Leffler /* 1135b032f27cSSam Leffler * Honor driver DATAPAD requirement. 1136b032f27cSSam Leffler */ 11378a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 1138b032f27cSSam Leffler hdrspace = roundup(hdrsize, sizeof(uint32_t)); 1139b032f27cSSam Leffler else 1140b032f27cSSam Leffler hdrspace = hdrsize; 114168e8e04eSSam Leffler 1142616190d0SSam Leffler if (__predict_true((m->m_flags & M_FF) == 0)) { 114368e8e04eSSam Leffler /* 114468e8e04eSSam Leffler * Normal frame. 114568e8e04eSSam Leffler */ 114659aa14a9SRui Paulo m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m); 11478a1b9b6aSSam Leffler if (m == NULL) { 11488a1b9b6aSSam Leffler /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 11490a915fadSSam Leffler goto bad; 11500a915fadSSam Leffler } 115168e8e04eSSam Leffler /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ 1152ab96db10SSam Leffler m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 11531a1e1d21SSam Leffler llc = mtod(m, struct llc *); 11541a1e1d21SSam Leffler llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 11551a1e1d21SSam Leffler llc->llc_control = LLC_UI; 11561a1e1d21SSam Leffler llc->llc_snap.org_code[0] = 0; 11571a1e1d21SSam Leffler llc->llc_snap.org_code[1] = 0; 11581a1e1d21SSam Leffler llc->llc_snap.org_code[2] = 0; 11591a1e1d21SSam Leffler llc->llc_snap.ether_type = eh.ether_type; 1160616190d0SSam Leffler } else { 1161616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 1162339ccfb3SSam Leffler /* 1163339ccfb3SSam Leffler * Aggregated frame. 1164339ccfb3SSam Leffler */ 116559aa14a9SRui Paulo m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key); 1166616190d0SSam Leffler if (m == NULL) 1167616190d0SSam Leffler #endif 1168616190d0SSam Leffler goto bad; 116968e8e04eSSam Leffler } 11708a1b9b6aSSam Leffler datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ 11718a1b9b6aSSam Leffler 117259aa14a9SRui Paulo M_PREPEND(m, hdrspace + meshhdrsize, M_DONTWAIT); 11731be50176SSam Leffler if (m == NULL) { 1174b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 11750a915fadSSam Leffler goto bad; 11761be50176SSam Leffler } 11771a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 11781a1e1d21SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 117968e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 118059aa14a9SRui Paulo qos = NULL; /* NB: quiet compiler */ 1181b032f27cSSam Leffler if (is4addr) { 1182b032f27cSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 1183b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 1184b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1185b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1186b032f27cSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 1187b032f27cSSam Leffler } else switch (vap->iv_opmode) { 11881a1e1d21SSam Leffler case IEEE80211_M_STA: 11891a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 11901a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 11911a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 11921a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 11931a1e1d21SSam Leffler break; 11941a1e1d21SSam Leffler case IEEE80211_M_IBSS: 11951a1e1d21SSam Leffler case IEEE80211_M_AHDEMO: 11961a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 11971a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 11981a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1199a8b16e87SSam Leffler /* 1200b032f27cSSam Leffler * NB: always use the bssid from iv_bss as the 1201a8b16e87SSam Leffler * neighbor's may be stale after an ibss merge 1202a8b16e87SSam Leffler */ 1203b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); 12041a1e1d21SSam Leffler break; 12051a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 12061a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 12071a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 12081a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 12091a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 12101a1e1d21SSam Leffler break; 121159aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 121259aa14a9SRui Paulo case IEEE80211_M_MBSS: 121359aa14a9SRui Paulo /* NB: offset by hdrspace to deal with DATAPAD */ 1214c104cff2SRui Paulo mc = (struct ieee80211_meshcntl_ae10 *) 121559aa14a9SRui Paulo (mtod(m, uint8_t *) + hdrspace); 121659aa14a9SRui Paulo switch (meshae) { 121759aa14a9SRui Paulo case 0: /* ucast, no proxy */ 121859aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 121959aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 122059aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 122159aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 122259aa14a9SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 122359aa14a9SRui Paulo mc->mc_flags = 0; 122459aa14a9SRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 122559aa14a9SRui Paulo break; 122659aa14a9SRui Paulo case 4: /* mcast, no proxy */ 122759aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 122859aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 122959aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 123059aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 123159aa14a9SRui Paulo mc->mc_flags = 0; /* NB: AE is really 0 */ 123259aa14a9SRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 123359aa14a9SRui Paulo break; 123459aa14a9SRui Paulo case 1: /* mcast, proxy */ 123559aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 123659aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 123759aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1238c104cff2SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr); 123959aa14a9SRui Paulo mc->mc_flags = 1; 124059aa14a9SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost); 124159aa14a9SRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 124259aa14a9SRui Paulo break; 124359aa14a9SRui Paulo case 2: /* ucast, proxy */ 124459aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 124559aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 124659aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1247c104cff2SRui Paulo /* XXX not right, need MeshDA */ 124859aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1249c104cff2SRui Paulo /* XXX assume are MeshSA */ 1250c104cff2SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr); 125159aa14a9SRui Paulo mc->mc_flags = 2; 1252c104cff2SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_dhost); 125359aa14a9SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost); 125459aa14a9SRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 125559aa14a9SRui Paulo break; 125659aa14a9SRui Paulo default: 125759aa14a9SRui Paulo KASSERT(0, ("meshae %d", meshae)); 125859aa14a9SRui Paulo break; 125959aa14a9SRui Paulo } 126059aa14a9SRui Paulo mc->mc_ttl = ms->ms_ttl; 126159aa14a9SRui Paulo ms->ms_seq++; 126259aa14a9SRui Paulo LE_WRITE_4(mc->mc_seq, ms->ms_seq); 126359aa14a9SRui Paulo break; 126459aa14a9SRui Paulo #endif 1265b032f27cSSam Leffler case IEEE80211_M_WDS: /* NB: is4addr should always be true */ 126659aa14a9SRui Paulo default: 12670a915fadSSam Leffler goto bad; 12681a1e1d21SSam Leffler } 1269bc5627d9SSam Leffler if (m->m_flags & M_MORE_DATA) 1270bc5627d9SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 12715e923d2eSSam Leffler if (addqos) { 12728a1b9b6aSSam Leffler int ac, tid; 12738a1b9b6aSSam Leffler 1274b032f27cSSam Leffler if (is4addr) { 1275b032f27cSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 127659aa14a9SRui Paulo /* NB: mesh case handled earlier */ 127759aa14a9SRui Paulo } else if (vap->iv_opmode != IEEE80211_M_MBSS) 1278b032f27cSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 12798a1b9b6aSSam Leffler ac = M_WME_GETAC(m); 12808a1b9b6aSSam Leffler /* map from access class/queue to 11e header priorty value */ 12818a1b9b6aSSam Leffler tid = WME_AC_TO_TID(ac); 1282b032f27cSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 12838a1b9b6aSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) 1284b032f27cSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 1285b032f27cSSam Leffler qos[1] = 0; 1286b032f27cSSam Leffler wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; 12878a1b9b6aSSam Leffler 128845f856e3SSam Leffler if ((m->m_flags & M_AMPDU_MPDU) == 0) { 128945f856e3SSam Leffler /* 129045f856e3SSam Leffler * NB: don't assign a sequence # to potential 129145f856e3SSam Leffler * aggregates; we expect this happens at the 129245f856e3SSam Leffler * point the frame comes off any aggregation q 129345f856e3SSam Leffler * as otherwise we may introduce holes in the 129445f856e3SSam Leffler * BA sequence space and/or make window accouting 129545f856e3SSam Leffler * more difficult. 129645f856e3SSam Leffler * 129745f856e3SSam Leffler * XXX may want to control this with a driver 129845f856e3SSam Leffler * capability; this may also change when we pull 129945f856e3SSam Leffler * aggregation up into net80211 130045f856e3SSam Leffler */ 13019e80b1dfSSam Leffler seqno = ni->ni_txseqs[tid]++; 130268e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 13039e80b1dfSSam Leffler htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 13049a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 130545f856e3SSam Leffler } 13068a1b9b6aSSam Leffler } else { 13079e80b1dfSSam Leffler seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 130868e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 13099e80b1dfSSam Leffler htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 13109a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 13118a1b9b6aSSam Leffler } 13129a841c7fSSam Leffler 131359aa14a9SRui Paulo 131468e8e04eSSam Leffler /* check if xmit fragmentation is required */ 1315b032f27cSSam Leffler txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && 131668e8e04eSSam Leffler !IEEE80211_IS_MULTICAST(wh->i_addr1) && 1317b032f27cSSam Leffler (vap->iv_caps & IEEE80211_C_TXFRAG) && 1318e9cfc1f5SSam Leffler (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0); 13195e923d2eSSam Leffler if (key != NULL) { 13205e923d2eSSam Leffler /* 13215e923d2eSSam Leffler * IEEE 802.1X: send EAPOL frames always in the clear. 13225e923d2eSSam Leffler * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 13235e923d2eSSam Leffler */ 1324b032f27cSSam Leffler if ((m->m_flags & M_EAPOL) == 0 || 1325b032f27cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) && 1326b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_STA ? 1327cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(key) : 1328cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { 13295e923d2eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 1330b032f27cSSam Leffler if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { 1331b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, 1332b032f27cSSam Leffler eh.ether_dhost, 1333b032f27cSSam Leffler "%s", "enmic failed, discard frame"); 1334b032f27cSSam Leffler vap->iv_stats.is_crypto_enmicfail++; 13355e923d2eSSam Leffler goto bad; 13365e923d2eSSam Leffler } 13375e923d2eSSam Leffler } 13385e923d2eSSam Leffler } 1339b032f27cSSam Leffler if (txfrag && !ieee80211_fragment(vap, m, hdrsize, 1340b032f27cSSam Leffler key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) 134168e8e04eSSam Leffler goto bad; 13428a1b9b6aSSam Leffler 1343c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 1344c1af44bdSSam Leffler 13458a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 13469e80b1dfSSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1347b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 13489e80b1dfSSam Leffler m->m_flags |= M_MCAST; 13499e80b1dfSSam Leffler } else 1350b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 13518a1b9b6aSSam Leffler IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); 13528a1b9b6aSSam Leffler 13531a1e1d21SSam Leffler return m; 13540a915fadSSam Leffler bad: 13550a915fadSSam Leffler if (m != NULL) 13560a915fadSSam Leffler m_freem(m); 13570a915fadSSam Leffler return NULL; 1358b032f27cSSam Leffler #undef WH4 13591a1e1d21SSam Leffler } 13601a1e1d21SSam Leffler 13611a1e1d21SSam Leffler /* 136268e8e04eSSam Leffler * Fragment the frame according to the specified mtu. 136368e8e04eSSam Leffler * The size of the 802.11 header (w/o padding) is provided 136468e8e04eSSam Leffler * so we don't need to recalculate it. We create a new 136568e8e04eSSam Leffler * mbuf for each fragment and chain it through m_nextpkt; 136668e8e04eSSam Leffler * we might be able to optimize this by reusing the original 136768e8e04eSSam Leffler * packet's mbufs but that is significantly more complicated. 136868e8e04eSSam Leffler */ 136968e8e04eSSam Leffler static int 1370b032f27cSSam Leffler ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, 137168e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu) 137268e8e04eSSam Leffler { 137368e8e04eSSam Leffler struct ieee80211_frame *wh, *whf; 137468e8e04eSSam Leffler struct mbuf *m, *prev, *next; 137568e8e04eSSam Leffler u_int totalhdrsize, fragno, fragsize, off, remainder, payload; 137668e8e04eSSam Leffler 137768e8e04eSSam Leffler KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); 137868e8e04eSSam Leffler KASSERT(m0->m_pkthdr.len > mtu, 137968e8e04eSSam Leffler ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); 138068e8e04eSSam Leffler 138168e8e04eSSam Leffler wh = mtod(m0, struct ieee80211_frame *); 138268e8e04eSSam Leffler /* NB: mark the first frag; it will be propagated below */ 138368e8e04eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; 138468e8e04eSSam Leffler totalhdrsize = hdrsize + ciphdrsize; 138568e8e04eSSam Leffler fragno = 1; 138668e8e04eSSam Leffler off = mtu - ciphdrsize; 138768e8e04eSSam Leffler remainder = m0->m_pkthdr.len - off; 138868e8e04eSSam Leffler prev = m0; 138968e8e04eSSam Leffler do { 139068e8e04eSSam Leffler fragsize = totalhdrsize + remainder; 139168e8e04eSSam Leffler if (fragsize > mtu) 139268e8e04eSSam Leffler fragsize = mtu; 1393b032f27cSSam Leffler /* XXX fragsize can be >2048! */ 139468e8e04eSSam Leffler KASSERT(fragsize < MCLBYTES, 139568e8e04eSSam Leffler ("fragment size %u too big!", fragsize)); 139668e8e04eSSam Leffler if (fragsize > MHLEN) 139768e8e04eSSam Leffler m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 139868e8e04eSSam Leffler else 139968e8e04eSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 140068e8e04eSSam Leffler if (m == NULL) 140168e8e04eSSam Leffler goto bad; 140268e8e04eSSam Leffler /* leave room to prepend any cipher header */ 140368e8e04eSSam Leffler m_align(m, fragsize - ciphdrsize); 140468e8e04eSSam Leffler 140568e8e04eSSam Leffler /* 140668e8e04eSSam Leffler * Form the header in the fragment. Note that since 140768e8e04eSSam Leffler * we mark the first fragment with the MORE_FRAG bit 140868e8e04eSSam Leffler * it automatically is propagated to each fragment; we 140968e8e04eSSam Leffler * need only clear it on the last fragment (done below). 141068e8e04eSSam Leffler */ 141168e8e04eSSam Leffler whf = mtod(m, struct ieee80211_frame *); 141268e8e04eSSam Leffler memcpy(whf, wh, hdrsize); 141368e8e04eSSam Leffler *(uint16_t *)&whf->i_seq[0] |= htole16( 141468e8e04eSSam Leffler (fragno & IEEE80211_SEQ_FRAG_MASK) << 141568e8e04eSSam Leffler IEEE80211_SEQ_FRAG_SHIFT); 141668e8e04eSSam Leffler fragno++; 141768e8e04eSSam Leffler 141868e8e04eSSam Leffler payload = fragsize - totalhdrsize; 141968e8e04eSSam Leffler /* NB: destination is known to be contiguous */ 142068e8e04eSSam Leffler m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrsize); 142168e8e04eSSam Leffler m->m_len = hdrsize + payload; 142268e8e04eSSam Leffler m->m_pkthdr.len = hdrsize + payload; 142368e8e04eSSam Leffler m->m_flags |= M_FRAG; 142468e8e04eSSam Leffler 142568e8e04eSSam Leffler /* chain up the fragment */ 142668e8e04eSSam Leffler prev->m_nextpkt = m; 142768e8e04eSSam Leffler prev = m; 142868e8e04eSSam Leffler 142968e8e04eSSam Leffler /* deduct fragment just formed */ 143068e8e04eSSam Leffler remainder -= payload; 143168e8e04eSSam Leffler off += payload; 143268e8e04eSSam Leffler } while (remainder != 0); 143351cec121SWeongyo Jeong 143451cec121SWeongyo Jeong /* set the last fragment */ 143551cec121SWeongyo Jeong m->m_flags |= M_LASTFRAG; 143668e8e04eSSam Leffler whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; 143768e8e04eSSam Leffler 143868e8e04eSSam Leffler /* strip first mbuf now that everything has been copied */ 143968e8e04eSSam Leffler m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); 144068e8e04eSSam Leffler m0->m_flags |= M_FIRSTFRAG | M_FRAG; 144168e8e04eSSam Leffler 1442b032f27cSSam Leffler vap->iv_stats.is_tx_fragframes++; 1443b032f27cSSam Leffler vap->iv_stats.is_tx_frags += fragno-1; 144468e8e04eSSam Leffler 144568e8e04eSSam Leffler return 1; 144668e8e04eSSam Leffler bad: 144768e8e04eSSam Leffler /* reclaim fragments but leave original frame for caller to free */ 144868e8e04eSSam Leffler for (m = m0->m_nextpkt; m != NULL; m = next) { 144968e8e04eSSam Leffler next = m->m_nextpkt; 145068e8e04eSSam Leffler m->m_nextpkt = NULL; /* XXX paranoid */ 145168e8e04eSSam Leffler m_freem(m); 145268e8e04eSSam Leffler } 145368e8e04eSSam Leffler m0->m_nextpkt = NULL; 145468e8e04eSSam Leffler return 0; 145568e8e04eSSam Leffler } 145668e8e04eSSam Leffler 145768e8e04eSSam Leffler /* 14581a1e1d21SSam Leffler * Add a supported rates element id to a frame. 14591a1e1d21SSam Leffler */ 146059aa14a9SRui Paulo uint8_t * 146168e8e04eSSam Leffler ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 14621a1e1d21SSam Leffler { 14631a1e1d21SSam Leffler int nrates; 14641a1e1d21SSam Leffler 14651a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_RATES; 14661a1e1d21SSam Leffler nrates = rs->rs_nrates; 14671a1e1d21SSam Leffler if (nrates > IEEE80211_RATE_SIZE) 14681a1e1d21SSam Leffler nrates = IEEE80211_RATE_SIZE; 14691a1e1d21SSam Leffler *frm++ = nrates; 14701a1e1d21SSam Leffler memcpy(frm, rs->rs_rates, nrates); 14711a1e1d21SSam Leffler return frm + nrates; 14721a1e1d21SSam Leffler } 14731a1e1d21SSam Leffler 14741a1e1d21SSam Leffler /* 14751a1e1d21SSam Leffler * Add an extended supported rates element id to a frame. 14761a1e1d21SSam Leffler */ 147759aa14a9SRui Paulo uint8_t * 147868e8e04eSSam Leffler ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 14791a1e1d21SSam Leffler { 14801a1e1d21SSam Leffler /* 14811a1e1d21SSam Leffler * Add an extended supported rates element if operating in 11g mode. 14821a1e1d21SSam Leffler */ 14831a1e1d21SSam Leffler if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 14841a1e1d21SSam Leffler int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 14851a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_XRATES; 14861a1e1d21SSam Leffler *frm++ = nrates; 14871a1e1d21SSam Leffler memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 14881a1e1d21SSam Leffler frm += nrates; 14891a1e1d21SSam Leffler } 14901a1e1d21SSam Leffler return frm; 14911a1e1d21SSam Leffler } 14921a1e1d21SSam Leffler 14931a1e1d21SSam Leffler /* 1494b032f27cSSam Leffler * Add an ssid element to a frame. 14951a1e1d21SSam Leffler */ 149668e8e04eSSam Leffler static uint8_t * 149768e8e04eSSam Leffler ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) 14981a1e1d21SSam Leffler { 14991a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 15001a1e1d21SSam Leffler *frm++ = len; 15011a1e1d21SSam Leffler memcpy(frm, ssid, len); 15021a1e1d21SSam Leffler return frm + len; 15031a1e1d21SSam Leffler } 15041a1e1d21SSam Leffler 15058a1b9b6aSSam Leffler /* 15068a1b9b6aSSam Leffler * Add an erp element to a frame. 15078a1b9b6aSSam Leffler */ 150868e8e04eSSam Leffler static uint8_t * 150968e8e04eSSam Leffler ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) 15101a1e1d21SSam Leffler { 151168e8e04eSSam Leffler uint8_t erp; 15121a1e1d21SSam Leffler 15138a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_ERP; 15148a1b9b6aSSam Leffler *frm++ = 1; 15158a1b9b6aSSam Leffler erp = 0; 15168a1b9b6aSSam Leffler if (ic->ic_nonerpsta != 0) 15178a1b9b6aSSam Leffler erp |= IEEE80211_ERP_NON_ERP_PRESENT; 15188a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEPROT) 15198a1b9b6aSSam Leffler erp |= IEEE80211_ERP_USE_PROTECTION; 15208a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEBARKER) 15218a1b9b6aSSam Leffler erp |= IEEE80211_ERP_LONG_PREAMBLE; 15228a1b9b6aSSam Leffler *frm++ = erp; 15238a1b9b6aSSam Leffler return frm; 15241a1e1d21SSam Leffler } 15251a1e1d21SSam Leffler 15268a1b9b6aSSam Leffler /* 1527b032f27cSSam Leffler * Add a CFParams element to a frame. 15288a1b9b6aSSam Leffler */ 152968e8e04eSSam Leffler static uint8_t * 1530b032f27cSSam Leffler ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) 15318a1b9b6aSSam Leffler { 1532b032f27cSSam Leffler #define ADDSHORT(frm, v) do { \ 153359aa14a9SRui Paulo LE_WRITE_2(frm, v); \ 1534b032f27cSSam Leffler frm += 2; \ 1535b032f27cSSam Leffler } while (0) 1536b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_CFPARMS; 1537b032f27cSSam Leffler *frm++ = 6; 1538b032f27cSSam Leffler *frm++ = 0; /* CFP count */ 1539b032f27cSSam Leffler *frm++ = 2; /* CFP period */ 1540b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ 1541b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ 15428a1b9b6aSSam Leffler return frm; 1543b032f27cSSam Leffler #undef ADDSHORT 1544b032f27cSSam Leffler } 1545b032f27cSSam Leffler 1546b032f27cSSam Leffler static __inline uint8_t * 1547b032f27cSSam Leffler add_appie(uint8_t *frm, const struct ieee80211_appie *ie) 1548b032f27cSSam Leffler { 1549b032f27cSSam Leffler memcpy(frm, ie->ie_data, ie->ie_len); 1550b032f27cSSam Leffler return frm + ie->ie_len; 1551b032f27cSSam Leffler } 1552b032f27cSSam Leffler 1553b032f27cSSam Leffler static __inline uint8_t * 1554b032f27cSSam Leffler add_ie(uint8_t *frm, const uint8_t *ie) 1555b032f27cSSam Leffler { 1556b032f27cSSam Leffler memcpy(frm, ie, 2 + ie[1]); 1557b032f27cSSam Leffler return frm + 2 + ie[1]; 15588a1b9b6aSSam Leffler } 15598a1b9b6aSSam Leffler 15608a1b9b6aSSam Leffler #define WME_OUI_BYTES 0x00, 0x50, 0xf2 15618a1b9b6aSSam Leffler /* 15628a1b9b6aSSam Leffler * Add a WME information element to a frame. 15638a1b9b6aSSam Leffler */ 156468e8e04eSSam Leffler static uint8_t * 156568e8e04eSSam Leffler ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 15668a1b9b6aSSam Leffler { 15678a1b9b6aSSam Leffler static const struct ieee80211_wme_info info = { 15688a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 15698a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_info) - 2, 15708a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 15718a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 15728a1b9b6aSSam Leffler .wme_subtype = WME_INFO_OUI_SUBTYPE, 15738a1b9b6aSSam Leffler .wme_version = WME_VERSION, 15748a1b9b6aSSam Leffler .wme_info = 0, 15758a1b9b6aSSam Leffler }; 15768a1b9b6aSSam Leffler memcpy(frm, &info, sizeof(info)); 15778a1b9b6aSSam Leffler return frm + sizeof(info); 15788a1b9b6aSSam Leffler } 15798a1b9b6aSSam Leffler 15808a1b9b6aSSam Leffler /* 15818a1b9b6aSSam Leffler * Add a WME parameters element to a frame. 15828a1b9b6aSSam Leffler */ 158368e8e04eSSam Leffler static uint8_t * 158468e8e04eSSam Leffler ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 15858a1b9b6aSSam Leffler { 15868a1b9b6aSSam Leffler #define SM(_v, _f) (((_v) << _f##_S) & _f) 15878a1b9b6aSSam Leffler #define ADDSHORT(frm, v) do { \ 158859aa14a9SRui Paulo LE_WRITE_2(frm, v); \ 15898a1b9b6aSSam Leffler frm += 2; \ 15908a1b9b6aSSam Leffler } while (0) 15918a1b9b6aSSam Leffler /* NB: this works 'cuz a param has an info at the front */ 15928a1b9b6aSSam Leffler static const struct ieee80211_wme_info param = { 15938a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 15948a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_param) - 2, 15958a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 15968a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 15978a1b9b6aSSam Leffler .wme_subtype = WME_PARAM_OUI_SUBTYPE, 15988a1b9b6aSSam Leffler .wme_version = WME_VERSION, 15998a1b9b6aSSam Leffler }; 16008a1b9b6aSSam Leffler int i; 16018a1b9b6aSSam Leffler 16028a1b9b6aSSam Leffler memcpy(frm, ¶m, sizeof(param)); 16038a1b9b6aSSam Leffler frm += __offsetof(struct ieee80211_wme_info, wme_info); 16048a1b9b6aSSam Leffler *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 16058a1b9b6aSSam Leffler *frm++ = 0; /* reserved field */ 16068a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 16078a1b9b6aSSam Leffler const struct wmeParams *ac = 16088a1b9b6aSSam Leffler &wme->wme_bssChanParams.cap_wmeParams[i]; 16098a1b9b6aSSam Leffler *frm++ = SM(i, WME_PARAM_ACI) 16108a1b9b6aSSam Leffler | SM(ac->wmep_acm, WME_PARAM_ACM) 16118a1b9b6aSSam Leffler | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) 16128a1b9b6aSSam Leffler ; 16138a1b9b6aSSam Leffler *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 16148a1b9b6aSSam Leffler | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) 16158a1b9b6aSSam Leffler ; 16168a1b9b6aSSam Leffler ADDSHORT(frm, ac->wmep_txopLimit); 16178a1b9b6aSSam Leffler } 16188a1b9b6aSSam Leffler return frm; 16198a1b9b6aSSam Leffler #undef SM 16208a1b9b6aSSam Leffler #undef ADDSHORT 16218a1b9b6aSSam Leffler } 16228a1b9b6aSSam Leffler #undef WME_OUI_BYTES 16238a1b9b6aSSam Leffler 16240a915fadSSam Leffler /* 1625b032f27cSSam Leffler * Add an 11h Power Constraint element to a frame. 1626b032f27cSSam Leffler */ 1627b032f27cSSam Leffler static uint8_t * 1628b032f27cSSam Leffler ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) 1629b032f27cSSam Leffler { 1630b032f27cSSam Leffler const struct ieee80211_channel *c = vap->iv_bss->ni_chan; 1631b032f27cSSam Leffler /* XXX per-vap tx power limit? */ 1632b032f27cSSam Leffler int8_t limit = vap->iv_ic->ic_txpowlimit / 2; 1633b032f27cSSam Leffler 1634b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCNSTR; 1635b032f27cSSam Leffler frm[1] = 1; 1636b032f27cSSam Leffler frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; 1637b032f27cSSam Leffler return frm + 3; 1638b032f27cSSam Leffler } 1639b032f27cSSam Leffler 1640b032f27cSSam Leffler /* 1641b032f27cSSam Leffler * Add an 11h Power Capability element to a frame. 1642b032f27cSSam Leffler */ 1643b032f27cSSam Leffler static uint8_t * 1644b032f27cSSam Leffler ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) 1645b032f27cSSam Leffler { 1646b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCAP; 1647b032f27cSSam Leffler frm[1] = 2; 1648b032f27cSSam Leffler frm[2] = c->ic_minpower; 1649b032f27cSSam Leffler frm[3] = c->ic_maxpower; 1650b032f27cSSam Leffler return frm + 4; 1651b032f27cSSam Leffler } 1652b032f27cSSam Leffler 1653b032f27cSSam Leffler /* 1654b032f27cSSam Leffler * Add an 11h Supported Channels element to a frame. 1655b032f27cSSam Leffler */ 1656b032f27cSSam Leffler static uint8_t * 1657b032f27cSSam Leffler ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) 1658b032f27cSSam Leffler { 1659b032f27cSSam Leffler static const int ielen = 26; 1660b032f27cSSam Leffler 1661b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_SUPPCHAN; 1662b032f27cSSam Leffler frm[1] = ielen; 1663b032f27cSSam Leffler /* XXX not correct */ 1664b032f27cSSam Leffler memcpy(frm+2, ic->ic_chan_avail, ielen); 1665b032f27cSSam Leffler return frm + 2 + ielen; 1666b032f27cSSam Leffler } 1667b032f27cSSam Leffler 1668b032f27cSSam Leffler /* 166932b0e64bSAdrian Chadd * Add an 11h Quiet time element to a frame. 167032b0e64bSAdrian Chadd */ 167132b0e64bSAdrian Chadd static uint8_t * 167232b0e64bSAdrian Chadd ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap) 167332b0e64bSAdrian Chadd { 167432b0e64bSAdrian Chadd struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm; 167532b0e64bSAdrian Chadd 167632b0e64bSAdrian Chadd quiet->quiet_ie = IEEE80211_ELEMID_QUIET; 167732b0e64bSAdrian Chadd quiet->len = 6; 167832b0e64bSAdrian Chadd if (vap->iv_quiet_count_value == 1) 167932b0e64bSAdrian Chadd vap->iv_quiet_count_value = vap->iv_quiet_count; 168032b0e64bSAdrian Chadd else if (vap->iv_quiet_count_value > 1) 168132b0e64bSAdrian Chadd vap->iv_quiet_count_value--; 168232b0e64bSAdrian Chadd 168332b0e64bSAdrian Chadd if (vap->iv_quiet_count_value == 0) { 168432b0e64bSAdrian Chadd /* value 0 is reserved as per 802.11h standerd */ 168532b0e64bSAdrian Chadd vap->iv_quiet_count_value = 1; 168632b0e64bSAdrian Chadd } 168732b0e64bSAdrian Chadd 168832b0e64bSAdrian Chadd quiet->tbttcount = vap->iv_quiet_count_value; 168932b0e64bSAdrian Chadd quiet->period = vap->iv_quiet_period; 169032b0e64bSAdrian Chadd quiet->duration = htole16(vap->iv_quiet_duration); 169132b0e64bSAdrian Chadd quiet->offset = htole16(vap->iv_quiet_offset); 169232b0e64bSAdrian Chadd return frm + sizeof(*quiet); 169332b0e64bSAdrian Chadd } 169432b0e64bSAdrian Chadd 169532b0e64bSAdrian Chadd /* 1696b032f27cSSam Leffler * Add an 11h Channel Switch Announcement element to a frame. 1697b032f27cSSam Leffler * Note that we use the per-vap CSA count to adjust the global 1698b032f27cSSam Leffler * counter so we can use this routine to form probe response 1699b032f27cSSam Leffler * frames and get the current count. 1700b032f27cSSam Leffler */ 1701b032f27cSSam Leffler static uint8_t * 1702b032f27cSSam Leffler ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) 1703b032f27cSSam Leffler { 1704b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 1705b032f27cSSam Leffler struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; 1706b032f27cSSam Leffler 1707c70761e6SSam Leffler csa->csa_ie = IEEE80211_ELEMID_CSA; 1708b032f27cSSam Leffler csa->csa_len = 3; 1709b032f27cSSam Leffler csa->csa_mode = 1; /* XXX force quiet on channel */ 1710b032f27cSSam Leffler csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); 1711b032f27cSSam Leffler csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; 1712b032f27cSSam Leffler return frm + sizeof(*csa); 1713b032f27cSSam Leffler } 1714b032f27cSSam Leffler 1715b032f27cSSam Leffler /* 1716b032f27cSSam Leffler * Add an 11h country information element to a frame. 1717b032f27cSSam Leffler */ 1718b032f27cSSam Leffler static uint8_t * 1719b032f27cSSam Leffler ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) 1720b032f27cSSam Leffler { 1721b032f27cSSam Leffler 1722b032f27cSSam Leffler if (ic->ic_countryie == NULL || 1723b032f27cSSam Leffler ic->ic_countryie_chan != ic->ic_bsschan) { 1724b032f27cSSam Leffler /* 1725b032f27cSSam Leffler * Handle lazy construction of ie. This is done on 1726b032f27cSSam Leffler * first use and after a channel change that requires 1727b032f27cSSam Leffler * re-calculation. 1728b032f27cSSam Leffler */ 1729b032f27cSSam Leffler if (ic->ic_countryie != NULL) 1730b032f27cSSam Leffler free(ic->ic_countryie, M_80211_NODE_IE); 1731b032f27cSSam Leffler ic->ic_countryie = ieee80211_alloc_countryie(ic); 1732b032f27cSSam Leffler if (ic->ic_countryie == NULL) 1733b032f27cSSam Leffler return frm; 1734b032f27cSSam Leffler ic->ic_countryie_chan = ic->ic_bsschan; 1735b032f27cSSam Leffler } 1736b032f27cSSam Leffler return add_appie(frm, ic->ic_countryie); 1737b032f27cSSam Leffler } 1738b032f27cSSam Leffler 1739b032f27cSSam Leffler /* 1740af8418dcSSam Leffler * Send a probe request frame with the specified ssid 1741af8418dcSSam Leffler * and any optional information element data. 1742af8418dcSSam Leffler */ 1743af8418dcSSam Leffler int 1744af8418dcSSam Leffler ieee80211_send_probereq(struct ieee80211_node *ni, 174568e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 174668e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 174768e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN], 1748b032f27cSSam Leffler const uint8_t *ssid, size_t ssidlen) 1749af8418dcSSam Leffler { 1750b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1751af8418dcSSam Leffler struct ieee80211com *ic = ni->ni_ic; 175216d7cbb1SSam Leffler const struct ieee80211_txparam *tp; 175316d7cbb1SSam Leffler struct ieee80211_bpf_params params; 1754af8418dcSSam Leffler struct ieee80211_frame *wh; 175541b3c790SSam Leffler const struct ieee80211_rateset *rs; 1756af8418dcSSam Leffler struct mbuf *m; 175768e8e04eSSam Leffler uint8_t *frm; 1758af8418dcSSam Leffler 1759b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 1760b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 1761b032f27cSSam Leffler "block %s frame in CAC state", "probe request"); 1762b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 1763b032f27cSSam Leffler return EIO; /* XXX */ 1764b032f27cSSam Leffler } 1765b032f27cSSam Leffler 1766af8418dcSSam Leffler /* 1767af8418dcSSam Leffler * Hold a reference on the node so it doesn't go away until after 1768af8418dcSSam Leffler * the xmit is complete all the way in the driver. On error we 1769af8418dcSSam Leffler * will remove our reference. 1770af8418dcSSam Leffler */ 1771b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1772af8418dcSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 1773af8418dcSSam Leffler __func__, __LINE__, 1774af8418dcSSam Leffler ni, ether_sprintf(ni->ni_macaddr), 1775af8418dcSSam Leffler ieee80211_node_refcnt(ni)+1); 1776af8418dcSSam Leffler ieee80211_ref_node(ni); 1777af8418dcSSam Leffler 1778af8418dcSSam Leffler /* 1779af8418dcSSam Leffler * prreq frame format 1780af8418dcSSam Leffler * [tlv] ssid 1781af8418dcSSam Leffler * [tlv] supported rates 1782b032f27cSSam Leffler * [tlv] RSN (optional) 1783af8418dcSSam Leffler * [tlv] extended supported rates 1784b032f27cSSam Leffler * [tlv] WPA (optional) 1785af8418dcSSam Leffler * [tlv] user-specified ie's 1786af8418dcSSam Leffler */ 1787af8418dcSSam Leffler m = ieee80211_getmgtframe(&frm, 178868e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 1789af8418dcSSam Leffler 2 + IEEE80211_NWID_LEN 1790af8418dcSSam Leffler + 2 + IEEE80211_RATE_SIZE 1791b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 1792af8418dcSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1793b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 1794b032f27cSSam Leffler + (vap->iv_appie_probereq != NULL ? 1795b032f27cSSam Leffler vap->iv_appie_probereq->ie_len : 0) 1796af8418dcSSam Leffler ); 1797af8418dcSSam Leffler if (m == NULL) { 1798b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 1799af8418dcSSam Leffler ieee80211_free_node(ni); 1800af8418dcSSam Leffler return ENOMEM; 1801af8418dcSSam Leffler } 1802af8418dcSSam Leffler 1803af8418dcSSam Leffler frm = ieee80211_add_ssid(frm, ssid, ssidlen); 180441b3c790SSam Leffler rs = ieee80211_get_suprates(ic, ic->ic_curchan); 180541b3c790SSam Leffler frm = ieee80211_add_rates(frm, rs); 1806b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 1807b032f27cSSam Leffler if (vap->iv_rsn_ie != NULL) 1808b032f27cSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 1809b032f27cSSam Leffler /* XXX else complain? */ 1810af8418dcSSam Leffler } 1811b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 1812b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 1813b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 1814b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 1815b032f27cSSam Leffler /* XXX else complain? */ 1816b032f27cSSam Leffler } 1817b032f27cSSam Leffler if (vap->iv_appie_probereq != NULL) 1818b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_probereq); 181968e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 1820af8418dcSSam Leffler 182116d7cbb1SSam Leffler KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), 182216d7cbb1SSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 1823af8418dcSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 182416d7cbb1SSam Leffler if (m == NULL) { 182516d7cbb1SSam Leffler /* NB: cannot happen */ 182616d7cbb1SSam Leffler ieee80211_free_node(ni); 1827af8418dcSSam Leffler return ENOMEM; 182816d7cbb1SSam Leffler } 1829af8418dcSSam Leffler 1830af8418dcSSam Leffler wh = mtod(m, struct ieee80211_frame *); 18319e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 1832af8418dcSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 18338ac160cdSSam Leffler IEEE80211_NONQOS_TID, sa, da, bssid); 1834af8418dcSSam Leffler /* XXX power management? */ 1835c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 1836af8418dcSSam Leffler 1837b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 1838b032f27cSSam Leffler 1839af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_probereq); 1840af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 1841af8418dcSSam Leffler 1842b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 1843b032f27cSSam Leffler "send probe req on channel %u bssid %s ssid \"%.*s\"\n", 1844b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid), 1845b032f27cSSam Leffler ssidlen, ssid); 1846af8418dcSSam Leffler 184716d7cbb1SSam Leffler memset(¶ms, 0, sizeof(params)); 184816d7cbb1SSam Leffler params.ibp_pri = M_WME_GETAC(m); 184916d7cbb1SSam Leffler tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 185016d7cbb1SSam Leffler params.ibp_rate0 = tp->mgmtrate; 185116d7cbb1SSam Leffler if (IEEE80211_IS_MULTICAST(da)) { 185216d7cbb1SSam Leffler params.ibp_flags |= IEEE80211_BPF_NOACK; 185316d7cbb1SSam Leffler params.ibp_try0 = 1; 185416d7cbb1SSam Leffler } else 185516d7cbb1SSam Leffler params.ibp_try0 = tp->maxretry; 185616d7cbb1SSam Leffler params.ibp_power = ni->ni_txpower; 185716d7cbb1SSam Leffler return ic->ic_raw_xmit(ni, m, ¶ms); 1858af8418dcSSam Leffler } 1859af8418dcSSam Leffler 1860af8418dcSSam Leffler /* 1861667dad55SSam Leffler * Calculate capability information for mgt frames. 1862667dad55SSam Leffler */ 186359aa14a9SRui Paulo uint16_t 186459aa14a9SRui Paulo ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) 1865667dad55SSam Leffler { 1866b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 186768e8e04eSSam Leffler uint16_t capinfo; 1868667dad55SSam Leffler 1869b032f27cSSam Leffler KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); 1870667dad55SSam Leffler 1871b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) 1872667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 1873b032f27cSSam Leffler else if (vap->iv_opmode == IEEE80211_M_IBSS) 1874667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_IBSS; 1875667dad55SSam Leffler else 1876667dad55SSam Leffler capinfo = 0; 1877b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 1878667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 1879667dad55SSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 1880667dad55SSam Leffler IEEE80211_IS_CHAN_2GHZ(chan)) 1881667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 1882667dad55SSam Leffler if (ic->ic_flags & IEEE80211_F_SHSLOT) 1883667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 1884b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) 1885b032f27cSSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 1886667dad55SSam Leffler return capinfo; 1887667dad55SSam Leffler } 1888667dad55SSam Leffler 1889667dad55SSam Leffler /* 18900a915fadSSam Leffler * Send a management frame. The node is for the destination (or ic_bss 18910a915fadSSam Leffler * when in station mode). Nodes other than ic_bss have their reference 18920a915fadSSam Leffler * count bumped to reflect our use for an indeterminant time. 18930a915fadSSam Leffler */ 18941a1e1d21SSam Leffler int 1895b032f27cSSam Leffler ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) 18961a1e1d21SSam Leffler { 18971b6167d2SSam Leffler #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) 1898b032f27cSSam Leffler #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) 1899b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1900b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 1901b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 19028ac160cdSSam Leffler struct ieee80211_bpf_params params; 19031a1e1d21SSam Leffler struct mbuf *m; 190468e8e04eSSam Leffler uint8_t *frm; 190568e8e04eSSam Leffler uint16_t capinfo; 190668e8e04eSSam Leffler int has_challenge, is_shared_key, ret, status; 19071a1e1d21SSam Leffler 19080a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 19090a915fadSSam Leffler 19100a915fadSSam Leffler /* 19110a915fadSSam Leffler * Hold a reference on the node so it doesn't go away until after 19120a915fadSSam Leffler * the xmit is complete all the way in the driver. On error we 19130a915fadSSam Leffler * will remove our reference. 19140a915fadSSam Leffler */ 1915b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 191649a15236SSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 19178a1b9b6aSSam Leffler __func__, __LINE__, 191849a15236SSam Leffler ni, ether_sprintf(ni->ni_macaddr), 19198a1b9b6aSSam Leffler ieee80211_node_refcnt(ni)+1); 19200a915fadSSam Leffler ieee80211_ref_node(ni); 19218a1b9b6aSSam Leffler 19228ac160cdSSam Leffler memset(¶ms, 0, sizeof(params)); 19231a1e1d21SSam Leffler switch (type) { 19241a1e1d21SSam Leffler 19251a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 19268a1b9b6aSSam Leffler status = arg >> 16; 19278a1b9b6aSSam Leffler arg &= 0xffff; 19288a1b9b6aSSam Leffler has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 19298a1b9b6aSSam Leffler arg == IEEE80211_AUTH_SHARED_RESPONSE) && 19308a1b9b6aSSam Leffler ni->ni_challenge != NULL); 19318a1b9b6aSSam Leffler 19328a1b9b6aSSam Leffler /* 19338a1b9b6aSSam Leffler * Deduce whether we're doing open authentication or 19348a1b9b6aSSam Leffler * shared key authentication. We do the latter if 19358a1b9b6aSSam Leffler * we're in the middle of a shared key authentication 19368a1b9b6aSSam Leffler * handshake or if we're initiating an authentication 19378a1b9b6aSSam Leffler * request and configured to use shared key. 19388a1b9b6aSSam Leffler */ 19398a1b9b6aSSam Leffler is_shared_key = has_challenge || 19408a1b9b6aSSam Leffler arg >= IEEE80211_AUTH_SHARED_RESPONSE || 19418a1b9b6aSSam Leffler (arg == IEEE80211_AUTH_SHARED_REQUEST && 1942b032f27cSSam Leffler bss->ni_authmode == IEEE80211_AUTH_SHARED); 19438a1b9b6aSSam Leffler 19448a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 194568e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 194668e8e04eSSam Leffler 3 * sizeof(uint16_t) 19478a1b9b6aSSam Leffler + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 194868e8e04eSSam Leffler sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) 19498a1b9b6aSSam Leffler ); 19501a1e1d21SSam Leffler if (m == NULL) 19518a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 19528a1b9b6aSSam Leffler 195368e8e04eSSam Leffler ((uint16_t *)frm)[0] = 19548a1b9b6aSSam Leffler (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) 19558a1b9b6aSSam Leffler : htole16(IEEE80211_AUTH_ALG_OPEN); 195668e8e04eSSam Leffler ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ 195768e8e04eSSam Leffler ((uint16_t *)frm)[2] = htole16(status);/* status */ 19588a1b9b6aSSam Leffler 19598a1b9b6aSSam Leffler if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 196068e8e04eSSam Leffler ((uint16_t *)frm)[3] = 19618a1b9b6aSSam Leffler htole16((IEEE80211_CHALLENGE_LEN << 8) | 19628a1b9b6aSSam Leffler IEEE80211_ELEMID_CHALLENGE); 196368e8e04eSSam Leffler memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, 19648a1b9b6aSSam Leffler IEEE80211_CHALLENGE_LEN); 19658a1b9b6aSSam Leffler m->m_pkthdr.len = m->m_len = 196668e8e04eSSam Leffler 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; 19678a1b9b6aSSam Leffler if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { 1968b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1969b032f27cSSam Leffler "request encrypt frame (%s)", __func__); 19708ac160cdSSam Leffler /* mark frame for encryption */ 19718ac160cdSSam Leffler params.ibp_flags |= IEEE80211_BPF_CRYPTO; 19728a1b9b6aSSam Leffler } 19738a1b9b6aSSam Leffler } else 197468e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); 19758a1b9b6aSSam Leffler 19768a1b9b6aSSam Leffler /* XXX not right for shared key */ 19778a1b9b6aSSam Leffler if (status == IEEE80211_STATUS_SUCCESS) 19788a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth); 19798a1b9b6aSSam Leffler else 19808a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth_fail); 19818a1b9b6aSSam Leffler 1982b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA) 198368e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 1984b032f27cSSam Leffler (void *) vap->iv_state); 19851a1e1d21SSam Leffler break; 19861a1e1d21SSam Leffler 19871a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 1988b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1989b032f27cSSam Leffler "send station deauthenticate (reason %d)", arg); 199068e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 199168e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 199268e8e04eSSam Leffler sizeof(uint16_t)); 19931a1e1d21SSam Leffler if (m == NULL) 19948a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 199568e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 199668e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 19978a1b9b6aSSam Leffler 19988a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_deauth); 19998a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); 20008a1b9b6aSSam Leffler 2001e4918ecdSSam Leffler ieee80211_node_unauthorize(ni); /* port closed */ 20021a1e1d21SSam Leffler break; 20031a1e1d21SSam Leffler 20041a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 20051a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 20061a1e1d21SSam Leffler /* 20071a1e1d21SSam Leffler * asreq frame format 20081a1e1d21SSam Leffler * [2] capability information 20091a1e1d21SSam Leffler * [2] listen interval 20101a1e1d21SSam Leffler * [6*] current AP address (reassoc only) 20111a1e1d21SSam Leffler * [tlv] ssid 20121a1e1d21SSam Leffler * [tlv] supported rates 20131a1e1d21SSam Leffler * [tlv] extended supported rates 2014b032f27cSSam Leffler * [4] power capability (optional) 2015b032f27cSSam Leffler * [28] supported channels (optional) 201668e8e04eSSam Leffler * [tlv] HT capabilities 2017b032f27cSSam Leffler * [tlv] WME (optional) 201868e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 201968e8e04eSSam Leffler * [tlv] Atheros capabilities (if negotiated) 2020b032f27cSSam Leffler * [tlv] AppIE's (optional) 20211a1e1d21SSam Leffler */ 20228a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 202368e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 202468e8e04eSSam Leffler sizeof(uint16_t) 202568e8e04eSSam Leffler + sizeof(uint16_t) 20261a1e1d21SSam Leffler + IEEE80211_ADDR_LEN 20278a1b9b6aSSam Leffler + 2 + IEEE80211_NWID_LEN 20281a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 20298a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2030b032f27cSSam Leffler + 4 2031b032f27cSSam Leffler + 2 + 26 20328a1b9b6aSSam Leffler + sizeof(struct ieee80211_wme_info) 2033b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 2034b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 2035616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 203668e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2037616190d0SSam Leffler #endif 2038b032f27cSSam Leffler + (vap->iv_appie_wpa != NULL ? 2039b032f27cSSam Leffler vap->iv_appie_wpa->ie_len : 0) 2040b032f27cSSam Leffler + (vap->iv_appie_assocreq != NULL ? 2041b032f27cSSam Leffler vap->iv_appie_assocreq->ie_len : 0) 20428a1b9b6aSSam Leffler ); 20431a1e1d21SSam Leffler if (m == NULL) 20448a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 20451a1e1d21SSam Leffler 2046b032f27cSSam Leffler KASSERT(vap->iv_opmode == IEEE80211_M_STA, 2047b032f27cSSam Leffler ("wrong mode %u", vap->iv_opmode)); 2048667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 2049b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 20501a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 20514f2e09c4SSam Leffler /* 20524f2e09c4SSam Leffler * NB: Some 11a AP's reject the request when 20534f2e09c4SSam Leffler * short premable is set. 20544f2e09c4SSam Leffler */ 20554f2e09c4SSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 2056b5c99415SSam Leffler IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 20571a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 205868e8e04eSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 20598a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHSLOT)) 20601a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 20611b6167d2SSam Leffler if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && 2062b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_DOTH)) 20631b6167d2SSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 206468e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 20651a1e1d21SSam Leffler frm += 2; 20661a1e1d21SSam Leffler 2067b032f27cSSam Leffler KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); 206868e8e04eSSam Leffler *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, 2069b032f27cSSam Leffler bss->ni_intval)); 20701a1e1d21SSam Leffler frm += 2; 20711a1e1d21SSam Leffler 20721a1e1d21SSam Leffler if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 2073b032f27cSSam Leffler IEEE80211_ADDR_COPY(frm, bss->ni_bssid); 20741a1e1d21SSam Leffler frm += IEEE80211_ADDR_LEN; 20751a1e1d21SSam Leffler } 20761a1e1d21SSam Leffler 20771a1e1d21SSam Leffler frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 20781a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 2079b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2080b032f27cSSam Leffler if (vap->iv_rsn_ie != NULL) 2081b032f27cSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2082b032f27cSSam Leffler /* XXX else complain? */ 20838a1b9b6aSSam Leffler } 2084b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 2085b032f27cSSam Leffler if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { 2086b032f27cSSam Leffler frm = ieee80211_add_powercapability(frm, 2087b032f27cSSam Leffler ic->ic_curchan); 2088b032f27cSSam Leffler frm = ieee80211_add_supportedchannels(frm, ic); 2089b032f27cSSam Leffler } 20902bfc8a91SSam Leffler if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 2091b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2092b032f27cSSam Leffler ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 2093b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, ni); 2094b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2095b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2096b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2097b032f27cSSam Leffler /* XXX else complain */ 2098b032f27cSSam Leffler } 2099b032f27cSSam Leffler if ((ic->ic_flags & IEEE80211_F_WME) && 2100b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 2101b032f27cSSam Leffler frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 21022bfc8a91SSam Leffler if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 2103b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2104b032f27cSSam Leffler ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 2105b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 2106616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 21074207227cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { 2108b032f27cSSam Leffler frm = ieee80211_add_ath(frm, 2109b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 21104207227cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 21114207227cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X) ? 21124207227cSSam Leffler vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 21134207227cSSam Leffler } 2114616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 2115b032f27cSSam Leffler if (vap->iv_appie_assocreq != NULL) 2116b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocreq); 211768e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 21181a1e1d21SSam Leffler 211968e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 2120b032f27cSSam Leffler (void *) vap->iv_state); 21211a1e1d21SSam Leffler break; 21221a1e1d21SSam Leffler 21231a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 21241a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 21251a1e1d21SSam Leffler /* 212668e8e04eSSam Leffler * asresp frame format 21271a1e1d21SSam Leffler * [2] capability information 21281a1e1d21SSam Leffler * [2] status 21291a1e1d21SSam Leffler * [2] association ID 21301a1e1d21SSam Leffler * [tlv] supported rates 21311a1e1d21SSam Leffler * [tlv] extended supported rates 2132b032f27cSSam Leffler * [tlv] HT capabilities (standard, if STA enabled) 2133b032f27cSSam Leffler * [tlv] HT information (standard, if STA enabled) 2134b032f27cSSam Leffler * [tlv] WME (if configured and STA enabled) 2135b032f27cSSam Leffler * [tlv] HT capabilities (vendor OUI, if STA enabled) 2136b032f27cSSam Leffler * [tlv] HT information (vendor OUI, if STA enabled) 2137b032f27cSSam Leffler * [tlv] Atheros capabilities (if STA enabled) 2138b032f27cSSam Leffler * [tlv] AppIE's (optional) 21391a1e1d21SSam Leffler */ 21408a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 214168e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 214268e8e04eSSam Leffler sizeof(uint16_t) 214368e8e04eSSam Leffler + sizeof(uint16_t) 214468e8e04eSSam Leffler + sizeof(uint16_t) 21451a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 21468a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 214768e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htcap) + 4 214868e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htinfo) + 4 2149b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 2150616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 215168e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2152616190d0SSam Leffler #endif 2153b032f27cSSam Leffler + (vap->iv_appie_assocresp != NULL ? 2154b032f27cSSam Leffler vap->iv_appie_assocresp->ie_len : 0) 21558a1b9b6aSSam Leffler ); 21561a1e1d21SSam Leffler if (m == NULL) 21578a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 21581a1e1d21SSam Leffler 215959aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 216068e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 21611a1e1d21SSam Leffler frm += 2; 21621a1e1d21SSam Leffler 216368e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* status */ 21641a1e1d21SSam Leffler frm += 2; 21651a1e1d21SSam Leffler 21668a1b9b6aSSam Leffler if (arg == IEEE80211_STATUS_SUCCESS) { 216768e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_associd); 21688a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc); 21698a1b9b6aSSam Leffler } else 21708a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc_fail); 21711a1e1d21SSam Leffler frm += 2; 21721a1e1d21SSam Leffler 21731a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 21741a1e1d21SSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 217568e8e04eSSam Leffler /* NB: respond according to what we received */ 21761b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { 217768e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 217868e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 217968e8e04eSSam Leffler } 2180b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_WME) && 2181b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 21821b6167d2SSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 21831b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { 21841b6167d2SSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 21851b6167d2SSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 218668e8e04eSSam Leffler } 2187616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 2188b032f27cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 218968e8e04eSSam Leffler frm = ieee80211_add_ath(frm, 2190b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 21914207227cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 21924207227cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X) ? 21934207227cSSam Leffler vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 2194616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 2195b032f27cSSam Leffler if (vap->iv_appie_assocresp != NULL) 2196b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocresp); 219768e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 21981a1e1d21SSam Leffler break; 21991a1e1d21SSam Leffler 22001a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DISASSOC: 2201b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 2202b032f27cSSam Leffler "send station disassociate (reason %d)", arg); 220368e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 220468e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 220568e8e04eSSam Leffler sizeof(uint16_t)); 22061a1e1d21SSam Leffler if (m == NULL) 22078a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 220868e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 220968e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 22108a1b9b6aSSam Leffler 22118a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_disassoc); 22128a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); 22131a1e1d21SSam Leffler break; 22141a1e1d21SSam Leffler 22151a1e1d21SSam Leffler default: 2216b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 2217b032f27cSSam Leffler "invalid mgmt frame type %u", type); 22181be50176SSam Leffler senderr(EINVAL, is_tx_unknownmgt); 22190a915fadSSam Leffler /* NOTREACHED */ 22201a1e1d21SSam Leffler } 222168e8e04eSSam Leffler 22228ac160cdSSam Leffler /* NB: force non-ProbeResp frames to the highest queue */ 22238ac160cdSSam Leffler params.ibp_pri = WME_AC_VO; 22248ac160cdSSam Leffler params.ibp_rate0 = bss->ni_txparms->mgmtrate; 22258ac160cdSSam Leffler /* NB: we know all frames are unicast */ 22268ac160cdSSam Leffler params.ibp_try0 = bss->ni_txparms->maxretry; 22278ac160cdSSam Leffler params.ibp_power = bss->ni_txpower; 22288ac160cdSSam Leffler return ieee80211_mgmt_output(ni, m, type, ¶ms); 22290a915fadSSam Leffler bad: 22308a1b9b6aSSam Leffler ieee80211_free_node(ni); 22311a1e1d21SSam Leffler return ret; 22320a915fadSSam Leffler #undef senderr 22331b6167d2SSam Leffler #undef HTFLAGS 22341a1e1d21SSam Leffler } 22358a1b9b6aSSam Leffler 2236b032f27cSSam Leffler /* 2237b032f27cSSam Leffler * Return an mbuf with a probe response frame in it. 2238b032f27cSSam Leffler * Space is left to prepend and 802.11 header at the 2239b032f27cSSam Leffler * front but it's left to the caller to fill in. 2240b032f27cSSam Leffler */ 2241b032f27cSSam Leffler struct mbuf * 2242b032f27cSSam Leffler ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) 2243b032f27cSSam Leffler { 2244b032f27cSSam Leffler struct ieee80211vap *vap = bss->ni_vap; 2245b032f27cSSam Leffler struct ieee80211com *ic = bss->ni_ic; 2246b032f27cSSam Leffler const struct ieee80211_rateset *rs; 2247b032f27cSSam Leffler struct mbuf *m; 2248b032f27cSSam Leffler uint16_t capinfo; 2249b032f27cSSam Leffler uint8_t *frm; 2250b032f27cSSam Leffler 2251b032f27cSSam Leffler /* 2252b032f27cSSam Leffler * probe response frame format 2253b032f27cSSam Leffler * [8] time stamp 2254b032f27cSSam Leffler * [2] beacon interval 2255b032f27cSSam Leffler * [2] cabability information 2256b032f27cSSam Leffler * [tlv] ssid 2257b032f27cSSam Leffler * [tlv] supported rates 2258b032f27cSSam Leffler * [tlv] parameter set (FH/DS) 2259b032f27cSSam Leffler * [tlv] parameter set (IBSS) 2260b032f27cSSam Leffler * [tlv] country (optional) 2261b032f27cSSam Leffler * [3] power control (optional) 2262b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 2263b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 2264b032f27cSSam Leffler * [tlv] extended supported rates 2265688fe74dSSam Leffler * [tlv] RSN (optional) 2266b032f27cSSam Leffler * [tlv] HT capabilities 2267b032f27cSSam Leffler * [tlv] HT information 2268b032f27cSSam Leffler * [tlv] WPA (optional) 2269b032f27cSSam Leffler * [tlv] WME (optional) 2270b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 2271b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 2272b032f27cSSam Leffler * [tlv] Atheros capabilities 2273b032f27cSSam Leffler * [tlv] AppIE's (optional) 227459aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 227559aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2276b032f27cSSam Leffler */ 2277b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 2278b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 2279b032f27cSSam Leffler 8 2280b032f27cSSam Leffler + sizeof(uint16_t) 2281b032f27cSSam Leffler + sizeof(uint16_t) 2282b032f27cSSam Leffler + 2 + IEEE80211_NWID_LEN 2283b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE 2284b032f27cSSam Leffler + 7 /* max(7,3) */ 2285b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE 2286b032f27cSSam Leffler + 3 2287b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) 228832b0e64bSAdrian Chadd + sizeof(struct ieee80211_quiet_ie) 2289b032f27cSSam Leffler + 3 2290b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2291688fe74dSSam Leffler + sizeof(struct ieee80211_ie_wpa) 2292b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 2293b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htinfo) 2294b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 2295b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 2296b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 2297b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htinfo) 2298616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 2299b032f27cSSam Leffler + sizeof(struct ieee80211_ath_ie) 2300616190d0SSam Leffler #endif 230159aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 230259aa14a9SRui Paulo + 2 + IEEE80211_MESHID_LEN 230359aa14a9SRui Paulo + sizeof(struct ieee80211_meshconf_ie) 230459aa14a9SRui Paulo #endif 2305b032f27cSSam Leffler + (vap->iv_appie_proberesp != NULL ? 2306b032f27cSSam Leffler vap->iv_appie_proberesp->ie_len : 0) 2307b032f27cSSam Leffler ); 2308b032f27cSSam Leffler if (m == NULL) { 2309b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 2310b032f27cSSam Leffler return NULL; 2311b032f27cSSam Leffler } 2312b032f27cSSam Leffler 2313b032f27cSSam Leffler memset(frm, 0, 8); /* timestamp should be filled later */ 2314b032f27cSSam Leffler frm += 8; 2315b032f27cSSam Leffler *(uint16_t *)frm = htole16(bss->ni_intval); 2316b032f27cSSam Leffler frm += 2; 231759aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 2318b032f27cSSam Leffler *(uint16_t *)frm = htole16(capinfo); 2319b032f27cSSam Leffler frm += 2; 2320b032f27cSSam Leffler 2321b032f27cSSam Leffler frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); 2322b032f27cSSam Leffler rs = ieee80211_get_suprates(ic, bss->ni_chan); 2323b032f27cSSam Leffler frm = ieee80211_add_rates(frm, rs); 2324b032f27cSSam Leffler 2325b032f27cSSam Leffler if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { 2326b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_FHPARMS; 2327b032f27cSSam Leffler *frm++ = 5; 2328b032f27cSSam Leffler *frm++ = bss->ni_fhdwell & 0x00ff; 2329b032f27cSSam Leffler *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; 2330b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANSET( 2331b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 2332b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANPAT( 2333b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 2334b032f27cSSam Leffler *frm++ = bss->ni_fhindex; 2335b032f27cSSam Leffler } else { 2336b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 2337b032f27cSSam Leffler *frm++ = 1; 2338b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); 2339b032f27cSSam Leffler } 2340b032f27cSSam Leffler 2341b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 2342b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 2343b032f27cSSam Leffler *frm++ = 2; 2344b032f27cSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 2345b032f27cSSam Leffler } 2346b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 2347b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2348b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 2349b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 2350b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) 2351b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 2352b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2353b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 2354b032f27cSSam Leffler } 235532b0e64bSAdrian Chadd if (vap->iv_flags & IEEE80211_F_DOTH) { 235632b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 235732b0e64bSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 235832b0e64bSAdrian Chadd if (vap->iv_quiet) 235932b0e64bSAdrian Chadd frm = ieee80211_add_quiet(frm, vap); 236032b0e64bSAdrian Chadd } 236132b0e64bSAdrian Chadd } 2362b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) 2363b032f27cSSam Leffler frm = ieee80211_add_erp(frm, ic); 2364b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2365688fe74dSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2366688fe74dSSam Leffler if (vap->iv_rsn_ie != NULL) 2367688fe74dSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2368688fe74dSSam Leffler /* XXX else complain? */ 2369688fe74dSSam Leffler } 2370b032f27cSSam Leffler /* 2371b032f27cSSam Leffler * NB: legacy 11b clients do not get certain ie's. 2372b032f27cSSam Leffler * The caller identifies such clients by passing 2373b032f27cSSam Leffler * a token in legacy to us. Could expand this to be 2374b032f27cSSam Leffler * any legacy client for stuff like HT ie's. 2375b032f27cSSam Leffler */ 2376b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 2377b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 2378b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, bss); 2379b032f27cSSam Leffler frm = ieee80211_add_htinfo(frm, bss); 2380b032f27cSSam Leffler } 2381b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2382b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2383b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2384b032f27cSSam Leffler /* XXX else complain? */ 2385b032f27cSSam Leffler } 2386b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) 2387b032f27cSSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 2388b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 23892bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) && 2390b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 2391b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, bss); 2392b032f27cSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, bss); 2393b032f27cSSam Leffler } 2394616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 23954207227cSSam Leffler if ((vap->iv_flags & IEEE80211_F_ATHEROS) && 23964207227cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) 23974207227cSSam Leffler frm = ieee80211_add_athcaps(frm, bss); 2398616190d0SSam Leffler #endif 2399b032f27cSSam Leffler if (vap->iv_appie_proberesp != NULL) 2400b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_proberesp); 240159aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 240259aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 240359aa14a9SRui Paulo frm = ieee80211_add_meshid(frm, vap); 240459aa14a9SRui Paulo frm = ieee80211_add_meshconf(frm, vap); 240559aa14a9SRui Paulo } 240659aa14a9SRui Paulo #endif 2407b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2408b032f27cSSam Leffler 2409b032f27cSSam Leffler return m; 2410b032f27cSSam Leffler } 2411b032f27cSSam Leffler 2412b032f27cSSam Leffler /* 2413b032f27cSSam Leffler * Send a probe response frame to the specified mac address. 2414b032f27cSSam Leffler * This does not go through the normal mgt frame api so we 2415b032f27cSSam Leffler * can specify the destination address and re-use the bss node 2416b032f27cSSam Leffler * for the sta reference. 2417b032f27cSSam Leffler */ 2418b032f27cSSam Leffler int 2419b032f27cSSam Leffler ieee80211_send_proberesp(struct ieee80211vap *vap, 2420b032f27cSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], int legacy) 2421b032f27cSSam Leffler { 2422b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 2423b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 2424b032f27cSSam Leffler struct ieee80211_frame *wh; 2425b032f27cSSam Leffler struct mbuf *m; 2426b032f27cSSam Leffler 2427b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 2428b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, 2429b032f27cSSam Leffler "block %s frame in CAC state", "probe response"); 2430b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 2431b032f27cSSam Leffler return EIO; /* XXX */ 2432b032f27cSSam Leffler } 2433b032f27cSSam Leffler 2434b032f27cSSam Leffler /* 2435b032f27cSSam Leffler * Hold a reference on the node so it doesn't go away until after 2436b032f27cSSam Leffler * the xmit is complete all the way in the driver. On error we 2437b032f27cSSam Leffler * will remove our reference. 2438b032f27cSSam Leffler */ 2439b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 2440b032f27cSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2441b032f27cSSam Leffler __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), 2442b032f27cSSam Leffler ieee80211_node_refcnt(bss)+1); 2443b032f27cSSam Leffler ieee80211_ref_node(bss); 2444b032f27cSSam Leffler 2445b032f27cSSam Leffler m = ieee80211_alloc_proberesp(bss, legacy); 2446b032f27cSSam Leffler if (m == NULL) { 2447b032f27cSSam Leffler ieee80211_free_node(bss); 2448b032f27cSSam Leffler return ENOMEM; 2449b032f27cSSam Leffler } 2450b032f27cSSam Leffler 2451b032f27cSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 2452b032f27cSSam Leffler KASSERT(m != NULL, ("no room for header")); 2453b032f27cSSam Leffler 2454b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 24559e80b1dfSSam Leffler ieee80211_send_setup(bss, m, 2456b032f27cSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, 24578ac160cdSSam Leffler IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); 2458b032f27cSSam Leffler /* XXX power management? */ 2459c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 2460b032f27cSSam Leffler 2461b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 2462b032f27cSSam Leffler 2463b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 2464b032f27cSSam Leffler "send probe resp on channel %u to %s%s\n", 2465b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), 2466b032f27cSSam Leffler legacy ? " <legacy>" : ""); 2467b032f27cSSam Leffler IEEE80211_NODE_STAT(bss, tx_mgmt); 2468b032f27cSSam Leffler 2469b032f27cSSam Leffler return ic->ic_raw_xmit(bss, m, NULL); 2470b032f27cSSam Leffler } 2471b032f27cSSam Leffler 2472b032f27cSSam Leffler /* 2473b032f27cSSam Leffler * Allocate and build a RTS (Request To Send) control frame. 2474b032f27cSSam Leffler */ 2475b032f27cSSam Leffler struct mbuf * 2476b032f27cSSam Leffler ieee80211_alloc_rts(struct ieee80211com *ic, 2477b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], 2478b032f27cSSam Leffler const uint8_t ta[IEEE80211_ADDR_LEN], 2479b032f27cSSam Leffler uint16_t dur) 2480b032f27cSSam Leffler { 2481b032f27cSSam Leffler struct ieee80211_frame_rts *rts; 2482b032f27cSSam Leffler struct mbuf *m; 2483b032f27cSSam Leffler 2484b032f27cSSam Leffler /* XXX honor ic_headroom */ 2485b032f27cSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 2486b032f27cSSam Leffler if (m != NULL) { 2487b032f27cSSam Leffler rts = mtod(m, struct ieee80211_frame_rts *); 2488b032f27cSSam Leffler rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2489b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; 2490b032f27cSSam Leffler rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2491b032f27cSSam Leffler *(u_int16_t *)rts->i_dur = htole16(dur); 2492b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ra, ra); 2493b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ta, ta); 2494b032f27cSSam Leffler 2495b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); 2496b032f27cSSam Leffler } 2497b032f27cSSam Leffler return m; 2498b032f27cSSam Leffler } 2499b032f27cSSam Leffler 2500b032f27cSSam Leffler /* 2501b032f27cSSam Leffler * Allocate and build a CTS (Clear To Send) control frame. 2502b032f27cSSam Leffler */ 2503b032f27cSSam Leffler struct mbuf * 2504b032f27cSSam Leffler ieee80211_alloc_cts(struct ieee80211com *ic, 2505b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) 2506b032f27cSSam Leffler { 2507b032f27cSSam Leffler struct ieee80211_frame_cts *cts; 2508b032f27cSSam Leffler struct mbuf *m; 2509b032f27cSSam Leffler 2510b032f27cSSam Leffler /* XXX honor ic_headroom */ 2511b032f27cSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 2512b032f27cSSam Leffler if (m != NULL) { 2513b032f27cSSam Leffler cts = mtod(m, struct ieee80211_frame_cts *); 2514b032f27cSSam Leffler cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2515b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; 2516b032f27cSSam Leffler cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2517b032f27cSSam Leffler *(u_int16_t *)cts->i_dur = htole16(dur); 2518b032f27cSSam Leffler IEEE80211_ADDR_COPY(cts->i_ra, ra); 2519b032f27cSSam Leffler 2520b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); 2521b032f27cSSam Leffler } 2522b032f27cSSam Leffler return m; 2523b032f27cSSam Leffler } 2524b032f27cSSam Leffler 252568e8e04eSSam Leffler static void 252668e8e04eSSam Leffler ieee80211_tx_mgt_timeout(void *arg) 252768e8e04eSSam Leffler { 252868e8e04eSSam Leffler struct ieee80211_node *ni = arg; 2529b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 253068e8e04eSSam Leffler 2531b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_INIT && 2532b032f27cSSam Leffler (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { 253368e8e04eSSam Leffler /* 253468e8e04eSSam Leffler * NB: it's safe to specify a timeout as the reason here; 253568e8e04eSSam Leffler * it'll only be used in the right state. 253668e8e04eSSam Leffler */ 2537b032f27cSSam Leffler ieee80211_new_state(vap, IEEE80211_S_SCAN, 253868e8e04eSSam Leffler IEEE80211_SCAN_FAIL_TIMEOUT); 253968e8e04eSSam Leffler } 254068e8e04eSSam Leffler } 254168e8e04eSSam Leffler 254268e8e04eSSam Leffler static void 254368e8e04eSSam Leffler ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) 254468e8e04eSSam Leffler { 2545b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 254668e8e04eSSam Leffler enum ieee80211_state ostate = (enum ieee80211_state) arg; 254768e8e04eSSam Leffler 254868e8e04eSSam Leffler /* 254968e8e04eSSam Leffler * Frame transmit completed; arrange timer callback. If 255068e8e04eSSam Leffler * transmit was successfuly we wait for response. Otherwise 255168e8e04eSSam Leffler * we arrange an immediate callback instead of doing the 255268e8e04eSSam Leffler * callback directly since we don't know what state the driver 255368e8e04eSSam Leffler * is in (e.g. what locks it is holding). This work should 255468e8e04eSSam Leffler * not be too time-critical and not happen too often so the 255568e8e04eSSam Leffler * added overhead is acceptable. 255668e8e04eSSam Leffler * 255768e8e04eSSam Leffler * XXX what happens if !acked but response shows up before callback? 255868e8e04eSSam Leffler */ 2559b032f27cSSam Leffler if (vap->iv_state == ostate) 2560b032f27cSSam Leffler callout_reset(&vap->iv_mgtsend, 256168e8e04eSSam Leffler status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, 256268e8e04eSSam Leffler ieee80211_tx_mgt_timeout, ni); 256368e8e04eSSam Leffler } 256468e8e04eSSam Leffler 2565b032f27cSSam Leffler static void 2566b032f27cSSam Leffler ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, 2567b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni) 25688a1b9b6aSSam Leffler { 2569b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2570b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 2571b032f27cSSam Leffler struct ieee80211_rateset *rs = &ni->ni_rates; 257268e8e04eSSam Leffler uint16_t capinfo; 25738a1b9b6aSSam Leffler 25748a1b9b6aSSam Leffler /* 25758a1b9b6aSSam Leffler * beacon frame format 25768a1b9b6aSSam Leffler * [8] time stamp 25778a1b9b6aSSam Leffler * [2] beacon interval 25788a1b9b6aSSam Leffler * [2] cabability information 25798a1b9b6aSSam Leffler * [tlv] ssid 25808a1b9b6aSSam Leffler * [tlv] supported rates 25818a1b9b6aSSam Leffler * [3] parameter set (DS) 2582b032f27cSSam Leffler * [8] CF parameter set (optional) 25838a1b9b6aSSam Leffler * [tlv] parameter set (IBSS/TIM) 2584b032f27cSSam Leffler * [tlv] country (optional) 2585b032f27cSSam Leffler * [3] power control (optional) 2586b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 25878a1b9b6aSSam Leffler * [tlv] extended rate phy (ERP) 25888a1b9b6aSSam Leffler * [tlv] extended supported rates 2589688fe74dSSam Leffler * [tlv] RSN parameters 259068e8e04eSSam Leffler * [tlv] HT capabilities 259168e8e04eSSam Leffler * [tlv] HT information 2592b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 2593b032f27cSSam Leffler * [tlv] WPA parameters 2594b032f27cSSam Leffler * [tlv] WME parameters 259568e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 259668e8e04eSSam Leffler * [tlv] Vendor OUI HT information (optional) 25974207227cSSam Leffler * [tlv] Atheros capabilities (optional) 259810ad9a77SSam Leffler * [tlv] TDMA parameters (optional) 259959aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 260059aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2601b032f27cSSam Leffler * [tlv] application data (optional) 26028a1b9b6aSSam Leffler */ 26038a1b9b6aSSam Leffler 26041b6167d2SSam Leffler memset(bo, 0, sizeof(*bo)); 26051b6167d2SSam Leffler 26068a1b9b6aSSam Leffler memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ 26078a1b9b6aSSam Leffler frm += 8; 260868e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_intval); 26098a1b9b6aSSam Leffler frm += 2; 261059aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 261168e8e04eSSam Leffler bo->bo_caps = (uint16_t *)frm; 261268e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 26138a1b9b6aSSam Leffler frm += 2; 26148a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 2615b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { 26168a1b9b6aSSam Leffler *frm++ = ni->ni_esslen; 26178a1b9b6aSSam Leffler memcpy(frm, ni->ni_essid, ni->ni_esslen); 26188a1b9b6aSSam Leffler frm += ni->ni_esslen; 26198a1b9b6aSSam Leffler } else 26208a1b9b6aSSam Leffler *frm++ = 0; 26218a1b9b6aSSam Leffler frm = ieee80211_add_rates(frm, rs); 2622b032f27cSSam Leffler if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { 26238a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 26248a1b9b6aSSam Leffler *frm++ = 1; 2625b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); 2626b032f27cSSam Leffler } 2627b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_PCF) { 2628b032f27cSSam Leffler bo->bo_cfp = frm; 2629b032f27cSSam Leffler frm = ieee80211_add_cfparms(frm, ic); 26308a1b9b6aSSam Leffler } 26318a1b9b6aSSam Leffler bo->bo_tim = frm; 2632b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 26338a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 26348a1b9b6aSSam Leffler *frm++ = 2; 26358a1b9b6aSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 26368a1b9b6aSSam Leffler bo->bo_tim_len = 0; 263759aa14a9SRui Paulo } else if (vap->iv_opmode == IEEE80211_M_HOSTAP || 263859aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { 263959aa14a9SRui Paulo /* TIM IE is the same for Mesh and Hostap */ 26408a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; 26418a1b9b6aSSam Leffler 26428a1b9b6aSSam Leffler tie->tim_ie = IEEE80211_ELEMID_TIM; 26438a1b9b6aSSam Leffler tie->tim_len = 4; /* length */ 26448a1b9b6aSSam Leffler tie->tim_count = 0; /* DTIM count */ 2645b032f27cSSam Leffler tie->tim_period = vap->iv_dtim_period; /* DTIM period */ 26468a1b9b6aSSam Leffler tie->tim_bitctl = 0; /* bitmap control */ 26478a1b9b6aSSam Leffler tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 26488a1b9b6aSSam Leffler frm += sizeof(struct ieee80211_tim_ie); 26498a1b9b6aSSam Leffler bo->bo_tim_len = 1; 26508a1b9b6aSSam Leffler } 2651b105a069SSam Leffler bo->bo_tim_trailer = frm; 2652b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 2653b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2654b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 2655b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 2656b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 2657b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 2658b032f27cSSam Leffler bo->bo_csa = frm; 2659b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2660b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 2661b032f27cSSam Leffler } else 2662b032f27cSSam Leffler bo->bo_csa = frm; 266332b0e64bSAdrian Chadd 266432b0e64bSAdrian Chadd if (vap->iv_flags & IEEE80211_F_DOTH) { 266532b0e64bSAdrian Chadd bo->bo_quiet = frm; 266632b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 266732b0e64bSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 266832b0e64bSAdrian Chadd if (vap->iv_quiet) 266932b0e64bSAdrian Chadd frm = ieee80211_add_quiet(frm,vap); 267032b0e64bSAdrian Chadd } 267132b0e64bSAdrian Chadd } else 267232b0e64bSAdrian Chadd bo->bo_quiet = frm; 267332b0e64bSAdrian Chadd 2674b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { 26750912bac9SSam Leffler bo->bo_erp = frm; 26768a1b9b6aSSam Leffler frm = ieee80211_add_erp(frm, ic); 26771b6167d2SSam Leffler } 267868e8e04eSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2679688fe74dSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2680688fe74dSSam Leffler if (vap->iv_rsn_ie != NULL) 2681688fe74dSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2682688fe74dSSam Leffler /* XXX else complain */ 2683688fe74dSSam Leffler } 2684b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { 268568e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 268668e8e04eSSam Leffler bo->bo_htinfo = frm; 268768e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 26881b6167d2SSam Leffler } 2689b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2690b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2691b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2692b032f27cSSam Leffler /* XXX else complain */ 2693b032f27cSSam Leffler } 2694b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 26951b6167d2SSam Leffler bo->bo_wme = frm; 26961b6167d2SSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 26971b6167d2SSam Leffler } 2698b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && 26992bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) { 270068e8e04eSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 270168e8e04eSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 27020912bac9SSam Leffler } 27034207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 27044207227cSSam Leffler if (vap->iv_flags & IEEE80211_F_ATHEROS) { 27054207227cSSam Leffler bo->bo_ath = frm; 27064207227cSSam Leffler frm = ieee80211_add_athcaps(frm, ni); 27074207227cSSam Leffler } 27084207227cSSam Leffler #endif 270910ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 271010ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 271110ad9a77SSam Leffler bo->bo_tdma = frm; 271210ad9a77SSam Leffler frm = ieee80211_add_tdma(frm, vap); 271310ad9a77SSam Leffler } 271410ad9a77SSam Leffler #endif 2715b032f27cSSam Leffler if (vap->iv_appie_beacon != NULL) { 2716b032f27cSSam Leffler bo->bo_appie = frm; 2717b032f27cSSam Leffler bo->bo_appie_len = vap->iv_appie_beacon->ie_len; 2718b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_beacon); 2719b032f27cSSam Leffler } 272059aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 272159aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 272259aa14a9SRui Paulo frm = ieee80211_add_meshid(frm, vap); 2723d093681cSRui Paulo bo->bo_meshconf = frm; 272459aa14a9SRui Paulo frm = ieee80211_add_meshconf(frm, vap); 272559aa14a9SRui Paulo } 272659aa14a9SRui Paulo #endif 2727b105a069SSam Leffler bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; 2728b032f27cSSam Leffler bo->bo_csa_trailer_len = frm - bo->bo_csa; 272968e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2730b032f27cSSam Leffler } 2731b032f27cSSam Leffler 2732b032f27cSSam Leffler /* 2733b032f27cSSam Leffler * Allocate a beacon frame and fillin the appropriate bits. 2734b032f27cSSam Leffler */ 2735b032f27cSSam Leffler struct mbuf * 2736b032f27cSSam Leffler ieee80211_beacon_alloc(struct ieee80211_node *ni, 2737b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo) 2738b032f27cSSam Leffler { 2739b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2740b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2741b032f27cSSam Leffler struct ifnet *ifp = vap->iv_ifp; 2742b032f27cSSam Leffler struct ieee80211_frame *wh; 2743b032f27cSSam Leffler struct mbuf *m; 2744b032f27cSSam Leffler int pktlen; 2745b032f27cSSam Leffler uint8_t *frm; 2746b032f27cSSam Leffler 2747b032f27cSSam Leffler /* 2748b032f27cSSam Leffler * beacon frame format 2749b032f27cSSam Leffler * [8] time stamp 2750b032f27cSSam Leffler * [2] beacon interval 2751b032f27cSSam Leffler * [2] cabability information 2752b032f27cSSam Leffler * [tlv] ssid 2753b032f27cSSam Leffler * [tlv] supported rates 2754b032f27cSSam Leffler * [3] parameter set (DS) 2755b032f27cSSam Leffler * [8] CF parameter set (optional) 2756b032f27cSSam Leffler * [tlv] parameter set (IBSS/TIM) 2757b032f27cSSam Leffler * [tlv] country (optional) 2758b032f27cSSam Leffler * [3] power control (optional) 2759b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 2760b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 2761b032f27cSSam Leffler * [tlv] extended supported rates 2762b032f27cSSam Leffler * [tlv] RSN parameters 2763b032f27cSSam Leffler * [tlv] HT capabilities 2764b032f27cSSam Leffler * [tlv] HT information 2765b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 2766b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 2767b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 2768b032f27cSSam Leffler * [tlv] WPA parameters 2769b032f27cSSam Leffler * [tlv] WME parameters 277010ad9a77SSam Leffler * [tlv] TDMA parameters (optional) 277159aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 277259aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2773b032f27cSSam Leffler * [tlv] application data (optional) 2774b032f27cSSam Leffler * NB: we allocate the max space required for the TIM bitmap. 2775b032f27cSSam Leffler * XXX how big is this? 2776b032f27cSSam Leffler */ 2777b032f27cSSam Leffler pktlen = 8 /* time stamp */ 2778b032f27cSSam Leffler + sizeof(uint16_t) /* beacon interval */ 2779b032f27cSSam Leffler + sizeof(uint16_t) /* capabilities */ 2780b032f27cSSam Leffler + 2 + ni->ni_esslen /* ssid */ 2781b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE /* supported rates */ 2782b032f27cSSam Leffler + 2 + 1 /* DS parameters */ 2783b032f27cSSam Leffler + 2 + 6 /* CF parameters */ 2784b032f27cSSam Leffler + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ 2785b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE /* country */ 2786b032f27cSSam Leffler + 2 + 1 /* power control */ 2787b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) /* CSA */ 278832b0e64bSAdrian Chadd + sizeof(struct ieee80211_quiet_ie) /* Quiet */ 2789b032f27cSSam Leffler + 2 + 1 /* ERP */ 2790b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2791b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2792b032f27cSSam Leffler 2*sizeof(struct ieee80211_ie_wpa) : 0) 2793b032f27cSSam Leffler /* XXX conditional? */ 2794b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ 2795b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ 2796b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ 2797b032f27cSSam Leffler sizeof(struct ieee80211_wme_param) : 0) 27984207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 27994207227cSSam Leffler + sizeof(struct ieee80211_ath_ie) /* ATH */ 28004207227cSSam Leffler #endif 280110ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 280210ad9a77SSam Leffler + (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */ 280310ad9a77SSam Leffler sizeof(struct ieee80211_tdma_param) : 0) 280410ad9a77SSam Leffler #endif 280559aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 280659aa14a9SRui Paulo + 2 + ni->ni_meshidlen 280759aa14a9SRui Paulo + sizeof(struct ieee80211_meshconf_ie) 280859aa14a9SRui Paulo #endif 2809b032f27cSSam Leffler + IEEE80211_MAX_APPIE 2810b032f27cSSam Leffler ; 2811b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 2812b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); 2813b032f27cSSam Leffler if (m == NULL) { 2814b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 2815b032f27cSSam Leffler "%s: cannot get buf; size %u\n", __func__, pktlen); 2816b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 2817b032f27cSSam Leffler return NULL; 2818b032f27cSSam Leffler } 2819b032f27cSSam Leffler ieee80211_beacon_construct(m, frm, bo, ni); 28208a1b9b6aSSam Leffler 28218a1b9b6aSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 28228a1b9b6aSSam Leffler KASSERT(m != NULL, ("no space for 802.11 header?")); 28238a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 28248a1b9b6aSSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 28258a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_BEACON; 28268a1b9b6aSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 282768e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 28288a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 2829b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 28308a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 283168e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 0; 28328a1b9b6aSSam Leffler 28338a1b9b6aSSam Leffler return m; 28348a1b9b6aSSam Leffler } 28358a1b9b6aSSam Leffler 28368a1b9b6aSSam Leffler /* 28378a1b9b6aSSam Leffler * Update the dynamic parts of a beacon frame based on the current state. 28388a1b9b6aSSam Leffler */ 28398a1b9b6aSSam Leffler int 2840b105a069SSam Leffler ieee80211_beacon_update(struct ieee80211_node *ni, 28418a1b9b6aSSam Leffler struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) 28428a1b9b6aSSam Leffler { 2843b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2844b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 28458a1b9b6aSSam Leffler int len_changed = 0; 284668e8e04eSSam Leffler uint16_t capinfo; 2847fa3324c9SAdrian Chadd struct ieee80211_frame *wh; 2848fa3324c9SAdrian Chadd ieee80211_seq seqno; 28498a1b9b6aSSam Leffler 2850b032f27cSSam Leffler IEEE80211_LOCK(ic); 2851b032f27cSSam Leffler /* 2852b032f27cSSam Leffler * Handle 11h channel change when we've reached the count. 2853b032f27cSSam Leffler * We must recalculate the beacon frame contents to account 2854b032f27cSSam Leffler * for the new channel. Note we do this only for the first 2855b032f27cSSam Leffler * vap that reaches this point; subsequent vaps just update 2856b032f27cSSam Leffler * their beacon state to reflect the recalculated channel. 2857b032f27cSSam Leffler */ 2858b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && 2859b032f27cSSam Leffler vap->iv_csa_count == ic->ic_csa_count) { 2860b032f27cSSam Leffler vap->iv_csa_count = 0; 2861b032f27cSSam Leffler /* 2862b032f27cSSam Leffler * Effect channel change before reconstructing the beacon 2863b032f27cSSam Leffler * frame contents as many places reference ni_chan. 2864b032f27cSSam Leffler */ 2865b032f27cSSam Leffler if (ic->ic_csa_newchan != NULL) 2866b032f27cSSam Leffler ieee80211_csa_completeswitch(ic); 2867b032f27cSSam Leffler /* 2868b032f27cSSam Leffler * NB: ieee80211_beacon_construct clears all pending 2869b032f27cSSam Leffler * updates in bo_flags so we don't need to explicitly 2870b032f27cSSam Leffler * clear IEEE80211_BEACON_CSA. 2871b032f27cSSam Leffler */ 2872b032f27cSSam Leffler ieee80211_beacon_construct(m, 2873b032f27cSSam Leffler mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni); 2874b032f27cSSam Leffler 2875b032f27cSSam Leffler /* XXX do WME aggressive mode processing? */ 2876b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 2877b032f27cSSam Leffler return 1; /* just assume length changed */ 2878b032f27cSSam Leffler } 2879b032f27cSSam Leffler 2880fa3324c9SAdrian Chadd wh = mtod(m, struct ieee80211_frame *); 2881fa3324c9SAdrian Chadd seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 2882fa3324c9SAdrian Chadd *(uint16_t *)&wh->i_seq[0] = 2883fa3324c9SAdrian Chadd htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 2884fa3324c9SAdrian Chadd M_SEQNO_SET(m, seqno); 2885fa3324c9SAdrian Chadd 28868a1b9b6aSSam Leffler /* XXX faster to recalculate entirely or just changes? */ 288759aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 28888a1b9b6aSSam Leffler *bo->bo_caps = htole16(capinfo); 28898a1b9b6aSSam Leffler 2890b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 28918a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 28928a1b9b6aSSam Leffler 28938a1b9b6aSSam Leffler /* 28948a1b9b6aSSam Leffler * Check for agressive mode change. When there is 28958a1b9b6aSSam Leffler * significant high priority traffic in the BSS 28968a1b9b6aSSam Leffler * throttle back BE traffic by using conservative 28978a1b9b6aSSam Leffler * parameters. Otherwise BE uses agressive params 28988a1b9b6aSSam Leffler * to optimize performance of legacy/non-QoS traffic. 28998a1b9b6aSSam Leffler */ 29008a1b9b6aSSam Leffler if (wme->wme_flags & WME_F_AGGRMODE) { 29018a1b9b6aSSam Leffler if (wme->wme_hipri_traffic > 29028a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 2903b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 29048a1b9b6aSSam Leffler "%s: traffic %u, disable aggressive mode\n", 29058a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 29068a1b9b6aSSam Leffler wme->wme_flags &= ~WME_F_AGGRMODE; 2907b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 29088a1b9b6aSSam Leffler wme->wme_hipri_traffic = 29098a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 29108a1b9b6aSSam Leffler } else 29118a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 29128a1b9b6aSSam Leffler } else { 29138a1b9b6aSSam Leffler if (wme->wme_hipri_traffic <= 29148a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 2915b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 29168a1b9b6aSSam Leffler "%s: traffic %u, enable aggressive mode\n", 29178a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 29188a1b9b6aSSam Leffler wme->wme_flags |= WME_F_AGGRMODE; 2919b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 29208a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 29218a1b9b6aSSam Leffler } else 29228a1b9b6aSSam Leffler wme->wme_hipri_traffic = 29238a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 29248a1b9b6aSSam Leffler } 2925b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { 29268a1b9b6aSSam Leffler (void) ieee80211_add_wme_param(bo->bo_wme, wme); 2927b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_WME); 29288a1b9b6aSSam Leffler } 29298a1b9b6aSSam Leffler } 29308a1b9b6aSSam Leffler 2931b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { 2932b032f27cSSam Leffler ieee80211_ht_update_beacon(vap, bo); 2933b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); 293468e8e04eSSam Leffler } 293510ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 293610ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 293710ad9a77SSam Leffler /* 293810ad9a77SSam Leffler * NB: the beacon is potentially updated every TBTT. 293910ad9a77SSam Leffler */ 294010ad9a77SSam Leffler ieee80211_tdma_update_beacon(vap, bo); 294110ad9a77SSam Leffler } 294210ad9a77SSam Leffler #endif 2943d093681cSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 2944d093681cSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 2945d093681cSRui Paulo ieee80211_mesh_update_beacon(vap, bo); 2946d093681cSRui Paulo #endif 2947d093681cSRui Paulo 294859aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP || 294959aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/ 29508a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = 29518a1b9b6aSSam Leffler (struct ieee80211_tim_ie *) bo->bo_tim; 2952b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { 29538a1b9b6aSSam Leffler u_int timlen, timoff, i; 29548a1b9b6aSSam Leffler /* 29558a1b9b6aSSam Leffler * ATIM/DTIM needs updating. If it fits in the 29568a1b9b6aSSam Leffler * current space allocated then just copy in the 29578a1b9b6aSSam Leffler * new bits. Otherwise we need to move any trailing 29588a1b9b6aSSam Leffler * data to make room. Note that we know there is 29598a1b9b6aSSam Leffler * contiguous space because ieee80211_beacon_allocate 29608a1b9b6aSSam Leffler * insures there is space in the mbuf to write a 2961b032f27cSSam Leffler * maximal-size virtual bitmap (based on iv_max_aid). 29628a1b9b6aSSam Leffler */ 29638a1b9b6aSSam Leffler /* 29648a1b9b6aSSam Leffler * Calculate the bitmap size and offset, copy any 29658a1b9b6aSSam Leffler * trailer out of the way, and then copy in the 29668a1b9b6aSSam Leffler * new bitmap and update the information element. 29678a1b9b6aSSam Leffler * Note that the tim bitmap must contain at least 29688a1b9b6aSSam Leffler * one byte and any offset must be even. 29698a1b9b6aSSam Leffler */ 2970b032f27cSSam Leffler if (vap->iv_ps_pending != 0) { 29718a1b9b6aSSam Leffler timoff = 128; /* impossibly large */ 2972b032f27cSSam Leffler for (i = 0; i < vap->iv_tim_len; i++) 2973b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) { 29748a1b9b6aSSam Leffler timoff = i &~ 1; 29758a1b9b6aSSam Leffler break; 29768a1b9b6aSSam Leffler } 29778a1b9b6aSSam Leffler KASSERT(timoff != 128, ("tim bitmap empty!")); 2978b032f27cSSam Leffler for (i = vap->iv_tim_len-1; i >= timoff; i--) 2979b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) 29808a1b9b6aSSam Leffler break; 29818a1b9b6aSSam Leffler timlen = 1 + (i - timoff); 29828a1b9b6aSSam Leffler } else { 29838a1b9b6aSSam Leffler timoff = 0; 29848a1b9b6aSSam Leffler timlen = 1; 29858a1b9b6aSSam Leffler } 29868a1b9b6aSSam Leffler if (timlen != bo->bo_tim_len) { 29878a1b9b6aSSam Leffler /* copy up/down trailer */ 29880912bac9SSam Leffler int adjust = tie->tim_bitmap+timlen 2989b105a069SSam Leffler - bo->bo_tim_trailer; 2990b105a069SSam Leffler ovbcopy(bo->bo_tim_trailer, 2991b105a069SSam Leffler bo->bo_tim_trailer+adjust, 2992b105a069SSam Leffler bo->bo_tim_trailer_len); 2993b105a069SSam Leffler bo->bo_tim_trailer += adjust; 29940912bac9SSam Leffler bo->bo_erp += adjust; 299568e8e04eSSam Leffler bo->bo_htinfo += adjust; 299602e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG 29974207227cSSam Leffler bo->bo_ath += adjust; 29984207227cSSam Leffler #endif 299902e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA 300092e870edSSam Leffler bo->bo_tdma += adjust; 300192e870edSSam Leffler #endif 300202e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH 3003d093681cSRui Paulo bo->bo_meshconf += adjust; 3004d093681cSRui Paulo #endif 3005b032f27cSSam Leffler bo->bo_appie += adjust; 3006b032f27cSSam Leffler bo->bo_wme += adjust; 3007b032f27cSSam Leffler bo->bo_csa += adjust; 300832b0e64bSAdrian Chadd bo->bo_quiet += adjust; 30098a1b9b6aSSam Leffler bo->bo_tim_len = timlen; 30108a1b9b6aSSam Leffler 30118a1b9b6aSSam Leffler /* update information element */ 30128a1b9b6aSSam Leffler tie->tim_len = 3 + timlen; 30138a1b9b6aSSam Leffler tie->tim_bitctl = timoff; 30148a1b9b6aSSam Leffler len_changed = 1; 30158a1b9b6aSSam Leffler } 3016b032f27cSSam Leffler memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, 30178a1b9b6aSSam Leffler bo->bo_tim_len); 30188a1b9b6aSSam Leffler 3019b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); 30208a1b9b6aSSam Leffler 3021b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 30228a1b9b6aSSam Leffler "%s: TIM updated, pending %u, off %u, len %u\n", 3023b032f27cSSam Leffler __func__, vap->iv_ps_pending, timoff, timlen); 30248a1b9b6aSSam Leffler } 30258a1b9b6aSSam Leffler /* count down DTIM period */ 30268a1b9b6aSSam Leffler if (tie->tim_count == 0) 30278a1b9b6aSSam Leffler tie->tim_count = tie->tim_period - 1; 30288a1b9b6aSSam Leffler else 30298a1b9b6aSSam Leffler tie->tim_count--; 30308a1b9b6aSSam Leffler /* update state for buffered multicast frames on DTIM */ 3031a196b35fSSam Leffler if (mcast && tie->tim_count == 0) 30328a1b9b6aSSam Leffler tie->tim_bitctl |= 1; 30338a1b9b6aSSam Leffler else 30348a1b9b6aSSam Leffler tie->tim_bitctl &= ~1; 3035b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { 3036b032f27cSSam Leffler struct ieee80211_csa_ie *csa = 3037b032f27cSSam Leffler (struct ieee80211_csa_ie *) bo->bo_csa; 3038b032f27cSSam Leffler 3039b032f27cSSam Leffler /* 3040b032f27cSSam Leffler * Insert or update CSA ie. If we're just starting 3041b032f27cSSam Leffler * to count down to the channel switch then we need 3042b032f27cSSam Leffler * to insert the CSA ie. Otherwise we just need to 3043b032f27cSSam Leffler * drop the count. The actual change happens above 3044b032f27cSSam Leffler * when the vap's count reaches the target count. 3045b032f27cSSam Leffler */ 3046b032f27cSSam Leffler if (vap->iv_csa_count == 0) { 3047b032f27cSSam Leffler memmove(&csa[1], csa, bo->bo_csa_trailer_len); 3048b032f27cSSam Leffler bo->bo_erp += sizeof(*csa); 3049d01b3c26SSam Leffler bo->bo_htinfo += sizeof(*csa); 3050b032f27cSSam Leffler bo->bo_wme += sizeof(*csa); 305102e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG 30524207227cSSam Leffler bo->bo_ath += sizeof(*csa); 30534207227cSSam Leffler #endif 305402e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA 305592e870edSSam Leffler bo->bo_tdma += sizeof(*csa); 305692e870edSSam Leffler #endif 305702e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH 3058d093681cSRui Paulo bo->bo_meshconf += sizeof(*csa); 3059d093681cSRui Paulo #endif 3060b032f27cSSam Leffler bo->bo_appie += sizeof(*csa); 3061b032f27cSSam Leffler bo->bo_csa_trailer_len += sizeof(*csa); 306232b0e64bSAdrian Chadd bo->bo_quiet += sizeof(*csa); 3063b032f27cSSam Leffler bo->bo_tim_trailer_len += sizeof(*csa); 3064b032f27cSSam Leffler m->m_len += sizeof(*csa); 3065b032f27cSSam Leffler m->m_pkthdr.len += sizeof(*csa); 3066b032f27cSSam Leffler 3067b032f27cSSam Leffler ieee80211_add_csa(bo->bo_csa, vap); 3068b032f27cSSam Leffler } else 3069b032f27cSSam Leffler csa->csa_count--; 3070b032f27cSSam Leffler vap->iv_csa_count++; 3071b032f27cSSam Leffler /* NB: don't clear IEEE80211_BEACON_CSA */ 3072b032f27cSSam Leffler } 307332b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 307432b0e64bSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS) ){ 307532b0e64bSAdrian Chadd if (vap->iv_quiet) 307632b0e64bSAdrian Chadd ieee80211_add_quiet(bo->bo_quiet, vap); 307732b0e64bSAdrian Chadd } 3078b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { 30790912bac9SSam Leffler /* 30800912bac9SSam Leffler * ERP element needs updating. 30810912bac9SSam Leffler */ 30820912bac9SSam Leffler (void) ieee80211_add_erp(bo->bo_erp, ic); 3083b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); 30840912bac9SSam Leffler } 30854207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 30864207227cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ATH)) { 30874207227cSSam Leffler ieee80211_add_athcaps(bo->bo_ath, ni); 30884207227cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ATH); 30894207227cSSam Leffler } 30904207227cSSam Leffler #endif 30918a1b9b6aSSam Leffler } 3092b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { 3093b032f27cSSam Leffler const struct ieee80211_appie *aie = vap->iv_appie_beacon; 3094b032f27cSSam Leffler int aielen; 3095b032f27cSSam Leffler uint8_t *frm; 3096b032f27cSSam Leffler 3097b032f27cSSam Leffler aielen = 0; 3098b032f27cSSam Leffler if (aie != NULL) 3099b032f27cSSam Leffler aielen += aie->ie_len; 3100b032f27cSSam Leffler if (aielen != bo->bo_appie_len) { 3101b032f27cSSam Leffler /* copy up/down trailer */ 3102b032f27cSSam Leffler int adjust = aielen - bo->bo_appie_len; 3103b032f27cSSam Leffler ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, 3104b032f27cSSam Leffler bo->bo_tim_trailer_len); 3105b032f27cSSam Leffler bo->bo_tim_trailer += adjust; 3106b032f27cSSam Leffler bo->bo_appie += adjust; 3107b032f27cSSam Leffler bo->bo_appie_len = aielen; 3108b032f27cSSam Leffler 3109b032f27cSSam Leffler len_changed = 1; 3110b032f27cSSam Leffler } 3111b032f27cSSam Leffler frm = bo->bo_appie; 3112b032f27cSSam Leffler if (aie != NULL) 3113b032f27cSSam Leffler frm = add_appie(frm, aie); 3114b032f27cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); 3115b032f27cSSam Leffler } 3116b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 31178a1b9b6aSSam Leffler 31188a1b9b6aSSam Leffler return len_changed; 31198a1b9b6aSSam Leffler } 3120