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 ifp->if_drv_flags |= IFF_DRV_OACTIVE; 161b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 162b032f27cSSam Leffler return; 163b032f27cSSam Leffler } 164b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 165b032f27cSSam Leffler } 166b032f27cSSam Leffler for (;;) { 167b032f27cSSam Leffler IFQ_DEQUEUE(&ifp->if_snd, m); 168b032f27cSSam Leffler if (m == NULL) 169b032f27cSSam Leffler break; 170b032f27cSSam Leffler /* 171b032f27cSSam Leffler * Sanitize mbuf flags for net80211 use. We cannot 172927ef5ffSSam Leffler * clear M_PWR_SAV or M_MORE_DATA because these may 173927ef5ffSSam Leffler * be set for frames that are re-submitted from the 174927ef5ffSSam Leffler * power save queue. 175b032f27cSSam Leffler * 176b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 177b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 178b032f27cSSam Leffler */ 179927ef5ffSSam Leffler m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); 180b032f27cSSam Leffler /* 181b032f27cSSam Leffler * Cancel any background scan. 182b032f27cSSam Leffler */ 183b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_SCAN) 184b032f27cSSam Leffler ieee80211_cancel_anyscan(vap); 185b032f27cSSam Leffler /* 186b032f27cSSam Leffler * Find the node for the destination so we can do 187b032f27cSSam Leffler * things like power save and fast frames aggregation. 188b032f27cSSam Leffler * 189b032f27cSSam Leffler * NB: past this point various code assumes the first 190b032f27cSSam Leffler * mbuf has the 802.3 header present (and contiguous). 191b032f27cSSam Leffler */ 192b032f27cSSam Leffler ni = NULL; 193b032f27cSSam Leffler if (m->m_len < sizeof(struct ether_header) && 194b032f27cSSam Leffler (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 195b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 196b032f27cSSam Leffler "discard frame, %s\n", "m_pullup failed"); 197b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX */ 198b032f27cSSam Leffler ifp->if_oerrors++; 199b032f27cSSam Leffler continue; 200b032f27cSSam Leffler } 201b032f27cSSam Leffler eh = mtod(m, struct ether_header *); 202b032f27cSSam Leffler if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 203b032f27cSSam Leffler if (IS_DWDS(vap)) { 204b032f27cSSam Leffler /* 205b032f27cSSam Leffler * Only unicast frames from the above go out 206b032f27cSSam Leffler * DWDS vaps; multicast frames are handled by 207b032f27cSSam Leffler * dispatching the frame as it comes through 208b032f27cSSam Leffler * the AP vap (see below). 209b032f27cSSam Leffler */ 210b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS, 211b032f27cSSam Leffler eh->ether_dhost, "mcast", "%s", "on DWDS"); 212b032f27cSSam Leffler vap->iv_stats.is_dwds_mcast++; 213b032f27cSSam Leffler m_freem(m); 214b032f27cSSam Leffler continue; 215b032f27cSSam Leffler } 216b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 217b032f27cSSam Leffler /* 218b032f27cSSam Leffler * Spam DWDS vap's w/ multicast traffic. 219b032f27cSSam Leffler */ 220b032f27cSSam Leffler /* XXX only if dwds in use? */ 221b032f27cSSam Leffler ieee80211_dwds_mcast(vap, m); 222b032f27cSSam Leffler } 223b032f27cSSam Leffler } 22459aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 22559aa14a9SRui Paulo if (vap->iv_opmode != IEEE80211_M_MBSS) { 22659aa14a9SRui Paulo #endif 227b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, eh->ether_dhost); 228b032f27cSSam Leffler if (ni == NULL) { 229b032f27cSSam Leffler /* NB: ieee80211_find_txnode does stat+msg */ 230b032f27cSSam Leffler ifp->if_oerrors++; 231b032f27cSSam Leffler m_freem(m); 232b032f27cSSam Leffler continue; 233b032f27cSSam Leffler } 2346ff2e10aSSam Leffler if (ni->ni_associd == 0 && 2351b999d64SSam Leffler (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { 236b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 237b032f27cSSam Leffler eh->ether_dhost, NULL, 238b032f27cSSam Leffler "sta not associated (type 0x%04x)", 239b032f27cSSam Leffler htons(eh->ether_type)); 240b032f27cSSam Leffler vap->iv_stats.is_tx_notassoc++; 241b032f27cSSam Leffler ifp->if_oerrors++; 242b032f27cSSam Leffler m_freem(m); 243b032f27cSSam Leffler ieee80211_free_node(ni); 244b032f27cSSam Leffler continue; 245b032f27cSSam Leffler } 24659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 24759aa14a9SRui Paulo } else { 248c104cff2SRui Paulo if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) { 249c104cff2SRui Paulo /* 250c104cff2SRui Paulo * Proxy station only if configured. 251c104cff2SRui Paulo */ 252c104cff2SRui Paulo if (!ieee80211_mesh_isproxyena(vap)) { 253c104cff2SRui Paulo IEEE80211_DISCARD_MAC(vap, 254c104cff2SRui Paulo IEEE80211_MSG_OUTPUT | 255c104cff2SRui Paulo IEEE80211_MSG_MESH, 256c104cff2SRui Paulo eh->ether_dhost, NULL, 257c104cff2SRui Paulo "%s", "proxy not enabled"); 258c104cff2SRui Paulo vap->iv_stats.is_mesh_notproxy++; 259c104cff2SRui Paulo ifp->if_oerrors++; 260c104cff2SRui Paulo m_freem(m); 261c104cff2SRui Paulo continue; 262c104cff2SRui Paulo } 263c104cff2SRui Paulo ieee80211_mesh_proxy_check(vap, eh->ether_shost); 264c104cff2SRui Paulo } 26559aa14a9SRui Paulo ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m); 26659aa14a9SRui Paulo if (ni == NULL) { 26759aa14a9SRui Paulo /* 268c104cff2SRui Paulo * NB: ieee80211_mesh_discover holds/disposes 269c104cff2SRui Paulo * frame (e.g. queueing on path discovery). 27059aa14a9SRui Paulo */ 27159aa14a9SRui Paulo ifp->if_oerrors++; 27259aa14a9SRui Paulo continue; 27359aa14a9SRui Paulo } 27459aa14a9SRui Paulo } 27559aa14a9SRui Paulo #endif 276b032f27cSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 277b032f27cSSam Leffler (m->m_flags & M_PWR_SAV) == 0) { 278b032f27cSSam Leffler /* 279b032f27cSSam Leffler * Station in power save mode; pass the frame 280b032f27cSSam Leffler * to the 802.11 layer and continue. We'll get 281b032f27cSSam Leffler * the frame back when the time is right. 282b032f27cSSam Leffler * XXX lose WDS vap linkage? 283b032f27cSSam Leffler */ 28463092fceSSam Leffler (void) ieee80211_pwrsave(ni, m); 285b032f27cSSam Leffler ieee80211_free_node(ni); 286b032f27cSSam Leffler continue; 287b032f27cSSam Leffler } 288b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 289b032f27cSSam Leffler if (ieee80211_classify(ni, m)) { 290b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 291b032f27cSSam Leffler eh->ether_dhost, NULL, 292b032f27cSSam Leffler "%s", "classification failure"); 293b032f27cSSam Leffler vap->iv_stats.is_tx_classify++; 294b032f27cSSam Leffler ifp->if_oerrors++; 295b032f27cSSam Leffler m_freem(m); 296b032f27cSSam Leffler ieee80211_free_node(ni); 297b032f27cSSam Leffler continue; 298b032f27cSSam Leffler } 2997ebe9c0eSSam Leffler /* 3007ebe9c0eSSam Leffler * Stash the node pointer. Note that we do this after 3017ebe9c0eSSam Leffler * any call to ieee80211_dwds_mcast because that code 3027ebe9c0eSSam Leffler * uses any existing value for rcvif to identify the 3037ebe9c0eSSam Leffler * interface it (might have been) received on. 3047ebe9c0eSSam Leffler */ 3057ebe9c0eSSam Leffler m->m_pkthdr.rcvif = (void *)ni; 306b032f27cSSam Leffler 307339ccfb3SSam Leffler BPF_MTAP(ifp, m); /* 802.3 tx */ 308b032f27cSSam Leffler 309168f582eSSam Leffler /* 310168f582eSSam Leffler * Check if A-MPDU tx aggregation is setup or if we 311168f582eSSam Leffler * should try to enable it. The sta must be associated 312168f582eSSam Leffler * with HT and A-MPDU enabled for use. When the policy 313168f582eSSam Leffler * routine decides we should enable A-MPDU we issue an 314168f582eSSam Leffler * ADDBA request and wait for a reply. The frame being 315168f582eSSam Leffler * encapsulated will go out w/o using A-MPDU, or possibly 316168f582eSSam Leffler * it might be collected by the driver and held/retransmit. 317168f582eSSam Leffler * The default ic_ampdu_enable routine handles staggering 318168f582eSSam Leffler * ADDBA requests in case the receiver NAK's us or we are 319168f582eSSam Leffler * otherwise unable to establish a BA stream. 320168f582eSSam Leffler */ 321168f582eSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && 3222bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) && 323168f582eSSam Leffler (m->m_flags & M_EAPOL) == 0) { 324168f582eSSam Leffler const int ac = M_WME_GETAC(m); 325168f582eSSam Leffler struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[ac]; 326168f582eSSam Leffler 327168f582eSSam Leffler ieee80211_txampdu_count_packet(tap); 328168f582eSSam Leffler if (IEEE80211_AMPDU_RUNNING(tap)) { 329168f582eSSam Leffler /* 330168f582eSSam Leffler * Operational, mark frame for aggregation. 331168f582eSSam Leffler * 332168f582eSSam Leffler * XXX do tx aggregation here 333168f582eSSam Leffler */ 334168f582eSSam Leffler m->m_flags |= M_AMPDU_MPDU; 335168f582eSSam Leffler } else if (!IEEE80211_AMPDU_REQUESTED(tap) && 336168f582eSSam Leffler ic->ic_ampdu_enable(ni, tap)) { 337168f582eSSam Leffler /* 338168f582eSSam Leffler * Not negotiated yet, request service. 339168f582eSSam Leffler */ 340168f582eSSam Leffler ieee80211_ampdu_request(ni, tap); 341168f582eSSam Leffler /* XXX hold frame for reply? */ 342168f582eSSam Leffler } 343168f582eSSam Leffler } 344339ccfb3SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 345168f582eSSam Leffler else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { 346339ccfb3SSam Leffler m = ieee80211_ff_check(ni, m); 347339ccfb3SSam Leffler if (m == NULL) { 348339ccfb3SSam Leffler /* NB: any ni ref held on stageq */ 349339ccfb3SSam Leffler continue; 350339ccfb3SSam Leffler } 351339ccfb3SSam Leffler } 352339ccfb3SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 3539fb0fccbSSam Leffler if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { 354b032f27cSSam Leffler /* 355339ccfb3SSam Leffler * Encapsulate the packet in prep for transmission. 356b032f27cSSam Leffler */ 357339ccfb3SSam Leffler m = ieee80211_encap(vap, ni, m); 358339ccfb3SSam Leffler if (m == NULL) { 359339ccfb3SSam Leffler /* NB: stat+msg handled in ieee80211_encap */ 360339ccfb3SSam Leffler ieee80211_free_node(ni); 361339ccfb3SSam Leffler continue; 362339ccfb3SSam Leffler } 3639fb0fccbSSam Leffler } 364b032f27cSSam Leffler 36572fecb4dSSam Leffler error = parent->if_transmit(parent, m); 366b032f27cSSam Leffler if (error != 0) { 367b032f27cSSam Leffler /* NB: IFQ_HANDOFF reclaims mbuf */ 368b032f27cSSam Leffler ieee80211_free_node(ni); 369b032f27cSSam Leffler } else { 370b032f27cSSam Leffler ifp->if_opackets++; 371b032f27cSSam Leffler } 372b032f27cSSam Leffler ic->ic_lastdata = ticks; 373b032f27cSSam Leffler } 374b032f27cSSam Leffler #undef IS_DWDS 375b032f27cSSam Leffler } 376b032f27cSSam Leffler 377b032f27cSSam Leffler /* 378b032f27cSSam Leffler * 802.11 output routine. This is (currently) used only to 379b032f27cSSam Leffler * connect bpf write calls to the 802.11 layer for injecting 380fad788b1SSam Leffler * raw 802.11 frames. 381b032f27cSSam Leffler */ 382b032f27cSSam Leffler int 383b032f27cSSam Leffler ieee80211_output(struct ifnet *ifp, struct mbuf *m, 384279aa3d4SKip Macy struct sockaddr *dst, struct route *ro) 385b032f27cSSam Leffler { 386b032f27cSSam Leffler #define senderr(e) do { error = (e); goto bad;} while (0) 387b032f27cSSam Leffler struct ieee80211_node *ni = NULL; 3888ed1835dSSam Leffler struct ieee80211vap *vap; 389b032f27cSSam Leffler struct ieee80211_frame *wh; 390b032f27cSSam Leffler int error; 391b032f27cSSam Leffler 3928ed1835dSSam Leffler if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 3938ed1835dSSam Leffler /* 3948ed1835dSSam Leffler * Short-circuit requests if the vap is marked OACTIVE 3958ed1835dSSam Leffler * as this can happen because a packet came down through 3968ed1835dSSam Leffler * ieee80211_start before the vap entered RUN state in 3978ed1835dSSam Leffler * which case it's ok to just drop the frame. This 3988ed1835dSSam Leffler * should not be necessary but callers of if_output don't 3998ed1835dSSam Leffler * check OACTIVE. 4008ed1835dSSam Leffler */ 4018ed1835dSSam Leffler senderr(ENETDOWN); 4028ed1835dSSam Leffler } 4038ed1835dSSam Leffler vap = ifp->if_softc; 404b032f27cSSam Leffler /* 405b032f27cSSam Leffler * Hand to the 802.3 code if not tagged as 406b032f27cSSam Leffler * a raw 802.11 frame. 407b032f27cSSam Leffler */ 408b032f27cSSam Leffler if (dst->sa_family != AF_IEEE80211) 409279aa3d4SKip Macy return vap->iv_output(ifp, m, dst, ro); 410b032f27cSSam Leffler #ifdef MAC 411c27b9cdbSRobert Watson error = mac_ifnet_check_transmit(ifp, m); 412b032f27cSSam Leffler if (error) 413b032f27cSSam Leffler senderr(error); 414b032f27cSSam Leffler #endif 415b032f27cSSam Leffler if (ifp->if_flags & IFF_MONITOR) 416b032f27cSSam Leffler senderr(ENETDOWN); 417b032f27cSSam Leffler if (!IFNET_IS_UP_RUNNING(ifp)) 418b032f27cSSam Leffler senderr(ENETDOWN); 419b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 420b032f27cSSam Leffler IEEE80211_DPRINTF(vap, 421b032f27cSSam Leffler IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 422b032f27cSSam Leffler "block %s frame in CAC state\n", "raw data"); 423b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 424b032f27cSSam Leffler senderr(EIO); /* XXX */ 4250d9aed8aSBernhard Schmidt } else if (vap->iv_state == IEEE80211_S_SCAN) 4260d9aed8aSBernhard Schmidt senderr(EIO); 427b032f27cSSam Leffler /* XXX bypass bridge, pfil, carp, etc. */ 428b032f27cSSam Leffler 429b032f27cSSam Leffler if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) 430b032f27cSSam Leffler senderr(EIO); /* XXX */ 431b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 432b032f27cSSam Leffler if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 433b032f27cSSam Leffler IEEE80211_FC0_VERSION_0) 434b032f27cSSam Leffler senderr(EIO); /* XXX */ 435b032f27cSSam Leffler 436b032f27cSSam Leffler /* locate destination node */ 437b032f27cSSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 438b032f27cSSam Leffler case IEEE80211_FC1_DIR_NODS: 439b032f27cSSam Leffler case IEEE80211_FC1_DIR_FROMDS: 440b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr1); 441b032f27cSSam Leffler break; 442b032f27cSSam Leffler case IEEE80211_FC1_DIR_TODS: 443b032f27cSSam Leffler case IEEE80211_FC1_DIR_DSTODS: 444b032f27cSSam Leffler if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) 445b032f27cSSam Leffler senderr(EIO); /* XXX */ 446b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr3); 447b032f27cSSam Leffler break; 448b032f27cSSam Leffler default: 449b032f27cSSam Leffler senderr(EIO); /* XXX */ 450b032f27cSSam Leffler } 451b032f27cSSam Leffler if (ni == NULL) { 452b032f27cSSam Leffler /* 453b032f27cSSam Leffler * Permit packets w/ bpf params through regardless 454b032f27cSSam Leffler * (see below about sa_len). 455b032f27cSSam Leffler */ 456b032f27cSSam Leffler if (dst->sa_len == 0) 457b032f27cSSam Leffler senderr(EHOSTUNREACH); 458b032f27cSSam Leffler ni = ieee80211_ref_node(vap->iv_bss); 459b032f27cSSam Leffler } 460b032f27cSSam Leffler 461b032f27cSSam Leffler /* 462b032f27cSSam Leffler * Sanitize mbuf for net80211 flags leaked from above. 463b032f27cSSam Leffler * 464b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 465b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 466b032f27cSSam Leffler */ 467b032f27cSSam Leffler m->m_flags &= ~M_80211_TX; 468b032f27cSSam Leffler 469b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 470b032f27cSSam Leffler /* XXX assumes an 802.3 frame */ 471b032f27cSSam Leffler if (ieee80211_classify(ni, m)) 472b032f27cSSam Leffler senderr(EIO); /* XXX */ 473b032f27cSSam Leffler 474224881b4SSam Leffler ifp->if_opackets++; 4750e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 4760e910c94SSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 4770e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 4780e910c94SSam Leffler m->m_flags |= M_MCAST; 4790e910c94SSam Leffler } else 4800e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 4810e910c94SSam Leffler /* NB: ieee80211_encap does not include 802.11 header */ 4820e910c94SSam Leffler IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len); 483b032f27cSSam Leffler 484b032f27cSSam Leffler /* 485b032f27cSSam Leffler * NB: DLT_IEEE802_11_RADIO identifies the parameters are 486b032f27cSSam Leffler * present by setting the sa_len field of the sockaddr (yes, 487b032f27cSSam Leffler * this is a hack). 488b032f27cSSam Leffler * NB: we assume sa_data is suitably aligned to cast. 489b032f27cSSam Leffler */ 490b032f27cSSam Leffler return vap->iv_ic->ic_raw_xmit(ni, m, 491b032f27cSSam Leffler (const struct ieee80211_bpf_params *)(dst->sa_len ? 492b032f27cSSam Leffler dst->sa_data : NULL)); 493b032f27cSSam Leffler bad: 494b032f27cSSam Leffler if (m != NULL) 495b032f27cSSam Leffler m_freem(m); 496b032f27cSSam Leffler if (ni != NULL) 497b032f27cSSam Leffler ieee80211_free_node(ni); 498224881b4SSam Leffler ifp->if_oerrors++; 499b032f27cSSam Leffler return error; 500b032f27cSSam Leffler #undef senderr 501b032f27cSSam Leffler } 502b032f27cSSam Leffler 503b032f27cSSam Leffler /* 504add59d08SSam Leffler * Set the direction field and address fields of an outgoing 5050e66722dSSam Leffler * frame. Note this should be called early on in constructing 5060e66722dSSam Leffler * a frame as it sets i_fc[1]; other bits can then be or'd in. 507add59d08SSam Leffler */ 50859aa14a9SRui Paulo void 509b032f27cSSam Leffler ieee80211_send_setup( 510add59d08SSam Leffler struct ieee80211_node *ni, 5119e80b1dfSSam Leffler struct mbuf *m, 5128ac160cdSSam Leffler int type, int tid, 51368e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 51468e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 51568e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN]) 516add59d08SSam Leffler { 517add59d08SSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) 51859aa14a9SRui Paulo struct ieee80211vap *vap = ni->ni_vap; 51950cfec0eSBernhard Schmidt struct ieee80211_tx_ampdu *tap; 5209e80b1dfSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 5219e80b1dfSSam Leffler ieee80211_seq seqno; 522add59d08SSam Leffler 523add59d08SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; 524add59d08SSam Leffler if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 525b032f27cSSam Leffler switch (vap->iv_opmode) { 526add59d08SSam Leffler case IEEE80211_M_STA: 527add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 528add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 529add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 530add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 531add59d08SSam Leffler break; 532add59d08SSam Leffler case IEEE80211_M_IBSS: 533add59d08SSam Leffler case IEEE80211_M_AHDEMO: 534add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 535add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 536add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 537add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 538add59d08SSam Leffler break; 539add59d08SSam Leffler case IEEE80211_M_HOSTAP: 540add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 541add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 542add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, bssid); 543add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, sa); 544add59d08SSam Leffler break; 54568e8e04eSSam Leffler case IEEE80211_M_WDS: 54668e8e04eSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 547b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 548b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 54968e8e04eSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 55068e8e04eSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 55168e8e04eSSam Leffler break; 55259aa14a9SRui Paulo case IEEE80211_M_MBSS: 55359aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 55459aa14a9SRui Paulo /* XXX add support for proxied addresses */ 55559aa14a9SRui Paulo if (IEEE80211_IS_MULTICAST(da)) { 55659aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 55759aa14a9SRui Paulo /* XXX next hop */ 55859aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 55959aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 56059aa14a9SRui Paulo vap->iv_myaddr); 56159aa14a9SRui Paulo } else { 56259aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 56359aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 56459aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 56559aa14a9SRui Paulo vap->iv_myaddr); 56659aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, da); 56759aa14a9SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 56859aa14a9SRui Paulo } 56959aa14a9SRui Paulo #endif 57059aa14a9SRui Paulo break; 571add59d08SSam Leffler case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ 572add59d08SSam Leffler break; 573add59d08SSam Leffler } 574add59d08SSam Leffler } else { 575add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 576add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 577add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 57859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 57959aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 58059aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, sa); 58159aa14a9SRui Paulo else 58259aa14a9SRui Paulo #endif 583add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 584add59d08SSam Leffler } 58568e8e04eSSam Leffler *(uint16_t *)&wh->i_dur[0] = 0; 5869e80b1dfSSam Leffler 58750cfec0eSBernhard Schmidt tap = &ni->ni_tx_ampdu[TID_TO_WME_AC(tid)]; 58850cfec0eSBernhard Schmidt if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) 58950cfec0eSBernhard Schmidt m->m_flags |= M_AMPDU_MPDU; 59050cfec0eSBernhard Schmidt else { 5919e80b1dfSSam Leffler seqno = ni->ni_txseqs[tid]++; 59250cfec0eSBernhard Schmidt *(uint16_t *)&wh->i_seq[0] = 59350cfec0eSBernhard Schmidt htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 5949a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 59550cfec0eSBernhard Schmidt } 5969e80b1dfSSam Leffler 5979e80b1dfSSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 5989e80b1dfSSam Leffler m->m_flags |= M_MCAST; 599add59d08SSam Leffler #undef WH4 600add59d08SSam Leffler } 601add59d08SSam Leffler 602add59d08SSam Leffler /* 6030a915fadSSam Leffler * Send a management frame to the specified node. The node pointer 6040a915fadSSam Leffler * must have a reference as the pointer will be passed to the driver 6050a915fadSSam Leffler * and potentially held for a long time. If the frame is successfully 6060a915fadSSam Leffler * dispatched to the driver, then it is responsible for freeing the 607b032f27cSSam Leffler * reference (and potentially free'ing up any associated storage); 608b032f27cSSam Leffler * otherwise deal with reclaiming any reference (on error). 6090a915fadSSam Leffler */ 61068e8e04eSSam Leffler int 6118ac160cdSSam Leffler ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, 6128ac160cdSSam Leffler struct ieee80211_bpf_params *params) 6131a1e1d21SSam Leffler { 614b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 615b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 6161a1e1d21SSam Leffler struct ieee80211_frame *wh; 6171a1e1d21SSam Leffler 6180a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 6191a1e1d21SSam Leffler 620b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 621b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 622b032f27cSSam Leffler ni, "block %s frame in CAC state", 623b032f27cSSam Leffler ieee80211_mgt_subtype_name[ 624b032f27cSSam Leffler (type & IEEE80211_FC0_SUBTYPE_MASK) >> 625b032f27cSSam Leffler IEEE80211_FC0_SUBTYPE_SHIFT]); 626b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 627b032f27cSSam Leffler ieee80211_free_node(ni); 628b032f27cSSam Leffler m_freem(m); 629b032f27cSSam Leffler return EIO; /* XXX */ 630b032f27cSSam Leffler } 631b032f27cSSam Leffler 6321a1e1d21SSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 633b032f27cSSam Leffler if (m == NULL) { 634b032f27cSSam Leffler ieee80211_free_node(ni); 6351a1e1d21SSam Leffler return ENOMEM; 636b032f27cSSam Leffler } 6370a915fadSSam Leffler 6381a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 6399e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 6408ac160cdSSam Leffler IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, 641b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 6428ac160cdSSam Leffler if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 643b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, 644b032f27cSSam Leffler "encrypting frame (%s)", __func__); 6458a1b9b6aSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 6468a1b9b6aSSam Leffler } 647c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 6488ac160cdSSam Leffler 6498ac160cdSSam Leffler KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); 6508ac160cdSSam Leffler M_WME_SETAC(m, params->ibp_pri); 6518ac160cdSSam Leffler 6528a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 6538a1b9b6aSSam Leffler /* avoid printing too many frames */ 654b032f27cSSam Leffler if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || 655b032f27cSSam Leffler ieee80211_msg_dumppkts(vap)) { 6568a1b9b6aSSam Leffler printf("[%s] send %s on channel %u\n", 6578a1b9b6aSSam Leffler ether_sprintf(wh->i_addr1), 6588a1b9b6aSSam Leffler ieee80211_mgt_subtype_name[ 6598a1b9b6aSSam Leffler (type & IEEE80211_FC0_SUBTYPE_MASK) >> 6608a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_SHIFT], 661b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan)); 6628a1b9b6aSSam Leffler } 6638a1b9b6aSSam Leffler #endif 6648a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 66568e8e04eSSam Leffler 6668ac160cdSSam Leffler return ic->ic_raw_xmit(ni, m, params); 667246b5467SSam Leffler } 668246b5467SSam Leffler 669246b5467SSam Leffler /* 6706683931eSSam Leffler * Send a null data frame to the specified node. If the station 6716683931eSSam Leffler * is setup for QoS then a QoS Null Data frame is constructed. 6726683931eSSam Leffler * If this is a WDS station then a 4-address frame is constructed. 67319ad2dd7SSam Leffler * 67419ad2dd7SSam Leffler * NB: the caller is assumed to have setup a node reference 67519ad2dd7SSam Leffler * for use; this is necessary to deal with a race condition 676b032f27cSSam Leffler * when probing for inactive stations. Like ieee80211_mgmt_output 677b032f27cSSam Leffler * we must cleanup any node reference on error; however we 678b032f27cSSam Leffler * can safely just unref it as we know it will never be the 679b032f27cSSam Leffler * last reference to the node. 6808a1b9b6aSSam Leffler */ 6818a1b9b6aSSam Leffler int 682f62121ceSSam Leffler ieee80211_send_nulldata(struct ieee80211_node *ni) 6838a1b9b6aSSam Leffler { 684b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 685f62121ceSSam Leffler struct ieee80211com *ic = ni->ni_ic; 6868a1b9b6aSSam Leffler struct mbuf *m; 6878a1b9b6aSSam Leffler struct ieee80211_frame *wh; 6886683931eSSam Leffler int hdrlen; 6896683931eSSam Leffler uint8_t *frm; 6908a1b9b6aSSam Leffler 691b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 692b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 693b032f27cSSam Leffler ni, "block %s frame in CAC state", "null data"); 694b032f27cSSam Leffler ieee80211_unref_node(&ni); 695b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 696b032f27cSSam Leffler return EIO; /* XXX */ 697b032f27cSSam Leffler } 698b032f27cSSam Leffler 6996683931eSSam Leffler if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) 7006683931eSSam Leffler hdrlen = sizeof(struct ieee80211_qosframe); 7016683931eSSam Leffler else 7026683931eSSam Leffler hdrlen = sizeof(struct ieee80211_frame); 7036683931eSSam Leffler /* NB: only WDS vap's get 4-address frames */ 7046683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 7056683931eSSam Leffler hdrlen += IEEE80211_ADDR_LEN; 7066683931eSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 7076683931eSSam Leffler hdrlen = roundup(hdrlen, sizeof(uint32_t)); 7086683931eSSam Leffler 7096683931eSSam Leffler m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); 7108a1b9b6aSSam Leffler if (m == NULL) { 7118a1b9b6aSSam Leffler /* XXX debug msg */ 71219ad2dd7SSam Leffler ieee80211_unref_node(&ni); 713b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 7148a1b9b6aSSam Leffler return ENOMEM; 7158a1b9b6aSSam Leffler } 7166683931eSSam Leffler KASSERT(M_LEADINGSPACE(m) >= hdrlen, 7176683931eSSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 7186683931eSSam Leffler M_PREPEND(m, hdrlen, M_DONTWAIT); 7196683931eSSam Leffler if (m == NULL) { 7206683931eSSam Leffler /* NB: cannot happen */ 7216683931eSSam Leffler ieee80211_free_node(ni); 7226683931eSSam Leffler return ENOMEM; 7236683931eSSam Leffler } 7248a1b9b6aSSam Leffler 7256683931eSSam Leffler wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ 7266683931eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 7276683931eSSam Leffler const int tid = WME_AC_TO_TID(WME_AC_BE); 7286683931eSSam Leffler uint8_t *qos; 7296683931eSSam Leffler 7309e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 7316683931eSSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, 7326683931eSSam Leffler tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 7336683931eSSam Leffler 7346683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 7356683931eSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 7366683931eSSam Leffler else 7376683931eSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 7386683931eSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 7396683931eSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) 7406683931eSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 7416683931eSSam Leffler qos[1] = 0; 7426683931eSSam Leffler } else { 7439e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 744add59d08SSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 7458ac160cdSSam Leffler IEEE80211_NONQOS_TID, 746b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 7476683931eSSam Leffler } 748b032f27cSSam Leffler if (vap->iv_opmode != IEEE80211_M_WDS) { 749add59d08SSam Leffler /* NB: power management bit is never sent by an AP */ 750add59d08SSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 751b032f27cSSam Leffler vap->iv_opmode != IEEE80211_M_HOSTAP) 752add59d08SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 753b032f27cSSam Leffler } 7546683931eSSam Leffler m->m_len = m->m_pkthdr.len = hdrlen; 755c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 7566683931eSSam Leffler 757bb239ce9SSam Leffler M_WME_SETAC(m, WME_AC_BE); 7588a1b9b6aSSam Leffler 7598a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 7608a1b9b6aSSam Leffler 761b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, 7626683931eSSam Leffler "send %snull data frame on channel %u, pwr mgt %s", 7636683931eSSam Leffler ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", 764b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), 765add59d08SSam Leffler wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 766add59d08SSam Leffler 767b032f27cSSam Leffler return ic->ic_raw_xmit(ni, m, NULL); 7688a1b9b6aSSam Leffler } 7698a1b9b6aSSam Leffler 7708a1b9b6aSSam Leffler /* 7718a1b9b6aSSam Leffler * Assign priority to a frame based on any vlan tag assigned 7728a1b9b6aSSam Leffler * to the station and/or any Diffserv setting in an IP header. 7738a1b9b6aSSam Leffler * Finally, if an ACM policy is setup (in station mode) it's 7748a1b9b6aSSam Leffler * applied. 7758a1b9b6aSSam Leffler */ 7768a1b9b6aSSam Leffler int 777b032f27cSSam Leffler ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) 7788a1b9b6aSSam Leffler { 779b032f27cSSam Leffler const struct ether_header *eh = mtod(m, struct ether_header *); 7808a1b9b6aSSam Leffler int v_wme_ac, d_wme_ac, ac; 7818a1b9b6aSSam Leffler 782b032f27cSSam Leffler /* 783b032f27cSSam Leffler * Always promote PAE/EAPOL frames to high priority. 784b032f27cSSam Leffler */ 785b032f27cSSam Leffler if (eh->ether_type == htons(ETHERTYPE_PAE)) { 786b032f27cSSam Leffler /* NB: mark so others don't need to check header */ 787b032f27cSSam Leffler m->m_flags |= M_EAPOL; 788b032f27cSSam Leffler ac = WME_AC_VO; 789b032f27cSSam Leffler goto done; 790b032f27cSSam Leffler } 791b032f27cSSam Leffler /* 792b032f27cSSam Leffler * Non-qos traffic goes to BE. 793b032f27cSSam Leffler */ 7948a1b9b6aSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { 7958a1b9b6aSSam Leffler ac = WME_AC_BE; 7968a1b9b6aSSam Leffler goto done; 7978a1b9b6aSSam Leffler } 7988a1b9b6aSSam Leffler 7998a1b9b6aSSam Leffler /* 8008a1b9b6aSSam Leffler * If node has a vlan tag then all traffic 8018a1b9b6aSSam Leffler * to it must have a matching tag. 8028a1b9b6aSSam Leffler */ 8038a1b9b6aSSam Leffler v_wme_ac = 0; 8048a1b9b6aSSam Leffler if (ni->ni_vlan != 0) { 80578ba57b9SAndre Oppermann if ((m->m_flags & M_VLANTAG) == 0) { 8068a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_novlantag); 8078a1b9b6aSSam Leffler return 1; 8088a1b9b6aSSam Leffler } 80978ba57b9SAndre Oppermann if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 8108a1b9b6aSSam Leffler EVL_VLANOFTAG(ni->ni_vlan)) { 8118a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 8128a1b9b6aSSam Leffler return 1; 8138a1b9b6aSSam Leffler } 8148a1b9b6aSSam Leffler /* map vlan priority to AC */ 815f4558c9aSSam Leffler v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); 8168a1b9b6aSSam Leffler } 8178a1b9b6aSSam Leffler 818e755a73dSSam Leffler /* XXX m_copydata may be too slow for fast path */ 8198a1b9b6aSSam Leffler #ifdef INET 8208a1b9b6aSSam Leffler if (eh->ether_type == htons(ETHERTYPE_IP)) { 821f4558c9aSSam Leffler uint8_t tos; 8228a1b9b6aSSam Leffler /* 823f4558c9aSSam Leffler * IP frame, map the DSCP bits from the TOS field. 8248a1b9b6aSSam Leffler */ 825f4558c9aSSam Leffler /* NB: ip header may not be in first mbuf */ 826f4558c9aSSam Leffler m_copydata(m, sizeof(struct ether_header) + 827f4558c9aSSam Leffler offsetof(struct ip, ip_tos), sizeof(tos), &tos); 828f4558c9aSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 829f4558c9aSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 8308a1b9b6aSSam Leffler } else { 8318a1b9b6aSSam Leffler #endif /* INET */ 832e755a73dSSam Leffler #ifdef INET6 833e755a73dSSam Leffler if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 834e755a73dSSam Leffler uint32_t flow; 835e755a73dSSam Leffler uint8_t tos; 836e755a73dSSam Leffler /* 837e755a73dSSam Leffler * IPv6 frame, map the DSCP bits from the TOS field. 838e755a73dSSam Leffler */ 839e755a73dSSam Leffler m_copydata(m, sizeof(struct ether_header) + 840e755a73dSSam Leffler offsetof(struct ip6_hdr, ip6_flow), sizeof(flow), 841e755a73dSSam Leffler (caddr_t) &flow); 842e755a73dSSam Leffler tos = (uint8_t)(ntohl(flow) >> 20); 843e755a73dSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 844e755a73dSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 845e755a73dSSam Leffler } else { 846e755a73dSSam Leffler #endif /* INET6 */ 8478a1b9b6aSSam Leffler d_wme_ac = WME_AC_BE; 848e755a73dSSam Leffler #ifdef INET6 849e755a73dSSam Leffler } 850e755a73dSSam Leffler #endif 8518a1b9b6aSSam Leffler #ifdef INET 8528a1b9b6aSSam Leffler } 8538a1b9b6aSSam Leffler #endif 8548a1b9b6aSSam Leffler /* 8558a1b9b6aSSam Leffler * Use highest priority AC. 8568a1b9b6aSSam Leffler */ 8578a1b9b6aSSam Leffler if (v_wme_ac > d_wme_ac) 8588a1b9b6aSSam Leffler ac = v_wme_ac; 8598a1b9b6aSSam Leffler else 8608a1b9b6aSSam Leffler ac = d_wme_ac; 8618a1b9b6aSSam Leffler 8628a1b9b6aSSam Leffler /* 8638a1b9b6aSSam Leffler * Apply ACM policy. 8648a1b9b6aSSam Leffler */ 865b032f27cSSam Leffler if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { 8668a1b9b6aSSam Leffler static const int acmap[4] = { 8678a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BE */ 8688a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BK */ 8698a1b9b6aSSam Leffler WME_AC_BE, /* WME_AC_VI */ 8708a1b9b6aSSam Leffler WME_AC_VI, /* WME_AC_VO */ 8718a1b9b6aSSam Leffler }; 872b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 873b032f27cSSam Leffler 8748a1b9b6aSSam Leffler while (ac != WME_AC_BK && 8758a1b9b6aSSam Leffler ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) 8768a1b9b6aSSam Leffler ac = acmap[ac]; 8778a1b9b6aSSam Leffler } 8788a1b9b6aSSam Leffler done: 8798a1b9b6aSSam Leffler M_WME_SETAC(m, ac); 8808a1b9b6aSSam Leffler return 0; 8818a1b9b6aSSam Leffler } 8828a1b9b6aSSam Leffler 8838a1b9b6aSSam Leffler /* 8845e923d2eSSam Leffler * Insure there is sufficient contiguous space to encapsulate the 8855e923d2eSSam Leffler * 802.11 data frame. If room isn't already there, arrange for it. 8865e923d2eSSam Leffler * Drivers and cipher modules assume we have done the necessary work 8875e923d2eSSam Leffler * and fail rudely if they don't find the space they need. 8885e923d2eSSam Leffler */ 889616190d0SSam Leffler struct mbuf * 890b032f27cSSam Leffler ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, 8915e923d2eSSam Leffler struct ieee80211_key *key, struct mbuf *m) 8925e923d2eSSam Leffler { 893ab96db10SSam Leffler #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) 894b032f27cSSam Leffler int needed_space = vap->iv_ic->ic_headroom + hdrsize; 8955e923d2eSSam Leffler 8965e923d2eSSam Leffler if (key != NULL) { 8975e923d2eSSam Leffler /* XXX belongs in crypto code? */ 8985e923d2eSSam Leffler needed_space += key->wk_cipher->ic_header; 8995e923d2eSSam Leffler /* XXX frags */ 90083a244dbSSam Leffler /* 90183a244dbSSam Leffler * When crypto is being done in the host we must insure 90283a244dbSSam Leffler * the data are writable for the cipher routines; clone 90383a244dbSSam Leffler * a writable mbuf chain. 90483a244dbSSam Leffler * XXX handle SWMIC specially 90583a244dbSSam Leffler */ 9065c1f7f19SSam Leffler if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { 90783a244dbSSam Leffler m = m_unshare(m, M_NOWAIT); 90883a244dbSSam Leffler if (m == NULL) { 909b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 91083a244dbSSam Leffler "%s: cannot get writable mbuf\n", __func__); 911b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ 91283a244dbSSam Leffler return NULL; 91383a244dbSSam Leffler } 91483a244dbSSam Leffler } 9155e923d2eSSam Leffler } 9165e923d2eSSam Leffler /* 9175e923d2eSSam Leffler * We know we are called just before stripping an Ethernet 9185e923d2eSSam Leffler * header and prepending an LLC header. This means we know 9195e923d2eSSam Leffler * there will be 920ab96db10SSam Leffler * sizeof(struct ether_header) - sizeof(struct llc) 9215e923d2eSSam Leffler * bytes recovered to which we need additional space for the 9225e923d2eSSam Leffler * 802.11 header and any crypto header. 9235e923d2eSSam Leffler */ 9245e923d2eSSam Leffler /* XXX check trailing space and copy instead? */ 9255e923d2eSSam Leffler if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { 9265e923d2eSSam Leffler struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); 9275e923d2eSSam Leffler if (n == NULL) { 928b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 9295e923d2eSSam Leffler "%s: cannot expand storage\n", __func__); 930b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 9315e923d2eSSam Leffler m_freem(m); 9325e923d2eSSam Leffler return NULL; 9335e923d2eSSam Leffler } 9345e923d2eSSam Leffler KASSERT(needed_space <= MHLEN, 9355e923d2eSSam Leffler ("not enough room, need %u got %zu\n", needed_space, MHLEN)); 9365e923d2eSSam Leffler /* 9375e923d2eSSam Leffler * Setup new mbuf to have leading space to prepend the 9385e923d2eSSam Leffler * 802.11 header and any crypto header bits that are 9395e923d2eSSam Leffler * required (the latter are added when the driver calls 9405e923d2eSSam Leffler * back to ieee80211_crypto_encap to do crypto encapsulation). 9415e923d2eSSam Leffler */ 9425e923d2eSSam Leffler /* NB: must be first 'cuz it clobbers m_data */ 9435e923d2eSSam Leffler m_move_pkthdr(n, m); 9445e923d2eSSam Leffler n->m_len = 0; /* NB: m_gethdr does not set */ 9455e923d2eSSam Leffler n->m_data += needed_space; 9465e923d2eSSam Leffler /* 9475e923d2eSSam Leffler * Pull up Ethernet header to create the expected layout. 9485e923d2eSSam Leffler * We could use m_pullup but that's overkill (i.e. we don't 9495e923d2eSSam Leffler * need the actual data) and it cannot fail so do it inline 9505e923d2eSSam Leffler * for speed. 9515e923d2eSSam Leffler */ 9525e923d2eSSam Leffler /* NB: struct ether_header is known to be contiguous */ 9535e923d2eSSam Leffler n->m_len += sizeof(struct ether_header); 9545e923d2eSSam Leffler m->m_len -= sizeof(struct ether_header); 9555e923d2eSSam Leffler m->m_data += sizeof(struct ether_header); 9565e923d2eSSam Leffler /* 9575e923d2eSSam Leffler * Replace the head of the chain. 9585e923d2eSSam Leffler */ 9595e923d2eSSam Leffler n->m_next = m; 9605e923d2eSSam Leffler m = n; 9615e923d2eSSam Leffler } 9625e923d2eSSam Leffler return m; 9635e923d2eSSam Leffler #undef TO_BE_RECLAIMED 9645e923d2eSSam Leffler } 9655e923d2eSSam Leffler 9665e923d2eSSam Leffler /* 9675e923d2eSSam Leffler * Return the transmit key to use in sending a unicast frame. 9685e923d2eSSam Leffler * If a unicast key is set we use that. When no unicast key is set 9695e923d2eSSam Leffler * we fall back to the default transmit key. 9708a1b9b6aSSam Leffler */ 9718a1b9b6aSSam Leffler static __inline struct ieee80211_key * 972b032f27cSSam Leffler ieee80211_crypto_getucastkey(struct ieee80211vap *vap, 973b032f27cSSam Leffler struct ieee80211_node *ni) 9748a1b9b6aSSam Leffler { 975cda15ce1SSam Leffler if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { 976b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 977b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 9788a1b9b6aSSam Leffler return NULL; 979b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 9808a1b9b6aSSam Leffler } else { 9818a1b9b6aSSam Leffler return &ni->ni_ucastkey; 9828a1b9b6aSSam Leffler } 9835e923d2eSSam Leffler } 9845e923d2eSSam Leffler 9855e923d2eSSam Leffler /* 9865e923d2eSSam Leffler * Return the transmit key to use in sending a multicast frame. 9875e923d2eSSam Leffler * Multicast traffic always uses the group key which is installed as 9885e923d2eSSam Leffler * the default tx key. 9895e923d2eSSam Leffler */ 9905e923d2eSSam Leffler static __inline struct ieee80211_key * 991b032f27cSSam Leffler ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, 992b032f27cSSam Leffler struct ieee80211_node *ni) 9935e923d2eSSam Leffler { 994b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 995b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 9965e923d2eSSam Leffler return NULL; 997b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 9988a1b9b6aSSam Leffler } 9998a1b9b6aSSam Leffler 10008a1b9b6aSSam Leffler /* 10018a1b9b6aSSam Leffler * Encapsulate an outbound data frame. The mbuf chain is updated. 10028a1b9b6aSSam Leffler * If an error is encountered NULL is returned. The caller is required 10038a1b9b6aSSam Leffler * to provide a node reference and pullup the ethernet header in the 10048a1b9b6aSSam Leffler * first mbuf. 1005b032f27cSSam Leffler * 1006b032f27cSSam Leffler * NB: Packet is assumed to be processed by ieee80211_classify which 1007b032f27cSSam Leffler * marked EAPOL frames w/ M_EAPOL. 10080a915fadSSam Leffler */ 10091a1e1d21SSam Leffler struct mbuf * 1010339ccfb3SSam Leffler ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni, 1011339ccfb3SSam Leffler struct mbuf *m) 10121a1e1d21SSam Leffler { 1013b032f27cSSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) 1014b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 101559aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 101659aa14a9SRui Paulo struct ieee80211_mesh_state *ms = vap->iv_mesh; 1017c104cff2SRui Paulo struct ieee80211_meshcntl_ae10 *mc; 101859aa14a9SRui Paulo #endif 10191a1e1d21SSam Leffler struct ether_header eh; 10201a1e1d21SSam Leffler struct ieee80211_frame *wh; 10218a1b9b6aSSam Leffler struct ieee80211_key *key; 10221a1e1d21SSam Leffler struct llc *llc; 1023616190d0SSam Leffler int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr; 10249e80b1dfSSam Leffler ieee80211_seq seqno; 102559aa14a9SRui Paulo int meshhdrsize, meshae; 102659aa14a9SRui Paulo uint8_t *qos; 10271a1e1d21SSam Leffler 102868e8e04eSSam Leffler /* 102968e8e04eSSam Leffler * Copy existing Ethernet header to a safe place. The 103068e8e04eSSam Leffler * rest of the code assumes it's ok to strip it when 103168e8e04eSSam Leffler * reorganizing state for the final encapsulation. 103268e8e04eSSam Leffler */ 10338a1b9b6aSSam Leffler KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); 1034b032f27cSSam Leffler ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); 10351a1e1d21SSam Leffler 10368a1b9b6aSSam Leffler /* 10378a1b9b6aSSam Leffler * Insure space for additional headers. First identify 10388a1b9b6aSSam Leffler * transmit key to use in calculating any buffer adjustments 10398a1b9b6aSSam Leffler * required. This is also used below to do privacy 10408a1b9b6aSSam Leffler * encapsulation work. Then calculate the 802.11 header 10418a1b9b6aSSam Leffler * size and any padding required by the driver. 10428a1b9b6aSSam Leffler * 10438a1b9b6aSSam Leffler * Note key may be NULL if we fall back to the default 10448a1b9b6aSSam Leffler * transmit key and that is not set. In that case the 10458a1b9b6aSSam Leffler * buffer may not be expanded as needed by the cipher 10468a1b9b6aSSam Leffler * routines, but they will/should discard it. 10478a1b9b6aSSam Leffler */ 1048b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) { 1049b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA || 1050b032f27cSSam Leffler !IEEE80211_IS_MULTICAST(eh.ether_dhost) || 1051b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_WDS && 1052b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) 1053b032f27cSSam Leffler key = ieee80211_crypto_getucastkey(vap, ni); 10545e923d2eSSam Leffler else 1055b032f27cSSam Leffler key = ieee80211_crypto_getmcastkey(vap, ni); 1056b032f27cSSam Leffler if (key == NULL && (m->m_flags & M_EAPOL) == 0) { 1057b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, 1058b032f27cSSam Leffler eh.ether_dhost, 1059b032f27cSSam Leffler "no default transmit key (%s) deftxkey %u", 1060b032f27cSSam Leffler __func__, vap->iv_def_txkey); 1061b032f27cSSam Leffler vap->iv_stats.is_tx_nodefkey++; 1062d72c7253SSam Leffler goto bad; 10638a1b9b6aSSam Leffler } 10648a1b9b6aSSam Leffler } else 10658a1b9b6aSSam Leffler key = NULL; 10665e923d2eSSam Leffler /* 10675e923d2eSSam Leffler * XXX Some ap's don't handle QoS-encapsulated EAPOL 10685e923d2eSSam Leffler * frames so suppress use. This may be an issue if other 10695e923d2eSSam Leffler * ap's require all data frames to be QoS-encapsulated 10705e923d2eSSam Leffler * once negotiated in which case we'll need to make this 10715e923d2eSSam Leffler * configurable. 10725e923d2eSSam Leffler */ 107368e8e04eSSam Leffler addqos = (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) && 1074b032f27cSSam Leffler (m->m_flags & M_EAPOL) == 0; 10755e923d2eSSam Leffler if (addqos) 10768a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_qosframe); 10778a1b9b6aSSam Leffler else 10788a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_frame); 107959aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 108059aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 108159aa14a9SRui Paulo /* 108259aa14a9SRui Paulo * Mesh data frames are encapsulated according to the 108359aa14a9SRui Paulo * rules of Section 11B.8.5 (p.139 of D3.0 spec). 108459aa14a9SRui Paulo * o Group Addressed data (aka multicast) originating 108559aa14a9SRui Paulo * at the local sta are sent w/ 3-address format and 108659aa14a9SRui Paulo * address extension mode 00 108759aa14a9SRui Paulo * o Individually Addressed data (aka unicast) originating 108859aa14a9SRui Paulo * at the local sta are sent w/ 4-address format and 108959aa14a9SRui Paulo * address extension mode 00 109059aa14a9SRui Paulo * o Group Addressed data forwarded from a non-mesh sta are 109159aa14a9SRui Paulo * sent w/ 3-address format and address extension mode 01 109259aa14a9SRui Paulo * o Individually Address data from another sta are sent 109359aa14a9SRui Paulo * w/ 4-address format and address extension mode 10 109459aa14a9SRui Paulo */ 109559aa14a9SRui Paulo is4addr = 0; /* NB: don't use, disable */ 1096c104cff2SRui Paulo if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) 1097c104cff2SRui Paulo hdrsize += IEEE80211_ADDR_LEN; /* unicast are 4-addr */ 109859aa14a9SRui Paulo meshhdrsize = sizeof(struct ieee80211_meshcntl); 109959aa14a9SRui Paulo /* XXX defines for AE modes */ 110059aa14a9SRui Paulo if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { 1101c104cff2SRui Paulo if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) 110259aa14a9SRui Paulo meshae = 0; 1103c104cff2SRui Paulo else 110459aa14a9SRui Paulo meshae = 4; /* NB: pseudo */ 110559aa14a9SRui Paulo } else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) { 110659aa14a9SRui Paulo meshae = 1; 1107c104cff2SRui Paulo meshhdrsize += 1*IEEE80211_ADDR_LEN; 110859aa14a9SRui Paulo } else { 110959aa14a9SRui Paulo meshae = 2; 1110c104cff2SRui Paulo meshhdrsize += 2*IEEE80211_ADDR_LEN; 111159aa14a9SRui Paulo } 111259aa14a9SRui Paulo } else { 111359aa14a9SRui Paulo #endif 1114b032f27cSSam Leffler /* 1115b032f27cSSam Leffler * 4-address frames need to be generated for: 11166437e6daSSam Leffler * o packets sent through a WDS vap (IEEE80211_M_WDS) 1117f2a6a13cSSam Leffler * o packets sent through a vap marked for relaying 1118f2a6a13cSSam Leffler * (e.g. a station operating with dynamic WDS) 1119b032f27cSSam Leffler */ 11206437e6daSSam Leffler is4addr = vap->iv_opmode == IEEE80211_M_WDS || 1121f2a6a13cSSam Leffler ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) && 1122b032f27cSSam Leffler !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); 1123b032f27cSSam Leffler if (is4addr) 1124b032f27cSSam Leffler hdrsize += IEEE80211_ADDR_LEN; 112559aa14a9SRui Paulo meshhdrsize = meshae = 0; 112659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 112759aa14a9SRui Paulo } 112859aa14a9SRui Paulo #endif 1129b032f27cSSam Leffler /* 1130b032f27cSSam Leffler * Honor driver DATAPAD requirement. 1131b032f27cSSam Leffler */ 11328a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 1133b032f27cSSam Leffler hdrspace = roundup(hdrsize, sizeof(uint32_t)); 1134b032f27cSSam Leffler else 1135b032f27cSSam Leffler hdrspace = hdrsize; 113668e8e04eSSam Leffler 1137616190d0SSam Leffler if (__predict_true((m->m_flags & M_FF) == 0)) { 113868e8e04eSSam Leffler /* 113968e8e04eSSam Leffler * Normal frame. 114068e8e04eSSam Leffler */ 114159aa14a9SRui Paulo m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m); 11428a1b9b6aSSam Leffler if (m == NULL) { 11438a1b9b6aSSam Leffler /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 11440a915fadSSam Leffler goto bad; 11450a915fadSSam Leffler } 114668e8e04eSSam Leffler /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ 1147ab96db10SSam Leffler m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 11481a1e1d21SSam Leffler llc = mtod(m, struct llc *); 11491a1e1d21SSam Leffler llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 11501a1e1d21SSam Leffler llc->llc_control = LLC_UI; 11511a1e1d21SSam Leffler llc->llc_snap.org_code[0] = 0; 11521a1e1d21SSam Leffler llc->llc_snap.org_code[1] = 0; 11531a1e1d21SSam Leffler llc->llc_snap.org_code[2] = 0; 11541a1e1d21SSam Leffler llc->llc_snap.ether_type = eh.ether_type; 1155616190d0SSam Leffler } else { 1156616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 1157339ccfb3SSam Leffler /* 1158339ccfb3SSam Leffler * Aggregated frame. 1159339ccfb3SSam Leffler */ 116059aa14a9SRui Paulo m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key); 1161616190d0SSam Leffler if (m == NULL) 1162616190d0SSam Leffler #endif 1163616190d0SSam Leffler goto bad; 116468e8e04eSSam Leffler } 11658a1b9b6aSSam Leffler datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ 11668a1b9b6aSSam Leffler 116759aa14a9SRui Paulo M_PREPEND(m, hdrspace + meshhdrsize, M_DONTWAIT); 11681be50176SSam Leffler if (m == NULL) { 1169b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 11700a915fadSSam Leffler goto bad; 11711be50176SSam Leffler } 11721a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 11731a1e1d21SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 117468e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 117559aa14a9SRui Paulo qos = NULL; /* NB: quiet compiler */ 1176b032f27cSSam Leffler if (is4addr) { 1177b032f27cSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 1178b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 1179b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1180b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1181b032f27cSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 1182b032f27cSSam Leffler } else switch (vap->iv_opmode) { 11831a1e1d21SSam Leffler case IEEE80211_M_STA: 11841a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 11851a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 11861a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 11871a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 11881a1e1d21SSam Leffler break; 11891a1e1d21SSam Leffler case IEEE80211_M_IBSS: 11901a1e1d21SSam Leffler case IEEE80211_M_AHDEMO: 11911a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 11921a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 11931a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1194a8b16e87SSam Leffler /* 1195b032f27cSSam Leffler * NB: always use the bssid from iv_bss as the 1196a8b16e87SSam Leffler * neighbor's may be stale after an ibss merge 1197a8b16e87SSam Leffler */ 1198b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); 11991a1e1d21SSam Leffler break; 12001a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 12011a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 12021a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 12031a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 12041a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 12051a1e1d21SSam Leffler break; 120659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 120759aa14a9SRui Paulo case IEEE80211_M_MBSS: 120859aa14a9SRui Paulo /* NB: offset by hdrspace to deal with DATAPAD */ 1209c104cff2SRui Paulo mc = (struct ieee80211_meshcntl_ae10 *) 121059aa14a9SRui Paulo (mtod(m, uint8_t *) + hdrspace); 121159aa14a9SRui Paulo switch (meshae) { 121259aa14a9SRui Paulo case 0: /* ucast, no proxy */ 121359aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 121459aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 121559aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 121659aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 121759aa14a9SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 121859aa14a9SRui Paulo mc->mc_flags = 0; 121959aa14a9SRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 122059aa14a9SRui Paulo break; 122159aa14a9SRui Paulo case 4: /* mcast, no proxy */ 122259aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 122359aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 122459aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 122559aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 122659aa14a9SRui Paulo mc->mc_flags = 0; /* NB: AE is really 0 */ 122759aa14a9SRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 122859aa14a9SRui Paulo break; 122959aa14a9SRui Paulo case 1: /* mcast, proxy */ 123059aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 123159aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 123259aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1233c104cff2SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr); 123459aa14a9SRui Paulo mc->mc_flags = 1; 123559aa14a9SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost); 123659aa14a9SRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 123759aa14a9SRui Paulo break; 123859aa14a9SRui Paulo case 2: /* ucast, proxy */ 123959aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 124059aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 124159aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1242c104cff2SRui Paulo /* XXX not right, need MeshDA */ 124359aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1244c104cff2SRui Paulo /* XXX assume are MeshSA */ 1245c104cff2SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr); 124659aa14a9SRui Paulo mc->mc_flags = 2; 1247c104cff2SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_dhost); 124859aa14a9SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost); 124959aa14a9SRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 125059aa14a9SRui Paulo break; 125159aa14a9SRui Paulo default: 125259aa14a9SRui Paulo KASSERT(0, ("meshae %d", meshae)); 125359aa14a9SRui Paulo break; 125459aa14a9SRui Paulo } 125559aa14a9SRui Paulo mc->mc_ttl = ms->ms_ttl; 125659aa14a9SRui Paulo ms->ms_seq++; 125759aa14a9SRui Paulo LE_WRITE_4(mc->mc_seq, ms->ms_seq); 125859aa14a9SRui Paulo break; 125959aa14a9SRui Paulo #endif 1260b032f27cSSam Leffler case IEEE80211_M_WDS: /* NB: is4addr should always be true */ 126159aa14a9SRui Paulo default: 12620a915fadSSam Leffler goto bad; 12631a1e1d21SSam Leffler } 1264bc5627d9SSam Leffler if (m->m_flags & M_MORE_DATA) 1265bc5627d9SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 12665e923d2eSSam Leffler if (addqos) { 12678a1b9b6aSSam Leffler int ac, tid; 12688a1b9b6aSSam Leffler 1269b032f27cSSam Leffler if (is4addr) { 1270b032f27cSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 127159aa14a9SRui Paulo /* NB: mesh case handled earlier */ 127259aa14a9SRui Paulo } else if (vap->iv_opmode != IEEE80211_M_MBSS) 1273b032f27cSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 12748a1b9b6aSSam Leffler ac = M_WME_GETAC(m); 12758a1b9b6aSSam Leffler /* map from access class/queue to 11e header priorty value */ 12768a1b9b6aSSam Leffler tid = WME_AC_TO_TID(ac); 1277b032f27cSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 12788a1b9b6aSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) 1279b032f27cSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 1280b032f27cSSam Leffler qos[1] = 0; 1281b032f27cSSam Leffler wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; 12828a1b9b6aSSam Leffler 128345f856e3SSam Leffler if ((m->m_flags & M_AMPDU_MPDU) == 0) { 128445f856e3SSam Leffler /* 128545f856e3SSam Leffler * NB: don't assign a sequence # to potential 128645f856e3SSam Leffler * aggregates; we expect this happens at the 128745f856e3SSam Leffler * point the frame comes off any aggregation q 128845f856e3SSam Leffler * as otherwise we may introduce holes in the 128945f856e3SSam Leffler * BA sequence space and/or make window accouting 129045f856e3SSam Leffler * more difficult. 129145f856e3SSam Leffler * 129245f856e3SSam Leffler * XXX may want to control this with a driver 129345f856e3SSam Leffler * capability; this may also change when we pull 129445f856e3SSam Leffler * aggregation up into net80211 129545f856e3SSam Leffler */ 12969e80b1dfSSam Leffler seqno = ni->ni_txseqs[tid]++; 129768e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 12989e80b1dfSSam Leffler htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 12999a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 130045f856e3SSam Leffler } 13018a1b9b6aSSam Leffler } else { 13029e80b1dfSSam Leffler seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 130368e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 13049e80b1dfSSam Leffler htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 13059a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 13068a1b9b6aSSam Leffler } 13079a841c7fSSam Leffler 130859aa14a9SRui Paulo 130968e8e04eSSam Leffler /* check if xmit fragmentation is required */ 1310b032f27cSSam Leffler txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && 131168e8e04eSSam Leffler !IEEE80211_IS_MULTICAST(wh->i_addr1) && 1312b032f27cSSam Leffler (vap->iv_caps & IEEE80211_C_TXFRAG) && 1313e9cfc1f5SSam Leffler (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0); 13145e923d2eSSam Leffler if (key != NULL) { 13155e923d2eSSam Leffler /* 13165e923d2eSSam Leffler * IEEE 802.1X: send EAPOL frames always in the clear. 13175e923d2eSSam Leffler * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 13185e923d2eSSam Leffler */ 1319b032f27cSSam Leffler if ((m->m_flags & M_EAPOL) == 0 || 1320b032f27cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) && 1321b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_STA ? 1322cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(key) : 1323cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { 13245e923d2eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 1325b032f27cSSam Leffler if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { 1326b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, 1327b032f27cSSam Leffler eh.ether_dhost, 1328b032f27cSSam Leffler "%s", "enmic failed, discard frame"); 1329b032f27cSSam Leffler vap->iv_stats.is_crypto_enmicfail++; 13305e923d2eSSam Leffler goto bad; 13315e923d2eSSam Leffler } 13325e923d2eSSam Leffler } 13335e923d2eSSam Leffler } 1334b032f27cSSam Leffler if (txfrag && !ieee80211_fragment(vap, m, hdrsize, 1335b032f27cSSam Leffler key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) 133668e8e04eSSam Leffler goto bad; 13378a1b9b6aSSam Leffler 1338c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 1339c1af44bdSSam Leffler 13408a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 13419e80b1dfSSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1342b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 13439e80b1dfSSam Leffler m->m_flags |= M_MCAST; 13449e80b1dfSSam Leffler } else 1345b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 13468a1b9b6aSSam Leffler IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); 13478a1b9b6aSSam Leffler 13481a1e1d21SSam Leffler return m; 13490a915fadSSam Leffler bad: 13500a915fadSSam Leffler if (m != NULL) 13510a915fadSSam Leffler m_freem(m); 13520a915fadSSam Leffler return NULL; 1353b032f27cSSam Leffler #undef WH4 13541a1e1d21SSam Leffler } 13551a1e1d21SSam Leffler 13561a1e1d21SSam Leffler /* 135768e8e04eSSam Leffler * Fragment the frame according to the specified mtu. 135868e8e04eSSam Leffler * The size of the 802.11 header (w/o padding) is provided 135968e8e04eSSam Leffler * so we don't need to recalculate it. We create a new 136068e8e04eSSam Leffler * mbuf for each fragment and chain it through m_nextpkt; 136168e8e04eSSam Leffler * we might be able to optimize this by reusing the original 136268e8e04eSSam Leffler * packet's mbufs but that is significantly more complicated. 136368e8e04eSSam Leffler */ 136468e8e04eSSam Leffler static int 1365b032f27cSSam Leffler ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, 136668e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu) 136768e8e04eSSam Leffler { 136868e8e04eSSam Leffler struct ieee80211_frame *wh, *whf; 136968e8e04eSSam Leffler struct mbuf *m, *prev, *next; 137068e8e04eSSam Leffler u_int totalhdrsize, fragno, fragsize, off, remainder, payload; 137168e8e04eSSam Leffler 137268e8e04eSSam Leffler KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); 137368e8e04eSSam Leffler KASSERT(m0->m_pkthdr.len > mtu, 137468e8e04eSSam Leffler ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); 137568e8e04eSSam Leffler 137668e8e04eSSam Leffler wh = mtod(m0, struct ieee80211_frame *); 137768e8e04eSSam Leffler /* NB: mark the first frag; it will be propagated below */ 137868e8e04eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; 137968e8e04eSSam Leffler totalhdrsize = hdrsize + ciphdrsize; 138068e8e04eSSam Leffler fragno = 1; 138168e8e04eSSam Leffler off = mtu - ciphdrsize; 138268e8e04eSSam Leffler remainder = m0->m_pkthdr.len - off; 138368e8e04eSSam Leffler prev = m0; 138468e8e04eSSam Leffler do { 138568e8e04eSSam Leffler fragsize = totalhdrsize + remainder; 138668e8e04eSSam Leffler if (fragsize > mtu) 138768e8e04eSSam Leffler fragsize = mtu; 1388b032f27cSSam Leffler /* XXX fragsize can be >2048! */ 138968e8e04eSSam Leffler KASSERT(fragsize < MCLBYTES, 139068e8e04eSSam Leffler ("fragment size %u too big!", fragsize)); 139168e8e04eSSam Leffler if (fragsize > MHLEN) 139268e8e04eSSam Leffler m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 139368e8e04eSSam Leffler else 139468e8e04eSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 139568e8e04eSSam Leffler if (m == NULL) 139668e8e04eSSam Leffler goto bad; 139768e8e04eSSam Leffler /* leave room to prepend any cipher header */ 139868e8e04eSSam Leffler m_align(m, fragsize - ciphdrsize); 139968e8e04eSSam Leffler 140068e8e04eSSam Leffler /* 140168e8e04eSSam Leffler * Form the header in the fragment. Note that since 140268e8e04eSSam Leffler * we mark the first fragment with the MORE_FRAG bit 140368e8e04eSSam Leffler * it automatically is propagated to each fragment; we 140468e8e04eSSam Leffler * need only clear it on the last fragment (done below). 140568e8e04eSSam Leffler */ 140668e8e04eSSam Leffler whf = mtod(m, struct ieee80211_frame *); 140768e8e04eSSam Leffler memcpy(whf, wh, hdrsize); 140868e8e04eSSam Leffler *(uint16_t *)&whf->i_seq[0] |= htole16( 140968e8e04eSSam Leffler (fragno & IEEE80211_SEQ_FRAG_MASK) << 141068e8e04eSSam Leffler IEEE80211_SEQ_FRAG_SHIFT); 141168e8e04eSSam Leffler fragno++; 141268e8e04eSSam Leffler 141368e8e04eSSam Leffler payload = fragsize - totalhdrsize; 141468e8e04eSSam Leffler /* NB: destination is known to be contiguous */ 141568e8e04eSSam Leffler m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrsize); 141668e8e04eSSam Leffler m->m_len = hdrsize + payload; 141768e8e04eSSam Leffler m->m_pkthdr.len = hdrsize + payload; 141868e8e04eSSam Leffler m->m_flags |= M_FRAG; 141968e8e04eSSam Leffler 142068e8e04eSSam Leffler /* chain up the fragment */ 142168e8e04eSSam Leffler prev->m_nextpkt = m; 142268e8e04eSSam Leffler prev = m; 142368e8e04eSSam Leffler 142468e8e04eSSam Leffler /* deduct fragment just formed */ 142568e8e04eSSam Leffler remainder -= payload; 142668e8e04eSSam Leffler off += payload; 142768e8e04eSSam Leffler } while (remainder != 0); 142851cec121SWeongyo Jeong 142951cec121SWeongyo Jeong /* set the last fragment */ 143051cec121SWeongyo Jeong m->m_flags |= M_LASTFRAG; 143168e8e04eSSam Leffler whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; 143268e8e04eSSam Leffler 143368e8e04eSSam Leffler /* strip first mbuf now that everything has been copied */ 143468e8e04eSSam Leffler m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); 143568e8e04eSSam Leffler m0->m_flags |= M_FIRSTFRAG | M_FRAG; 143668e8e04eSSam Leffler 1437b032f27cSSam Leffler vap->iv_stats.is_tx_fragframes++; 1438b032f27cSSam Leffler vap->iv_stats.is_tx_frags += fragno-1; 143968e8e04eSSam Leffler 144068e8e04eSSam Leffler return 1; 144168e8e04eSSam Leffler bad: 144268e8e04eSSam Leffler /* reclaim fragments but leave original frame for caller to free */ 144368e8e04eSSam Leffler for (m = m0->m_nextpkt; m != NULL; m = next) { 144468e8e04eSSam Leffler next = m->m_nextpkt; 144568e8e04eSSam Leffler m->m_nextpkt = NULL; /* XXX paranoid */ 144668e8e04eSSam Leffler m_freem(m); 144768e8e04eSSam Leffler } 144868e8e04eSSam Leffler m0->m_nextpkt = NULL; 144968e8e04eSSam Leffler return 0; 145068e8e04eSSam Leffler } 145168e8e04eSSam Leffler 145268e8e04eSSam Leffler /* 14531a1e1d21SSam Leffler * Add a supported rates element id to a frame. 14541a1e1d21SSam Leffler */ 145559aa14a9SRui Paulo uint8_t * 145668e8e04eSSam Leffler ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 14571a1e1d21SSam Leffler { 14581a1e1d21SSam Leffler int nrates; 14591a1e1d21SSam Leffler 14601a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_RATES; 14611a1e1d21SSam Leffler nrates = rs->rs_nrates; 14621a1e1d21SSam Leffler if (nrates > IEEE80211_RATE_SIZE) 14631a1e1d21SSam Leffler nrates = IEEE80211_RATE_SIZE; 14641a1e1d21SSam Leffler *frm++ = nrates; 14651a1e1d21SSam Leffler memcpy(frm, rs->rs_rates, nrates); 14661a1e1d21SSam Leffler return frm + nrates; 14671a1e1d21SSam Leffler } 14681a1e1d21SSam Leffler 14691a1e1d21SSam Leffler /* 14701a1e1d21SSam Leffler * Add an extended supported rates element id to a frame. 14711a1e1d21SSam Leffler */ 147259aa14a9SRui Paulo uint8_t * 147368e8e04eSSam Leffler ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 14741a1e1d21SSam Leffler { 14751a1e1d21SSam Leffler /* 14761a1e1d21SSam Leffler * Add an extended supported rates element if operating in 11g mode. 14771a1e1d21SSam Leffler */ 14781a1e1d21SSam Leffler if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 14791a1e1d21SSam Leffler int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 14801a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_XRATES; 14811a1e1d21SSam Leffler *frm++ = nrates; 14821a1e1d21SSam Leffler memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 14831a1e1d21SSam Leffler frm += nrates; 14841a1e1d21SSam Leffler } 14851a1e1d21SSam Leffler return frm; 14861a1e1d21SSam Leffler } 14871a1e1d21SSam Leffler 14881a1e1d21SSam Leffler /* 1489b032f27cSSam Leffler * Add an ssid element to a frame. 14901a1e1d21SSam Leffler */ 149168e8e04eSSam Leffler static uint8_t * 149268e8e04eSSam Leffler ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) 14931a1e1d21SSam Leffler { 14941a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 14951a1e1d21SSam Leffler *frm++ = len; 14961a1e1d21SSam Leffler memcpy(frm, ssid, len); 14971a1e1d21SSam Leffler return frm + len; 14981a1e1d21SSam Leffler } 14991a1e1d21SSam Leffler 15008a1b9b6aSSam Leffler /* 15018a1b9b6aSSam Leffler * Add an erp element to a frame. 15028a1b9b6aSSam Leffler */ 150368e8e04eSSam Leffler static uint8_t * 150468e8e04eSSam Leffler ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) 15051a1e1d21SSam Leffler { 150668e8e04eSSam Leffler uint8_t erp; 15071a1e1d21SSam Leffler 15088a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_ERP; 15098a1b9b6aSSam Leffler *frm++ = 1; 15108a1b9b6aSSam Leffler erp = 0; 15118a1b9b6aSSam Leffler if (ic->ic_nonerpsta != 0) 15128a1b9b6aSSam Leffler erp |= IEEE80211_ERP_NON_ERP_PRESENT; 15138a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEPROT) 15148a1b9b6aSSam Leffler erp |= IEEE80211_ERP_USE_PROTECTION; 15158a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEBARKER) 15168a1b9b6aSSam Leffler erp |= IEEE80211_ERP_LONG_PREAMBLE; 15178a1b9b6aSSam Leffler *frm++ = erp; 15188a1b9b6aSSam Leffler return frm; 15191a1e1d21SSam Leffler } 15201a1e1d21SSam Leffler 15218a1b9b6aSSam Leffler /* 1522b032f27cSSam Leffler * Add a CFParams element to a frame. 15238a1b9b6aSSam Leffler */ 152468e8e04eSSam Leffler static uint8_t * 1525b032f27cSSam Leffler ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) 15268a1b9b6aSSam Leffler { 1527b032f27cSSam Leffler #define ADDSHORT(frm, v) do { \ 152859aa14a9SRui Paulo LE_WRITE_2(frm, v); \ 1529b032f27cSSam Leffler frm += 2; \ 1530b032f27cSSam Leffler } while (0) 1531b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_CFPARMS; 1532b032f27cSSam Leffler *frm++ = 6; 1533b032f27cSSam Leffler *frm++ = 0; /* CFP count */ 1534b032f27cSSam Leffler *frm++ = 2; /* CFP period */ 1535b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ 1536b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ 15378a1b9b6aSSam Leffler return frm; 1538b032f27cSSam Leffler #undef ADDSHORT 1539b032f27cSSam Leffler } 1540b032f27cSSam Leffler 1541b032f27cSSam Leffler static __inline uint8_t * 1542b032f27cSSam Leffler add_appie(uint8_t *frm, const struct ieee80211_appie *ie) 1543b032f27cSSam Leffler { 1544b032f27cSSam Leffler memcpy(frm, ie->ie_data, ie->ie_len); 1545b032f27cSSam Leffler return frm + ie->ie_len; 1546b032f27cSSam Leffler } 1547b032f27cSSam Leffler 1548b032f27cSSam Leffler static __inline uint8_t * 1549b032f27cSSam Leffler add_ie(uint8_t *frm, const uint8_t *ie) 1550b032f27cSSam Leffler { 1551b032f27cSSam Leffler memcpy(frm, ie, 2 + ie[1]); 1552b032f27cSSam Leffler return frm + 2 + ie[1]; 15538a1b9b6aSSam Leffler } 15548a1b9b6aSSam Leffler 15558a1b9b6aSSam Leffler #define WME_OUI_BYTES 0x00, 0x50, 0xf2 15568a1b9b6aSSam Leffler /* 15578a1b9b6aSSam Leffler * Add a WME information element to a frame. 15588a1b9b6aSSam Leffler */ 155968e8e04eSSam Leffler static uint8_t * 156068e8e04eSSam Leffler ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 15618a1b9b6aSSam Leffler { 15628a1b9b6aSSam Leffler static const struct ieee80211_wme_info info = { 15638a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 15648a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_info) - 2, 15658a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 15668a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 15678a1b9b6aSSam Leffler .wme_subtype = WME_INFO_OUI_SUBTYPE, 15688a1b9b6aSSam Leffler .wme_version = WME_VERSION, 15698a1b9b6aSSam Leffler .wme_info = 0, 15708a1b9b6aSSam Leffler }; 15718a1b9b6aSSam Leffler memcpy(frm, &info, sizeof(info)); 15728a1b9b6aSSam Leffler return frm + sizeof(info); 15738a1b9b6aSSam Leffler } 15748a1b9b6aSSam Leffler 15758a1b9b6aSSam Leffler /* 15768a1b9b6aSSam Leffler * Add a WME parameters element to a frame. 15778a1b9b6aSSam Leffler */ 157868e8e04eSSam Leffler static uint8_t * 157968e8e04eSSam Leffler ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 15808a1b9b6aSSam Leffler { 15818a1b9b6aSSam Leffler #define SM(_v, _f) (((_v) << _f##_S) & _f) 15828a1b9b6aSSam Leffler #define ADDSHORT(frm, v) do { \ 158359aa14a9SRui Paulo LE_WRITE_2(frm, v); \ 15848a1b9b6aSSam Leffler frm += 2; \ 15858a1b9b6aSSam Leffler } while (0) 15868a1b9b6aSSam Leffler /* NB: this works 'cuz a param has an info at the front */ 15878a1b9b6aSSam Leffler static const struct ieee80211_wme_info param = { 15888a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 15898a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_param) - 2, 15908a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 15918a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 15928a1b9b6aSSam Leffler .wme_subtype = WME_PARAM_OUI_SUBTYPE, 15938a1b9b6aSSam Leffler .wme_version = WME_VERSION, 15948a1b9b6aSSam Leffler }; 15958a1b9b6aSSam Leffler int i; 15968a1b9b6aSSam Leffler 15978a1b9b6aSSam Leffler memcpy(frm, ¶m, sizeof(param)); 15988a1b9b6aSSam Leffler frm += __offsetof(struct ieee80211_wme_info, wme_info); 15998a1b9b6aSSam Leffler *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 16008a1b9b6aSSam Leffler *frm++ = 0; /* reserved field */ 16018a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 16028a1b9b6aSSam Leffler const struct wmeParams *ac = 16038a1b9b6aSSam Leffler &wme->wme_bssChanParams.cap_wmeParams[i]; 16048a1b9b6aSSam Leffler *frm++ = SM(i, WME_PARAM_ACI) 16058a1b9b6aSSam Leffler | SM(ac->wmep_acm, WME_PARAM_ACM) 16068a1b9b6aSSam Leffler | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) 16078a1b9b6aSSam Leffler ; 16088a1b9b6aSSam Leffler *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 16098a1b9b6aSSam Leffler | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) 16108a1b9b6aSSam Leffler ; 16118a1b9b6aSSam Leffler ADDSHORT(frm, ac->wmep_txopLimit); 16128a1b9b6aSSam Leffler } 16138a1b9b6aSSam Leffler return frm; 16148a1b9b6aSSam Leffler #undef SM 16158a1b9b6aSSam Leffler #undef ADDSHORT 16168a1b9b6aSSam Leffler } 16178a1b9b6aSSam Leffler #undef WME_OUI_BYTES 16188a1b9b6aSSam Leffler 16190a915fadSSam Leffler /* 1620b032f27cSSam Leffler * Add an 11h Power Constraint element to a frame. 1621b032f27cSSam Leffler */ 1622b032f27cSSam Leffler static uint8_t * 1623b032f27cSSam Leffler ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) 1624b032f27cSSam Leffler { 1625b032f27cSSam Leffler const struct ieee80211_channel *c = vap->iv_bss->ni_chan; 1626b032f27cSSam Leffler /* XXX per-vap tx power limit? */ 1627b032f27cSSam Leffler int8_t limit = vap->iv_ic->ic_txpowlimit / 2; 1628b032f27cSSam Leffler 1629b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCNSTR; 1630b032f27cSSam Leffler frm[1] = 1; 1631b032f27cSSam Leffler frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; 1632b032f27cSSam Leffler return frm + 3; 1633b032f27cSSam Leffler } 1634b032f27cSSam Leffler 1635b032f27cSSam Leffler /* 1636b032f27cSSam Leffler * Add an 11h Power Capability element to a frame. 1637b032f27cSSam Leffler */ 1638b032f27cSSam Leffler static uint8_t * 1639b032f27cSSam Leffler ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) 1640b032f27cSSam Leffler { 1641b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCAP; 1642b032f27cSSam Leffler frm[1] = 2; 1643b032f27cSSam Leffler frm[2] = c->ic_minpower; 1644b032f27cSSam Leffler frm[3] = c->ic_maxpower; 1645b032f27cSSam Leffler return frm + 4; 1646b032f27cSSam Leffler } 1647b032f27cSSam Leffler 1648b032f27cSSam Leffler /* 1649b032f27cSSam Leffler * Add an 11h Supported Channels element to a frame. 1650b032f27cSSam Leffler */ 1651b032f27cSSam Leffler static uint8_t * 1652b032f27cSSam Leffler ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) 1653b032f27cSSam Leffler { 1654b032f27cSSam Leffler static const int ielen = 26; 1655b032f27cSSam Leffler 1656b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_SUPPCHAN; 1657b032f27cSSam Leffler frm[1] = ielen; 1658b032f27cSSam Leffler /* XXX not correct */ 1659b032f27cSSam Leffler memcpy(frm+2, ic->ic_chan_avail, ielen); 1660b032f27cSSam Leffler return frm + 2 + ielen; 1661b032f27cSSam Leffler } 1662b032f27cSSam Leffler 1663b032f27cSSam Leffler /* 1664b032f27cSSam Leffler * Add an 11h Channel Switch Announcement element to a frame. 1665b032f27cSSam Leffler * Note that we use the per-vap CSA count to adjust the global 1666b032f27cSSam Leffler * counter so we can use this routine to form probe response 1667b032f27cSSam Leffler * frames and get the current count. 1668b032f27cSSam Leffler */ 1669b032f27cSSam Leffler static uint8_t * 1670b032f27cSSam Leffler ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) 1671b032f27cSSam Leffler { 1672b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 1673b032f27cSSam Leffler struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; 1674b032f27cSSam Leffler 1675c70761e6SSam Leffler csa->csa_ie = IEEE80211_ELEMID_CSA; 1676b032f27cSSam Leffler csa->csa_len = 3; 1677b032f27cSSam Leffler csa->csa_mode = 1; /* XXX force quiet on channel */ 1678b032f27cSSam Leffler csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); 1679b032f27cSSam Leffler csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; 1680b032f27cSSam Leffler return frm + sizeof(*csa); 1681b032f27cSSam Leffler } 1682b032f27cSSam Leffler 1683b032f27cSSam Leffler /* 1684b032f27cSSam Leffler * Add an 11h country information element to a frame. 1685b032f27cSSam Leffler */ 1686b032f27cSSam Leffler static uint8_t * 1687b032f27cSSam Leffler ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) 1688b032f27cSSam Leffler { 1689b032f27cSSam Leffler 1690b032f27cSSam Leffler if (ic->ic_countryie == NULL || 1691b032f27cSSam Leffler ic->ic_countryie_chan != ic->ic_bsschan) { 1692b032f27cSSam Leffler /* 1693b032f27cSSam Leffler * Handle lazy construction of ie. This is done on 1694b032f27cSSam Leffler * first use and after a channel change that requires 1695b032f27cSSam Leffler * re-calculation. 1696b032f27cSSam Leffler */ 1697b032f27cSSam Leffler if (ic->ic_countryie != NULL) 1698b032f27cSSam Leffler free(ic->ic_countryie, M_80211_NODE_IE); 1699b032f27cSSam Leffler ic->ic_countryie = ieee80211_alloc_countryie(ic); 1700b032f27cSSam Leffler if (ic->ic_countryie == NULL) 1701b032f27cSSam Leffler return frm; 1702b032f27cSSam Leffler ic->ic_countryie_chan = ic->ic_bsschan; 1703b032f27cSSam Leffler } 1704b032f27cSSam Leffler return add_appie(frm, ic->ic_countryie); 1705b032f27cSSam Leffler } 1706b032f27cSSam Leffler 1707b032f27cSSam Leffler /* 1708af8418dcSSam Leffler * Send a probe request frame with the specified ssid 1709af8418dcSSam Leffler * and any optional information element data. 1710af8418dcSSam Leffler */ 1711af8418dcSSam Leffler int 1712af8418dcSSam Leffler ieee80211_send_probereq(struct ieee80211_node *ni, 171368e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 171468e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 171568e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN], 1716b032f27cSSam Leffler const uint8_t *ssid, size_t ssidlen) 1717af8418dcSSam Leffler { 1718b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1719af8418dcSSam Leffler struct ieee80211com *ic = ni->ni_ic; 172016d7cbb1SSam Leffler const struct ieee80211_txparam *tp; 172116d7cbb1SSam Leffler struct ieee80211_bpf_params params; 1722af8418dcSSam Leffler struct ieee80211_frame *wh; 172341b3c790SSam Leffler const struct ieee80211_rateset *rs; 1724af8418dcSSam Leffler struct mbuf *m; 172568e8e04eSSam Leffler uint8_t *frm; 1726af8418dcSSam Leffler 1727b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 1728b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 1729b032f27cSSam Leffler "block %s frame in CAC state", "probe request"); 1730b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 1731b032f27cSSam Leffler return EIO; /* XXX */ 1732b032f27cSSam Leffler } 1733b032f27cSSam Leffler 1734af8418dcSSam Leffler /* 1735af8418dcSSam Leffler * Hold a reference on the node so it doesn't go away until after 1736af8418dcSSam Leffler * the xmit is complete all the way in the driver. On error we 1737af8418dcSSam Leffler * will remove our reference. 1738af8418dcSSam Leffler */ 1739b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1740af8418dcSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 1741af8418dcSSam Leffler __func__, __LINE__, 1742af8418dcSSam Leffler ni, ether_sprintf(ni->ni_macaddr), 1743af8418dcSSam Leffler ieee80211_node_refcnt(ni)+1); 1744af8418dcSSam Leffler ieee80211_ref_node(ni); 1745af8418dcSSam Leffler 1746af8418dcSSam Leffler /* 1747af8418dcSSam Leffler * prreq frame format 1748af8418dcSSam Leffler * [tlv] ssid 1749af8418dcSSam Leffler * [tlv] supported rates 1750b032f27cSSam Leffler * [tlv] RSN (optional) 1751af8418dcSSam Leffler * [tlv] extended supported rates 1752b032f27cSSam Leffler * [tlv] WPA (optional) 1753af8418dcSSam Leffler * [tlv] user-specified ie's 1754af8418dcSSam Leffler */ 1755af8418dcSSam Leffler m = ieee80211_getmgtframe(&frm, 175668e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 1757af8418dcSSam Leffler 2 + IEEE80211_NWID_LEN 1758af8418dcSSam Leffler + 2 + IEEE80211_RATE_SIZE 1759b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 1760af8418dcSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1761b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 1762b032f27cSSam Leffler + (vap->iv_appie_probereq != NULL ? 1763b032f27cSSam Leffler vap->iv_appie_probereq->ie_len : 0) 1764af8418dcSSam Leffler ); 1765af8418dcSSam Leffler if (m == NULL) { 1766b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 1767af8418dcSSam Leffler ieee80211_free_node(ni); 1768af8418dcSSam Leffler return ENOMEM; 1769af8418dcSSam Leffler } 1770af8418dcSSam Leffler 1771af8418dcSSam Leffler frm = ieee80211_add_ssid(frm, ssid, ssidlen); 177241b3c790SSam Leffler rs = ieee80211_get_suprates(ic, ic->ic_curchan); 177341b3c790SSam Leffler frm = ieee80211_add_rates(frm, rs); 1774b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 1775b032f27cSSam Leffler if (vap->iv_rsn_ie != NULL) 1776b032f27cSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 1777b032f27cSSam Leffler /* XXX else complain? */ 1778af8418dcSSam Leffler } 1779b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 1780b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 1781b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 1782b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 1783b032f27cSSam Leffler /* XXX else complain? */ 1784b032f27cSSam Leffler } 1785b032f27cSSam Leffler if (vap->iv_appie_probereq != NULL) 1786b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_probereq); 178768e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 1788af8418dcSSam Leffler 178916d7cbb1SSam Leffler KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), 179016d7cbb1SSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 1791af8418dcSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 179216d7cbb1SSam Leffler if (m == NULL) { 179316d7cbb1SSam Leffler /* NB: cannot happen */ 179416d7cbb1SSam Leffler ieee80211_free_node(ni); 1795af8418dcSSam Leffler return ENOMEM; 179616d7cbb1SSam Leffler } 1797af8418dcSSam Leffler 1798af8418dcSSam Leffler wh = mtod(m, struct ieee80211_frame *); 17999e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 1800af8418dcSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 18018ac160cdSSam Leffler IEEE80211_NONQOS_TID, sa, da, bssid); 1802af8418dcSSam Leffler /* XXX power management? */ 1803c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 1804af8418dcSSam Leffler 1805b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 1806b032f27cSSam Leffler 1807af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_probereq); 1808af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 1809af8418dcSSam Leffler 1810b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 1811b032f27cSSam Leffler "send probe req on channel %u bssid %s ssid \"%.*s\"\n", 1812b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid), 1813b032f27cSSam Leffler ssidlen, ssid); 1814af8418dcSSam Leffler 181516d7cbb1SSam Leffler memset(¶ms, 0, sizeof(params)); 181616d7cbb1SSam Leffler params.ibp_pri = M_WME_GETAC(m); 181716d7cbb1SSam Leffler tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 181816d7cbb1SSam Leffler params.ibp_rate0 = tp->mgmtrate; 181916d7cbb1SSam Leffler if (IEEE80211_IS_MULTICAST(da)) { 182016d7cbb1SSam Leffler params.ibp_flags |= IEEE80211_BPF_NOACK; 182116d7cbb1SSam Leffler params.ibp_try0 = 1; 182216d7cbb1SSam Leffler } else 182316d7cbb1SSam Leffler params.ibp_try0 = tp->maxretry; 182416d7cbb1SSam Leffler params.ibp_power = ni->ni_txpower; 182516d7cbb1SSam Leffler return ic->ic_raw_xmit(ni, m, ¶ms); 1826af8418dcSSam Leffler } 1827af8418dcSSam Leffler 1828af8418dcSSam Leffler /* 1829667dad55SSam Leffler * Calculate capability information for mgt frames. 1830667dad55SSam Leffler */ 183159aa14a9SRui Paulo uint16_t 183259aa14a9SRui Paulo ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) 1833667dad55SSam Leffler { 1834b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 183568e8e04eSSam Leffler uint16_t capinfo; 1836667dad55SSam Leffler 1837b032f27cSSam Leffler KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); 1838667dad55SSam Leffler 1839b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) 1840667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 1841b032f27cSSam Leffler else if (vap->iv_opmode == IEEE80211_M_IBSS) 1842667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_IBSS; 1843667dad55SSam Leffler else 1844667dad55SSam Leffler capinfo = 0; 1845b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 1846667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 1847667dad55SSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 1848667dad55SSam Leffler IEEE80211_IS_CHAN_2GHZ(chan)) 1849667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 1850667dad55SSam Leffler if (ic->ic_flags & IEEE80211_F_SHSLOT) 1851667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 1852b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) 1853b032f27cSSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 1854667dad55SSam Leffler return capinfo; 1855667dad55SSam Leffler } 1856667dad55SSam Leffler 1857667dad55SSam Leffler /* 18580a915fadSSam Leffler * Send a management frame. The node is for the destination (or ic_bss 18590a915fadSSam Leffler * when in station mode). Nodes other than ic_bss have their reference 18600a915fadSSam Leffler * count bumped to reflect our use for an indeterminant time. 18610a915fadSSam Leffler */ 18621a1e1d21SSam Leffler int 1863b032f27cSSam Leffler ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) 18641a1e1d21SSam Leffler { 18651b6167d2SSam Leffler #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) 1866b032f27cSSam Leffler #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) 1867b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1868b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 1869b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 18708ac160cdSSam Leffler struct ieee80211_bpf_params params; 18711a1e1d21SSam Leffler struct mbuf *m; 187268e8e04eSSam Leffler uint8_t *frm; 187368e8e04eSSam Leffler uint16_t capinfo; 187468e8e04eSSam Leffler int has_challenge, is_shared_key, ret, status; 18751a1e1d21SSam Leffler 18760a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 18770a915fadSSam Leffler 18780a915fadSSam Leffler /* 18790a915fadSSam Leffler * Hold a reference on the node so it doesn't go away until after 18800a915fadSSam Leffler * the xmit is complete all the way in the driver. On error we 18810a915fadSSam Leffler * will remove our reference. 18820a915fadSSam Leffler */ 1883b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 188449a15236SSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 18858a1b9b6aSSam Leffler __func__, __LINE__, 188649a15236SSam Leffler ni, ether_sprintf(ni->ni_macaddr), 18878a1b9b6aSSam Leffler ieee80211_node_refcnt(ni)+1); 18880a915fadSSam Leffler ieee80211_ref_node(ni); 18898a1b9b6aSSam Leffler 18908ac160cdSSam Leffler memset(¶ms, 0, sizeof(params)); 18911a1e1d21SSam Leffler switch (type) { 18921a1e1d21SSam Leffler 18931a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 18948a1b9b6aSSam Leffler status = arg >> 16; 18958a1b9b6aSSam Leffler arg &= 0xffff; 18968a1b9b6aSSam Leffler has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 18978a1b9b6aSSam Leffler arg == IEEE80211_AUTH_SHARED_RESPONSE) && 18988a1b9b6aSSam Leffler ni->ni_challenge != NULL); 18998a1b9b6aSSam Leffler 19008a1b9b6aSSam Leffler /* 19018a1b9b6aSSam Leffler * Deduce whether we're doing open authentication or 19028a1b9b6aSSam Leffler * shared key authentication. We do the latter if 19038a1b9b6aSSam Leffler * we're in the middle of a shared key authentication 19048a1b9b6aSSam Leffler * handshake or if we're initiating an authentication 19058a1b9b6aSSam Leffler * request and configured to use shared key. 19068a1b9b6aSSam Leffler */ 19078a1b9b6aSSam Leffler is_shared_key = has_challenge || 19088a1b9b6aSSam Leffler arg >= IEEE80211_AUTH_SHARED_RESPONSE || 19098a1b9b6aSSam Leffler (arg == IEEE80211_AUTH_SHARED_REQUEST && 1910b032f27cSSam Leffler bss->ni_authmode == IEEE80211_AUTH_SHARED); 19118a1b9b6aSSam Leffler 19128a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 191368e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 191468e8e04eSSam Leffler 3 * sizeof(uint16_t) 19158a1b9b6aSSam Leffler + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 191668e8e04eSSam Leffler sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) 19178a1b9b6aSSam Leffler ); 19181a1e1d21SSam Leffler if (m == NULL) 19198a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 19208a1b9b6aSSam Leffler 192168e8e04eSSam Leffler ((uint16_t *)frm)[0] = 19228a1b9b6aSSam Leffler (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) 19238a1b9b6aSSam Leffler : htole16(IEEE80211_AUTH_ALG_OPEN); 192468e8e04eSSam Leffler ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ 192568e8e04eSSam Leffler ((uint16_t *)frm)[2] = htole16(status);/* status */ 19268a1b9b6aSSam Leffler 19278a1b9b6aSSam Leffler if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 192868e8e04eSSam Leffler ((uint16_t *)frm)[3] = 19298a1b9b6aSSam Leffler htole16((IEEE80211_CHALLENGE_LEN << 8) | 19308a1b9b6aSSam Leffler IEEE80211_ELEMID_CHALLENGE); 193168e8e04eSSam Leffler memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, 19328a1b9b6aSSam Leffler IEEE80211_CHALLENGE_LEN); 19338a1b9b6aSSam Leffler m->m_pkthdr.len = m->m_len = 193468e8e04eSSam Leffler 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; 19358a1b9b6aSSam Leffler if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { 1936b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1937b032f27cSSam Leffler "request encrypt frame (%s)", __func__); 19388ac160cdSSam Leffler /* mark frame for encryption */ 19398ac160cdSSam Leffler params.ibp_flags |= IEEE80211_BPF_CRYPTO; 19408a1b9b6aSSam Leffler } 19418a1b9b6aSSam Leffler } else 194268e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); 19438a1b9b6aSSam Leffler 19448a1b9b6aSSam Leffler /* XXX not right for shared key */ 19458a1b9b6aSSam Leffler if (status == IEEE80211_STATUS_SUCCESS) 19468a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth); 19478a1b9b6aSSam Leffler else 19488a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth_fail); 19498a1b9b6aSSam Leffler 1950b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA) 195168e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 1952b032f27cSSam Leffler (void *) vap->iv_state); 19531a1e1d21SSam Leffler break; 19541a1e1d21SSam Leffler 19551a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 1956b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1957b032f27cSSam Leffler "send station deauthenticate (reason %d)", arg); 195868e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 195968e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 196068e8e04eSSam Leffler sizeof(uint16_t)); 19611a1e1d21SSam Leffler if (m == NULL) 19628a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 196368e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 196468e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 19658a1b9b6aSSam Leffler 19668a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_deauth); 19678a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); 19688a1b9b6aSSam Leffler 1969e4918ecdSSam Leffler ieee80211_node_unauthorize(ni); /* port closed */ 19701a1e1d21SSam Leffler break; 19711a1e1d21SSam Leffler 19721a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 19731a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 19741a1e1d21SSam Leffler /* 19751a1e1d21SSam Leffler * asreq frame format 19761a1e1d21SSam Leffler * [2] capability information 19771a1e1d21SSam Leffler * [2] listen interval 19781a1e1d21SSam Leffler * [6*] current AP address (reassoc only) 19791a1e1d21SSam Leffler * [tlv] ssid 19801a1e1d21SSam Leffler * [tlv] supported rates 19811a1e1d21SSam Leffler * [tlv] extended supported rates 1982b032f27cSSam Leffler * [4] power capability (optional) 1983b032f27cSSam Leffler * [28] supported channels (optional) 198468e8e04eSSam Leffler * [tlv] HT capabilities 1985b032f27cSSam Leffler * [tlv] WME (optional) 198668e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 198768e8e04eSSam Leffler * [tlv] Atheros capabilities (if negotiated) 1988b032f27cSSam Leffler * [tlv] AppIE's (optional) 19891a1e1d21SSam Leffler */ 19908a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 199168e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 199268e8e04eSSam Leffler sizeof(uint16_t) 199368e8e04eSSam Leffler + sizeof(uint16_t) 19941a1e1d21SSam Leffler + IEEE80211_ADDR_LEN 19958a1b9b6aSSam Leffler + 2 + IEEE80211_NWID_LEN 19961a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 19978a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1998b032f27cSSam Leffler + 4 1999b032f27cSSam Leffler + 2 + 26 20008a1b9b6aSSam Leffler + sizeof(struct ieee80211_wme_info) 2001b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 2002b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 2003616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 200468e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2005616190d0SSam Leffler #endif 2006b032f27cSSam Leffler + (vap->iv_appie_wpa != NULL ? 2007b032f27cSSam Leffler vap->iv_appie_wpa->ie_len : 0) 2008b032f27cSSam Leffler + (vap->iv_appie_assocreq != NULL ? 2009b032f27cSSam Leffler vap->iv_appie_assocreq->ie_len : 0) 20108a1b9b6aSSam Leffler ); 20111a1e1d21SSam Leffler if (m == NULL) 20128a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 20131a1e1d21SSam Leffler 2014b032f27cSSam Leffler KASSERT(vap->iv_opmode == IEEE80211_M_STA, 2015b032f27cSSam Leffler ("wrong mode %u", vap->iv_opmode)); 2016667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 2017b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 20181a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 20194f2e09c4SSam Leffler /* 20204f2e09c4SSam Leffler * NB: Some 11a AP's reject the request when 20214f2e09c4SSam Leffler * short premable is set. 20224f2e09c4SSam Leffler */ 20234f2e09c4SSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 2024b5c99415SSam Leffler IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 20251a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 202668e8e04eSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 20278a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHSLOT)) 20281a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 20291b6167d2SSam Leffler if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && 2030b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_DOTH)) 20311b6167d2SSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 203268e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 20331a1e1d21SSam Leffler frm += 2; 20341a1e1d21SSam Leffler 2035b032f27cSSam Leffler KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); 203668e8e04eSSam Leffler *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, 2037b032f27cSSam Leffler bss->ni_intval)); 20381a1e1d21SSam Leffler frm += 2; 20391a1e1d21SSam Leffler 20401a1e1d21SSam Leffler if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 2041b032f27cSSam Leffler IEEE80211_ADDR_COPY(frm, bss->ni_bssid); 20421a1e1d21SSam Leffler frm += IEEE80211_ADDR_LEN; 20431a1e1d21SSam Leffler } 20441a1e1d21SSam Leffler 20451a1e1d21SSam Leffler frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 20461a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 2047b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2048b032f27cSSam Leffler if (vap->iv_rsn_ie != NULL) 2049b032f27cSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2050b032f27cSSam Leffler /* XXX else complain? */ 20518a1b9b6aSSam Leffler } 2052b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 2053b032f27cSSam Leffler if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { 2054b032f27cSSam Leffler frm = ieee80211_add_powercapability(frm, 2055b032f27cSSam Leffler ic->ic_curchan); 2056b032f27cSSam Leffler frm = ieee80211_add_supportedchannels(frm, ic); 2057b032f27cSSam Leffler } 20582bfc8a91SSam Leffler if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 2059b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2060b032f27cSSam Leffler ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 2061b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, ni); 2062b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2063b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2064b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2065b032f27cSSam Leffler /* XXX else complain */ 2066b032f27cSSam Leffler } 2067b032f27cSSam Leffler if ((ic->ic_flags & IEEE80211_F_WME) && 2068b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 2069b032f27cSSam Leffler frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 20702bfc8a91SSam Leffler if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 2071b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2072b032f27cSSam Leffler ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 2073b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 2074616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 20754207227cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { 2076b032f27cSSam Leffler frm = ieee80211_add_ath(frm, 2077b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 20784207227cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 20794207227cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X) ? 20804207227cSSam Leffler vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 20814207227cSSam Leffler } 2082616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 2083b032f27cSSam Leffler if (vap->iv_appie_assocreq != NULL) 2084b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocreq); 208568e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 20861a1e1d21SSam Leffler 208768e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 2088b032f27cSSam Leffler (void *) vap->iv_state); 20891a1e1d21SSam Leffler break; 20901a1e1d21SSam Leffler 20911a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 20921a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 20931a1e1d21SSam Leffler /* 209468e8e04eSSam Leffler * asresp frame format 20951a1e1d21SSam Leffler * [2] capability information 20961a1e1d21SSam Leffler * [2] status 20971a1e1d21SSam Leffler * [2] association ID 20981a1e1d21SSam Leffler * [tlv] supported rates 20991a1e1d21SSam Leffler * [tlv] extended supported rates 2100b032f27cSSam Leffler * [tlv] HT capabilities (standard, if STA enabled) 2101b032f27cSSam Leffler * [tlv] HT information (standard, if STA enabled) 2102b032f27cSSam Leffler * [tlv] WME (if configured and STA enabled) 2103b032f27cSSam Leffler * [tlv] HT capabilities (vendor OUI, if STA enabled) 2104b032f27cSSam Leffler * [tlv] HT information (vendor OUI, if STA enabled) 2105b032f27cSSam Leffler * [tlv] Atheros capabilities (if STA enabled) 2106b032f27cSSam Leffler * [tlv] AppIE's (optional) 21071a1e1d21SSam Leffler */ 21088a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 210968e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 211068e8e04eSSam Leffler sizeof(uint16_t) 211168e8e04eSSam Leffler + sizeof(uint16_t) 211268e8e04eSSam Leffler + sizeof(uint16_t) 21131a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 21148a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 211568e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htcap) + 4 211668e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htinfo) + 4 2117b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 2118616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 211968e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2120616190d0SSam Leffler #endif 2121b032f27cSSam Leffler + (vap->iv_appie_assocresp != NULL ? 2122b032f27cSSam Leffler vap->iv_appie_assocresp->ie_len : 0) 21238a1b9b6aSSam Leffler ); 21241a1e1d21SSam Leffler if (m == NULL) 21258a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 21261a1e1d21SSam Leffler 212759aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 212868e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 21291a1e1d21SSam Leffler frm += 2; 21301a1e1d21SSam Leffler 213168e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* status */ 21321a1e1d21SSam Leffler frm += 2; 21331a1e1d21SSam Leffler 21348a1b9b6aSSam Leffler if (arg == IEEE80211_STATUS_SUCCESS) { 213568e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_associd); 21368a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc); 21378a1b9b6aSSam Leffler } else 21388a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc_fail); 21391a1e1d21SSam Leffler frm += 2; 21401a1e1d21SSam Leffler 21411a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 21421a1e1d21SSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 214368e8e04eSSam Leffler /* NB: respond according to what we received */ 21441b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { 214568e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 214668e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 214768e8e04eSSam Leffler } 2148b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_WME) && 2149b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 21501b6167d2SSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 21511b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { 21521b6167d2SSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 21531b6167d2SSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 215468e8e04eSSam Leffler } 2155616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 2156b032f27cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 215768e8e04eSSam Leffler frm = ieee80211_add_ath(frm, 2158b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 21594207227cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 21604207227cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X) ? 21614207227cSSam Leffler vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 2162616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 2163b032f27cSSam Leffler if (vap->iv_appie_assocresp != NULL) 2164b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocresp); 216568e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 21661a1e1d21SSam Leffler break; 21671a1e1d21SSam Leffler 21681a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DISASSOC: 2169b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 2170b032f27cSSam Leffler "send station disassociate (reason %d)", arg); 217168e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 217268e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 217368e8e04eSSam Leffler sizeof(uint16_t)); 21741a1e1d21SSam Leffler if (m == NULL) 21758a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 217668e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 217768e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 21788a1b9b6aSSam Leffler 21798a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_disassoc); 21808a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); 21811a1e1d21SSam Leffler break; 21821a1e1d21SSam Leffler 21831a1e1d21SSam Leffler default: 2184b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 2185b032f27cSSam Leffler "invalid mgmt frame type %u", type); 21861be50176SSam Leffler senderr(EINVAL, is_tx_unknownmgt); 21870a915fadSSam Leffler /* NOTREACHED */ 21881a1e1d21SSam Leffler } 218968e8e04eSSam Leffler 21908ac160cdSSam Leffler /* NB: force non-ProbeResp frames to the highest queue */ 21918ac160cdSSam Leffler params.ibp_pri = WME_AC_VO; 21928ac160cdSSam Leffler params.ibp_rate0 = bss->ni_txparms->mgmtrate; 21938ac160cdSSam Leffler /* NB: we know all frames are unicast */ 21948ac160cdSSam Leffler params.ibp_try0 = bss->ni_txparms->maxretry; 21958ac160cdSSam Leffler params.ibp_power = bss->ni_txpower; 21968ac160cdSSam Leffler return ieee80211_mgmt_output(ni, m, type, ¶ms); 21970a915fadSSam Leffler bad: 21988a1b9b6aSSam Leffler ieee80211_free_node(ni); 21991a1e1d21SSam Leffler return ret; 22000a915fadSSam Leffler #undef senderr 22011b6167d2SSam Leffler #undef HTFLAGS 22021a1e1d21SSam Leffler } 22038a1b9b6aSSam Leffler 2204b032f27cSSam Leffler /* 2205b032f27cSSam Leffler * Return an mbuf with a probe response frame in it. 2206b032f27cSSam Leffler * Space is left to prepend and 802.11 header at the 2207b032f27cSSam Leffler * front but it's left to the caller to fill in. 2208b032f27cSSam Leffler */ 2209b032f27cSSam Leffler struct mbuf * 2210b032f27cSSam Leffler ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) 2211b032f27cSSam Leffler { 2212b032f27cSSam Leffler struct ieee80211vap *vap = bss->ni_vap; 2213b032f27cSSam Leffler struct ieee80211com *ic = bss->ni_ic; 2214b032f27cSSam Leffler const struct ieee80211_rateset *rs; 2215b032f27cSSam Leffler struct mbuf *m; 2216b032f27cSSam Leffler uint16_t capinfo; 2217b032f27cSSam Leffler uint8_t *frm; 2218b032f27cSSam Leffler 2219b032f27cSSam Leffler /* 2220b032f27cSSam Leffler * probe response frame format 2221b032f27cSSam Leffler * [8] time stamp 2222b032f27cSSam Leffler * [2] beacon interval 2223b032f27cSSam Leffler * [2] cabability information 2224b032f27cSSam Leffler * [tlv] ssid 2225b032f27cSSam Leffler * [tlv] supported rates 2226b032f27cSSam Leffler * [tlv] parameter set (FH/DS) 2227b032f27cSSam Leffler * [tlv] parameter set (IBSS) 2228b032f27cSSam Leffler * [tlv] country (optional) 2229b032f27cSSam Leffler * [3] power control (optional) 2230b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 2231b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 2232b032f27cSSam Leffler * [tlv] extended supported rates 2233688fe74dSSam Leffler * [tlv] RSN (optional) 2234b032f27cSSam Leffler * [tlv] HT capabilities 2235b032f27cSSam Leffler * [tlv] HT information 2236b032f27cSSam Leffler * [tlv] WPA (optional) 2237b032f27cSSam Leffler * [tlv] WME (optional) 2238b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 2239b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 2240b032f27cSSam Leffler * [tlv] Atheros capabilities 2241b032f27cSSam Leffler * [tlv] AppIE's (optional) 224259aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 224359aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2244b032f27cSSam Leffler */ 2245b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 2246b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 2247b032f27cSSam Leffler 8 2248b032f27cSSam Leffler + sizeof(uint16_t) 2249b032f27cSSam Leffler + sizeof(uint16_t) 2250b032f27cSSam Leffler + 2 + IEEE80211_NWID_LEN 2251b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE 2252b032f27cSSam Leffler + 7 /* max(7,3) */ 2253b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE 2254b032f27cSSam Leffler + 3 2255b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) 2256b032f27cSSam Leffler + 3 2257b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2258688fe74dSSam Leffler + sizeof(struct ieee80211_ie_wpa) 2259b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 2260b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htinfo) 2261b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 2262b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 2263b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 2264b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htinfo) 2265616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 2266b032f27cSSam Leffler + sizeof(struct ieee80211_ath_ie) 2267616190d0SSam Leffler #endif 226859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 226959aa14a9SRui Paulo + 2 + IEEE80211_MESHID_LEN 227059aa14a9SRui Paulo + sizeof(struct ieee80211_meshconf_ie) 227159aa14a9SRui Paulo #endif 2272b032f27cSSam Leffler + (vap->iv_appie_proberesp != NULL ? 2273b032f27cSSam Leffler vap->iv_appie_proberesp->ie_len : 0) 2274b032f27cSSam Leffler ); 2275b032f27cSSam Leffler if (m == NULL) { 2276b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 2277b032f27cSSam Leffler return NULL; 2278b032f27cSSam Leffler } 2279b032f27cSSam Leffler 2280b032f27cSSam Leffler memset(frm, 0, 8); /* timestamp should be filled later */ 2281b032f27cSSam Leffler frm += 8; 2282b032f27cSSam Leffler *(uint16_t *)frm = htole16(bss->ni_intval); 2283b032f27cSSam Leffler frm += 2; 228459aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 2285b032f27cSSam Leffler *(uint16_t *)frm = htole16(capinfo); 2286b032f27cSSam Leffler frm += 2; 2287b032f27cSSam Leffler 2288b032f27cSSam Leffler frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); 2289b032f27cSSam Leffler rs = ieee80211_get_suprates(ic, bss->ni_chan); 2290b032f27cSSam Leffler frm = ieee80211_add_rates(frm, rs); 2291b032f27cSSam Leffler 2292b032f27cSSam Leffler if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { 2293b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_FHPARMS; 2294b032f27cSSam Leffler *frm++ = 5; 2295b032f27cSSam Leffler *frm++ = bss->ni_fhdwell & 0x00ff; 2296b032f27cSSam Leffler *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; 2297b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANSET( 2298b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 2299b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANPAT( 2300b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 2301b032f27cSSam Leffler *frm++ = bss->ni_fhindex; 2302b032f27cSSam Leffler } else { 2303b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 2304b032f27cSSam Leffler *frm++ = 1; 2305b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); 2306b032f27cSSam Leffler } 2307b032f27cSSam Leffler 2308b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 2309b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 2310b032f27cSSam Leffler *frm++ = 2; 2311b032f27cSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 2312b032f27cSSam Leffler } 2313b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 2314b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2315b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 2316b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 2317b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) 2318b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 2319b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2320b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 2321b032f27cSSam Leffler } 2322b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) 2323b032f27cSSam Leffler frm = ieee80211_add_erp(frm, ic); 2324b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2325688fe74dSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2326688fe74dSSam Leffler if (vap->iv_rsn_ie != NULL) 2327688fe74dSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2328688fe74dSSam Leffler /* XXX else complain? */ 2329688fe74dSSam Leffler } 2330b032f27cSSam Leffler /* 2331b032f27cSSam Leffler * NB: legacy 11b clients do not get certain ie's. 2332b032f27cSSam Leffler * The caller identifies such clients by passing 2333b032f27cSSam Leffler * a token in legacy to us. Could expand this to be 2334b032f27cSSam Leffler * any legacy client for stuff like HT ie's. 2335b032f27cSSam Leffler */ 2336b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 2337b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 2338b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, bss); 2339b032f27cSSam Leffler frm = ieee80211_add_htinfo(frm, bss); 2340b032f27cSSam Leffler } 2341b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2342b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2343b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2344b032f27cSSam Leffler /* XXX else complain? */ 2345b032f27cSSam Leffler } 2346b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) 2347b032f27cSSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 2348b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 23492bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) && 2350b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 2351b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, bss); 2352b032f27cSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, bss); 2353b032f27cSSam Leffler } 2354616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 23554207227cSSam Leffler if ((vap->iv_flags & IEEE80211_F_ATHEROS) && 23564207227cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) 23574207227cSSam Leffler frm = ieee80211_add_athcaps(frm, bss); 2358616190d0SSam Leffler #endif 2359b032f27cSSam Leffler if (vap->iv_appie_proberesp != NULL) 2360b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_proberesp); 236159aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 236259aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 236359aa14a9SRui Paulo frm = ieee80211_add_meshid(frm, vap); 236459aa14a9SRui Paulo frm = ieee80211_add_meshconf(frm, vap); 236559aa14a9SRui Paulo } 236659aa14a9SRui Paulo #endif 2367b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2368b032f27cSSam Leffler 2369b032f27cSSam Leffler return m; 2370b032f27cSSam Leffler } 2371b032f27cSSam Leffler 2372b032f27cSSam Leffler /* 2373b032f27cSSam Leffler * Send a probe response frame to the specified mac address. 2374b032f27cSSam Leffler * This does not go through the normal mgt frame api so we 2375b032f27cSSam Leffler * can specify the destination address and re-use the bss node 2376b032f27cSSam Leffler * for the sta reference. 2377b032f27cSSam Leffler */ 2378b032f27cSSam Leffler int 2379b032f27cSSam Leffler ieee80211_send_proberesp(struct ieee80211vap *vap, 2380b032f27cSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], int legacy) 2381b032f27cSSam Leffler { 2382b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 2383b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 2384b032f27cSSam Leffler struct ieee80211_frame *wh; 2385b032f27cSSam Leffler struct mbuf *m; 2386b032f27cSSam Leffler 2387b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 2388b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, 2389b032f27cSSam Leffler "block %s frame in CAC state", "probe response"); 2390b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 2391b032f27cSSam Leffler return EIO; /* XXX */ 2392b032f27cSSam Leffler } 2393b032f27cSSam Leffler 2394b032f27cSSam Leffler /* 2395b032f27cSSam Leffler * Hold a reference on the node so it doesn't go away until after 2396b032f27cSSam Leffler * the xmit is complete all the way in the driver. On error we 2397b032f27cSSam Leffler * will remove our reference. 2398b032f27cSSam Leffler */ 2399b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 2400b032f27cSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2401b032f27cSSam Leffler __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), 2402b032f27cSSam Leffler ieee80211_node_refcnt(bss)+1); 2403b032f27cSSam Leffler ieee80211_ref_node(bss); 2404b032f27cSSam Leffler 2405b032f27cSSam Leffler m = ieee80211_alloc_proberesp(bss, legacy); 2406b032f27cSSam Leffler if (m == NULL) { 2407b032f27cSSam Leffler ieee80211_free_node(bss); 2408b032f27cSSam Leffler return ENOMEM; 2409b032f27cSSam Leffler } 2410b032f27cSSam Leffler 2411b032f27cSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 2412b032f27cSSam Leffler KASSERT(m != NULL, ("no room for header")); 2413b032f27cSSam Leffler 2414b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 24159e80b1dfSSam Leffler ieee80211_send_setup(bss, m, 2416b032f27cSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, 24178ac160cdSSam Leffler IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); 2418b032f27cSSam Leffler /* XXX power management? */ 2419c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 2420b032f27cSSam Leffler 2421b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 2422b032f27cSSam Leffler 2423b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 2424b032f27cSSam Leffler "send probe resp on channel %u to %s%s\n", 2425b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), 2426b032f27cSSam Leffler legacy ? " <legacy>" : ""); 2427b032f27cSSam Leffler IEEE80211_NODE_STAT(bss, tx_mgmt); 2428b032f27cSSam Leffler 2429b032f27cSSam Leffler return ic->ic_raw_xmit(bss, m, NULL); 2430b032f27cSSam Leffler } 2431b032f27cSSam Leffler 2432b032f27cSSam Leffler /* 2433b032f27cSSam Leffler * Allocate and build a RTS (Request To Send) control frame. 2434b032f27cSSam Leffler */ 2435b032f27cSSam Leffler struct mbuf * 2436b032f27cSSam Leffler ieee80211_alloc_rts(struct ieee80211com *ic, 2437b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], 2438b032f27cSSam Leffler const uint8_t ta[IEEE80211_ADDR_LEN], 2439b032f27cSSam Leffler uint16_t dur) 2440b032f27cSSam Leffler { 2441b032f27cSSam Leffler struct ieee80211_frame_rts *rts; 2442b032f27cSSam Leffler struct mbuf *m; 2443b032f27cSSam Leffler 2444b032f27cSSam Leffler /* XXX honor ic_headroom */ 2445b032f27cSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 2446b032f27cSSam Leffler if (m != NULL) { 2447b032f27cSSam Leffler rts = mtod(m, struct ieee80211_frame_rts *); 2448b032f27cSSam Leffler rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2449b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; 2450b032f27cSSam Leffler rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2451b032f27cSSam Leffler *(u_int16_t *)rts->i_dur = htole16(dur); 2452b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ra, ra); 2453b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ta, ta); 2454b032f27cSSam Leffler 2455b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); 2456b032f27cSSam Leffler } 2457b032f27cSSam Leffler return m; 2458b032f27cSSam Leffler } 2459b032f27cSSam Leffler 2460b032f27cSSam Leffler /* 2461b032f27cSSam Leffler * Allocate and build a CTS (Clear To Send) control frame. 2462b032f27cSSam Leffler */ 2463b032f27cSSam Leffler struct mbuf * 2464b032f27cSSam Leffler ieee80211_alloc_cts(struct ieee80211com *ic, 2465b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) 2466b032f27cSSam Leffler { 2467b032f27cSSam Leffler struct ieee80211_frame_cts *cts; 2468b032f27cSSam Leffler struct mbuf *m; 2469b032f27cSSam Leffler 2470b032f27cSSam Leffler /* XXX honor ic_headroom */ 2471b032f27cSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 2472b032f27cSSam Leffler if (m != NULL) { 2473b032f27cSSam Leffler cts = mtod(m, struct ieee80211_frame_cts *); 2474b032f27cSSam Leffler cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2475b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; 2476b032f27cSSam Leffler cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2477b032f27cSSam Leffler *(u_int16_t *)cts->i_dur = htole16(dur); 2478b032f27cSSam Leffler IEEE80211_ADDR_COPY(cts->i_ra, ra); 2479b032f27cSSam Leffler 2480b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); 2481b032f27cSSam Leffler } 2482b032f27cSSam Leffler return m; 2483b032f27cSSam Leffler } 2484b032f27cSSam Leffler 248568e8e04eSSam Leffler static void 248668e8e04eSSam Leffler ieee80211_tx_mgt_timeout(void *arg) 248768e8e04eSSam Leffler { 248868e8e04eSSam Leffler struct ieee80211_node *ni = arg; 2489b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 249068e8e04eSSam Leffler 2491b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_INIT && 2492b032f27cSSam Leffler (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { 249368e8e04eSSam Leffler /* 249468e8e04eSSam Leffler * NB: it's safe to specify a timeout as the reason here; 249568e8e04eSSam Leffler * it'll only be used in the right state. 249668e8e04eSSam Leffler */ 2497b032f27cSSam Leffler ieee80211_new_state(vap, IEEE80211_S_SCAN, 249868e8e04eSSam Leffler IEEE80211_SCAN_FAIL_TIMEOUT); 249968e8e04eSSam Leffler } 250068e8e04eSSam Leffler } 250168e8e04eSSam Leffler 250268e8e04eSSam Leffler static void 250368e8e04eSSam Leffler ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) 250468e8e04eSSam Leffler { 2505b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 250668e8e04eSSam Leffler enum ieee80211_state ostate = (enum ieee80211_state) arg; 250768e8e04eSSam Leffler 250868e8e04eSSam Leffler /* 250968e8e04eSSam Leffler * Frame transmit completed; arrange timer callback. If 251068e8e04eSSam Leffler * transmit was successfuly we wait for response. Otherwise 251168e8e04eSSam Leffler * we arrange an immediate callback instead of doing the 251268e8e04eSSam Leffler * callback directly since we don't know what state the driver 251368e8e04eSSam Leffler * is in (e.g. what locks it is holding). This work should 251468e8e04eSSam Leffler * not be too time-critical and not happen too often so the 251568e8e04eSSam Leffler * added overhead is acceptable. 251668e8e04eSSam Leffler * 251768e8e04eSSam Leffler * XXX what happens if !acked but response shows up before callback? 251868e8e04eSSam Leffler */ 2519b032f27cSSam Leffler if (vap->iv_state == ostate) 2520b032f27cSSam Leffler callout_reset(&vap->iv_mgtsend, 252168e8e04eSSam Leffler status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, 252268e8e04eSSam Leffler ieee80211_tx_mgt_timeout, ni); 252368e8e04eSSam Leffler } 252468e8e04eSSam Leffler 2525b032f27cSSam Leffler static void 2526b032f27cSSam Leffler ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, 2527b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni) 25288a1b9b6aSSam Leffler { 2529b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2530b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 2531b032f27cSSam Leffler struct ieee80211_rateset *rs = &ni->ni_rates; 253268e8e04eSSam Leffler uint16_t capinfo; 25338a1b9b6aSSam Leffler 25348a1b9b6aSSam Leffler /* 25358a1b9b6aSSam Leffler * beacon frame format 25368a1b9b6aSSam Leffler * [8] time stamp 25378a1b9b6aSSam Leffler * [2] beacon interval 25388a1b9b6aSSam Leffler * [2] cabability information 25398a1b9b6aSSam Leffler * [tlv] ssid 25408a1b9b6aSSam Leffler * [tlv] supported rates 25418a1b9b6aSSam Leffler * [3] parameter set (DS) 2542b032f27cSSam Leffler * [8] CF parameter set (optional) 25438a1b9b6aSSam Leffler * [tlv] parameter set (IBSS/TIM) 2544b032f27cSSam Leffler * [tlv] country (optional) 2545b032f27cSSam Leffler * [3] power control (optional) 2546b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 25478a1b9b6aSSam Leffler * [tlv] extended rate phy (ERP) 25488a1b9b6aSSam Leffler * [tlv] extended supported rates 2549688fe74dSSam Leffler * [tlv] RSN parameters 255068e8e04eSSam Leffler * [tlv] HT capabilities 255168e8e04eSSam Leffler * [tlv] HT information 2552b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 2553b032f27cSSam Leffler * [tlv] WPA parameters 2554b032f27cSSam Leffler * [tlv] WME parameters 255568e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 255668e8e04eSSam Leffler * [tlv] Vendor OUI HT information (optional) 25574207227cSSam Leffler * [tlv] Atheros capabilities (optional) 255810ad9a77SSam Leffler * [tlv] TDMA parameters (optional) 255959aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 256059aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2561b032f27cSSam Leffler * [tlv] application data (optional) 25628a1b9b6aSSam Leffler */ 25638a1b9b6aSSam Leffler 25641b6167d2SSam Leffler memset(bo, 0, sizeof(*bo)); 25651b6167d2SSam Leffler 25668a1b9b6aSSam Leffler memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ 25678a1b9b6aSSam Leffler frm += 8; 256868e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_intval); 25698a1b9b6aSSam Leffler frm += 2; 257059aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 257168e8e04eSSam Leffler bo->bo_caps = (uint16_t *)frm; 257268e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 25738a1b9b6aSSam Leffler frm += 2; 25748a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 2575b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { 25768a1b9b6aSSam Leffler *frm++ = ni->ni_esslen; 25778a1b9b6aSSam Leffler memcpy(frm, ni->ni_essid, ni->ni_esslen); 25788a1b9b6aSSam Leffler frm += ni->ni_esslen; 25798a1b9b6aSSam Leffler } else 25808a1b9b6aSSam Leffler *frm++ = 0; 25818a1b9b6aSSam Leffler frm = ieee80211_add_rates(frm, rs); 2582b032f27cSSam Leffler if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { 25838a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 25848a1b9b6aSSam Leffler *frm++ = 1; 2585b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); 2586b032f27cSSam Leffler } 2587b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_PCF) { 2588b032f27cSSam Leffler bo->bo_cfp = frm; 2589b032f27cSSam Leffler frm = ieee80211_add_cfparms(frm, ic); 25908a1b9b6aSSam Leffler } 25918a1b9b6aSSam Leffler bo->bo_tim = frm; 2592b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 25938a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 25948a1b9b6aSSam Leffler *frm++ = 2; 25958a1b9b6aSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 25968a1b9b6aSSam Leffler bo->bo_tim_len = 0; 259759aa14a9SRui Paulo } else if (vap->iv_opmode == IEEE80211_M_HOSTAP || 259859aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { 259959aa14a9SRui Paulo /* TIM IE is the same for Mesh and Hostap */ 26008a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; 26018a1b9b6aSSam Leffler 26028a1b9b6aSSam Leffler tie->tim_ie = IEEE80211_ELEMID_TIM; 26038a1b9b6aSSam Leffler tie->tim_len = 4; /* length */ 26048a1b9b6aSSam Leffler tie->tim_count = 0; /* DTIM count */ 2605b032f27cSSam Leffler tie->tim_period = vap->iv_dtim_period; /* DTIM period */ 26068a1b9b6aSSam Leffler tie->tim_bitctl = 0; /* bitmap control */ 26078a1b9b6aSSam Leffler tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 26088a1b9b6aSSam Leffler frm += sizeof(struct ieee80211_tim_ie); 26098a1b9b6aSSam Leffler bo->bo_tim_len = 1; 26108a1b9b6aSSam Leffler } 2611b105a069SSam Leffler bo->bo_tim_trailer = frm; 2612b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 2613b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2614b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 2615b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 2616b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 2617b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 2618b032f27cSSam Leffler bo->bo_csa = frm; 2619b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2620b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 2621b032f27cSSam Leffler } else 2622b032f27cSSam Leffler bo->bo_csa = frm; 2623b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { 26240912bac9SSam Leffler bo->bo_erp = frm; 26258a1b9b6aSSam Leffler frm = ieee80211_add_erp(frm, ic); 26261b6167d2SSam Leffler } 262768e8e04eSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2628688fe74dSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2629688fe74dSSam Leffler if (vap->iv_rsn_ie != NULL) 2630688fe74dSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2631688fe74dSSam Leffler /* XXX else complain */ 2632688fe74dSSam Leffler } 2633b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { 263468e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 263568e8e04eSSam Leffler bo->bo_htinfo = frm; 263668e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 26371b6167d2SSam Leffler } 2638b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2639b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2640b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2641b032f27cSSam Leffler /* XXX else complain */ 2642b032f27cSSam Leffler } 2643b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 26441b6167d2SSam Leffler bo->bo_wme = frm; 26451b6167d2SSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 26461b6167d2SSam Leffler } 2647b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && 26482bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) { 264968e8e04eSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 265068e8e04eSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 26510912bac9SSam Leffler } 26524207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 26534207227cSSam Leffler if (vap->iv_flags & IEEE80211_F_ATHEROS) { 26544207227cSSam Leffler bo->bo_ath = frm; 26554207227cSSam Leffler frm = ieee80211_add_athcaps(frm, ni); 26564207227cSSam Leffler } 26574207227cSSam Leffler #endif 265810ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 265910ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 266010ad9a77SSam Leffler bo->bo_tdma = frm; 266110ad9a77SSam Leffler frm = ieee80211_add_tdma(frm, vap); 266210ad9a77SSam Leffler } 266310ad9a77SSam Leffler #endif 2664b032f27cSSam Leffler if (vap->iv_appie_beacon != NULL) { 2665b032f27cSSam Leffler bo->bo_appie = frm; 2666b032f27cSSam Leffler bo->bo_appie_len = vap->iv_appie_beacon->ie_len; 2667b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_beacon); 2668b032f27cSSam Leffler } 266959aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 267059aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 267159aa14a9SRui Paulo frm = ieee80211_add_meshid(frm, vap); 2672d093681cSRui Paulo bo->bo_meshconf = frm; 267359aa14a9SRui Paulo frm = ieee80211_add_meshconf(frm, vap); 267459aa14a9SRui Paulo } 267559aa14a9SRui Paulo #endif 2676b105a069SSam Leffler bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; 2677b032f27cSSam Leffler bo->bo_csa_trailer_len = frm - bo->bo_csa; 267868e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2679b032f27cSSam Leffler } 2680b032f27cSSam Leffler 2681b032f27cSSam Leffler /* 2682b032f27cSSam Leffler * Allocate a beacon frame and fillin the appropriate bits. 2683b032f27cSSam Leffler */ 2684b032f27cSSam Leffler struct mbuf * 2685b032f27cSSam Leffler ieee80211_beacon_alloc(struct ieee80211_node *ni, 2686b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo) 2687b032f27cSSam Leffler { 2688b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2689b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2690b032f27cSSam Leffler struct ifnet *ifp = vap->iv_ifp; 2691b032f27cSSam Leffler struct ieee80211_frame *wh; 2692b032f27cSSam Leffler struct mbuf *m; 2693b032f27cSSam Leffler int pktlen; 2694b032f27cSSam Leffler uint8_t *frm; 2695b032f27cSSam Leffler 2696b032f27cSSam Leffler /* 2697b032f27cSSam Leffler * beacon frame format 2698b032f27cSSam Leffler * [8] time stamp 2699b032f27cSSam Leffler * [2] beacon interval 2700b032f27cSSam Leffler * [2] cabability information 2701b032f27cSSam Leffler * [tlv] ssid 2702b032f27cSSam Leffler * [tlv] supported rates 2703b032f27cSSam Leffler * [3] parameter set (DS) 2704b032f27cSSam Leffler * [8] CF parameter set (optional) 2705b032f27cSSam Leffler * [tlv] parameter set (IBSS/TIM) 2706b032f27cSSam Leffler * [tlv] country (optional) 2707b032f27cSSam Leffler * [3] power control (optional) 2708b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 2709b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 2710b032f27cSSam Leffler * [tlv] extended supported rates 2711b032f27cSSam Leffler * [tlv] RSN parameters 2712b032f27cSSam Leffler * [tlv] HT capabilities 2713b032f27cSSam Leffler * [tlv] HT information 2714b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 2715b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 2716b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 2717b032f27cSSam Leffler * [tlv] WPA parameters 2718b032f27cSSam Leffler * [tlv] WME parameters 271910ad9a77SSam Leffler * [tlv] TDMA parameters (optional) 272059aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 272159aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2722b032f27cSSam Leffler * [tlv] application data (optional) 2723b032f27cSSam Leffler * NB: we allocate the max space required for the TIM bitmap. 2724b032f27cSSam Leffler * XXX how big is this? 2725b032f27cSSam Leffler */ 2726b032f27cSSam Leffler pktlen = 8 /* time stamp */ 2727b032f27cSSam Leffler + sizeof(uint16_t) /* beacon interval */ 2728b032f27cSSam Leffler + sizeof(uint16_t) /* capabilities */ 2729b032f27cSSam Leffler + 2 + ni->ni_esslen /* ssid */ 2730b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE /* supported rates */ 2731b032f27cSSam Leffler + 2 + 1 /* DS parameters */ 2732b032f27cSSam Leffler + 2 + 6 /* CF parameters */ 2733b032f27cSSam Leffler + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ 2734b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE /* country */ 2735b032f27cSSam Leffler + 2 + 1 /* power control */ 2736b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) /* CSA */ 2737b032f27cSSam Leffler + 2 + 1 /* ERP */ 2738b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2739b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2740b032f27cSSam Leffler 2*sizeof(struct ieee80211_ie_wpa) : 0) 2741b032f27cSSam Leffler /* XXX conditional? */ 2742b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ 2743b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ 2744b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ 2745b032f27cSSam Leffler sizeof(struct ieee80211_wme_param) : 0) 27464207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 27474207227cSSam Leffler + sizeof(struct ieee80211_ath_ie) /* ATH */ 27484207227cSSam Leffler #endif 274910ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 275010ad9a77SSam Leffler + (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */ 275110ad9a77SSam Leffler sizeof(struct ieee80211_tdma_param) : 0) 275210ad9a77SSam Leffler #endif 275359aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 275459aa14a9SRui Paulo + 2 + ni->ni_meshidlen 275559aa14a9SRui Paulo + sizeof(struct ieee80211_meshconf_ie) 275659aa14a9SRui Paulo #endif 2757b032f27cSSam Leffler + IEEE80211_MAX_APPIE 2758b032f27cSSam Leffler ; 2759b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 2760b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); 2761b032f27cSSam Leffler if (m == NULL) { 2762b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 2763b032f27cSSam Leffler "%s: cannot get buf; size %u\n", __func__, pktlen); 2764b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 2765b032f27cSSam Leffler return NULL; 2766b032f27cSSam Leffler } 2767b032f27cSSam Leffler ieee80211_beacon_construct(m, frm, bo, ni); 27688a1b9b6aSSam Leffler 27698a1b9b6aSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 27708a1b9b6aSSam Leffler KASSERT(m != NULL, ("no space for 802.11 header?")); 27718a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 27728a1b9b6aSSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 27738a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_BEACON; 27748a1b9b6aSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 277568e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 27768a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 2777b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 27788a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 277968e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 0; 27808a1b9b6aSSam Leffler 27818a1b9b6aSSam Leffler return m; 27828a1b9b6aSSam Leffler } 27838a1b9b6aSSam Leffler 27848a1b9b6aSSam Leffler /* 27858a1b9b6aSSam Leffler * Update the dynamic parts of a beacon frame based on the current state. 27868a1b9b6aSSam Leffler */ 27878a1b9b6aSSam Leffler int 2788b105a069SSam Leffler ieee80211_beacon_update(struct ieee80211_node *ni, 27898a1b9b6aSSam Leffler struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) 27908a1b9b6aSSam Leffler { 2791b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2792b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 27938a1b9b6aSSam Leffler int len_changed = 0; 279468e8e04eSSam Leffler uint16_t capinfo; 2795*fa3324c9SAdrian Chadd struct ieee80211_frame *wh; 2796*fa3324c9SAdrian Chadd ieee80211_seq seqno; 27978a1b9b6aSSam Leffler 2798b032f27cSSam Leffler IEEE80211_LOCK(ic); 2799b032f27cSSam Leffler /* 2800b032f27cSSam Leffler * Handle 11h channel change when we've reached the count. 2801b032f27cSSam Leffler * We must recalculate the beacon frame contents to account 2802b032f27cSSam Leffler * for the new channel. Note we do this only for the first 2803b032f27cSSam Leffler * vap that reaches this point; subsequent vaps just update 2804b032f27cSSam Leffler * their beacon state to reflect the recalculated channel. 2805b032f27cSSam Leffler */ 2806b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && 2807b032f27cSSam Leffler vap->iv_csa_count == ic->ic_csa_count) { 2808b032f27cSSam Leffler vap->iv_csa_count = 0; 2809b032f27cSSam Leffler /* 2810b032f27cSSam Leffler * Effect channel change before reconstructing the beacon 2811b032f27cSSam Leffler * frame contents as many places reference ni_chan. 2812b032f27cSSam Leffler */ 2813b032f27cSSam Leffler if (ic->ic_csa_newchan != NULL) 2814b032f27cSSam Leffler ieee80211_csa_completeswitch(ic); 2815b032f27cSSam Leffler /* 2816b032f27cSSam Leffler * NB: ieee80211_beacon_construct clears all pending 2817b032f27cSSam Leffler * updates in bo_flags so we don't need to explicitly 2818b032f27cSSam Leffler * clear IEEE80211_BEACON_CSA. 2819b032f27cSSam Leffler */ 2820b032f27cSSam Leffler ieee80211_beacon_construct(m, 2821b032f27cSSam Leffler mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni); 2822b032f27cSSam Leffler 2823b032f27cSSam Leffler /* XXX do WME aggressive mode processing? */ 2824b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 2825b032f27cSSam Leffler return 1; /* just assume length changed */ 2826b032f27cSSam Leffler } 2827b032f27cSSam Leffler 2828*fa3324c9SAdrian Chadd wh = mtod(m, struct ieee80211_frame *); 2829*fa3324c9SAdrian Chadd seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 2830*fa3324c9SAdrian Chadd *(uint16_t *)&wh->i_seq[0] = 2831*fa3324c9SAdrian Chadd htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 2832*fa3324c9SAdrian Chadd M_SEQNO_SET(m, seqno); 2833*fa3324c9SAdrian Chadd 28348a1b9b6aSSam Leffler /* XXX faster to recalculate entirely or just changes? */ 283559aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 28368a1b9b6aSSam Leffler *bo->bo_caps = htole16(capinfo); 28378a1b9b6aSSam Leffler 2838b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 28398a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 28408a1b9b6aSSam Leffler 28418a1b9b6aSSam Leffler /* 28428a1b9b6aSSam Leffler * Check for agressive mode change. When there is 28438a1b9b6aSSam Leffler * significant high priority traffic in the BSS 28448a1b9b6aSSam Leffler * throttle back BE traffic by using conservative 28458a1b9b6aSSam Leffler * parameters. Otherwise BE uses agressive params 28468a1b9b6aSSam Leffler * to optimize performance of legacy/non-QoS traffic. 28478a1b9b6aSSam Leffler */ 28488a1b9b6aSSam Leffler if (wme->wme_flags & WME_F_AGGRMODE) { 28498a1b9b6aSSam Leffler if (wme->wme_hipri_traffic > 28508a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 2851b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 28528a1b9b6aSSam Leffler "%s: traffic %u, disable aggressive mode\n", 28538a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 28548a1b9b6aSSam Leffler wme->wme_flags &= ~WME_F_AGGRMODE; 2855b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 28568a1b9b6aSSam Leffler wme->wme_hipri_traffic = 28578a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 28588a1b9b6aSSam Leffler } else 28598a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 28608a1b9b6aSSam Leffler } else { 28618a1b9b6aSSam Leffler if (wme->wme_hipri_traffic <= 28628a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 2863b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 28648a1b9b6aSSam Leffler "%s: traffic %u, enable aggressive mode\n", 28658a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 28668a1b9b6aSSam Leffler wme->wme_flags |= WME_F_AGGRMODE; 2867b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 28688a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 28698a1b9b6aSSam Leffler } else 28708a1b9b6aSSam Leffler wme->wme_hipri_traffic = 28718a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 28728a1b9b6aSSam Leffler } 2873b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { 28748a1b9b6aSSam Leffler (void) ieee80211_add_wme_param(bo->bo_wme, wme); 2875b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_WME); 28768a1b9b6aSSam Leffler } 28778a1b9b6aSSam Leffler } 28788a1b9b6aSSam Leffler 2879b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { 2880b032f27cSSam Leffler ieee80211_ht_update_beacon(vap, bo); 2881b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); 288268e8e04eSSam Leffler } 288310ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 288410ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 288510ad9a77SSam Leffler /* 288610ad9a77SSam Leffler * NB: the beacon is potentially updated every TBTT. 288710ad9a77SSam Leffler */ 288810ad9a77SSam Leffler ieee80211_tdma_update_beacon(vap, bo); 288910ad9a77SSam Leffler } 289010ad9a77SSam Leffler #endif 2891d093681cSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 2892d093681cSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 2893d093681cSRui Paulo ieee80211_mesh_update_beacon(vap, bo); 2894d093681cSRui Paulo #endif 2895d093681cSRui Paulo 289659aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP || 289759aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/ 28988a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = 28998a1b9b6aSSam Leffler (struct ieee80211_tim_ie *) bo->bo_tim; 2900b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { 29018a1b9b6aSSam Leffler u_int timlen, timoff, i; 29028a1b9b6aSSam Leffler /* 29038a1b9b6aSSam Leffler * ATIM/DTIM needs updating. If it fits in the 29048a1b9b6aSSam Leffler * current space allocated then just copy in the 29058a1b9b6aSSam Leffler * new bits. Otherwise we need to move any trailing 29068a1b9b6aSSam Leffler * data to make room. Note that we know there is 29078a1b9b6aSSam Leffler * contiguous space because ieee80211_beacon_allocate 29088a1b9b6aSSam Leffler * insures there is space in the mbuf to write a 2909b032f27cSSam Leffler * maximal-size virtual bitmap (based on iv_max_aid). 29108a1b9b6aSSam Leffler */ 29118a1b9b6aSSam Leffler /* 29128a1b9b6aSSam Leffler * Calculate the bitmap size and offset, copy any 29138a1b9b6aSSam Leffler * trailer out of the way, and then copy in the 29148a1b9b6aSSam Leffler * new bitmap and update the information element. 29158a1b9b6aSSam Leffler * Note that the tim bitmap must contain at least 29168a1b9b6aSSam Leffler * one byte and any offset must be even. 29178a1b9b6aSSam Leffler */ 2918b032f27cSSam Leffler if (vap->iv_ps_pending != 0) { 29198a1b9b6aSSam Leffler timoff = 128; /* impossibly large */ 2920b032f27cSSam Leffler for (i = 0; i < vap->iv_tim_len; i++) 2921b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) { 29228a1b9b6aSSam Leffler timoff = i &~ 1; 29238a1b9b6aSSam Leffler break; 29248a1b9b6aSSam Leffler } 29258a1b9b6aSSam Leffler KASSERT(timoff != 128, ("tim bitmap empty!")); 2926b032f27cSSam Leffler for (i = vap->iv_tim_len-1; i >= timoff; i--) 2927b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) 29288a1b9b6aSSam Leffler break; 29298a1b9b6aSSam Leffler timlen = 1 + (i - timoff); 29308a1b9b6aSSam Leffler } else { 29318a1b9b6aSSam Leffler timoff = 0; 29328a1b9b6aSSam Leffler timlen = 1; 29338a1b9b6aSSam Leffler } 29348a1b9b6aSSam Leffler if (timlen != bo->bo_tim_len) { 29358a1b9b6aSSam Leffler /* copy up/down trailer */ 29360912bac9SSam Leffler int adjust = tie->tim_bitmap+timlen 2937b105a069SSam Leffler - bo->bo_tim_trailer; 2938b105a069SSam Leffler ovbcopy(bo->bo_tim_trailer, 2939b105a069SSam Leffler bo->bo_tim_trailer+adjust, 2940b105a069SSam Leffler bo->bo_tim_trailer_len); 2941b105a069SSam Leffler bo->bo_tim_trailer += adjust; 29420912bac9SSam Leffler bo->bo_erp += adjust; 294368e8e04eSSam Leffler bo->bo_htinfo += adjust; 294402e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG 29454207227cSSam Leffler bo->bo_ath += adjust; 29464207227cSSam Leffler #endif 294702e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA 294892e870edSSam Leffler bo->bo_tdma += adjust; 294992e870edSSam Leffler #endif 295002e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH 2951d093681cSRui Paulo bo->bo_meshconf += adjust; 2952d093681cSRui Paulo #endif 2953b032f27cSSam Leffler bo->bo_appie += adjust; 2954b032f27cSSam Leffler bo->bo_wme += adjust; 2955b032f27cSSam Leffler bo->bo_csa += adjust; 29568a1b9b6aSSam Leffler bo->bo_tim_len = timlen; 29578a1b9b6aSSam Leffler 29588a1b9b6aSSam Leffler /* update information element */ 29598a1b9b6aSSam Leffler tie->tim_len = 3 + timlen; 29608a1b9b6aSSam Leffler tie->tim_bitctl = timoff; 29618a1b9b6aSSam Leffler len_changed = 1; 29628a1b9b6aSSam Leffler } 2963b032f27cSSam Leffler memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, 29648a1b9b6aSSam Leffler bo->bo_tim_len); 29658a1b9b6aSSam Leffler 2966b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); 29678a1b9b6aSSam Leffler 2968b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 29698a1b9b6aSSam Leffler "%s: TIM updated, pending %u, off %u, len %u\n", 2970b032f27cSSam Leffler __func__, vap->iv_ps_pending, timoff, timlen); 29718a1b9b6aSSam Leffler } 29728a1b9b6aSSam Leffler /* count down DTIM period */ 29738a1b9b6aSSam Leffler if (tie->tim_count == 0) 29748a1b9b6aSSam Leffler tie->tim_count = tie->tim_period - 1; 29758a1b9b6aSSam Leffler else 29768a1b9b6aSSam Leffler tie->tim_count--; 29778a1b9b6aSSam Leffler /* update state for buffered multicast frames on DTIM */ 2978a196b35fSSam Leffler if (mcast && tie->tim_count == 0) 29798a1b9b6aSSam Leffler tie->tim_bitctl |= 1; 29808a1b9b6aSSam Leffler else 29818a1b9b6aSSam Leffler tie->tim_bitctl &= ~1; 2982b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { 2983b032f27cSSam Leffler struct ieee80211_csa_ie *csa = 2984b032f27cSSam Leffler (struct ieee80211_csa_ie *) bo->bo_csa; 2985b032f27cSSam Leffler 2986b032f27cSSam Leffler /* 2987b032f27cSSam Leffler * Insert or update CSA ie. If we're just starting 2988b032f27cSSam Leffler * to count down to the channel switch then we need 2989b032f27cSSam Leffler * to insert the CSA ie. Otherwise we just need to 2990b032f27cSSam Leffler * drop the count. The actual change happens above 2991b032f27cSSam Leffler * when the vap's count reaches the target count. 2992b032f27cSSam Leffler */ 2993b032f27cSSam Leffler if (vap->iv_csa_count == 0) { 2994b032f27cSSam Leffler memmove(&csa[1], csa, bo->bo_csa_trailer_len); 2995b032f27cSSam Leffler bo->bo_erp += sizeof(*csa); 2996d01b3c26SSam Leffler bo->bo_htinfo += sizeof(*csa); 2997b032f27cSSam Leffler bo->bo_wme += sizeof(*csa); 299802e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG 29994207227cSSam Leffler bo->bo_ath += sizeof(*csa); 30004207227cSSam Leffler #endif 300102e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA 300292e870edSSam Leffler bo->bo_tdma += sizeof(*csa); 300392e870edSSam Leffler #endif 300402e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH 3005d093681cSRui Paulo bo->bo_meshconf += sizeof(*csa); 3006d093681cSRui Paulo #endif 3007b032f27cSSam Leffler bo->bo_appie += sizeof(*csa); 3008b032f27cSSam Leffler bo->bo_csa_trailer_len += sizeof(*csa); 3009b032f27cSSam Leffler bo->bo_tim_trailer_len += sizeof(*csa); 3010b032f27cSSam Leffler m->m_len += sizeof(*csa); 3011b032f27cSSam Leffler m->m_pkthdr.len += sizeof(*csa); 3012b032f27cSSam Leffler 3013b032f27cSSam Leffler ieee80211_add_csa(bo->bo_csa, vap); 3014b032f27cSSam Leffler } else 3015b032f27cSSam Leffler csa->csa_count--; 3016b032f27cSSam Leffler vap->iv_csa_count++; 3017b032f27cSSam Leffler /* NB: don't clear IEEE80211_BEACON_CSA */ 3018b032f27cSSam Leffler } 3019b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { 30200912bac9SSam Leffler /* 30210912bac9SSam Leffler * ERP element needs updating. 30220912bac9SSam Leffler */ 30230912bac9SSam Leffler (void) ieee80211_add_erp(bo->bo_erp, ic); 3024b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); 30250912bac9SSam Leffler } 30264207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 30274207227cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ATH)) { 30284207227cSSam Leffler ieee80211_add_athcaps(bo->bo_ath, ni); 30294207227cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ATH); 30304207227cSSam Leffler } 30314207227cSSam Leffler #endif 30328a1b9b6aSSam Leffler } 3033b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { 3034b032f27cSSam Leffler const struct ieee80211_appie *aie = vap->iv_appie_beacon; 3035b032f27cSSam Leffler int aielen; 3036b032f27cSSam Leffler uint8_t *frm; 3037b032f27cSSam Leffler 3038b032f27cSSam Leffler aielen = 0; 3039b032f27cSSam Leffler if (aie != NULL) 3040b032f27cSSam Leffler aielen += aie->ie_len; 3041b032f27cSSam Leffler if (aielen != bo->bo_appie_len) { 3042b032f27cSSam Leffler /* copy up/down trailer */ 3043b032f27cSSam Leffler int adjust = aielen - bo->bo_appie_len; 3044b032f27cSSam Leffler ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, 3045b032f27cSSam Leffler bo->bo_tim_trailer_len); 3046b032f27cSSam Leffler bo->bo_tim_trailer += adjust; 3047b032f27cSSam Leffler bo->bo_appie += adjust; 3048b032f27cSSam Leffler bo->bo_appie_len = aielen; 3049b032f27cSSam Leffler 3050b032f27cSSam Leffler len_changed = 1; 3051b032f27cSSam Leffler } 3052b032f27cSSam Leffler frm = bo->bo_appie; 3053b032f27cSSam Leffler if (aie != NULL) 3054b032f27cSSam Leffler frm = add_appie(frm, aie); 3055b032f27cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); 3056b032f27cSSam Leffler } 3057b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 30588a1b9b6aSSam Leffler 30598a1b9b6aSSam Leffler return len_changed; 30608a1b9b6aSSam Leffler } 3061