11a1e1d21SSam Leffler /*- 27535e66aSSam Leffler * Copyright (c) 2001 Atsushi Onoe 310ad9a77SSam Leffler * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 41a1e1d21SSam Leffler * All rights reserved. 51a1e1d21SSam Leffler * 61a1e1d21SSam Leffler * Redistribution and use in source and binary forms, with or without 71a1e1d21SSam Leffler * modification, are permitted provided that the following conditions 81a1e1d21SSam Leffler * are met: 91a1e1d21SSam Leffler * 1. Redistributions of source code must retain the above copyright 107535e66aSSam Leffler * notice, this list of conditions and the following disclaimer. 117535e66aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 127535e66aSSam Leffler * notice, this list of conditions and the following disclaimer in the 137535e66aSSam Leffler * documentation and/or other materials provided with the distribution. 141a1e1d21SSam Leffler * 157535e66aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 167535e66aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 177535e66aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 187535e66aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 197535e66aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 207535e66aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 217535e66aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 227535e66aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 237535e66aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 247535e66aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251a1e1d21SSam Leffler */ 261a1e1d21SSam Leffler 271a1e1d21SSam Leffler #include <sys/cdefs.h> 281a1e1d21SSam Leffler __FBSDID("$FreeBSD$"); 291a1e1d21SSam Leffler 301a1e1d21SSam Leffler #include "opt_inet.h" 31e755a73dSSam Leffler #include "opt_inet6.h" 32b032f27cSSam Leffler #include "opt_wlan.h" 331a1e1d21SSam Leffler 341a1e1d21SSam Leffler #include <sys/param.h> 351a1e1d21SSam Leffler #include <sys/systm.h> 361a1e1d21SSam Leffler #include <sys/mbuf.h> 371a1e1d21SSam Leffler #include <sys/kernel.h> 381a1e1d21SSam Leffler #include <sys/endian.h> 391a1e1d21SSam Leffler 408a1b9b6aSSam Leffler #include <sys/socket.h> 411a1e1d21SSam Leffler 421a1e1d21SSam Leffler #include <net/bpf.h> 438a1b9b6aSSam Leffler #include <net/ethernet.h> 448a1b9b6aSSam Leffler #include <net/if.h> 458a1b9b6aSSam Leffler #include <net/if_llc.h> 468a1b9b6aSSam Leffler #include <net/if_media.h> 478a1b9b6aSSam Leffler #include <net/if_vlan_var.h> 488a1b9b6aSSam Leffler 498a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h> 5068e8e04eSSam Leffler #include <net80211/ieee80211_regdomain.h> 51616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 52616190d0SSam Leffler #include <net80211/ieee80211_superg.h> 53616190d0SSam Leffler #endif 5410ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 5510ad9a77SSam Leffler #include <net80211/ieee80211_tdma.h> 5610ad9a77SSam Leffler #endif 57b032f27cSSam Leffler #include <net80211/ieee80211_wds.h> 5859aa14a9SRui Paulo #include <net80211/ieee80211_mesh.h> 591a1e1d21SSam Leffler 608355d59dSBjoern A. Zeeb #if defined(INET) || defined(INET6) 611a1e1d21SSam Leffler #include <netinet/in.h> 628355d59dSBjoern A. Zeeb #endif 638355d59dSBjoern A. Zeeb 648355d59dSBjoern A. Zeeb #ifdef INET 651a1e1d21SSam Leffler #include <netinet/if_ether.h> 668a1b9b6aSSam Leffler #include <netinet/in_systm.h> 678a1b9b6aSSam Leffler #include <netinet/ip.h> 688a1b9b6aSSam Leffler #endif 69e755a73dSSam Leffler #ifdef INET6 70e755a73dSSam Leffler #include <netinet/ip6.h> 71e755a73dSSam Leffler #endif 728a1b9b6aSSam Leffler 73c27b9cdbSRobert Watson #include <security/mac/mac_framework.h> 74c27b9cdbSRobert Watson 7568e8e04eSSam Leffler #define ETHER_HEADER_COPY(dst, src) \ 7668e8e04eSSam Leffler memcpy(dst, src, sizeof(struct ether_header)) 7768e8e04eSSam Leffler 7859aa14a9SRui Paulo /* unalligned little endian access */ 7959aa14a9SRui Paulo #define LE_WRITE_2(p, v) do { \ 8059aa14a9SRui Paulo ((uint8_t *)(p))[0] = (v) & 0xff; \ 8159aa14a9SRui Paulo ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 8259aa14a9SRui Paulo } while (0) 8359aa14a9SRui Paulo #define LE_WRITE_4(p, v) do { \ 8459aa14a9SRui Paulo ((uint8_t *)(p))[0] = (v) & 0xff; \ 8559aa14a9SRui Paulo ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 8659aa14a9SRui Paulo ((uint8_t *)(p))[2] = ((v) >> 16) & 0xff; \ 8759aa14a9SRui Paulo ((uint8_t *)(p))[3] = ((v) >> 24) & 0xff; \ 8859aa14a9SRui Paulo } while (0) 8959aa14a9SRui Paulo 90b032f27cSSam Leffler static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *, 9168e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu); 9268e8e04eSSam Leffler static void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int); 9368e8e04eSSam Leffler 948a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 958a1b9b6aSSam Leffler /* 968a1b9b6aSSam Leffler * Decide if an outbound management frame should be 978a1b9b6aSSam Leffler * printed when debugging is enabled. This filters some 988a1b9b6aSSam Leffler * of the less interesting frames that come frequently 998a1b9b6aSSam Leffler * (e.g. beacons). 1008a1b9b6aSSam Leffler */ 1018a1b9b6aSSam Leffler static __inline int 102b032f27cSSam Leffler doprint(struct ieee80211vap *vap, int subtype) 1038a1b9b6aSSam Leffler { 1048a1b9b6aSSam Leffler switch (subtype) { 1058a1b9b6aSSam Leffler case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 106b032f27cSSam Leffler return (vap->iv_opmode == IEEE80211_M_IBSS); 1078a1b9b6aSSam Leffler } 1088a1b9b6aSSam Leffler return 1; 1098a1b9b6aSSam Leffler } 1101a1e1d21SSam Leffler #endif 1111a1e1d21SSam Leffler 1120a915fadSSam Leffler /* 113b032f27cSSam Leffler * Start method for vap's. All packets from the stack come 114b032f27cSSam Leffler * through here. We handle common processing of the packets 115b032f27cSSam Leffler * before dispatching them to the underlying device. 116b032f27cSSam Leffler */ 117b032f27cSSam Leffler void 118b032f27cSSam Leffler ieee80211_start(struct ifnet *ifp) 119b032f27cSSam Leffler { 120b032f27cSSam Leffler #define IS_DWDS(vap) \ 121b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_WDS && \ 122b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0) 123b032f27cSSam Leffler struct ieee80211vap *vap = ifp->if_softc; 124b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 125b032f27cSSam Leffler struct ifnet *parent = ic->ic_ifp; 126b032f27cSSam Leffler struct ieee80211_node *ni; 127b032f27cSSam Leffler struct mbuf *m; 128b032f27cSSam Leffler struct ether_header *eh; 129b032f27cSSam Leffler int error; 130b032f27cSSam Leffler 131b032f27cSSam Leffler /* NB: parent must be up and running */ 132b032f27cSSam Leffler if (!IFNET_IS_UP_RUNNING(parent)) { 133b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 134b032f27cSSam Leffler "%s: ignore queue, parent %s not up+running\n", 135b032f27cSSam Leffler __func__, parent->if_xname); 136b032f27cSSam Leffler /* XXX stat */ 137b032f27cSSam Leffler return; 138b032f27cSSam Leffler } 139b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_SLEEP) { 140b032f27cSSam Leffler /* 141b032f27cSSam Leffler * In power save, wakeup device for transmit. 142b032f27cSSam Leffler */ 143b032f27cSSam Leffler ieee80211_new_state(vap, IEEE80211_S_RUN, 0); 144b032f27cSSam Leffler return; 145b032f27cSSam Leffler } 146b032f27cSSam Leffler /* 147b032f27cSSam Leffler * No data frames go out unless we're running. 148b032f27cSSam Leffler * Note in particular this covers CAC and CSA 149b032f27cSSam Leffler * states (though maybe we should check muting 150b032f27cSSam Leffler * for CSA). 151b032f27cSSam Leffler */ 152b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_RUN) { 153b032f27cSSam Leffler IEEE80211_LOCK(ic); 154b032f27cSSam Leffler /* re-check under the com lock to avoid races */ 155b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_RUN) { 156b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 157b032f27cSSam Leffler "%s: ignore queue, in %s state\n", 158b032f27cSSam Leffler __func__, ieee80211_state_name[vap->iv_state]); 159b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 160b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 16170e0b5acSAdrian Chadd IFQ_LOCK(&ifp->if_snd); 16270e0b5acSAdrian Chadd ifp->if_drv_flags |= IFF_DRV_OACTIVE; 16370e0b5acSAdrian Chadd IFQ_UNLOCK(&ifp->if_snd); 164b032f27cSSam Leffler return; 165b032f27cSSam Leffler } 166b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 167b032f27cSSam Leffler } 168b032f27cSSam Leffler for (;;) { 169b032f27cSSam Leffler IFQ_DEQUEUE(&ifp->if_snd, m); 170b032f27cSSam Leffler if (m == NULL) 171b032f27cSSam Leffler break; 172b032f27cSSam Leffler /* 173b032f27cSSam Leffler * Sanitize mbuf flags for net80211 use. We cannot 174927ef5ffSSam Leffler * clear M_PWR_SAV or M_MORE_DATA because these may 175927ef5ffSSam Leffler * be set for frames that are re-submitted from the 176927ef5ffSSam Leffler * power save queue. 177b032f27cSSam Leffler * 178b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 179b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 180b032f27cSSam Leffler */ 181927ef5ffSSam Leffler m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); 182b032f27cSSam Leffler /* 183b032f27cSSam Leffler * Cancel any background scan. 184b032f27cSSam Leffler */ 185b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_SCAN) 186b032f27cSSam Leffler ieee80211_cancel_anyscan(vap); 187b032f27cSSam Leffler /* 188b032f27cSSam Leffler * Find the node for the destination so we can do 189b032f27cSSam Leffler * things like power save and fast frames aggregation. 190b032f27cSSam Leffler * 191b032f27cSSam Leffler * NB: past this point various code assumes the first 192b032f27cSSam Leffler * mbuf has the 802.3 header present (and contiguous). 193b032f27cSSam Leffler */ 194b032f27cSSam Leffler ni = NULL; 195b032f27cSSam Leffler if (m->m_len < sizeof(struct ether_header) && 196b032f27cSSam Leffler (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 197b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 198b032f27cSSam Leffler "discard frame, %s\n", "m_pullup failed"); 199b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX */ 200b032f27cSSam Leffler ifp->if_oerrors++; 201b032f27cSSam Leffler continue; 202b032f27cSSam Leffler } 203b032f27cSSam Leffler eh = mtod(m, struct ether_header *); 204b032f27cSSam Leffler if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 205b032f27cSSam Leffler if (IS_DWDS(vap)) { 206b032f27cSSam Leffler /* 207b032f27cSSam Leffler * Only unicast frames from the above go out 208b032f27cSSam Leffler * DWDS vaps; multicast frames are handled by 209b032f27cSSam Leffler * dispatching the frame as it comes through 210b032f27cSSam Leffler * the AP vap (see below). 211b032f27cSSam Leffler */ 212b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS, 213b032f27cSSam Leffler eh->ether_dhost, "mcast", "%s", "on DWDS"); 214b032f27cSSam Leffler vap->iv_stats.is_dwds_mcast++; 215b032f27cSSam Leffler m_freem(m); 216b032f27cSSam Leffler continue; 217b032f27cSSam Leffler } 218b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 219b032f27cSSam Leffler /* 220b032f27cSSam Leffler * Spam DWDS vap's w/ multicast traffic. 221b032f27cSSam Leffler */ 222b032f27cSSam Leffler /* XXX only if dwds in use? */ 223b032f27cSSam Leffler ieee80211_dwds_mcast(vap, m); 224b032f27cSSam Leffler } 225b032f27cSSam Leffler } 22659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 22759aa14a9SRui Paulo if (vap->iv_opmode != IEEE80211_M_MBSS) { 22859aa14a9SRui Paulo #endif 229b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, eh->ether_dhost); 230b032f27cSSam Leffler if (ni == NULL) { 231b032f27cSSam Leffler /* NB: ieee80211_find_txnode does stat+msg */ 232b032f27cSSam Leffler ifp->if_oerrors++; 233b032f27cSSam Leffler m_freem(m); 234b032f27cSSam Leffler continue; 235b032f27cSSam Leffler } 2366ff2e10aSSam Leffler if (ni->ni_associd == 0 && 2371b999d64SSam Leffler (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { 238b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 239b032f27cSSam Leffler eh->ether_dhost, NULL, 240b032f27cSSam Leffler "sta not associated (type 0x%04x)", 241b032f27cSSam Leffler htons(eh->ether_type)); 242b032f27cSSam Leffler vap->iv_stats.is_tx_notassoc++; 243b032f27cSSam Leffler ifp->if_oerrors++; 244b032f27cSSam Leffler m_freem(m); 245b032f27cSSam Leffler ieee80211_free_node(ni); 246b032f27cSSam Leffler continue; 247b032f27cSSam Leffler } 24859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 24959aa14a9SRui Paulo } else { 250c104cff2SRui Paulo if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) { 251c104cff2SRui Paulo /* 252c104cff2SRui Paulo * Proxy station only if configured. 253c104cff2SRui Paulo */ 254c104cff2SRui Paulo if (!ieee80211_mesh_isproxyena(vap)) { 255c104cff2SRui Paulo IEEE80211_DISCARD_MAC(vap, 256c104cff2SRui Paulo IEEE80211_MSG_OUTPUT | 257c104cff2SRui Paulo IEEE80211_MSG_MESH, 258c104cff2SRui Paulo eh->ether_dhost, NULL, 259c104cff2SRui Paulo "%s", "proxy not enabled"); 260c104cff2SRui Paulo vap->iv_stats.is_mesh_notproxy++; 261c104cff2SRui Paulo ifp->if_oerrors++; 262c104cff2SRui Paulo m_freem(m); 263c104cff2SRui Paulo continue; 264c104cff2SRui Paulo } 265c104cff2SRui Paulo ieee80211_mesh_proxy_check(vap, eh->ether_shost); 266c104cff2SRui Paulo } 26759aa14a9SRui Paulo ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m); 26859aa14a9SRui Paulo if (ni == NULL) { 26959aa14a9SRui Paulo /* 270c104cff2SRui Paulo * NB: ieee80211_mesh_discover holds/disposes 271c104cff2SRui Paulo * frame (e.g. queueing on path discovery). 27259aa14a9SRui Paulo */ 27359aa14a9SRui Paulo ifp->if_oerrors++; 27459aa14a9SRui Paulo continue; 27559aa14a9SRui Paulo } 27659aa14a9SRui Paulo } 27759aa14a9SRui Paulo #endif 278b032f27cSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 279b032f27cSSam Leffler (m->m_flags & M_PWR_SAV) == 0) { 280b032f27cSSam Leffler /* 281b032f27cSSam Leffler * Station in power save mode; pass the frame 282b032f27cSSam Leffler * to the 802.11 layer and continue. We'll get 283b032f27cSSam Leffler * the frame back when the time is right. 284b032f27cSSam Leffler * XXX lose WDS vap linkage? 285b032f27cSSam Leffler */ 28663092fceSSam Leffler (void) ieee80211_pwrsave(ni, m); 287b032f27cSSam Leffler ieee80211_free_node(ni); 288b032f27cSSam Leffler continue; 289b032f27cSSam Leffler } 290b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 291b032f27cSSam Leffler if (ieee80211_classify(ni, m)) { 292b032f27cSSam Leffler IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 293b032f27cSSam Leffler eh->ether_dhost, NULL, 294b032f27cSSam Leffler "%s", "classification failure"); 295b032f27cSSam Leffler vap->iv_stats.is_tx_classify++; 296b032f27cSSam Leffler ifp->if_oerrors++; 297b032f27cSSam Leffler m_freem(m); 298b032f27cSSam Leffler ieee80211_free_node(ni); 299b032f27cSSam Leffler continue; 300b032f27cSSam Leffler } 3017ebe9c0eSSam Leffler /* 3027ebe9c0eSSam Leffler * Stash the node pointer. Note that we do this after 3037ebe9c0eSSam Leffler * any call to ieee80211_dwds_mcast because that code 3047ebe9c0eSSam Leffler * uses any existing value for rcvif to identify the 3057ebe9c0eSSam Leffler * interface it (might have been) received on. 3067ebe9c0eSSam Leffler */ 3077ebe9c0eSSam Leffler m->m_pkthdr.rcvif = (void *)ni; 308b032f27cSSam Leffler 309339ccfb3SSam Leffler BPF_MTAP(ifp, m); /* 802.3 tx */ 310b032f27cSSam Leffler 311168f582eSSam Leffler /* 312168f582eSSam Leffler * Check if A-MPDU tx aggregation is setup or if we 313168f582eSSam Leffler * should try to enable it. The sta must be associated 314168f582eSSam Leffler * with HT and A-MPDU enabled for use. When the policy 315168f582eSSam Leffler * routine decides we should enable A-MPDU we issue an 316168f582eSSam Leffler * ADDBA request and wait for a reply. The frame being 317168f582eSSam Leffler * encapsulated will go out w/o using A-MPDU, or possibly 318168f582eSSam Leffler * it might be collected by the driver and held/retransmit. 319168f582eSSam Leffler * The default ic_ampdu_enable routine handles staggering 320168f582eSSam Leffler * ADDBA requests in case the receiver NAK's us or we are 321168f582eSSam Leffler * otherwise unable to establish a BA stream. 322168f582eSSam Leffler */ 323168f582eSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && 3242bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) && 325168f582eSSam Leffler (m->m_flags & M_EAPOL) == 0) { 326*2aa563dfSAdrian Chadd int tid = WME_AC_TO_TID(M_WME_GETAC(m)); 327*2aa563dfSAdrian Chadd struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; 328168f582eSSam Leffler 329168f582eSSam Leffler ieee80211_txampdu_count_packet(tap); 330168f582eSSam Leffler if (IEEE80211_AMPDU_RUNNING(tap)) { 331168f582eSSam Leffler /* 332168f582eSSam Leffler * Operational, mark frame for aggregation. 333168f582eSSam Leffler * 334168f582eSSam Leffler * XXX do tx aggregation here 335168f582eSSam Leffler */ 336168f582eSSam Leffler m->m_flags |= M_AMPDU_MPDU; 337168f582eSSam Leffler } else if (!IEEE80211_AMPDU_REQUESTED(tap) && 338168f582eSSam Leffler ic->ic_ampdu_enable(ni, tap)) { 339168f582eSSam Leffler /* 340168f582eSSam Leffler * Not negotiated yet, request service. 341168f582eSSam Leffler */ 342168f582eSSam Leffler ieee80211_ampdu_request(ni, tap); 343168f582eSSam Leffler /* XXX hold frame for reply? */ 344168f582eSSam Leffler } 345168f582eSSam Leffler } 346339ccfb3SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 347168f582eSSam Leffler else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { 348339ccfb3SSam Leffler m = ieee80211_ff_check(ni, m); 349339ccfb3SSam Leffler if (m == NULL) { 350339ccfb3SSam Leffler /* NB: any ni ref held on stageq */ 351339ccfb3SSam Leffler continue; 352339ccfb3SSam Leffler } 353339ccfb3SSam Leffler } 354339ccfb3SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 3559fb0fccbSSam Leffler if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { 356b032f27cSSam Leffler /* 357339ccfb3SSam Leffler * Encapsulate the packet in prep for transmission. 358b032f27cSSam Leffler */ 359339ccfb3SSam Leffler m = ieee80211_encap(vap, ni, m); 360339ccfb3SSam Leffler if (m == NULL) { 361339ccfb3SSam Leffler /* NB: stat+msg handled in ieee80211_encap */ 362339ccfb3SSam Leffler ieee80211_free_node(ni); 363339ccfb3SSam Leffler continue; 364339ccfb3SSam Leffler } 3659fb0fccbSSam Leffler } 366b032f27cSSam Leffler 36772fecb4dSSam Leffler error = parent->if_transmit(parent, m); 368b032f27cSSam Leffler if (error != 0) { 369b032f27cSSam Leffler /* NB: IFQ_HANDOFF reclaims mbuf */ 370b032f27cSSam Leffler ieee80211_free_node(ni); 371b032f27cSSam Leffler } else { 372b032f27cSSam Leffler ifp->if_opackets++; 373b032f27cSSam Leffler } 374b032f27cSSam Leffler ic->ic_lastdata = ticks; 375b032f27cSSam Leffler } 376b032f27cSSam Leffler #undef IS_DWDS 377b032f27cSSam Leffler } 378b032f27cSSam Leffler 379b032f27cSSam Leffler /* 380b032f27cSSam Leffler * 802.11 output routine. This is (currently) used only to 381b032f27cSSam Leffler * connect bpf write calls to the 802.11 layer for injecting 382fad788b1SSam Leffler * raw 802.11 frames. 383b032f27cSSam Leffler */ 384b032f27cSSam Leffler int 385b032f27cSSam Leffler ieee80211_output(struct ifnet *ifp, struct mbuf *m, 386279aa3d4SKip Macy struct sockaddr *dst, struct route *ro) 387b032f27cSSam Leffler { 388b032f27cSSam Leffler #define senderr(e) do { error = (e); goto bad;} while (0) 389b032f27cSSam Leffler struct ieee80211_node *ni = NULL; 3908ed1835dSSam Leffler struct ieee80211vap *vap; 391b032f27cSSam Leffler struct ieee80211_frame *wh; 392b032f27cSSam Leffler int error; 393b032f27cSSam Leffler 39470e0b5acSAdrian Chadd IFQ_LOCK(&ifp->if_snd); 3958ed1835dSSam Leffler if (ifp->if_drv_flags & IFF_DRV_OACTIVE) { 39670e0b5acSAdrian Chadd IFQ_UNLOCK(&ifp->if_snd); 3978ed1835dSSam Leffler /* 3988ed1835dSSam Leffler * Short-circuit requests if the vap is marked OACTIVE 3998ed1835dSSam Leffler * as this can happen because a packet came down through 4008ed1835dSSam Leffler * ieee80211_start before the vap entered RUN state in 4018ed1835dSSam Leffler * which case it's ok to just drop the frame. This 4028ed1835dSSam Leffler * should not be necessary but callers of if_output don't 4038ed1835dSSam Leffler * check OACTIVE. 4048ed1835dSSam Leffler */ 4058ed1835dSSam Leffler senderr(ENETDOWN); 4068ed1835dSSam Leffler } 40770e0b5acSAdrian Chadd IFQ_UNLOCK(&ifp->if_snd); 4088ed1835dSSam Leffler vap = ifp->if_softc; 409b032f27cSSam Leffler /* 410b032f27cSSam Leffler * Hand to the 802.3 code if not tagged as 411b032f27cSSam Leffler * a raw 802.11 frame. 412b032f27cSSam Leffler */ 413b032f27cSSam Leffler if (dst->sa_family != AF_IEEE80211) 414279aa3d4SKip Macy return vap->iv_output(ifp, m, dst, ro); 415b032f27cSSam Leffler #ifdef MAC 416c27b9cdbSRobert Watson error = mac_ifnet_check_transmit(ifp, m); 417b032f27cSSam Leffler if (error) 418b032f27cSSam Leffler senderr(error); 419b032f27cSSam Leffler #endif 420b032f27cSSam Leffler if (ifp->if_flags & IFF_MONITOR) 421b032f27cSSam Leffler senderr(ENETDOWN); 422b032f27cSSam Leffler if (!IFNET_IS_UP_RUNNING(ifp)) 423b032f27cSSam Leffler senderr(ENETDOWN); 424b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 425b032f27cSSam Leffler IEEE80211_DPRINTF(vap, 426b032f27cSSam Leffler IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 427b032f27cSSam Leffler "block %s frame in CAC state\n", "raw data"); 428b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 429b032f27cSSam Leffler senderr(EIO); /* XXX */ 4300d9aed8aSBernhard Schmidt } else if (vap->iv_state == IEEE80211_S_SCAN) 4310d9aed8aSBernhard Schmidt senderr(EIO); 432b032f27cSSam Leffler /* XXX bypass bridge, pfil, carp, etc. */ 433b032f27cSSam Leffler 434b032f27cSSam Leffler if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) 435b032f27cSSam Leffler senderr(EIO); /* XXX */ 436b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 437b032f27cSSam Leffler if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 438b032f27cSSam Leffler IEEE80211_FC0_VERSION_0) 439b032f27cSSam Leffler senderr(EIO); /* XXX */ 440b032f27cSSam Leffler 441b032f27cSSam Leffler /* locate destination node */ 442b032f27cSSam Leffler switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 443b032f27cSSam Leffler case IEEE80211_FC1_DIR_NODS: 444b032f27cSSam Leffler case IEEE80211_FC1_DIR_FROMDS: 445b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr1); 446b032f27cSSam Leffler break; 447b032f27cSSam Leffler case IEEE80211_FC1_DIR_TODS: 448b032f27cSSam Leffler case IEEE80211_FC1_DIR_DSTODS: 449b032f27cSSam Leffler if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) 450b032f27cSSam Leffler senderr(EIO); /* XXX */ 451b032f27cSSam Leffler ni = ieee80211_find_txnode(vap, wh->i_addr3); 452b032f27cSSam Leffler break; 453b032f27cSSam Leffler default: 454b032f27cSSam Leffler senderr(EIO); /* XXX */ 455b032f27cSSam Leffler } 456b032f27cSSam Leffler if (ni == NULL) { 457b032f27cSSam Leffler /* 458b032f27cSSam Leffler * Permit packets w/ bpf params through regardless 459b032f27cSSam Leffler * (see below about sa_len). 460b032f27cSSam Leffler */ 461b032f27cSSam Leffler if (dst->sa_len == 0) 462b032f27cSSam Leffler senderr(EHOSTUNREACH); 463b032f27cSSam Leffler ni = ieee80211_ref_node(vap->iv_bss); 464b032f27cSSam Leffler } 465b032f27cSSam Leffler 466b032f27cSSam Leffler /* 467b032f27cSSam Leffler * Sanitize mbuf for net80211 flags leaked from above. 468b032f27cSSam Leffler * 469b032f27cSSam Leffler * NB: This must be done before ieee80211_classify as 470b032f27cSSam Leffler * it marks EAPOL in frames with M_EAPOL. 471b032f27cSSam Leffler */ 472b032f27cSSam Leffler m->m_flags &= ~M_80211_TX; 473b032f27cSSam Leffler 474b032f27cSSam Leffler /* calculate priority so drivers can find the tx queue */ 475b032f27cSSam Leffler /* XXX assumes an 802.3 frame */ 476b032f27cSSam Leffler if (ieee80211_classify(ni, m)) 477b032f27cSSam Leffler senderr(EIO); /* XXX */ 478b032f27cSSam Leffler 479224881b4SSam Leffler ifp->if_opackets++; 4800e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 4810e910c94SSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 4820e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 4830e910c94SSam Leffler m->m_flags |= M_MCAST; 4840e910c94SSam Leffler } else 4850e910c94SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 4860e910c94SSam Leffler /* NB: ieee80211_encap does not include 802.11 header */ 4870e910c94SSam Leffler IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len); 488b032f27cSSam Leffler 489b032f27cSSam Leffler /* 490b032f27cSSam Leffler * NB: DLT_IEEE802_11_RADIO identifies the parameters are 491b032f27cSSam Leffler * present by setting the sa_len field of the sockaddr (yes, 492b032f27cSSam Leffler * this is a hack). 493b032f27cSSam Leffler * NB: we assume sa_data is suitably aligned to cast. 494b032f27cSSam Leffler */ 495b032f27cSSam Leffler return vap->iv_ic->ic_raw_xmit(ni, m, 496b032f27cSSam Leffler (const struct ieee80211_bpf_params *)(dst->sa_len ? 497b032f27cSSam Leffler dst->sa_data : NULL)); 498b032f27cSSam Leffler bad: 499b032f27cSSam Leffler if (m != NULL) 500b032f27cSSam Leffler m_freem(m); 501b032f27cSSam Leffler if (ni != NULL) 502b032f27cSSam Leffler ieee80211_free_node(ni); 503224881b4SSam Leffler ifp->if_oerrors++; 504b032f27cSSam Leffler return error; 505b032f27cSSam Leffler #undef senderr 506b032f27cSSam Leffler } 507b032f27cSSam Leffler 508b032f27cSSam Leffler /* 509add59d08SSam Leffler * Set the direction field and address fields of an outgoing 5100e66722dSSam Leffler * frame. Note this should be called early on in constructing 5110e66722dSSam Leffler * a frame as it sets i_fc[1]; other bits can then be or'd in. 512add59d08SSam Leffler */ 51359aa14a9SRui Paulo void 514b032f27cSSam Leffler ieee80211_send_setup( 515add59d08SSam Leffler struct ieee80211_node *ni, 5169e80b1dfSSam Leffler struct mbuf *m, 5178ac160cdSSam Leffler int type, int tid, 51868e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 51968e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 52068e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN]) 521add59d08SSam Leffler { 522add59d08SSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) 52359aa14a9SRui Paulo struct ieee80211vap *vap = ni->ni_vap; 52450cfec0eSBernhard Schmidt struct ieee80211_tx_ampdu *tap; 5259e80b1dfSSam Leffler struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 5269e80b1dfSSam Leffler ieee80211_seq seqno; 527add59d08SSam Leffler 528add59d08SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; 529add59d08SSam Leffler if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 530b032f27cSSam Leffler switch (vap->iv_opmode) { 531add59d08SSam Leffler case IEEE80211_M_STA: 532add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 533add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 534add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 535add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 536add59d08SSam Leffler break; 537add59d08SSam Leffler case IEEE80211_M_IBSS: 538add59d08SSam Leffler case IEEE80211_M_AHDEMO: 539add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 540add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 541add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 542add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 543add59d08SSam Leffler break; 544add59d08SSam Leffler case IEEE80211_M_HOSTAP: 545add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 546add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 547add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, bssid); 548add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, sa); 549add59d08SSam Leffler break; 55068e8e04eSSam Leffler case IEEE80211_M_WDS: 55168e8e04eSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 552b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 553b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 55468e8e04eSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, da); 55568e8e04eSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 55668e8e04eSSam Leffler break; 55759aa14a9SRui Paulo case IEEE80211_M_MBSS: 55859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 55959aa14a9SRui Paulo /* XXX add support for proxied addresses */ 56059aa14a9SRui Paulo if (IEEE80211_IS_MULTICAST(da)) { 56159aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 56259aa14a9SRui Paulo /* XXX next hop */ 56359aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 56459aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 56559aa14a9SRui Paulo vap->iv_myaddr); 56659aa14a9SRui Paulo } else { 56759aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 56859aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 56959aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 57059aa14a9SRui Paulo vap->iv_myaddr); 57159aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, da); 57259aa14a9SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 57359aa14a9SRui Paulo } 57459aa14a9SRui Paulo #endif 57559aa14a9SRui Paulo break; 576add59d08SSam Leffler case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ 577add59d08SSam Leffler break; 578add59d08SSam Leffler } 579add59d08SSam Leffler } else { 580add59d08SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 581add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, da); 582add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, sa); 58359aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 58459aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 58559aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, sa); 58659aa14a9SRui Paulo else 58759aa14a9SRui Paulo #endif 588add59d08SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 589add59d08SSam Leffler } 59068e8e04eSSam Leffler *(uint16_t *)&wh->i_dur[0] = 0; 5919e80b1dfSSam Leffler 592*2aa563dfSAdrian Chadd tap = &ni->ni_tx_ampdu[tid]; 59350cfec0eSBernhard Schmidt if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) 59450cfec0eSBernhard Schmidt m->m_flags |= M_AMPDU_MPDU; 59550cfec0eSBernhard Schmidt else { 5969e80b1dfSSam Leffler seqno = ni->ni_txseqs[tid]++; 59750cfec0eSBernhard Schmidt *(uint16_t *)&wh->i_seq[0] = 59850cfec0eSBernhard Schmidt htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 5999a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 60050cfec0eSBernhard Schmidt } 6019e80b1dfSSam Leffler 6029e80b1dfSSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 6039e80b1dfSSam Leffler m->m_flags |= M_MCAST; 604add59d08SSam Leffler #undef WH4 605add59d08SSam Leffler } 606add59d08SSam Leffler 607add59d08SSam Leffler /* 6080a915fadSSam Leffler * Send a management frame to the specified node. The node pointer 6090a915fadSSam Leffler * must have a reference as the pointer will be passed to the driver 6100a915fadSSam Leffler * and potentially held for a long time. If the frame is successfully 6110a915fadSSam Leffler * dispatched to the driver, then it is responsible for freeing the 612b032f27cSSam Leffler * reference (and potentially free'ing up any associated storage); 613b032f27cSSam Leffler * otherwise deal with reclaiming any reference (on error). 6140a915fadSSam Leffler */ 61568e8e04eSSam Leffler int 6168ac160cdSSam Leffler ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, 6178ac160cdSSam Leffler struct ieee80211_bpf_params *params) 6181a1e1d21SSam Leffler { 619b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 620b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 6211a1e1d21SSam Leffler struct ieee80211_frame *wh; 6221a1e1d21SSam Leffler 6230a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 6241a1e1d21SSam Leffler 625b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 626b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 627b032f27cSSam Leffler ni, "block %s frame in CAC state", 628b032f27cSSam Leffler ieee80211_mgt_subtype_name[ 629b032f27cSSam Leffler (type & IEEE80211_FC0_SUBTYPE_MASK) >> 630b032f27cSSam Leffler IEEE80211_FC0_SUBTYPE_SHIFT]); 631b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 632b032f27cSSam Leffler ieee80211_free_node(ni); 633b032f27cSSam Leffler m_freem(m); 634b032f27cSSam Leffler return EIO; /* XXX */ 635b032f27cSSam Leffler } 636b032f27cSSam Leffler 6371a1e1d21SSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 638b032f27cSSam Leffler if (m == NULL) { 639b032f27cSSam Leffler ieee80211_free_node(ni); 6401a1e1d21SSam Leffler return ENOMEM; 641b032f27cSSam Leffler } 6420a915fadSSam Leffler 6431a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 6449e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 6458ac160cdSSam Leffler IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, 646b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 6478ac160cdSSam Leffler if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 648b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, 649b032f27cSSam Leffler "encrypting frame (%s)", __func__); 6508a1b9b6aSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 6518a1b9b6aSSam Leffler } 652c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 6538ac160cdSSam Leffler 6548ac160cdSSam Leffler KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); 6558ac160cdSSam Leffler M_WME_SETAC(m, params->ibp_pri); 6568ac160cdSSam Leffler 6578a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 6588a1b9b6aSSam Leffler /* avoid printing too many frames */ 659b032f27cSSam Leffler if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || 660b032f27cSSam Leffler ieee80211_msg_dumppkts(vap)) { 6618a1b9b6aSSam Leffler printf("[%s] send %s on channel %u\n", 6628a1b9b6aSSam Leffler ether_sprintf(wh->i_addr1), 6638a1b9b6aSSam Leffler ieee80211_mgt_subtype_name[ 6648a1b9b6aSSam Leffler (type & IEEE80211_FC0_SUBTYPE_MASK) >> 6658a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_SHIFT], 666b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan)); 6678a1b9b6aSSam Leffler } 6688a1b9b6aSSam Leffler #endif 6698a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 67068e8e04eSSam Leffler 6718ac160cdSSam Leffler return ic->ic_raw_xmit(ni, m, params); 672246b5467SSam Leffler } 673246b5467SSam Leffler 674246b5467SSam Leffler /* 6756683931eSSam Leffler * Send a null data frame to the specified node. If the station 6766683931eSSam Leffler * is setup for QoS then a QoS Null Data frame is constructed. 6776683931eSSam Leffler * If this is a WDS station then a 4-address frame is constructed. 67819ad2dd7SSam Leffler * 67919ad2dd7SSam Leffler * NB: the caller is assumed to have setup a node reference 68019ad2dd7SSam Leffler * for use; this is necessary to deal with a race condition 681b032f27cSSam Leffler * when probing for inactive stations. Like ieee80211_mgmt_output 682b032f27cSSam Leffler * we must cleanup any node reference on error; however we 683b032f27cSSam Leffler * can safely just unref it as we know it will never be the 684b032f27cSSam Leffler * last reference to the node. 6858a1b9b6aSSam Leffler */ 6868a1b9b6aSSam Leffler int 687f62121ceSSam Leffler ieee80211_send_nulldata(struct ieee80211_node *ni) 6888a1b9b6aSSam Leffler { 689b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 690f62121ceSSam Leffler struct ieee80211com *ic = ni->ni_ic; 6918a1b9b6aSSam Leffler struct mbuf *m; 6928a1b9b6aSSam Leffler struct ieee80211_frame *wh; 6936683931eSSam Leffler int hdrlen; 6946683931eSSam Leffler uint8_t *frm; 6958a1b9b6aSSam Leffler 696b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 697b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 698b032f27cSSam Leffler ni, "block %s frame in CAC state", "null data"); 699b032f27cSSam Leffler ieee80211_unref_node(&ni); 700b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 701b032f27cSSam Leffler return EIO; /* XXX */ 702b032f27cSSam Leffler } 703b032f27cSSam Leffler 7046683931eSSam Leffler if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) 7056683931eSSam Leffler hdrlen = sizeof(struct ieee80211_qosframe); 7066683931eSSam Leffler else 7076683931eSSam Leffler hdrlen = sizeof(struct ieee80211_frame); 7086683931eSSam Leffler /* NB: only WDS vap's get 4-address frames */ 7096683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 7106683931eSSam Leffler hdrlen += IEEE80211_ADDR_LEN; 7116683931eSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 7126683931eSSam Leffler hdrlen = roundup(hdrlen, sizeof(uint32_t)); 7136683931eSSam Leffler 7146683931eSSam Leffler m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); 7158a1b9b6aSSam Leffler if (m == NULL) { 7168a1b9b6aSSam Leffler /* XXX debug msg */ 71719ad2dd7SSam Leffler ieee80211_unref_node(&ni); 718b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 7198a1b9b6aSSam Leffler return ENOMEM; 7208a1b9b6aSSam Leffler } 7216683931eSSam Leffler KASSERT(M_LEADINGSPACE(m) >= hdrlen, 7226683931eSSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 7236683931eSSam Leffler M_PREPEND(m, hdrlen, M_DONTWAIT); 7246683931eSSam Leffler if (m == NULL) { 7256683931eSSam Leffler /* NB: cannot happen */ 7266683931eSSam Leffler ieee80211_free_node(ni); 7276683931eSSam Leffler return ENOMEM; 7286683931eSSam Leffler } 7298a1b9b6aSSam Leffler 7306683931eSSam Leffler wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ 7316683931eSSam Leffler if (ni->ni_flags & IEEE80211_NODE_QOS) { 7326683931eSSam Leffler const int tid = WME_AC_TO_TID(WME_AC_BE); 7336683931eSSam Leffler uint8_t *qos; 7346683931eSSam Leffler 7359e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 7366683931eSSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, 7376683931eSSam Leffler tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 7386683931eSSam Leffler 7396683931eSSam Leffler if (vap->iv_opmode == IEEE80211_M_WDS) 7406683931eSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 7416683931eSSam Leffler else 7426683931eSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 7436683931eSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 7446683931eSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) 7456683931eSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 7466683931eSSam Leffler qos[1] = 0; 7476683931eSSam Leffler } else { 7489e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 749add59d08SSam Leffler IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 7508ac160cdSSam Leffler IEEE80211_NONQOS_TID, 751b032f27cSSam Leffler vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 7526683931eSSam Leffler } 753b032f27cSSam Leffler if (vap->iv_opmode != IEEE80211_M_WDS) { 754add59d08SSam Leffler /* NB: power management bit is never sent by an AP */ 755add59d08SSam Leffler if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 756b032f27cSSam Leffler vap->iv_opmode != IEEE80211_M_HOSTAP) 757add59d08SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 758b032f27cSSam Leffler } 7596683931eSSam Leffler m->m_len = m->m_pkthdr.len = hdrlen; 760c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 7616683931eSSam Leffler 762bb239ce9SSam Leffler M_WME_SETAC(m, WME_AC_BE); 7638a1b9b6aSSam Leffler 7648a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 7658a1b9b6aSSam Leffler 766b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, 7676683931eSSam Leffler "send %snull data frame on channel %u, pwr mgt %s", 7686683931eSSam Leffler ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", 769b5c99415SSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), 770add59d08SSam Leffler wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 771add59d08SSam Leffler 772b032f27cSSam Leffler return ic->ic_raw_xmit(ni, m, NULL); 7738a1b9b6aSSam Leffler } 7748a1b9b6aSSam Leffler 7758a1b9b6aSSam Leffler /* 7768a1b9b6aSSam Leffler * Assign priority to a frame based on any vlan tag assigned 7778a1b9b6aSSam Leffler * to the station and/or any Diffserv setting in an IP header. 7788a1b9b6aSSam Leffler * Finally, if an ACM policy is setup (in station mode) it's 7798a1b9b6aSSam Leffler * applied. 7808a1b9b6aSSam Leffler */ 7818a1b9b6aSSam Leffler int 782b032f27cSSam Leffler ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) 7838a1b9b6aSSam Leffler { 784b032f27cSSam Leffler const struct ether_header *eh = mtod(m, struct ether_header *); 7858a1b9b6aSSam Leffler int v_wme_ac, d_wme_ac, ac; 7868a1b9b6aSSam Leffler 787b032f27cSSam Leffler /* 788b032f27cSSam Leffler * Always promote PAE/EAPOL frames to high priority. 789b032f27cSSam Leffler */ 790b032f27cSSam Leffler if (eh->ether_type == htons(ETHERTYPE_PAE)) { 791b032f27cSSam Leffler /* NB: mark so others don't need to check header */ 792b032f27cSSam Leffler m->m_flags |= M_EAPOL; 793b032f27cSSam Leffler ac = WME_AC_VO; 794b032f27cSSam Leffler goto done; 795b032f27cSSam Leffler } 796b032f27cSSam Leffler /* 797b032f27cSSam Leffler * Non-qos traffic goes to BE. 798b032f27cSSam Leffler */ 7998a1b9b6aSSam Leffler if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { 8008a1b9b6aSSam Leffler ac = WME_AC_BE; 8018a1b9b6aSSam Leffler goto done; 8028a1b9b6aSSam Leffler } 8038a1b9b6aSSam Leffler 8048a1b9b6aSSam Leffler /* 8058a1b9b6aSSam Leffler * If node has a vlan tag then all traffic 8068a1b9b6aSSam Leffler * to it must have a matching tag. 8078a1b9b6aSSam Leffler */ 8088a1b9b6aSSam Leffler v_wme_ac = 0; 8098a1b9b6aSSam Leffler if (ni->ni_vlan != 0) { 81078ba57b9SAndre Oppermann if ((m->m_flags & M_VLANTAG) == 0) { 8118a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_novlantag); 8128a1b9b6aSSam Leffler return 1; 8138a1b9b6aSSam Leffler } 81478ba57b9SAndre Oppermann if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 8158a1b9b6aSSam Leffler EVL_VLANOFTAG(ni->ni_vlan)) { 8168a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 8178a1b9b6aSSam Leffler return 1; 8188a1b9b6aSSam Leffler } 8198a1b9b6aSSam Leffler /* map vlan priority to AC */ 820f4558c9aSSam Leffler v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); 8218a1b9b6aSSam Leffler } 8228a1b9b6aSSam Leffler 823e755a73dSSam Leffler /* XXX m_copydata may be too slow for fast path */ 8248a1b9b6aSSam Leffler #ifdef INET 8258a1b9b6aSSam Leffler if (eh->ether_type == htons(ETHERTYPE_IP)) { 826f4558c9aSSam Leffler uint8_t tos; 8278a1b9b6aSSam Leffler /* 828f4558c9aSSam Leffler * IP frame, map the DSCP bits from the TOS field. 8298a1b9b6aSSam Leffler */ 830f4558c9aSSam Leffler /* NB: ip header may not be in first mbuf */ 831f4558c9aSSam Leffler m_copydata(m, sizeof(struct ether_header) + 832f4558c9aSSam Leffler offsetof(struct ip, ip_tos), sizeof(tos), &tos); 833f4558c9aSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 834f4558c9aSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 8358a1b9b6aSSam Leffler } else { 8368a1b9b6aSSam Leffler #endif /* INET */ 837e755a73dSSam Leffler #ifdef INET6 838e755a73dSSam Leffler if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 839e755a73dSSam Leffler uint32_t flow; 840e755a73dSSam Leffler uint8_t tos; 841e755a73dSSam Leffler /* 8426ffd0ca9SBjoern A. Zeeb * IPv6 frame, map the DSCP bits from the traffic class field. 843e755a73dSSam Leffler */ 844e755a73dSSam Leffler m_copydata(m, sizeof(struct ether_header) + 845e755a73dSSam Leffler offsetof(struct ip6_hdr, ip6_flow), sizeof(flow), 846e755a73dSSam Leffler (caddr_t) &flow); 847e755a73dSSam Leffler tos = (uint8_t)(ntohl(flow) >> 20); 848e755a73dSSam Leffler tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 849e755a73dSSam Leffler d_wme_ac = TID_TO_WME_AC(tos); 850e755a73dSSam Leffler } else { 851e755a73dSSam Leffler #endif /* INET6 */ 8528a1b9b6aSSam Leffler d_wme_ac = WME_AC_BE; 853e755a73dSSam Leffler #ifdef INET6 854e755a73dSSam Leffler } 855e755a73dSSam Leffler #endif 8568a1b9b6aSSam Leffler #ifdef INET 8578a1b9b6aSSam Leffler } 8588a1b9b6aSSam Leffler #endif 8598a1b9b6aSSam Leffler /* 8608a1b9b6aSSam Leffler * Use highest priority AC. 8618a1b9b6aSSam Leffler */ 8628a1b9b6aSSam Leffler if (v_wme_ac > d_wme_ac) 8638a1b9b6aSSam Leffler ac = v_wme_ac; 8648a1b9b6aSSam Leffler else 8658a1b9b6aSSam Leffler ac = d_wme_ac; 8668a1b9b6aSSam Leffler 8678a1b9b6aSSam Leffler /* 8688a1b9b6aSSam Leffler * Apply ACM policy. 8698a1b9b6aSSam Leffler */ 870b032f27cSSam Leffler if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { 8718a1b9b6aSSam Leffler static const int acmap[4] = { 8728a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BE */ 8738a1b9b6aSSam Leffler WME_AC_BK, /* WME_AC_BK */ 8748a1b9b6aSSam Leffler WME_AC_BE, /* WME_AC_VI */ 8758a1b9b6aSSam Leffler WME_AC_VI, /* WME_AC_VO */ 8768a1b9b6aSSam Leffler }; 877b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 878b032f27cSSam Leffler 8798a1b9b6aSSam Leffler while (ac != WME_AC_BK && 8808a1b9b6aSSam Leffler ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) 8818a1b9b6aSSam Leffler ac = acmap[ac]; 8828a1b9b6aSSam Leffler } 8838a1b9b6aSSam Leffler done: 8848a1b9b6aSSam Leffler M_WME_SETAC(m, ac); 8858a1b9b6aSSam Leffler return 0; 8868a1b9b6aSSam Leffler } 8878a1b9b6aSSam Leffler 8888a1b9b6aSSam Leffler /* 8895e923d2eSSam Leffler * Insure there is sufficient contiguous space to encapsulate the 8905e923d2eSSam Leffler * 802.11 data frame. If room isn't already there, arrange for it. 8915e923d2eSSam Leffler * Drivers and cipher modules assume we have done the necessary work 8925e923d2eSSam Leffler * and fail rudely if they don't find the space they need. 8935e923d2eSSam Leffler */ 894616190d0SSam Leffler struct mbuf * 895b032f27cSSam Leffler ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, 8965e923d2eSSam Leffler struct ieee80211_key *key, struct mbuf *m) 8975e923d2eSSam Leffler { 898ab96db10SSam Leffler #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) 899b032f27cSSam Leffler int needed_space = vap->iv_ic->ic_headroom + hdrsize; 9005e923d2eSSam Leffler 9015e923d2eSSam Leffler if (key != NULL) { 9025e923d2eSSam Leffler /* XXX belongs in crypto code? */ 9035e923d2eSSam Leffler needed_space += key->wk_cipher->ic_header; 9045e923d2eSSam Leffler /* XXX frags */ 90583a244dbSSam Leffler /* 90683a244dbSSam Leffler * When crypto is being done in the host we must insure 90783a244dbSSam Leffler * the data are writable for the cipher routines; clone 90883a244dbSSam Leffler * a writable mbuf chain. 90983a244dbSSam Leffler * XXX handle SWMIC specially 91083a244dbSSam Leffler */ 9115c1f7f19SSam Leffler if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { 91283a244dbSSam Leffler m = m_unshare(m, M_NOWAIT); 91383a244dbSSam Leffler if (m == NULL) { 914b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 91583a244dbSSam Leffler "%s: cannot get writable mbuf\n", __func__); 916b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ 91783a244dbSSam Leffler return NULL; 91883a244dbSSam Leffler } 91983a244dbSSam Leffler } 9205e923d2eSSam Leffler } 9215e923d2eSSam Leffler /* 9225e923d2eSSam Leffler * We know we are called just before stripping an Ethernet 9235e923d2eSSam Leffler * header and prepending an LLC header. This means we know 9245e923d2eSSam Leffler * there will be 925ab96db10SSam Leffler * sizeof(struct ether_header) - sizeof(struct llc) 9265e923d2eSSam Leffler * bytes recovered to which we need additional space for the 9275e923d2eSSam Leffler * 802.11 header and any crypto header. 9285e923d2eSSam Leffler */ 9295e923d2eSSam Leffler /* XXX check trailing space and copy instead? */ 9305e923d2eSSam Leffler if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { 9315e923d2eSSam Leffler struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); 9325e923d2eSSam Leffler if (n == NULL) { 933b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 9345e923d2eSSam Leffler "%s: cannot expand storage\n", __func__); 935b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 9365e923d2eSSam Leffler m_freem(m); 9375e923d2eSSam Leffler return NULL; 9385e923d2eSSam Leffler } 9395e923d2eSSam Leffler KASSERT(needed_space <= MHLEN, 9405e923d2eSSam Leffler ("not enough room, need %u got %zu\n", needed_space, MHLEN)); 9415e923d2eSSam Leffler /* 9425e923d2eSSam Leffler * Setup new mbuf to have leading space to prepend the 9435e923d2eSSam Leffler * 802.11 header and any crypto header bits that are 9445e923d2eSSam Leffler * required (the latter are added when the driver calls 9455e923d2eSSam Leffler * back to ieee80211_crypto_encap to do crypto encapsulation). 9465e923d2eSSam Leffler */ 9475e923d2eSSam Leffler /* NB: must be first 'cuz it clobbers m_data */ 9485e923d2eSSam Leffler m_move_pkthdr(n, m); 9495e923d2eSSam Leffler n->m_len = 0; /* NB: m_gethdr does not set */ 9505e923d2eSSam Leffler n->m_data += needed_space; 9515e923d2eSSam Leffler /* 9525e923d2eSSam Leffler * Pull up Ethernet header to create the expected layout. 9535e923d2eSSam Leffler * We could use m_pullup but that's overkill (i.e. we don't 9545e923d2eSSam Leffler * need the actual data) and it cannot fail so do it inline 9555e923d2eSSam Leffler * for speed. 9565e923d2eSSam Leffler */ 9575e923d2eSSam Leffler /* NB: struct ether_header is known to be contiguous */ 9585e923d2eSSam Leffler n->m_len += sizeof(struct ether_header); 9595e923d2eSSam Leffler m->m_len -= sizeof(struct ether_header); 9605e923d2eSSam Leffler m->m_data += sizeof(struct ether_header); 9615e923d2eSSam Leffler /* 9625e923d2eSSam Leffler * Replace the head of the chain. 9635e923d2eSSam Leffler */ 9645e923d2eSSam Leffler n->m_next = m; 9655e923d2eSSam Leffler m = n; 9665e923d2eSSam Leffler } 9675e923d2eSSam Leffler return m; 9685e923d2eSSam Leffler #undef TO_BE_RECLAIMED 9695e923d2eSSam Leffler } 9705e923d2eSSam Leffler 9715e923d2eSSam Leffler /* 9725e923d2eSSam Leffler * Return the transmit key to use in sending a unicast frame. 9735e923d2eSSam Leffler * If a unicast key is set we use that. When no unicast key is set 9745e923d2eSSam Leffler * we fall back to the default transmit key. 9758a1b9b6aSSam Leffler */ 9768a1b9b6aSSam Leffler static __inline struct ieee80211_key * 977b032f27cSSam Leffler ieee80211_crypto_getucastkey(struct ieee80211vap *vap, 978b032f27cSSam Leffler struct ieee80211_node *ni) 9798a1b9b6aSSam Leffler { 980cda15ce1SSam Leffler if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { 981b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 982b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 9838a1b9b6aSSam Leffler return NULL; 984b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 9858a1b9b6aSSam Leffler } else { 9868a1b9b6aSSam Leffler return &ni->ni_ucastkey; 9878a1b9b6aSSam Leffler } 9885e923d2eSSam Leffler } 9895e923d2eSSam Leffler 9905e923d2eSSam Leffler /* 9915e923d2eSSam Leffler * Return the transmit key to use in sending a multicast frame. 9925e923d2eSSam Leffler * Multicast traffic always uses the group key which is installed as 9935e923d2eSSam Leffler * the default tx key. 9945e923d2eSSam Leffler */ 9955e923d2eSSam Leffler static __inline struct ieee80211_key * 996b032f27cSSam Leffler ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, 997b032f27cSSam Leffler struct ieee80211_node *ni) 9985e923d2eSSam Leffler { 999b032f27cSSam Leffler if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 1000b032f27cSSam Leffler IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 10015e923d2eSSam Leffler return NULL; 1002b032f27cSSam Leffler return &vap->iv_nw_keys[vap->iv_def_txkey]; 10038a1b9b6aSSam Leffler } 10048a1b9b6aSSam Leffler 10058a1b9b6aSSam Leffler /* 10068a1b9b6aSSam Leffler * Encapsulate an outbound data frame. The mbuf chain is updated. 10078a1b9b6aSSam Leffler * If an error is encountered NULL is returned. The caller is required 10088a1b9b6aSSam Leffler * to provide a node reference and pullup the ethernet header in the 10098a1b9b6aSSam Leffler * first mbuf. 1010b032f27cSSam Leffler * 1011b032f27cSSam Leffler * NB: Packet is assumed to be processed by ieee80211_classify which 1012b032f27cSSam Leffler * marked EAPOL frames w/ M_EAPOL. 10130a915fadSSam Leffler */ 10141a1e1d21SSam Leffler struct mbuf * 1015339ccfb3SSam Leffler ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni, 1016339ccfb3SSam Leffler struct mbuf *m) 10171a1e1d21SSam Leffler { 1018b032f27cSSam Leffler #define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) 1019b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 102059aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 102159aa14a9SRui Paulo struct ieee80211_mesh_state *ms = vap->iv_mesh; 1022c104cff2SRui Paulo struct ieee80211_meshcntl_ae10 *mc; 102359aa14a9SRui Paulo #endif 10241a1e1d21SSam Leffler struct ether_header eh; 10251a1e1d21SSam Leffler struct ieee80211_frame *wh; 10268a1b9b6aSSam Leffler struct ieee80211_key *key; 10271a1e1d21SSam Leffler struct llc *llc; 1028616190d0SSam Leffler int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr; 10299e80b1dfSSam Leffler ieee80211_seq seqno; 103059aa14a9SRui Paulo int meshhdrsize, meshae; 103159aa14a9SRui Paulo uint8_t *qos; 10321a1e1d21SSam Leffler 103368e8e04eSSam Leffler /* 103468e8e04eSSam Leffler * Copy existing Ethernet header to a safe place. The 103568e8e04eSSam Leffler * rest of the code assumes it's ok to strip it when 103668e8e04eSSam Leffler * reorganizing state for the final encapsulation. 103768e8e04eSSam Leffler */ 10388a1b9b6aSSam Leffler KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); 1039b032f27cSSam Leffler ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); 10401a1e1d21SSam Leffler 10418a1b9b6aSSam Leffler /* 10428a1b9b6aSSam Leffler * Insure space for additional headers. First identify 10438a1b9b6aSSam Leffler * transmit key to use in calculating any buffer adjustments 10448a1b9b6aSSam Leffler * required. This is also used below to do privacy 10458a1b9b6aSSam Leffler * encapsulation work. Then calculate the 802.11 header 10468a1b9b6aSSam Leffler * size and any padding required by the driver. 10478a1b9b6aSSam Leffler * 10488a1b9b6aSSam Leffler * Note key may be NULL if we fall back to the default 10498a1b9b6aSSam Leffler * transmit key and that is not set. In that case the 10508a1b9b6aSSam Leffler * buffer may not be expanded as needed by the cipher 10518a1b9b6aSSam Leffler * routines, but they will/should discard it. 10528a1b9b6aSSam Leffler */ 1053b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) { 1054b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA || 1055b032f27cSSam Leffler !IEEE80211_IS_MULTICAST(eh.ether_dhost) || 1056b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_WDS && 1057b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) 1058b032f27cSSam Leffler key = ieee80211_crypto_getucastkey(vap, ni); 10595e923d2eSSam Leffler else 1060b032f27cSSam Leffler key = ieee80211_crypto_getmcastkey(vap, ni); 1061b032f27cSSam Leffler if (key == NULL && (m->m_flags & M_EAPOL) == 0) { 1062b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, 1063b032f27cSSam Leffler eh.ether_dhost, 1064b032f27cSSam Leffler "no default transmit key (%s) deftxkey %u", 1065b032f27cSSam Leffler __func__, vap->iv_def_txkey); 1066b032f27cSSam Leffler vap->iv_stats.is_tx_nodefkey++; 1067d72c7253SSam Leffler goto bad; 10688a1b9b6aSSam Leffler } 10698a1b9b6aSSam Leffler } else 10708a1b9b6aSSam Leffler key = NULL; 10715e923d2eSSam Leffler /* 10725e923d2eSSam Leffler * XXX Some ap's don't handle QoS-encapsulated EAPOL 10735e923d2eSSam Leffler * frames so suppress use. This may be an issue if other 10745e923d2eSSam Leffler * ap's require all data frames to be QoS-encapsulated 10755e923d2eSSam Leffler * once negotiated in which case we'll need to make this 10765e923d2eSSam Leffler * configurable. 107791216c71SAdrian Chadd * NB: mesh data frames are QoS. 10785e923d2eSSam Leffler */ 107991216c71SAdrian Chadd addqos = ((ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) || 108091216c71SAdrian Chadd (vap->iv_opmode == IEEE80211_M_MBSS)) && 1081b032f27cSSam Leffler (m->m_flags & M_EAPOL) == 0; 10825e923d2eSSam Leffler if (addqos) 10838a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_qosframe); 10848a1b9b6aSSam Leffler else 10858a1b9b6aSSam Leffler hdrsize = sizeof(struct ieee80211_frame); 108659aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 108759aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 108859aa14a9SRui Paulo /* 108959aa14a9SRui Paulo * Mesh data frames are encapsulated according to the 109059aa14a9SRui Paulo * rules of Section 11B.8.5 (p.139 of D3.0 spec). 109159aa14a9SRui Paulo * o Group Addressed data (aka multicast) originating 109259aa14a9SRui Paulo * at the local sta are sent w/ 3-address format and 109359aa14a9SRui Paulo * address extension mode 00 109459aa14a9SRui Paulo * o Individually Addressed data (aka unicast) originating 109559aa14a9SRui Paulo * at the local sta are sent w/ 4-address format and 109659aa14a9SRui Paulo * address extension mode 00 109759aa14a9SRui Paulo * o Group Addressed data forwarded from a non-mesh sta are 109859aa14a9SRui Paulo * sent w/ 3-address format and address extension mode 01 109959aa14a9SRui Paulo * o Individually Address data from another sta are sent 110059aa14a9SRui Paulo * w/ 4-address format and address extension mode 10 110159aa14a9SRui Paulo */ 110259aa14a9SRui Paulo is4addr = 0; /* NB: don't use, disable */ 1103c104cff2SRui Paulo if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) 1104c104cff2SRui Paulo hdrsize += IEEE80211_ADDR_LEN; /* unicast are 4-addr */ 110559aa14a9SRui Paulo meshhdrsize = sizeof(struct ieee80211_meshcntl); 110659aa14a9SRui Paulo /* XXX defines for AE modes */ 110759aa14a9SRui Paulo if (IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { 1108c104cff2SRui Paulo if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) 110959aa14a9SRui Paulo meshae = 0; 1110c104cff2SRui Paulo else 111159aa14a9SRui Paulo meshae = 4; /* NB: pseudo */ 111259aa14a9SRui Paulo } else if (IEEE80211_IS_MULTICAST(eh.ether_dhost)) { 111359aa14a9SRui Paulo meshae = 1; 1114c104cff2SRui Paulo meshhdrsize += 1*IEEE80211_ADDR_LEN; 111559aa14a9SRui Paulo } else { 111659aa14a9SRui Paulo meshae = 2; 1117c104cff2SRui Paulo meshhdrsize += 2*IEEE80211_ADDR_LEN; 111859aa14a9SRui Paulo } 111959aa14a9SRui Paulo } else { 112059aa14a9SRui Paulo #endif 1121b032f27cSSam Leffler /* 1122b032f27cSSam Leffler * 4-address frames need to be generated for: 11236437e6daSSam Leffler * o packets sent through a WDS vap (IEEE80211_M_WDS) 1124f2a6a13cSSam Leffler * o packets sent through a vap marked for relaying 1125f2a6a13cSSam Leffler * (e.g. a station operating with dynamic WDS) 1126b032f27cSSam Leffler */ 11276437e6daSSam Leffler is4addr = vap->iv_opmode == IEEE80211_M_WDS || 1128f2a6a13cSSam Leffler ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) && 1129b032f27cSSam Leffler !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); 1130b032f27cSSam Leffler if (is4addr) 1131b032f27cSSam Leffler hdrsize += IEEE80211_ADDR_LEN; 113259aa14a9SRui Paulo meshhdrsize = meshae = 0; 113359aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 113459aa14a9SRui Paulo } 113559aa14a9SRui Paulo #endif 1136b032f27cSSam Leffler /* 1137b032f27cSSam Leffler * Honor driver DATAPAD requirement. 1138b032f27cSSam Leffler */ 11398a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_DATAPAD) 1140b032f27cSSam Leffler hdrspace = roundup(hdrsize, sizeof(uint32_t)); 1141b032f27cSSam Leffler else 1142b032f27cSSam Leffler hdrspace = hdrsize; 114368e8e04eSSam Leffler 1144616190d0SSam Leffler if (__predict_true((m->m_flags & M_FF) == 0)) { 114568e8e04eSSam Leffler /* 114668e8e04eSSam Leffler * Normal frame. 114768e8e04eSSam Leffler */ 114859aa14a9SRui Paulo m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m); 11498a1b9b6aSSam Leffler if (m == NULL) { 11508a1b9b6aSSam Leffler /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 11510a915fadSSam Leffler goto bad; 11520a915fadSSam Leffler } 115368e8e04eSSam Leffler /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ 1154ab96db10SSam Leffler m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 11551a1e1d21SSam Leffler llc = mtod(m, struct llc *); 11561a1e1d21SSam Leffler llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 11571a1e1d21SSam Leffler llc->llc_control = LLC_UI; 11581a1e1d21SSam Leffler llc->llc_snap.org_code[0] = 0; 11591a1e1d21SSam Leffler llc->llc_snap.org_code[1] = 0; 11601a1e1d21SSam Leffler llc->llc_snap.org_code[2] = 0; 11611a1e1d21SSam Leffler llc->llc_snap.ether_type = eh.ether_type; 1162616190d0SSam Leffler } else { 1163616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 1164339ccfb3SSam Leffler /* 1165339ccfb3SSam Leffler * Aggregated frame. 1166339ccfb3SSam Leffler */ 116759aa14a9SRui Paulo m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key); 1168616190d0SSam Leffler if (m == NULL) 1169616190d0SSam Leffler #endif 1170616190d0SSam Leffler goto bad; 117168e8e04eSSam Leffler } 11728a1b9b6aSSam Leffler datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ 11738a1b9b6aSSam Leffler 117459aa14a9SRui Paulo M_PREPEND(m, hdrspace + meshhdrsize, M_DONTWAIT); 11751be50176SSam Leffler if (m == NULL) { 1176b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 11770a915fadSSam Leffler goto bad; 11781be50176SSam Leffler } 11791a1e1d21SSam Leffler wh = mtod(m, struct ieee80211_frame *); 11801a1e1d21SSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 118168e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 118259aa14a9SRui Paulo qos = NULL; /* NB: quiet compiler */ 1183b032f27cSSam Leffler if (is4addr) { 1184b032f27cSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 1185b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 1186b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1187b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1188b032f27cSSam Leffler IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 1189b032f27cSSam Leffler } else switch (vap->iv_opmode) { 11901a1e1d21SSam Leffler case IEEE80211_M_STA: 11911a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 11921a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 11931a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 11941a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 11951a1e1d21SSam Leffler break; 11961a1e1d21SSam Leffler case IEEE80211_M_IBSS: 11971a1e1d21SSam Leffler case IEEE80211_M_AHDEMO: 11981a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 11991a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 12001a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1201a8b16e87SSam Leffler /* 1202b032f27cSSam Leffler * NB: always use the bssid from iv_bss as the 1203a8b16e87SSam Leffler * neighbor's may be stale after an ibss merge 1204a8b16e87SSam Leffler */ 1205b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); 12061a1e1d21SSam Leffler break; 12071a1e1d21SSam Leffler case IEEE80211_M_HOSTAP: 12081a1e1d21SSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 12091a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 12101a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 12111a1e1d21SSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 12121a1e1d21SSam Leffler break; 121359aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 121459aa14a9SRui Paulo case IEEE80211_M_MBSS: 121559aa14a9SRui Paulo /* NB: offset by hdrspace to deal with DATAPAD */ 1216c104cff2SRui Paulo mc = (struct ieee80211_meshcntl_ae10 *) 121759aa14a9SRui Paulo (mtod(m, uint8_t *) + hdrspace); 121859aa14a9SRui Paulo switch (meshae) { 121959aa14a9SRui Paulo case 0: /* ucast, no proxy */ 122059aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 122159aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 122259aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 122359aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 122459aa14a9SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 122559aa14a9SRui Paulo mc->mc_flags = 0; 122659aa14a9SRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 122759aa14a9SRui Paulo break; 122859aa14a9SRui Paulo case 4: /* mcast, no proxy */ 122959aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 123059aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 123159aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 123259aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 123359aa14a9SRui Paulo mc->mc_flags = 0; /* NB: AE is really 0 */ 123459aa14a9SRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 123559aa14a9SRui Paulo break; 123659aa14a9SRui Paulo case 1: /* mcast, proxy */ 123759aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 123859aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 123959aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1240c104cff2SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr); 124159aa14a9SRui Paulo mc->mc_flags = 1; 124259aa14a9SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_shost); 124359aa14a9SRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 124459aa14a9SRui Paulo break; 124559aa14a9SRui Paulo case 2: /* ucast, proxy */ 124659aa14a9SRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 124759aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 124859aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1249c104cff2SRui Paulo /* XXX not right, need MeshDA */ 125059aa14a9SRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1251c104cff2SRui Paulo /* XXX assume are MeshSA */ 1252c104cff2SRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr); 125359aa14a9SRui Paulo mc->mc_flags = 2; 1254c104cff2SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr4, eh.ether_dhost); 125559aa14a9SRui Paulo IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_shost); 125659aa14a9SRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 125759aa14a9SRui Paulo break; 125859aa14a9SRui Paulo default: 125959aa14a9SRui Paulo KASSERT(0, ("meshae %d", meshae)); 126059aa14a9SRui Paulo break; 126159aa14a9SRui Paulo } 126259aa14a9SRui Paulo mc->mc_ttl = ms->ms_ttl; 126359aa14a9SRui Paulo ms->ms_seq++; 126459aa14a9SRui Paulo LE_WRITE_4(mc->mc_seq, ms->ms_seq); 126559aa14a9SRui Paulo break; 126659aa14a9SRui Paulo #endif 1267b032f27cSSam Leffler case IEEE80211_M_WDS: /* NB: is4addr should always be true */ 126859aa14a9SRui Paulo default: 12690a915fadSSam Leffler goto bad; 12701a1e1d21SSam Leffler } 1271bc5627d9SSam Leffler if (m->m_flags & M_MORE_DATA) 1272bc5627d9SSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 12735e923d2eSSam Leffler if (addqos) { 12748a1b9b6aSSam Leffler int ac, tid; 12758a1b9b6aSSam Leffler 1276b032f27cSSam Leffler if (is4addr) { 1277b032f27cSSam Leffler qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 127859aa14a9SRui Paulo /* NB: mesh case handled earlier */ 127959aa14a9SRui Paulo } else if (vap->iv_opmode != IEEE80211_M_MBSS) 1280b032f27cSSam Leffler qos = ((struct ieee80211_qosframe *) wh)->i_qos; 12818a1b9b6aSSam Leffler ac = M_WME_GETAC(m); 12828a1b9b6aSSam Leffler /* map from access class/queue to 11e header priorty value */ 12838a1b9b6aSSam Leffler tid = WME_AC_TO_TID(ac); 1284b032f27cSSam Leffler qos[0] = tid & IEEE80211_QOS_TID; 12858a1b9b6aSSam Leffler if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) 1286b032f27cSSam Leffler qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 128791216c71SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH 128891216c71SAdrian Chadd if (vap->iv_opmode == IEEE80211_M_MBSS) { 128991216c71SAdrian Chadd qos[1] |= IEEE80211_QOS_MC; 129091216c71SAdrian Chadd } else 129191216c71SAdrian Chadd #endif 1292b032f27cSSam Leffler qos[1] = 0; 1293b032f27cSSam Leffler wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; 12948a1b9b6aSSam Leffler 129545f856e3SSam Leffler if ((m->m_flags & M_AMPDU_MPDU) == 0) { 129645f856e3SSam Leffler /* 129745f856e3SSam Leffler * NB: don't assign a sequence # to potential 129845f856e3SSam Leffler * aggregates; we expect this happens at the 129945f856e3SSam Leffler * point the frame comes off any aggregation q 130045f856e3SSam Leffler * as otherwise we may introduce holes in the 130145f856e3SSam Leffler * BA sequence space and/or make window accouting 130245f856e3SSam Leffler * more difficult. 130345f856e3SSam Leffler * 130445f856e3SSam Leffler * XXX may want to control this with a driver 130545f856e3SSam Leffler * capability; this may also change when we pull 130645f856e3SSam Leffler * aggregation up into net80211 130745f856e3SSam Leffler */ 13089e80b1dfSSam Leffler seqno = ni->ni_txseqs[tid]++; 130968e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 13109e80b1dfSSam Leffler htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 13119a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 131245f856e3SSam Leffler } 13138a1b9b6aSSam Leffler } else { 13149e80b1dfSSam Leffler seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 131568e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 13169e80b1dfSSam Leffler htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 13179a841c7fSSam Leffler M_SEQNO_SET(m, seqno); 13188a1b9b6aSSam Leffler } 13199a841c7fSSam Leffler 132059aa14a9SRui Paulo 132168e8e04eSSam Leffler /* check if xmit fragmentation is required */ 1322b032f27cSSam Leffler txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && 132368e8e04eSSam Leffler !IEEE80211_IS_MULTICAST(wh->i_addr1) && 1324b032f27cSSam Leffler (vap->iv_caps & IEEE80211_C_TXFRAG) && 1325e9cfc1f5SSam Leffler (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0); 13265e923d2eSSam Leffler if (key != NULL) { 13275e923d2eSSam Leffler /* 13285e923d2eSSam Leffler * IEEE 802.1X: send EAPOL frames always in the clear. 13295e923d2eSSam Leffler * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 13305e923d2eSSam Leffler */ 1331b032f27cSSam Leffler if ((m->m_flags & M_EAPOL) == 0 || 1332b032f27cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) && 1333b032f27cSSam Leffler (vap->iv_opmode == IEEE80211_M_STA ? 1334cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(key) : 1335cda15ce1SSam Leffler !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { 13365e923d2eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_WEP; 1337b032f27cSSam Leffler if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { 1338b032f27cSSam Leffler IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, 1339b032f27cSSam Leffler eh.ether_dhost, 1340b032f27cSSam Leffler "%s", "enmic failed, discard frame"); 1341b032f27cSSam Leffler vap->iv_stats.is_crypto_enmicfail++; 13425e923d2eSSam Leffler goto bad; 13435e923d2eSSam Leffler } 13445e923d2eSSam Leffler } 13455e923d2eSSam Leffler } 1346b032f27cSSam Leffler if (txfrag && !ieee80211_fragment(vap, m, hdrsize, 1347b032f27cSSam Leffler key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) 134868e8e04eSSam Leffler goto bad; 13498a1b9b6aSSam Leffler 1350c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 1351c1af44bdSSam Leffler 13528a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_data); 13539e80b1dfSSam Leffler if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1354b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_mcast); 13559e80b1dfSSam Leffler m->m_flags |= M_MCAST; 13569e80b1dfSSam Leffler } else 1357b6e9b119SSam Leffler IEEE80211_NODE_STAT(ni, tx_ucast); 13588a1b9b6aSSam Leffler IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); 13598a1b9b6aSSam Leffler 13601a1e1d21SSam Leffler return m; 13610a915fadSSam Leffler bad: 13620a915fadSSam Leffler if (m != NULL) 13630a915fadSSam Leffler m_freem(m); 13640a915fadSSam Leffler return NULL; 1365b032f27cSSam Leffler #undef WH4 13661a1e1d21SSam Leffler } 13671a1e1d21SSam Leffler 13681a1e1d21SSam Leffler /* 136968e8e04eSSam Leffler * Fragment the frame according to the specified mtu. 137068e8e04eSSam Leffler * The size of the 802.11 header (w/o padding) is provided 137168e8e04eSSam Leffler * so we don't need to recalculate it. We create a new 137268e8e04eSSam Leffler * mbuf for each fragment and chain it through m_nextpkt; 137368e8e04eSSam Leffler * we might be able to optimize this by reusing the original 137468e8e04eSSam Leffler * packet's mbufs but that is significantly more complicated. 137568e8e04eSSam Leffler */ 137668e8e04eSSam Leffler static int 1377b032f27cSSam Leffler ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, 137868e8e04eSSam Leffler u_int hdrsize, u_int ciphdrsize, u_int mtu) 137968e8e04eSSam Leffler { 138068e8e04eSSam Leffler struct ieee80211_frame *wh, *whf; 138168e8e04eSSam Leffler struct mbuf *m, *prev, *next; 138268e8e04eSSam Leffler u_int totalhdrsize, fragno, fragsize, off, remainder, payload; 138368e8e04eSSam Leffler 138468e8e04eSSam Leffler KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); 138568e8e04eSSam Leffler KASSERT(m0->m_pkthdr.len > mtu, 138668e8e04eSSam Leffler ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); 138768e8e04eSSam Leffler 138868e8e04eSSam Leffler wh = mtod(m0, struct ieee80211_frame *); 138968e8e04eSSam Leffler /* NB: mark the first frag; it will be propagated below */ 139068e8e04eSSam Leffler wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; 139168e8e04eSSam Leffler totalhdrsize = hdrsize + ciphdrsize; 139268e8e04eSSam Leffler fragno = 1; 139368e8e04eSSam Leffler off = mtu - ciphdrsize; 139468e8e04eSSam Leffler remainder = m0->m_pkthdr.len - off; 139568e8e04eSSam Leffler prev = m0; 139668e8e04eSSam Leffler do { 139768e8e04eSSam Leffler fragsize = totalhdrsize + remainder; 139868e8e04eSSam Leffler if (fragsize > mtu) 139968e8e04eSSam Leffler fragsize = mtu; 1400b032f27cSSam Leffler /* XXX fragsize can be >2048! */ 140168e8e04eSSam Leffler KASSERT(fragsize < MCLBYTES, 140268e8e04eSSam Leffler ("fragment size %u too big!", fragsize)); 140368e8e04eSSam Leffler if (fragsize > MHLEN) 140468e8e04eSSam Leffler m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 140568e8e04eSSam Leffler else 140668e8e04eSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 140768e8e04eSSam Leffler if (m == NULL) 140868e8e04eSSam Leffler goto bad; 140968e8e04eSSam Leffler /* leave room to prepend any cipher header */ 141068e8e04eSSam Leffler m_align(m, fragsize - ciphdrsize); 141168e8e04eSSam Leffler 141268e8e04eSSam Leffler /* 141368e8e04eSSam Leffler * Form the header in the fragment. Note that since 141468e8e04eSSam Leffler * we mark the first fragment with the MORE_FRAG bit 141568e8e04eSSam Leffler * it automatically is propagated to each fragment; we 141668e8e04eSSam Leffler * need only clear it on the last fragment (done below). 141791216c71SAdrian Chadd * NB: frag 1+ dont have Mesh Control field present. 141868e8e04eSSam Leffler */ 141968e8e04eSSam Leffler whf = mtod(m, struct ieee80211_frame *); 142068e8e04eSSam Leffler memcpy(whf, wh, hdrsize); 142191216c71SAdrian Chadd #ifdef IEEE80211_SUPPORT_MESH 142291216c71SAdrian Chadd if (vap->iv_opmode == IEEE80211_M_MBSS) { 142391216c71SAdrian Chadd if (IEEE80211_IS_DSTODS(wh)) 142491216c71SAdrian Chadd ((struct ieee80211_qosframe_addr4 *) 142591216c71SAdrian Chadd whf)->i_qos[1] &= ~IEEE80211_QOS_MC; 142691216c71SAdrian Chadd else 142791216c71SAdrian Chadd ((struct ieee80211_qosframe *) 142891216c71SAdrian Chadd whf)->i_qos[1] &= ~IEEE80211_QOS_MC; 142991216c71SAdrian Chadd } 143091216c71SAdrian Chadd #endif 143168e8e04eSSam Leffler *(uint16_t *)&whf->i_seq[0] |= htole16( 143268e8e04eSSam Leffler (fragno & IEEE80211_SEQ_FRAG_MASK) << 143368e8e04eSSam Leffler IEEE80211_SEQ_FRAG_SHIFT); 143468e8e04eSSam Leffler fragno++; 143568e8e04eSSam Leffler 143668e8e04eSSam Leffler payload = fragsize - totalhdrsize; 143768e8e04eSSam Leffler /* NB: destination is known to be contiguous */ 143868e8e04eSSam Leffler m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrsize); 143968e8e04eSSam Leffler m->m_len = hdrsize + payload; 144068e8e04eSSam Leffler m->m_pkthdr.len = hdrsize + payload; 144168e8e04eSSam Leffler m->m_flags |= M_FRAG; 144268e8e04eSSam Leffler 144368e8e04eSSam Leffler /* chain up the fragment */ 144468e8e04eSSam Leffler prev->m_nextpkt = m; 144568e8e04eSSam Leffler prev = m; 144668e8e04eSSam Leffler 144768e8e04eSSam Leffler /* deduct fragment just formed */ 144868e8e04eSSam Leffler remainder -= payload; 144968e8e04eSSam Leffler off += payload; 145068e8e04eSSam Leffler } while (remainder != 0); 145151cec121SWeongyo Jeong 145251cec121SWeongyo Jeong /* set the last fragment */ 145351cec121SWeongyo Jeong m->m_flags |= M_LASTFRAG; 145468e8e04eSSam Leffler whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; 145568e8e04eSSam Leffler 145668e8e04eSSam Leffler /* strip first mbuf now that everything has been copied */ 145768e8e04eSSam Leffler m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); 145868e8e04eSSam Leffler m0->m_flags |= M_FIRSTFRAG | M_FRAG; 145968e8e04eSSam Leffler 1460b032f27cSSam Leffler vap->iv_stats.is_tx_fragframes++; 1461b032f27cSSam Leffler vap->iv_stats.is_tx_frags += fragno-1; 146268e8e04eSSam Leffler 146368e8e04eSSam Leffler return 1; 146468e8e04eSSam Leffler bad: 146568e8e04eSSam Leffler /* reclaim fragments but leave original frame for caller to free */ 146668e8e04eSSam Leffler for (m = m0->m_nextpkt; m != NULL; m = next) { 146768e8e04eSSam Leffler next = m->m_nextpkt; 146868e8e04eSSam Leffler m->m_nextpkt = NULL; /* XXX paranoid */ 146968e8e04eSSam Leffler m_freem(m); 147068e8e04eSSam Leffler } 147168e8e04eSSam Leffler m0->m_nextpkt = NULL; 147268e8e04eSSam Leffler return 0; 147368e8e04eSSam Leffler } 147468e8e04eSSam Leffler 147568e8e04eSSam Leffler /* 14761a1e1d21SSam Leffler * Add a supported rates element id to a frame. 14771a1e1d21SSam Leffler */ 147859aa14a9SRui Paulo uint8_t * 147968e8e04eSSam Leffler ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 14801a1e1d21SSam Leffler { 14811a1e1d21SSam Leffler int nrates; 14821a1e1d21SSam Leffler 14831a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_RATES; 14841a1e1d21SSam Leffler nrates = rs->rs_nrates; 14851a1e1d21SSam Leffler if (nrates > IEEE80211_RATE_SIZE) 14861a1e1d21SSam Leffler nrates = IEEE80211_RATE_SIZE; 14871a1e1d21SSam Leffler *frm++ = nrates; 14881a1e1d21SSam Leffler memcpy(frm, rs->rs_rates, nrates); 14891a1e1d21SSam Leffler return frm + nrates; 14901a1e1d21SSam Leffler } 14911a1e1d21SSam Leffler 14921a1e1d21SSam Leffler /* 14931a1e1d21SSam Leffler * Add an extended supported rates element id to a frame. 14941a1e1d21SSam Leffler */ 149559aa14a9SRui Paulo uint8_t * 149668e8e04eSSam Leffler ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 14971a1e1d21SSam Leffler { 14981a1e1d21SSam Leffler /* 14991a1e1d21SSam Leffler * Add an extended supported rates element if operating in 11g mode. 15001a1e1d21SSam Leffler */ 15011a1e1d21SSam Leffler if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 15021a1e1d21SSam Leffler int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 15031a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_XRATES; 15041a1e1d21SSam Leffler *frm++ = nrates; 15051a1e1d21SSam Leffler memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 15061a1e1d21SSam Leffler frm += nrates; 15071a1e1d21SSam Leffler } 15081a1e1d21SSam Leffler return frm; 15091a1e1d21SSam Leffler } 15101a1e1d21SSam Leffler 15111a1e1d21SSam Leffler /* 1512b032f27cSSam Leffler * Add an ssid element to a frame. 15131a1e1d21SSam Leffler */ 151468e8e04eSSam Leffler static uint8_t * 151568e8e04eSSam Leffler ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) 15161a1e1d21SSam Leffler { 15171a1e1d21SSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 15181a1e1d21SSam Leffler *frm++ = len; 15191a1e1d21SSam Leffler memcpy(frm, ssid, len); 15201a1e1d21SSam Leffler return frm + len; 15211a1e1d21SSam Leffler } 15221a1e1d21SSam Leffler 15238a1b9b6aSSam Leffler /* 15248a1b9b6aSSam Leffler * Add an erp element to a frame. 15258a1b9b6aSSam Leffler */ 152668e8e04eSSam Leffler static uint8_t * 152768e8e04eSSam Leffler ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) 15281a1e1d21SSam Leffler { 152968e8e04eSSam Leffler uint8_t erp; 15301a1e1d21SSam Leffler 15318a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_ERP; 15328a1b9b6aSSam Leffler *frm++ = 1; 15338a1b9b6aSSam Leffler erp = 0; 15348a1b9b6aSSam Leffler if (ic->ic_nonerpsta != 0) 15358a1b9b6aSSam Leffler erp |= IEEE80211_ERP_NON_ERP_PRESENT; 15368a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEPROT) 15378a1b9b6aSSam Leffler erp |= IEEE80211_ERP_USE_PROTECTION; 15388a1b9b6aSSam Leffler if (ic->ic_flags & IEEE80211_F_USEBARKER) 15398a1b9b6aSSam Leffler erp |= IEEE80211_ERP_LONG_PREAMBLE; 15408a1b9b6aSSam Leffler *frm++ = erp; 15418a1b9b6aSSam Leffler return frm; 15421a1e1d21SSam Leffler } 15431a1e1d21SSam Leffler 15448a1b9b6aSSam Leffler /* 1545b032f27cSSam Leffler * Add a CFParams element to a frame. 15468a1b9b6aSSam Leffler */ 154768e8e04eSSam Leffler static uint8_t * 1548b032f27cSSam Leffler ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) 15498a1b9b6aSSam Leffler { 1550b032f27cSSam Leffler #define ADDSHORT(frm, v) do { \ 155159aa14a9SRui Paulo LE_WRITE_2(frm, v); \ 1552b032f27cSSam Leffler frm += 2; \ 1553b032f27cSSam Leffler } while (0) 1554b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_CFPARMS; 1555b032f27cSSam Leffler *frm++ = 6; 1556b032f27cSSam Leffler *frm++ = 0; /* CFP count */ 1557b032f27cSSam Leffler *frm++ = 2; /* CFP period */ 1558b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ 1559b032f27cSSam Leffler ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ 15608a1b9b6aSSam Leffler return frm; 1561b032f27cSSam Leffler #undef ADDSHORT 1562b032f27cSSam Leffler } 1563b032f27cSSam Leffler 1564b032f27cSSam Leffler static __inline uint8_t * 1565b032f27cSSam Leffler add_appie(uint8_t *frm, const struct ieee80211_appie *ie) 1566b032f27cSSam Leffler { 1567b032f27cSSam Leffler memcpy(frm, ie->ie_data, ie->ie_len); 1568b032f27cSSam Leffler return frm + ie->ie_len; 1569b032f27cSSam Leffler } 1570b032f27cSSam Leffler 1571b032f27cSSam Leffler static __inline uint8_t * 1572b032f27cSSam Leffler add_ie(uint8_t *frm, const uint8_t *ie) 1573b032f27cSSam Leffler { 1574b032f27cSSam Leffler memcpy(frm, ie, 2 + ie[1]); 1575b032f27cSSam Leffler return frm + 2 + ie[1]; 15768a1b9b6aSSam Leffler } 15778a1b9b6aSSam Leffler 15788a1b9b6aSSam Leffler #define WME_OUI_BYTES 0x00, 0x50, 0xf2 15798a1b9b6aSSam Leffler /* 15808a1b9b6aSSam Leffler * Add a WME information element to a frame. 15818a1b9b6aSSam Leffler */ 158268e8e04eSSam Leffler static uint8_t * 158368e8e04eSSam Leffler ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 15848a1b9b6aSSam Leffler { 15858a1b9b6aSSam Leffler static const struct ieee80211_wme_info info = { 15868a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 15878a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_info) - 2, 15888a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 15898a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 15908a1b9b6aSSam Leffler .wme_subtype = WME_INFO_OUI_SUBTYPE, 15918a1b9b6aSSam Leffler .wme_version = WME_VERSION, 15928a1b9b6aSSam Leffler .wme_info = 0, 15938a1b9b6aSSam Leffler }; 15948a1b9b6aSSam Leffler memcpy(frm, &info, sizeof(info)); 15958a1b9b6aSSam Leffler return frm + sizeof(info); 15968a1b9b6aSSam Leffler } 15978a1b9b6aSSam Leffler 15988a1b9b6aSSam Leffler /* 15998a1b9b6aSSam Leffler * Add a WME parameters element to a frame. 16008a1b9b6aSSam Leffler */ 160168e8e04eSSam Leffler static uint8_t * 160268e8e04eSSam Leffler ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 16038a1b9b6aSSam Leffler { 16048a1b9b6aSSam Leffler #define SM(_v, _f) (((_v) << _f##_S) & _f) 16058a1b9b6aSSam Leffler #define ADDSHORT(frm, v) do { \ 160659aa14a9SRui Paulo LE_WRITE_2(frm, v); \ 16078a1b9b6aSSam Leffler frm += 2; \ 16088a1b9b6aSSam Leffler } while (0) 16098a1b9b6aSSam Leffler /* NB: this works 'cuz a param has an info at the front */ 16108a1b9b6aSSam Leffler static const struct ieee80211_wme_info param = { 16118a1b9b6aSSam Leffler .wme_id = IEEE80211_ELEMID_VENDOR, 16128a1b9b6aSSam Leffler .wme_len = sizeof(struct ieee80211_wme_param) - 2, 16138a1b9b6aSSam Leffler .wme_oui = { WME_OUI_BYTES }, 16148a1b9b6aSSam Leffler .wme_type = WME_OUI_TYPE, 16158a1b9b6aSSam Leffler .wme_subtype = WME_PARAM_OUI_SUBTYPE, 16168a1b9b6aSSam Leffler .wme_version = WME_VERSION, 16178a1b9b6aSSam Leffler }; 16188a1b9b6aSSam Leffler int i; 16198a1b9b6aSSam Leffler 16208a1b9b6aSSam Leffler memcpy(frm, ¶m, sizeof(param)); 16218a1b9b6aSSam Leffler frm += __offsetof(struct ieee80211_wme_info, wme_info); 16228a1b9b6aSSam Leffler *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 16238a1b9b6aSSam Leffler *frm++ = 0; /* reserved field */ 16248a1b9b6aSSam Leffler for (i = 0; i < WME_NUM_AC; i++) { 16258a1b9b6aSSam Leffler const struct wmeParams *ac = 16268a1b9b6aSSam Leffler &wme->wme_bssChanParams.cap_wmeParams[i]; 16278a1b9b6aSSam Leffler *frm++ = SM(i, WME_PARAM_ACI) 16288a1b9b6aSSam Leffler | SM(ac->wmep_acm, WME_PARAM_ACM) 16298a1b9b6aSSam Leffler | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) 16308a1b9b6aSSam Leffler ; 16318a1b9b6aSSam Leffler *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 16328a1b9b6aSSam Leffler | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) 16338a1b9b6aSSam Leffler ; 16348a1b9b6aSSam Leffler ADDSHORT(frm, ac->wmep_txopLimit); 16358a1b9b6aSSam Leffler } 16368a1b9b6aSSam Leffler return frm; 16378a1b9b6aSSam Leffler #undef SM 16388a1b9b6aSSam Leffler #undef ADDSHORT 16398a1b9b6aSSam Leffler } 16408a1b9b6aSSam Leffler #undef WME_OUI_BYTES 16418a1b9b6aSSam Leffler 16420a915fadSSam Leffler /* 1643b032f27cSSam Leffler * Add an 11h Power Constraint element to a frame. 1644b032f27cSSam Leffler */ 1645b032f27cSSam Leffler static uint8_t * 1646b032f27cSSam Leffler ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) 1647b032f27cSSam Leffler { 1648b032f27cSSam Leffler const struct ieee80211_channel *c = vap->iv_bss->ni_chan; 1649b032f27cSSam Leffler /* XXX per-vap tx power limit? */ 1650b032f27cSSam Leffler int8_t limit = vap->iv_ic->ic_txpowlimit / 2; 1651b032f27cSSam Leffler 1652b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCNSTR; 1653b032f27cSSam Leffler frm[1] = 1; 1654b032f27cSSam Leffler frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; 1655b032f27cSSam Leffler return frm + 3; 1656b032f27cSSam Leffler } 1657b032f27cSSam Leffler 1658b032f27cSSam Leffler /* 1659b032f27cSSam Leffler * Add an 11h Power Capability element to a frame. 1660b032f27cSSam Leffler */ 1661b032f27cSSam Leffler static uint8_t * 1662b032f27cSSam Leffler ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) 1663b032f27cSSam Leffler { 1664b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_PWRCAP; 1665b032f27cSSam Leffler frm[1] = 2; 1666b032f27cSSam Leffler frm[2] = c->ic_minpower; 1667b032f27cSSam Leffler frm[3] = c->ic_maxpower; 1668b032f27cSSam Leffler return frm + 4; 1669b032f27cSSam Leffler } 1670b032f27cSSam Leffler 1671b032f27cSSam Leffler /* 1672b032f27cSSam Leffler * Add an 11h Supported Channels element to a frame. 1673b032f27cSSam Leffler */ 1674b032f27cSSam Leffler static uint8_t * 1675b032f27cSSam Leffler ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) 1676b032f27cSSam Leffler { 1677b032f27cSSam Leffler static const int ielen = 26; 1678b032f27cSSam Leffler 1679b032f27cSSam Leffler frm[0] = IEEE80211_ELEMID_SUPPCHAN; 1680b032f27cSSam Leffler frm[1] = ielen; 1681b032f27cSSam Leffler /* XXX not correct */ 1682b032f27cSSam Leffler memcpy(frm+2, ic->ic_chan_avail, ielen); 1683b032f27cSSam Leffler return frm + 2 + ielen; 1684b032f27cSSam Leffler } 1685b032f27cSSam Leffler 1686b032f27cSSam Leffler /* 168732b0e64bSAdrian Chadd * Add an 11h Quiet time element to a frame. 168832b0e64bSAdrian Chadd */ 168932b0e64bSAdrian Chadd static uint8_t * 169032b0e64bSAdrian Chadd ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap) 169132b0e64bSAdrian Chadd { 169232b0e64bSAdrian Chadd struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm; 169332b0e64bSAdrian Chadd 169432b0e64bSAdrian Chadd quiet->quiet_ie = IEEE80211_ELEMID_QUIET; 169532b0e64bSAdrian Chadd quiet->len = 6; 169632b0e64bSAdrian Chadd if (vap->iv_quiet_count_value == 1) 169732b0e64bSAdrian Chadd vap->iv_quiet_count_value = vap->iv_quiet_count; 169832b0e64bSAdrian Chadd else if (vap->iv_quiet_count_value > 1) 169932b0e64bSAdrian Chadd vap->iv_quiet_count_value--; 170032b0e64bSAdrian Chadd 170132b0e64bSAdrian Chadd if (vap->iv_quiet_count_value == 0) { 170232b0e64bSAdrian Chadd /* value 0 is reserved as per 802.11h standerd */ 170332b0e64bSAdrian Chadd vap->iv_quiet_count_value = 1; 170432b0e64bSAdrian Chadd } 170532b0e64bSAdrian Chadd 170632b0e64bSAdrian Chadd quiet->tbttcount = vap->iv_quiet_count_value; 170732b0e64bSAdrian Chadd quiet->period = vap->iv_quiet_period; 170832b0e64bSAdrian Chadd quiet->duration = htole16(vap->iv_quiet_duration); 170932b0e64bSAdrian Chadd quiet->offset = htole16(vap->iv_quiet_offset); 171032b0e64bSAdrian Chadd return frm + sizeof(*quiet); 171132b0e64bSAdrian Chadd } 171232b0e64bSAdrian Chadd 171332b0e64bSAdrian Chadd /* 1714b032f27cSSam Leffler * Add an 11h Channel Switch Announcement element to a frame. 1715b032f27cSSam Leffler * Note that we use the per-vap CSA count to adjust the global 1716b032f27cSSam Leffler * counter so we can use this routine to form probe response 1717b032f27cSSam Leffler * frames and get the current count. 1718b032f27cSSam Leffler */ 1719b032f27cSSam Leffler static uint8_t * 1720b032f27cSSam Leffler ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) 1721b032f27cSSam Leffler { 1722b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 1723b032f27cSSam Leffler struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; 1724b032f27cSSam Leffler 1725c70761e6SSam Leffler csa->csa_ie = IEEE80211_ELEMID_CSA; 1726b032f27cSSam Leffler csa->csa_len = 3; 1727b032f27cSSam Leffler csa->csa_mode = 1; /* XXX force quiet on channel */ 1728b032f27cSSam Leffler csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); 1729b032f27cSSam Leffler csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; 1730b032f27cSSam Leffler return frm + sizeof(*csa); 1731b032f27cSSam Leffler } 1732b032f27cSSam Leffler 1733b032f27cSSam Leffler /* 1734b032f27cSSam Leffler * Add an 11h country information element to a frame. 1735b032f27cSSam Leffler */ 1736b032f27cSSam Leffler static uint8_t * 1737b032f27cSSam Leffler ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) 1738b032f27cSSam Leffler { 1739b032f27cSSam Leffler 1740b032f27cSSam Leffler if (ic->ic_countryie == NULL || 1741b032f27cSSam Leffler ic->ic_countryie_chan != ic->ic_bsschan) { 1742b032f27cSSam Leffler /* 1743b032f27cSSam Leffler * Handle lazy construction of ie. This is done on 1744b032f27cSSam Leffler * first use and after a channel change that requires 1745b032f27cSSam Leffler * re-calculation. 1746b032f27cSSam Leffler */ 1747b032f27cSSam Leffler if (ic->ic_countryie != NULL) 1748b032f27cSSam Leffler free(ic->ic_countryie, M_80211_NODE_IE); 1749b032f27cSSam Leffler ic->ic_countryie = ieee80211_alloc_countryie(ic); 1750b032f27cSSam Leffler if (ic->ic_countryie == NULL) 1751b032f27cSSam Leffler return frm; 1752b032f27cSSam Leffler ic->ic_countryie_chan = ic->ic_bsschan; 1753b032f27cSSam Leffler } 1754b032f27cSSam Leffler return add_appie(frm, ic->ic_countryie); 1755b032f27cSSam Leffler } 1756b032f27cSSam Leffler 1757b032f27cSSam Leffler /* 1758af8418dcSSam Leffler * Send a probe request frame with the specified ssid 1759af8418dcSSam Leffler * and any optional information element data. 1760af8418dcSSam Leffler */ 1761af8418dcSSam Leffler int 1762af8418dcSSam Leffler ieee80211_send_probereq(struct ieee80211_node *ni, 176368e8e04eSSam Leffler const uint8_t sa[IEEE80211_ADDR_LEN], 176468e8e04eSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], 176568e8e04eSSam Leffler const uint8_t bssid[IEEE80211_ADDR_LEN], 1766b032f27cSSam Leffler const uint8_t *ssid, size_t ssidlen) 1767af8418dcSSam Leffler { 1768b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1769af8418dcSSam Leffler struct ieee80211com *ic = ni->ni_ic; 177016d7cbb1SSam Leffler const struct ieee80211_txparam *tp; 177116d7cbb1SSam Leffler struct ieee80211_bpf_params params; 1772af8418dcSSam Leffler struct ieee80211_frame *wh; 177341b3c790SSam Leffler const struct ieee80211_rateset *rs; 1774af8418dcSSam Leffler struct mbuf *m; 177568e8e04eSSam Leffler uint8_t *frm; 1776af8418dcSSam Leffler 1777b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 1778b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 1779b032f27cSSam Leffler "block %s frame in CAC state", "probe request"); 1780b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 1781b032f27cSSam Leffler return EIO; /* XXX */ 1782b032f27cSSam Leffler } 1783b032f27cSSam Leffler 1784af8418dcSSam Leffler /* 1785af8418dcSSam Leffler * Hold a reference on the node so it doesn't go away until after 1786af8418dcSSam Leffler * the xmit is complete all the way in the driver. On error we 1787af8418dcSSam Leffler * will remove our reference. 1788af8418dcSSam Leffler */ 1789b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 1790af8418dcSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 1791af8418dcSSam Leffler __func__, __LINE__, 1792af8418dcSSam Leffler ni, ether_sprintf(ni->ni_macaddr), 1793af8418dcSSam Leffler ieee80211_node_refcnt(ni)+1); 1794af8418dcSSam Leffler ieee80211_ref_node(ni); 1795af8418dcSSam Leffler 1796af8418dcSSam Leffler /* 1797af8418dcSSam Leffler * prreq frame format 1798af8418dcSSam Leffler * [tlv] ssid 1799af8418dcSSam Leffler * [tlv] supported rates 1800b032f27cSSam Leffler * [tlv] RSN (optional) 1801af8418dcSSam Leffler * [tlv] extended supported rates 1802b032f27cSSam Leffler * [tlv] WPA (optional) 1803af8418dcSSam Leffler * [tlv] user-specified ie's 1804af8418dcSSam Leffler */ 1805af8418dcSSam Leffler m = ieee80211_getmgtframe(&frm, 180668e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 1807af8418dcSSam Leffler 2 + IEEE80211_NWID_LEN 1808af8418dcSSam Leffler + 2 + IEEE80211_RATE_SIZE 1809b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 1810af8418dcSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 1811b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 1812b032f27cSSam Leffler + (vap->iv_appie_probereq != NULL ? 1813b032f27cSSam Leffler vap->iv_appie_probereq->ie_len : 0) 1814af8418dcSSam Leffler ); 1815af8418dcSSam Leffler if (m == NULL) { 1816b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 1817af8418dcSSam Leffler ieee80211_free_node(ni); 1818af8418dcSSam Leffler return ENOMEM; 1819af8418dcSSam Leffler } 1820af8418dcSSam Leffler 1821af8418dcSSam Leffler frm = ieee80211_add_ssid(frm, ssid, ssidlen); 182241b3c790SSam Leffler rs = ieee80211_get_suprates(ic, ic->ic_curchan); 182341b3c790SSam Leffler frm = ieee80211_add_rates(frm, rs); 1824b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 1825b032f27cSSam Leffler if (vap->iv_rsn_ie != NULL) 1826b032f27cSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 1827b032f27cSSam Leffler /* XXX else complain? */ 1828af8418dcSSam Leffler } 1829b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 1830b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 1831b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 1832b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 1833b032f27cSSam Leffler /* XXX else complain? */ 1834b032f27cSSam Leffler } 1835b032f27cSSam Leffler if (vap->iv_appie_probereq != NULL) 1836b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_probereq); 183768e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 1838af8418dcSSam Leffler 183916d7cbb1SSam Leffler KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), 184016d7cbb1SSam Leffler ("leading space %zd", M_LEADINGSPACE(m))); 1841af8418dcSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 184216d7cbb1SSam Leffler if (m == NULL) { 184316d7cbb1SSam Leffler /* NB: cannot happen */ 184416d7cbb1SSam Leffler ieee80211_free_node(ni); 1845af8418dcSSam Leffler return ENOMEM; 184616d7cbb1SSam Leffler } 1847af8418dcSSam Leffler 1848af8418dcSSam Leffler wh = mtod(m, struct ieee80211_frame *); 18499e80b1dfSSam Leffler ieee80211_send_setup(ni, m, 1850af8418dcSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 18518ac160cdSSam Leffler IEEE80211_NONQOS_TID, sa, da, bssid); 1852af8418dcSSam Leffler /* XXX power management? */ 1853c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 1854af8418dcSSam Leffler 1855b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 1856b032f27cSSam Leffler 1857af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_probereq); 1858af8418dcSSam Leffler IEEE80211_NODE_STAT(ni, tx_mgmt); 1859af8418dcSSam Leffler 1860b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 1861b032f27cSSam Leffler "send probe req on channel %u bssid %s ssid \"%.*s\"\n", 1862b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid), 1863b032f27cSSam Leffler ssidlen, ssid); 1864af8418dcSSam Leffler 186516d7cbb1SSam Leffler memset(¶ms, 0, sizeof(params)); 186616d7cbb1SSam Leffler params.ibp_pri = M_WME_GETAC(m); 186716d7cbb1SSam Leffler tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 186816d7cbb1SSam Leffler params.ibp_rate0 = tp->mgmtrate; 186916d7cbb1SSam Leffler if (IEEE80211_IS_MULTICAST(da)) { 187016d7cbb1SSam Leffler params.ibp_flags |= IEEE80211_BPF_NOACK; 187116d7cbb1SSam Leffler params.ibp_try0 = 1; 187216d7cbb1SSam Leffler } else 187316d7cbb1SSam Leffler params.ibp_try0 = tp->maxretry; 187416d7cbb1SSam Leffler params.ibp_power = ni->ni_txpower; 187516d7cbb1SSam Leffler return ic->ic_raw_xmit(ni, m, ¶ms); 1876af8418dcSSam Leffler } 1877af8418dcSSam Leffler 1878af8418dcSSam Leffler /* 1879667dad55SSam Leffler * Calculate capability information for mgt frames. 1880667dad55SSam Leffler */ 188159aa14a9SRui Paulo uint16_t 188259aa14a9SRui Paulo ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) 1883667dad55SSam Leffler { 1884b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 188568e8e04eSSam Leffler uint16_t capinfo; 1886667dad55SSam Leffler 1887b032f27cSSam Leffler KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); 1888667dad55SSam Leffler 1889b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_HOSTAP) 1890667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 1891b032f27cSSam Leffler else if (vap->iv_opmode == IEEE80211_M_IBSS) 1892667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_IBSS; 1893667dad55SSam Leffler else 1894667dad55SSam Leffler capinfo = 0; 1895b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 1896667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 1897667dad55SSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 1898667dad55SSam Leffler IEEE80211_IS_CHAN_2GHZ(chan)) 1899667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 1900667dad55SSam Leffler if (ic->ic_flags & IEEE80211_F_SHSLOT) 1901667dad55SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 1902b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) 1903b032f27cSSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 1904667dad55SSam Leffler return capinfo; 1905667dad55SSam Leffler } 1906667dad55SSam Leffler 1907667dad55SSam Leffler /* 19080a915fadSSam Leffler * Send a management frame. The node is for the destination (or ic_bss 19090a915fadSSam Leffler * when in station mode). Nodes other than ic_bss have their reference 19100a915fadSSam Leffler * count bumped to reflect our use for an indeterminant time. 19110a915fadSSam Leffler */ 19121a1e1d21SSam Leffler int 1913b032f27cSSam Leffler ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) 19141a1e1d21SSam Leffler { 19151b6167d2SSam Leffler #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) 1916b032f27cSSam Leffler #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) 1917b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 1918b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 1919b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 19208ac160cdSSam Leffler struct ieee80211_bpf_params params; 19211a1e1d21SSam Leffler struct mbuf *m; 192268e8e04eSSam Leffler uint8_t *frm; 192368e8e04eSSam Leffler uint16_t capinfo; 192468e8e04eSSam Leffler int has_challenge, is_shared_key, ret, status; 19251a1e1d21SSam Leffler 19260a915fadSSam Leffler KASSERT(ni != NULL, ("null node")); 19270a915fadSSam Leffler 19280a915fadSSam Leffler /* 19290a915fadSSam Leffler * Hold a reference on the node so it doesn't go away until after 19300a915fadSSam Leffler * the xmit is complete all the way in the driver. On error we 19310a915fadSSam Leffler * will remove our reference. 19320a915fadSSam Leffler */ 1933b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 193449a15236SSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 19358a1b9b6aSSam Leffler __func__, __LINE__, 193649a15236SSam Leffler ni, ether_sprintf(ni->ni_macaddr), 19378a1b9b6aSSam Leffler ieee80211_node_refcnt(ni)+1); 19380a915fadSSam Leffler ieee80211_ref_node(ni); 19398a1b9b6aSSam Leffler 19408ac160cdSSam Leffler memset(¶ms, 0, sizeof(params)); 19411a1e1d21SSam Leffler switch (type) { 19421a1e1d21SSam Leffler 19431a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_AUTH: 19448a1b9b6aSSam Leffler status = arg >> 16; 19458a1b9b6aSSam Leffler arg &= 0xffff; 19468a1b9b6aSSam Leffler has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 19478a1b9b6aSSam Leffler arg == IEEE80211_AUTH_SHARED_RESPONSE) && 19488a1b9b6aSSam Leffler ni->ni_challenge != NULL); 19498a1b9b6aSSam Leffler 19508a1b9b6aSSam Leffler /* 19518a1b9b6aSSam Leffler * Deduce whether we're doing open authentication or 19528a1b9b6aSSam Leffler * shared key authentication. We do the latter if 19538a1b9b6aSSam Leffler * we're in the middle of a shared key authentication 19548a1b9b6aSSam Leffler * handshake or if we're initiating an authentication 19558a1b9b6aSSam Leffler * request and configured to use shared key. 19568a1b9b6aSSam Leffler */ 19578a1b9b6aSSam Leffler is_shared_key = has_challenge || 19588a1b9b6aSSam Leffler arg >= IEEE80211_AUTH_SHARED_RESPONSE || 19598a1b9b6aSSam Leffler (arg == IEEE80211_AUTH_SHARED_REQUEST && 1960b032f27cSSam Leffler bss->ni_authmode == IEEE80211_AUTH_SHARED); 19618a1b9b6aSSam Leffler 19628a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 196368e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 196468e8e04eSSam Leffler 3 * sizeof(uint16_t) 19658a1b9b6aSSam Leffler + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 196668e8e04eSSam Leffler sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) 19678a1b9b6aSSam Leffler ); 19681a1e1d21SSam Leffler if (m == NULL) 19698a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 19708a1b9b6aSSam Leffler 197168e8e04eSSam Leffler ((uint16_t *)frm)[0] = 19728a1b9b6aSSam Leffler (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) 19738a1b9b6aSSam Leffler : htole16(IEEE80211_AUTH_ALG_OPEN); 197468e8e04eSSam Leffler ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ 197568e8e04eSSam Leffler ((uint16_t *)frm)[2] = htole16(status);/* status */ 19768a1b9b6aSSam Leffler 19778a1b9b6aSSam Leffler if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 197868e8e04eSSam Leffler ((uint16_t *)frm)[3] = 19798a1b9b6aSSam Leffler htole16((IEEE80211_CHALLENGE_LEN << 8) | 19808a1b9b6aSSam Leffler IEEE80211_ELEMID_CHALLENGE); 198168e8e04eSSam Leffler memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, 19828a1b9b6aSSam Leffler IEEE80211_CHALLENGE_LEN); 19838a1b9b6aSSam Leffler m->m_pkthdr.len = m->m_len = 198468e8e04eSSam Leffler 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; 19858a1b9b6aSSam Leffler if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { 1986b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 1987b032f27cSSam Leffler "request encrypt frame (%s)", __func__); 19888ac160cdSSam Leffler /* mark frame for encryption */ 19898ac160cdSSam Leffler params.ibp_flags |= IEEE80211_BPF_CRYPTO; 19908a1b9b6aSSam Leffler } 19918a1b9b6aSSam Leffler } else 199268e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); 19938a1b9b6aSSam Leffler 19948a1b9b6aSSam Leffler /* XXX not right for shared key */ 19958a1b9b6aSSam Leffler if (status == IEEE80211_STATUS_SUCCESS) 19968a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth); 19978a1b9b6aSSam Leffler else 19988a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_auth_fail); 19998a1b9b6aSSam Leffler 2000b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_STA) 200168e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 2002b032f27cSSam Leffler (void *) vap->iv_state); 20031a1e1d21SSam Leffler break; 20041a1e1d21SSam Leffler 20051a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DEAUTH: 2006b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 2007b032f27cSSam Leffler "send station deauthenticate (reason %d)", arg); 200868e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 200968e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 201068e8e04eSSam Leffler sizeof(uint16_t)); 20111a1e1d21SSam Leffler if (m == NULL) 20128a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 201368e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 201468e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 20158a1b9b6aSSam Leffler 20168a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_deauth); 20178a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); 20188a1b9b6aSSam Leffler 2019e4918ecdSSam Leffler ieee80211_node_unauthorize(ni); /* port closed */ 20201a1e1d21SSam Leffler break; 20211a1e1d21SSam Leffler 20221a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 20231a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 20241a1e1d21SSam Leffler /* 20251a1e1d21SSam Leffler * asreq frame format 20261a1e1d21SSam Leffler * [2] capability information 20271a1e1d21SSam Leffler * [2] listen interval 20281a1e1d21SSam Leffler * [6*] current AP address (reassoc only) 20291a1e1d21SSam Leffler * [tlv] ssid 20301a1e1d21SSam Leffler * [tlv] supported rates 20311a1e1d21SSam Leffler * [tlv] extended supported rates 2032b032f27cSSam Leffler * [4] power capability (optional) 2033b032f27cSSam Leffler * [28] supported channels (optional) 203468e8e04eSSam Leffler * [tlv] HT capabilities 2035b032f27cSSam Leffler * [tlv] WME (optional) 203668e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 203768e8e04eSSam Leffler * [tlv] Atheros capabilities (if negotiated) 2038b032f27cSSam Leffler * [tlv] AppIE's (optional) 20391a1e1d21SSam Leffler */ 20408a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 204168e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 204268e8e04eSSam Leffler sizeof(uint16_t) 204368e8e04eSSam Leffler + sizeof(uint16_t) 20441a1e1d21SSam Leffler + IEEE80211_ADDR_LEN 20458a1b9b6aSSam Leffler + 2 + IEEE80211_NWID_LEN 20461a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 20478a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2048b032f27cSSam Leffler + 4 2049b032f27cSSam Leffler + 2 + 26 20508a1b9b6aSSam Leffler + sizeof(struct ieee80211_wme_info) 2051b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 2052b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 2053616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 205468e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2055616190d0SSam Leffler #endif 2056b032f27cSSam Leffler + (vap->iv_appie_wpa != NULL ? 2057b032f27cSSam Leffler vap->iv_appie_wpa->ie_len : 0) 2058b032f27cSSam Leffler + (vap->iv_appie_assocreq != NULL ? 2059b032f27cSSam Leffler vap->iv_appie_assocreq->ie_len : 0) 20608a1b9b6aSSam Leffler ); 20611a1e1d21SSam Leffler if (m == NULL) 20628a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 20631a1e1d21SSam Leffler 2064b032f27cSSam Leffler KASSERT(vap->iv_opmode == IEEE80211_M_STA, 2065b032f27cSSam Leffler ("wrong mode %u", vap->iv_opmode)); 2066667dad55SSam Leffler capinfo = IEEE80211_CAPINFO_ESS; 2067b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_PRIVACY) 20681a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_PRIVACY; 20694f2e09c4SSam Leffler /* 20704f2e09c4SSam Leffler * NB: Some 11a AP's reject the request when 20714f2e09c4SSam Leffler * short premable is set. 20724f2e09c4SSam Leffler */ 20734f2e09c4SSam Leffler if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 2074b5c99415SSam Leffler IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 20751a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 207668e8e04eSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 20778a1b9b6aSSam Leffler (ic->ic_caps & IEEE80211_C_SHSLOT)) 20781a1e1d21SSam Leffler capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 20791b6167d2SSam Leffler if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && 2080b032f27cSSam Leffler (vap->iv_flags & IEEE80211_F_DOTH)) 20811b6167d2SSam Leffler capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 208268e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 20831a1e1d21SSam Leffler frm += 2; 20841a1e1d21SSam Leffler 2085b032f27cSSam Leffler KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); 208668e8e04eSSam Leffler *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, 2087b032f27cSSam Leffler bss->ni_intval)); 20881a1e1d21SSam Leffler frm += 2; 20891a1e1d21SSam Leffler 20901a1e1d21SSam Leffler if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 2091b032f27cSSam Leffler IEEE80211_ADDR_COPY(frm, bss->ni_bssid); 20921a1e1d21SSam Leffler frm += IEEE80211_ADDR_LEN; 20931a1e1d21SSam Leffler } 20941a1e1d21SSam Leffler 20951a1e1d21SSam Leffler frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 20961a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 2097b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2098b032f27cSSam Leffler if (vap->iv_rsn_ie != NULL) 2099b032f27cSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2100b032f27cSSam Leffler /* XXX else complain? */ 21018a1b9b6aSSam Leffler } 2102b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 2103b032f27cSSam Leffler if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { 2104b032f27cSSam Leffler frm = ieee80211_add_powercapability(frm, 2105b032f27cSSam Leffler ic->ic_curchan); 2106b032f27cSSam Leffler frm = ieee80211_add_supportedchannels(frm, ic); 2107b032f27cSSam Leffler } 21082bfc8a91SSam Leffler if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 2109b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2110b032f27cSSam Leffler ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 2111b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, ni); 2112b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2113b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2114b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2115b032f27cSSam Leffler /* XXX else complain */ 2116b032f27cSSam Leffler } 2117b032f27cSSam Leffler if ((ic->ic_flags & IEEE80211_F_WME) && 2118b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 2119b032f27cSSam Leffler frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 21202bfc8a91SSam Leffler if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 2121b032f27cSSam Leffler ni->ni_ies.htcap_ie != NULL && 2122b032f27cSSam Leffler ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 2123b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 2124616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 21254207227cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { 2126b032f27cSSam Leffler frm = ieee80211_add_ath(frm, 2127b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 21284207227cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 21294207227cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X) ? 21304207227cSSam Leffler vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 21314207227cSSam Leffler } 2132616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 2133b032f27cSSam Leffler if (vap->iv_appie_assocreq != NULL) 2134b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocreq); 213568e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 21361a1e1d21SSam Leffler 213768e8e04eSSam Leffler ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 2138b032f27cSSam Leffler (void *) vap->iv_state); 21391a1e1d21SSam Leffler break; 21401a1e1d21SSam Leffler 21411a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 21421a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 21431a1e1d21SSam Leffler /* 214468e8e04eSSam Leffler * asresp frame format 21451a1e1d21SSam Leffler * [2] capability information 21461a1e1d21SSam Leffler * [2] status 21471a1e1d21SSam Leffler * [2] association ID 21481a1e1d21SSam Leffler * [tlv] supported rates 21491a1e1d21SSam Leffler * [tlv] extended supported rates 2150b032f27cSSam Leffler * [tlv] HT capabilities (standard, if STA enabled) 2151b032f27cSSam Leffler * [tlv] HT information (standard, if STA enabled) 2152b032f27cSSam Leffler * [tlv] WME (if configured and STA enabled) 2153b032f27cSSam Leffler * [tlv] HT capabilities (vendor OUI, if STA enabled) 2154b032f27cSSam Leffler * [tlv] HT information (vendor OUI, if STA enabled) 2155b032f27cSSam Leffler * [tlv] Atheros capabilities (if STA enabled) 2156b032f27cSSam Leffler * [tlv] AppIE's (optional) 21571a1e1d21SSam Leffler */ 21588a1b9b6aSSam Leffler m = ieee80211_getmgtframe(&frm, 215968e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 216068e8e04eSSam Leffler sizeof(uint16_t) 216168e8e04eSSam Leffler + sizeof(uint16_t) 216268e8e04eSSam Leffler + sizeof(uint16_t) 21631a1e1d21SSam Leffler + 2 + IEEE80211_RATE_SIZE 21648a1b9b6aSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 216568e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htcap) + 4 216668e8e04eSSam Leffler + sizeof(struct ieee80211_ie_htinfo) + 4 2167b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 2168616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 216968e8e04eSSam Leffler + sizeof(struct ieee80211_ath_ie) 2170616190d0SSam Leffler #endif 2171b032f27cSSam Leffler + (vap->iv_appie_assocresp != NULL ? 2172b032f27cSSam Leffler vap->iv_appie_assocresp->ie_len : 0) 21738a1b9b6aSSam Leffler ); 21741a1e1d21SSam Leffler if (m == NULL) 21758a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 21761a1e1d21SSam Leffler 217759aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 217868e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 21791a1e1d21SSam Leffler frm += 2; 21801a1e1d21SSam Leffler 218168e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* status */ 21821a1e1d21SSam Leffler frm += 2; 21831a1e1d21SSam Leffler 21848a1b9b6aSSam Leffler if (arg == IEEE80211_STATUS_SUCCESS) { 218568e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_associd); 21868a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc); 21878a1b9b6aSSam Leffler } else 21888a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_assoc_fail); 21891a1e1d21SSam Leffler frm += 2; 21901a1e1d21SSam Leffler 21911a1e1d21SSam Leffler frm = ieee80211_add_rates(frm, &ni->ni_rates); 21921a1e1d21SSam Leffler frm = ieee80211_add_xrates(frm, &ni->ni_rates); 219368e8e04eSSam Leffler /* NB: respond according to what we received */ 21941b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { 219568e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 219668e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 219768e8e04eSSam Leffler } 2198b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_WME) && 2199b032f27cSSam Leffler ni->ni_ies.wme_ie != NULL) 22001b6167d2SSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 22011b6167d2SSam Leffler if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { 22021b6167d2SSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 22031b6167d2SSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 220468e8e04eSSam Leffler } 2205616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 2206b032f27cSSam Leffler if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 220768e8e04eSSam Leffler frm = ieee80211_add_ath(frm, 2208b032f27cSSam Leffler IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 22094207227cSSam Leffler ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 22104207227cSSam Leffler ni->ni_authmode != IEEE80211_AUTH_8021X) ? 22114207227cSSam Leffler vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 2212616190d0SSam Leffler #endif /* IEEE80211_SUPPORT_SUPERG */ 2213b032f27cSSam Leffler if (vap->iv_appie_assocresp != NULL) 2214b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_assocresp); 221568e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 22161a1e1d21SSam Leffler break; 22171a1e1d21SSam Leffler 22181a1e1d21SSam Leffler case IEEE80211_FC0_SUBTYPE_DISASSOC: 2219b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 2220b032f27cSSam Leffler "send station disassociate (reason %d)", arg); 222168e8e04eSSam Leffler m = ieee80211_getmgtframe(&frm, 222268e8e04eSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 222368e8e04eSSam Leffler sizeof(uint16_t)); 22241a1e1d21SSam Leffler if (m == NULL) 22258a1b9b6aSSam Leffler senderr(ENOMEM, is_tx_nobuf); 222668e8e04eSSam Leffler *(uint16_t *)frm = htole16(arg); /* reason */ 222768e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 22288a1b9b6aSSam Leffler 22298a1b9b6aSSam Leffler IEEE80211_NODE_STAT(ni, tx_disassoc); 22308a1b9b6aSSam Leffler IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); 22311a1e1d21SSam Leffler break; 22321a1e1d21SSam Leffler 22331a1e1d21SSam Leffler default: 2234b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 2235b032f27cSSam Leffler "invalid mgmt frame type %u", type); 22361be50176SSam Leffler senderr(EINVAL, is_tx_unknownmgt); 22370a915fadSSam Leffler /* NOTREACHED */ 22381a1e1d21SSam Leffler } 223968e8e04eSSam Leffler 22408ac160cdSSam Leffler /* NB: force non-ProbeResp frames to the highest queue */ 22418ac160cdSSam Leffler params.ibp_pri = WME_AC_VO; 22428ac160cdSSam Leffler params.ibp_rate0 = bss->ni_txparms->mgmtrate; 22438ac160cdSSam Leffler /* NB: we know all frames are unicast */ 22448ac160cdSSam Leffler params.ibp_try0 = bss->ni_txparms->maxretry; 22458ac160cdSSam Leffler params.ibp_power = bss->ni_txpower; 22468ac160cdSSam Leffler return ieee80211_mgmt_output(ni, m, type, ¶ms); 22470a915fadSSam Leffler bad: 22488a1b9b6aSSam Leffler ieee80211_free_node(ni); 22491a1e1d21SSam Leffler return ret; 22500a915fadSSam Leffler #undef senderr 22511b6167d2SSam Leffler #undef HTFLAGS 22521a1e1d21SSam Leffler } 22538a1b9b6aSSam Leffler 2254b032f27cSSam Leffler /* 2255b032f27cSSam Leffler * Return an mbuf with a probe response frame in it. 2256b032f27cSSam Leffler * Space is left to prepend and 802.11 header at the 2257b032f27cSSam Leffler * front but it's left to the caller to fill in. 2258b032f27cSSam Leffler */ 2259b032f27cSSam Leffler struct mbuf * 2260b032f27cSSam Leffler ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) 2261b032f27cSSam Leffler { 2262b032f27cSSam Leffler struct ieee80211vap *vap = bss->ni_vap; 2263b032f27cSSam Leffler struct ieee80211com *ic = bss->ni_ic; 2264b032f27cSSam Leffler const struct ieee80211_rateset *rs; 2265b032f27cSSam Leffler struct mbuf *m; 2266b032f27cSSam Leffler uint16_t capinfo; 2267b032f27cSSam Leffler uint8_t *frm; 2268b032f27cSSam Leffler 2269b032f27cSSam Leffler /* 2270b032f27cSSam Leffler * probe response frame format 2271b032f27cSSam Leffler * [8] time stamp 2272b032f27cSSam Leffler * [2] beacon interval 2273b032f27cSSam Leffler * [2] cabability information 2274b032f27cSSam Leffler * [tlv] ssid 2275b032f27cSSam Leffler * [tlv] supported rates 2276b032f27cSSam Leffler * [tlv] parameter set (FH/DS) 2277b032f27cSSam Leffler * [tlv] parameter set (IBSS) 2278b032f27cSSam Leffler * [tlv] country (optional) 2279b032f27cSSam Leffler * [3] power control (optional) 2280b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 2281b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 2282b032f27cSSam Leffler * [tlv] extended supported rates 2283688fe74dSSam Leffler * [tlv] RSN (optional) 2284b032f27cSSam Leffler * [tlv] HT capabilities 2285b032f27cSSam Leffler * [tlv] HT information 2286b032f27cSSam Leffler * [tlv] WPA (optional) 2287b032f27cSSam Leffler * [tlv] WME (optional) 2288b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 2289b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 2290b032f27cSSam Leffler * [tlv] Atheros capabilities 2291b032f27cSSam Leffler * [tlv] AppIE's (optional) 229259aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 229359aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2294b032f27cSSam Leffler */ 2295b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 2296b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), 2297b032f27cSSam Leffler 8 2298b032f27cSSam Leffler + sizeof(uint16_t) 2299b032f27cSSam Leffler + sizeof(uint16_t) 2300b032f27cSSam Leffler + 2 + IEEE80211_NWID_LEN 2301b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE 2302b032f27cSSam Leffler + 7 /* max(7,3) */ 2303b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE 2304b032f27cSSam Leffler + 3 2305b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) 230632b0e64bSAdrian Chadd + sizeof(struct ieee80211_quiet_ie) 2307b032f27cSSam Leffler + 3 2308b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2309688fe74dSSam Leffler + sizeof(struct ieee80211_ie_wpa) 2310b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htcap) 2311b032f27cSSam Leffler + sizeof(struct ieee80211_ie_htinfo) 2312b032f27cSSam Leffler + sizeof(struct ieee80211_ie_wpa) 2313b032f27cSSam Leffler + sizeof(struct ieee80211_wme_param) 2314b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htcap) 2315b032f27cSSam Leffler + 4 + sizeof(struct ieee80211_ie_htinfo) 2316616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 2317b032f27cSSam Leffler + sizeof(struct ieee80211_ath_ie) 2318616190d0SSam Leffler #endif 231959aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 232059aa14a9SRui Paulo + 2 + IEEE80211_MESHID_LEN 232159aa14a9SRui Paulo + sizeof(struct ieee80211_meshconf_ie) 232259aa14a9SRui Paulo #endif 2323b032f27cSSam Leffler + (vap->iv_appie_proberesp != NULL ? 2324b032f27cSSam Leffler vap->iv_appie_proberesp->ie_len : 0) 2325b032f27cSSam Leffler ); 2326b032f27cSSam Leffler if (m == NULL) { 2327b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 2328b032f27cSSam Leffler return NULL; 2329b032f27cSSam Leffler } 2330b032f27cSSam Leffler 2331b032f27cSSam Leffler memset(frm, 0, 8); /* timestamp should be filled later */ 2332b032f27cSSam Leffler frm += 8; 2333b032f27cSSam Leffler *(uint16_t *)frm = htole16(bss->ni_intval); 2334b032f27cSSam Leffler frm += 2; 233559aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 2336b032f27cSSam Leffler *(uint16_t *)frm = htole16(capinfo); 2337b032f27cSSam Leffler frm += 2; 2338b032f27cSSam Leffler 2339b032f27cSSam Leffler frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); 2340b032f27cSSam Leffler rs = ieee80211_get_suprates(ic, bss->ni_chan); 2341b032f27cSSam Leffler frm = ieee80211_add_rates(frm, rs); 2342b032f27cSSam Leffler 2343b032f27cSSam Leffler if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { 2344b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_FHPARMS; 2345b032f27cSSam Leffler *frm++ = 5; 2346b032f27cSSam Leffler *frm++ = bss->ni_fhdwell & 0x00ff; 2347b032f27cSSam Leffler *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; 2348b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANSET( 2349b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 2350b032f27cSSam Leffler *frm++ = IEEE80211_FH_CHANPAT( 2351b032f27cSSam Leffler ieee80211_chan2ieee(ic, bss->ni_chan)); 2352b032f27cSSam Leffler *frm++ = bss->ni_fhindex; 2353b032f27cSSam Leffler } else { 2354b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 2355b032f27cSSam Leffler *frm++ = 1; 2356b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); 2357b032f27cSSam Leffler } 2358b032f27cSSam Leffler 2359b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 2360b032f27cSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 2361b032f27cSSam Leffler *frm++ = 2; 2362b032f27cSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 2363b032f27cSSam Leffler } 2364b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 2365b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2366b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 2367b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 2368b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) 2369b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 2370b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2371b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 2372b032f27cSSam Leffler } 237332b0e64bSAdrian Chadd if (vap->iv_flags & IEEE80211_F_DOTH) { 237432b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 237532b0e64bSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 237632b0e64bSAdrian Chadd if (vap->iv_quiet) 237732b0e64bSAdrian Chadd frm = ieee80211_add_quiet(frm, vap); 237832b0e64bSAdrian Chadd } 237932b0e64bSAdrian Chadd } 2380b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) 2381b032f27cSSam Leffler frm = ieee80211_add_erp(frm, ic); 2382b032f27cSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2383688fe74dSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2384688fe74dSSam Leffler if (vap->iv_rsn_ie != NULL) 2385688fe74dSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2386688fe74dSSam Leffler /* XXX else complain? */ 2387688fe74dSSam Leffler } 2388b032f27cSSam Leffler /* 2389b032f27cSSam Leffler * NB: legacy 11b clients do not get certain ie's. 2390b032f27cSSam Leffler * The caller identifies such clients by passing 2391b032f27cSSam Leffler * a token in legacy to us. Could expand this to be 2392b032f27cSSam Leffler * any legacy client for stuff like HT ie's. 2393b032f27cSSam Leffler */ 2394b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 2395b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 2396b032f27cSSam Leffler frm = ieee80211_add_htcap(frm, bss); 2397b032f27cSSam Leffler frm = ieee80211_add_htinfo(frm, bss); 2398b032f27cSSam Leffler } 2399b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2400b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2401b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2402b032f27cSSam Leffler /* XXX else complain? */ 2403b032f27cSSam Leffler } 2404b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) 2405b032f27cSSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 2406b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 24072bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) && 2408b032f27cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) { 2409b032f27cSSam Leffler frm = ieee80211_add_htcap_vendor(frm, bss); 2410b032f27cSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, bss); 2411b032f27cSSam Leffler } 2412616190d0SSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 24134207227cSSam Leffler if ((vap->iv_flags & IEEE80211_F_ATHEROS) && 24144207227cSSam Leffler legacy != IEEE80211_SEND_LEGACY_11B) 24154207227cSSam Leffler frm = ieee80211_add_athcaps(frm, bss); 2416616190d0SSam Leffler #endif 2417b032f27cSSam Leffler if (vap->iv_appie_proberesp != NULL) 2418b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_proberesp); 241959aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 242059aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 242159aa14a9SRui Paulo frm = ieee80211_add_meshid(frm, vap); 242259aa14a9SRui Paulo frm = ieee80211_add_meshconf(frm, vap); 242359aa14a9SRui Paulo } 242459aa14a9SRui Paulo #endif 2425b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2426b032f27cSSam Leffler 2427b032f27cSSam Leffler return m; 2428b032f27cSSam Leffler } 2429b032f27cSSam Leffler 2430b032f27cSSam Leffler /* 2431b032f27cSSam Leffler * Send a probe response frame to the specified mac address. 2432b032f27cSSam Leffler * This does not go through the normal mgt frame api so we 2433b032f27cSSam Leffler * can specify the destination address and re-use the bss node 2434b032f27cSSam Leffler * for the sta reference. 2435b032f27cSSam Leffler */ 2436b032f27cSSam Leffler int 2437b032f27cSSam Leffler ieee80211_send_proberesp(struct ieee80211vap *vap, 2438b032f27cSSam Leffler const uint8_t da[IEEE80211_ADDR_LEN], int legacy) 2439b032f27cSSam Leffler { 2440b032f27cSSam Leffler struct ieee80211_node *bss = vap->iv_bss; 2441b032f27cSSam Leffler struct ieee80211com *ic = vap->iv_ic; 2442b032f27cSSam Leffler struct ieee80211_frame *wh; 2443b032f27cSSam Leffler struct mbuf *m; 2444b032f27cSSam Leffler 2445b032f27cSSam Leffler if (vap->iv_state == IEEE80211_S_CAC) { 2446b032f27cSSam Leffler IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, 2447b032f27cSSam Leffler "block %s frame in CAC state", "probe response"); 2448b032f27cSSam Leffler vap->iv_stats.is_tx_badstate++; 2449b032f27cSSam Leffler return EIO; /* XXX */ 2450b032f27cSSam Leffler } 2451b032f27cSSam Leffler 2452b032f27cSSam Leffler /* 2453b032f27cSSam Leffler * Hold a reference on the node so it doesn't go away until after 2454b032f27cSSam Leffler * the xmit is complete all the way in the driver. On error we 2455b032f27cSSam Leffler * will remove our reference. 2456b032f27cSSam Leffler */ 2457b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 2458b032f27cSSam Leffler "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2459b032f27cSSam Leffler __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), 2460b032f27cSSam Leffler ieee80211_node_refcnt(bss)+1); 2461b032f27cSSam Leffler ieee80211_ref_node(bss); 2462b032f27cSSam Leffler 2463b032f27cSSam Leffler m = ieee80211_alloc_proberesp(bss, legacy); 2464b032f27cSSam Leffler if (m == NULL) { 2465b032f27cSSam Leffler ieee80211_free_node(bss); 2466b032f27cSSam Leffler return ENOMEM; 2467b032f27cSSam Leffler } 2468b032f27cSSam Leffler 2469b032f27cSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 2470b032f27cSSam Leffler KASSERT(m != NULL, ("no room for header")); 2471b032f27cSSam Leffler 2472b032f27cSSam Leffler wh = mtod(m, struct ieee80211_frame *); 24739e80b1dfSSam Leffler ieee80211_send_setup(bss, m, 2474b032f27cSSam Leffler IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, 24758ac160cdSSam Leffler IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); 2476b032f27cSSam Leffler /* XXX power management? */ 2477c1af44bdSSam Leffler m->m_flags |= M_ENCAP; /* mark encapsulated */ 2478b032f27cSSam Leffler 2479b032f27cSSam Leffler M_WME_SETAC(m, WME_AC_BE); 2480b032f27cSSam Leffler 2481b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 2482b032f27cSSam Leffler "send probe resp on channel %u to %s%s\n", 2483b032f27cSSam Leffler ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), 2484b032f27cSSam Leffler legacy ? " <legacy>" : ""); 2485b032f27cSSam Leffler IEEE80211_NODE_STAT(bss, tx_mgmt); 2486b032f27cSSam Leffler 2487b032f27cSSam Leffler return ic->ic_raw_xmit(bss, m, NULL); 2488b032f27cSSam Leffler } 2489b032f27cSSam Leffler 2490b032f27cSSam Leffler /* 2491b032f27cSSam Leffler * Allocate and build a RTS (Request To Send) control frame. 2492b032f27cSSam Leffler */ 2493b032f27cSSam Leffler struct mbuf * 2494b032f27cSSam Leffler ieee80211_alloc_rts(struct ieee80211com *ic, 2495b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], 2496b032f27cSSam Leffler const uint8_t ta[IEEE80211_ADDR_LEN], 2497b032f27cSSam Leffler uint16_t dur) 2498b032f27cSSam Leffler { 2499b032f27cSSam Leffler struct ieee80211_frame_rts *rts; 2500b032f27cSSam Leffler struct mbuf *m; 2501b032f27cSSam Leffler 2502b032f27cSSam Leffler /* XXX honor ic_headroom */ 2503b032f27cSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 2504b032f27cSSam Leffler if (m != NULL) { 2505b032f27cSSam Leffler rts = mtod(m, struct ieee80211_frame_rts *); 2506b032f27cSSam Leffler rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2507b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; 2508b032f27cSSam Leffler rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2509b032f27cSSam Leffler *(u_int16_t *)rts->i_dur = htole16(dur); 2510b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ra, ra); 2511b032f27cSSam Leffler IEEE80211_ADDR_COPY(rts->i_ta, ta); 2512b032f27cSSam Leffler 2513b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); 2514b032f27cSSam Leffler } 2515b032f27cSSam Leffler return m; 2516b032f27cSSam Leffler } 2517b032f27cSSam Leffler 2518b032f27cSSam Leffler /* 2519b032f27cSSam Leffler * Allocate and build a CTS (Clear To Send) control frame. 2520b032f27cSSam Leffler */ 2521b032f27cSSam Leffler struct mbuf * 2522b032f27cSSam Leffler ieee80211_alloc_cts(struct ieee80211com *ic, 2523b032f27cSSam Leffler const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) 2524b032f27cSSam Leffler { 2525b032f27cSSam Leffler struct ieee80211_frame_cts *cts; 2526b032f27cSSam Leffler struct mbuf *m; 2527b032f27cSSam Leffler 2528b032f27cSSam Leffler /* XXX honor ic_headroom */ 2529b032f27cSSam Leffler m = m_gethdr(M_DONTWAIT, MT_DATA); 2530b032f27cSSam Leffler if (m != NULL) { 2531b032f27cSSam Leffler cts = mtod(m, struct ieee80211_frame_cts *); 2532b032f27cSSam Leffler cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 2533b032f27cSSam Leffler IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; 2534b032f27cSSam Leffler cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 2535b032f27cSSam Leffler *(u_int16_t *)cts->i_dur = htole16(dur); 2536b032f27cSSam Leffler IEEE80211_ADDR_COPY(cts->i_ra, ra); 2537b032f27cSSam Leffler 2538b032f27cSSam Leffler m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); 2539b032f27cSSam Leffler } 2540b032f27cSSam Leffler return m; 2541b032f27cSSam Leffler } 2542b032f27cSSam Leffler 254368e8e04eSSam Leffler static void 254468e8e04eSSam Leffler ieee80211_tx_mgt_timeout(void *arg) 254568e8e04eSSam Leffler { 254668e8e04eSSam Leffler struct ieee80211_node *ni = arg; 2547b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 254868e8e04eSSam Leffler 2549b032f27cSSam Leffler if (vap->iv_state != IEEE80211_S_INIT && 2550b032f27cSSam Leffler (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { 255168e8e04eSSam Leffler /* 255268e8e04eSSam Leffler * NB: it's safe to specify a timeout as the reason here; 255368e8e04eSSam Leffler * it'll only be used in the right state. 255468e8e04eSSam Leffler */ 2555b032f27cSSam Leffler ieee80211_new_state(vap, IEEE80211_S_SCAN, 255668e8e04eSSam Leffler IEEE80211_SCAN_FAIL_TIMEOUT); 255768e8e04eSSam Leffler } 255868e8e04eSSam Leffler } 255968e8e04eSSam Leffler 256068e8e04eSSam Leffler static void 256168e8e04eSSam Leffler ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) 256268e8e04eSSam Leffler { 2563b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 256468e8e04eSSam Leffler enum ieee80211_state ostate = (enum ieee80211_state) arg; 256568e8e04eSSam Leffler 256668e8e04eSSam Leffler /* 256768e8e04eSSam Leffler * Frame transmit completed; arrange timer callback. If 256868e8e04eSSam Leffler * transmit was successfuly we wait for response. Otherwise 256968e8e04eSSam Leffler * we arrange an immediate callback instead of doing the 257068e8e04eSSam Leffler * callback directly since we don't know what state the driver 257168e8e04eSSam Leffler * is in (e.g. what locks it is holding). This work should 257268e8e04eSSam Leffler * not be too time-critical and not happen too often so the 257368e8e04eSSam Leffler * added overhead is acceptable. 257468e8e04eSSam Leffler * 257568e8e04eSSam Leffler * XXX what happens if !acked but response shows up before callback? 257668e8e04eSSam Leffler */ 2577b032f27cSSam Leffler if (vap->iv_state == ostate) 2578b032f27cSSam Leffler callout_reset(&vap->iv_mgtsend, 257968e8e04eSSam Leffler status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, 258068e8e04eSSam Leffler ieee80211_tx_mgt_timeout, ni); 258168e8e04eSSam Leffler } 258268e8e04eSSam Leffler 2583b032f27cSSam Leffler static void 2584b032f27cSSam Leffler ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, 2585b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni) 25868a1b9b6aSSam Leffler { 2587b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2588b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 2589b032f27cSSam Leffler struct ieee80211_rateset *rs = &ni->ni_rates; 259068e8e04eSSam Leffler uint16_t capinfo; 25918a1b9b6aSSam Leffler 25928a1b9b6aSSam Leffler /* 25938a1b9b6aSSam Leffler * beacon frame format 25948a1b9b6aSSam Leffler * [8] time stamp 25958a1b9b6aSSam Leffler * [2] beacon interval 25968a1b9b6aSSam Leffler * [2] cabability information 25978a1b9b6aSSam Leffler * [tlv] ssid 25988a1b9b6aSSam Leffler * [tlv] supported rates 25998a1b9b6aSSam Leffler * [3] parameter set (DS) 2600b032f27cSSam Leffler * [8] CF parameter set (optional) 26018a1b9b6aSSam Leffler * [tlv] parameter set (IBSS/TIM) 2602b032f27cSSam Leffler * [tlv] country (optional) 2603b032f27cSSam Leffler * [3] power control (optional) 2604b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 26058a1b9b6aSSam Leffler * [tlv] extended rate phy (ERP) 26068a1b9b6aSSam Leffler * [tlv] extended supported rates 2607688fe74dSSam Leffler * [tlv] RSN parameters 260868e8e04eSSam Leffler * [tlv] HT capabilities 260968e8e04eSSam Leffler * [tlv] HT information 2610b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 2611b032f27cSSam Leffler * [tlv] WPA parameters 2612b032f27cSSam Leffler * [tlv] WME parameters 261368e8e04eSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 261468e8e04eSSam Leffler * [tlv] Vendor OUI HT information (optional) 26154207227cSSam Leffler * [tlv] Atheros capabilities (optional) 261610ad9a77SSam Leffler * [tlv] TDMA parameters (optional) 261759aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 261859aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2619b032f27cSSam Leffler * [tlv] application data (optional) 26208a1b9b6aSSam Leffler */ 26218a1b9b6aSSam Leffler 26221b6167d2SSam Leffler memset(bo, 0, sizeof(*bo)); 26231b6167d2SSam Leffler 26248a1b9b6aSSam Leffler memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ 26258a1b9b6aSSam Leffler frm += 8; 262668e8e04eSSam Leffler *(uint16_t *)frm = htole16(ni->ni_intval); 26278a1b9b6aSSam Leffler frm += 2; 262859aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 262968e8e04eSSam Leffler bo->bo_caps = (uint16_t *)frm; 263068e8e04eSSam Leffler *(uint16_t *)frm = htole16(capinfo); 26318a1b9b6aSSam Leffler frm += 2; 26328a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_SSID; 2633b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { 26348a1b9b6aSSam Leffler *frm++ = ni->ni_esslen; 26358a1b9b6aSSam Leffler memcpy(frm, ni->ni_essid, ni->ni_esslen); 26368a1b9b6aSSam Leffler frm += ni->ni_esslen; 26378a1b9b6aSSam Leffler } else 26388a1b9b6aSSam Leffler *frm++ = 0; 26398a1b9b6aSSam Leffler frm = ieee80211_add_rates(frm, rs); 2640b032f27cSSam Leffler if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { 26418a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_DSPARMS; 26428a1b9b6aSSam Leffler *frm++ = 1; 2643b032f27cSSam Leffler *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); 2644b032f27cSSam Leffler } 2645b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_PCF) { 2646b032f27cSSam Leffler bo->bo_cfp = frm; 2647b032f27cSSam Leffler frm = ieee80211_add_cfparms(frm, ic); 26488a1b9b6aSSam Leffler } 26498a1b9b6aSSam Leffler bo->bo_tim = frm; 2650b032f27cSSam Leffler if (vap->iv_opmode == IEEE80211_M_IBSS) { 26518a1b9b6aSSam Leffler *frm++ = IEEE80211_ELEMID_IBSSPARMS; 26528a1b9b6aSSam Leffler *frm++ = 2; 26538a1b9b6aSSam Leffler *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 26548a1b9b6aSSam Leffler bo->bo_tim_len = 0; 265559aa14a9SRui Paulo } else if (vap->iv_opmode == IEEE80211_M_HOSTAP || 265659aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { 265759aa14a9SRui Paulo /* TIM IE is the same for Mesh and Hostap */ 26588a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; 26598a1b9b6aSSam Leffler 26608a1b9b6aSSam Leffler tie->tim_ie = IEEE80211_ELEMID_TIM; 26618a1b9b6aSSam Leffler tie->tim_len = 4; /* length */ 26628a1b9b6aSSam Leffler tie->tim_count = 0; /* DTIM count */ 2663b032f27cSSam Leffler tie->tim_period = vap->iv_dtim_period; /* DTIM period */ 26648a1b9b6aSSam Leffler tie->tim_bitctl = 0; /* bitmap control */ 26658a1b9b6aSSam Leffler tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 26668a1b9b6aSSam Leffler frm += sizeof(struct ieee80211_tim_ie); 26678a1b9b6aSSam Leffler bo->bo_tim_len = 1; 26688a1b9b6aSSam Leffler } 2669b105a069SSam Leffler bo->bo_tim_trailer = frm; 2670b032f27cSSam Leffler if ((vap->iv_flags & IEEE80211_F_DOTH) || 2671b032f27cSSam Leffler (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 2672b032f27cSSam Leffler frm = ieee80211_add_countryie(frm, ic); 2673b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_DOTH) { 2674b032f27cSSam Leffler if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 2675b032f27cSSam Leffler frm = ieee80211_add_powerconstraint(frm, vap); 2676b032f27cSSam Leffler bo->bo_csa = frm; 2677b032f27cSSam Leffler if (ic->ic_flags & IEEE80211_F_CSAPENDING) 2678b032f27cSSam Leffler frm = ieee80211_add_csa(frm, vap); 2679b032f27cSSam Leffler } else 2680b032f27cSSam Leffler bo->bo_csa = frm; 268132b0e64bSAdrian Chadd 268232b0e64bSAdrian Chadd if (vap->iv_flags & IEEE80211_F_DOTH) { 268332b0e64bSAdrian Chadd bo->bo_quiet = frm; 268432b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 268532b0e64bSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 268632b0e64bSAdrian Chadd if (vap->iv_quiet) 268732b0e64bSAdrian Chadd frm = ieee80211_add_quiet(frm,vap); 268832b0e64bSAdrian Chadd } 268932b0e64bSAdrian Chadd } else 269032b0e64bSAdrian Chadd bo->bo_quiet = frm; 269132b0e64bSAdrian Chadd 2692b032f27cSSam Leffler if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { 26930912bac9SSam Leffler bo->bo_erp = frm; 26948a1b9b6aSSam Leffler frm = ieee80211_add_erp(frm, ic); 26951b6167d2SSam Leffler } 269668e8e04eSSam Leffler frm = ieee80211_add_xrates(frm, rs); 2697688fe74dSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA2) { 2698688fe74dSSam Leffler if (vap->iv_rsn_ie != NULL) 2699688fe74dSSam Leffler frm = add_ie(frm, vap->iv_rsn_ie); 2700688fe74dSSam Leffler /* XXX else complain */ 2701688fe74dSSam Leffler } 2702b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { 270368e8e04eSSam Leffler frm = ieee80211_add_htcap(frm, ni); 270468e8e04eSSam Leffler bo->bo_htinfo = frm; 270568e8e04eSSam Leffler frm = ieee80211_add_htinfo(frm, ni); 27061b6167d2SSam Leffler } 2707b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WPA1) { 2708b032f27cSSam Leffler if (vap->iv_wpa_ie != NULL) 2709b032f27cSSam Leffler frm = add_ie(frm, vap->iv_wpa_ie); 2710b032f27cSSam Leffler /* XXX else complain */ 2711b032f27cSSam Leffler } 2712b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 27131b6167d2SSam Leffler bo->bo_wme = frm; 27141b6167d2SSam Leffler frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 27151b6167d2SSam Leffler } 2716b032f27cSSam Leffler if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && 27172bfc8a91SSam Leffler (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) { 271868e8e04eSSam Leffler frm = ieee80211_add_htcap_vendor(frm, ni); 271968e8e04eSSam Leffler frm = ieee80211_add_htinfo_vendor(frm, ni); 27200912bac9SSam Leffler } 27214207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 27224207227cSSam Leffler if (vap->iv_flags & IEEE80211_F_ATHEROS) { 27234207227cSSam Leffler bo->bo_ath = frm; 27244207227cSSam Leffler frm = ieee80211_add_athcaps(frm, ni); 27254207227cSSam Leffler } 27264207227cSSam Leffler #endif 272710ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 272810ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 272910ad9a77SSam Leffler bo->bo_tdma = frm; 273010ad9a77SSam Leffler frm = ieee80211_add_tdma(frm, vap); 273110ad9a77SSam Leffler } 273210ad9a77SSam Leffler #endif 2733b032f27cSSam Leffler if (vap->iv_appie_beacon != NULL) { 2734b032f27cSSam Leffler bo->bo_appie = frm; 2735b032f27cSSam Leffler bo->bo_appie_len = vap->iv_appie_beacon->ie_len; 2736b032f27cSSam Leffler frm = add_appie(frm, vap->iv_appie_beacon); 2737b032f27cSSam Leffler } 273859aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 273959aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 274059aa14a9SRui Paulo frm = ieee80211_add_meshid(frm, vap); 2741d093681cSRui Paulo bo->bo_meshconf = frm; 274259aa14a9SRui Paulo frm = ieee80211_add_meshconf(frm, vap); 274359aa14a9SRui Paulo } 274459aa14a9SRui Paulo #endif 2745b105a069SSam Leffler bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; 2746b032f27cSSam Leffler bo->bo_csa_trailer_len = frm - bo->bo_csa; 274768e8e04eSSam Leffler m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2748b032f27cSSam Leffler } 2749b032f27cSSam Leffler 2750b032f27cSSam Leffler /* 2751b032f27cSSam Leffler * Allocate a beacon frame and fillin the appropriate bits. 2752b032f27cSSam Leffler */ 2753b032f27cSSam Leffler struct mbuf * 2754b032f27cSSam Leffler ieee80211_beacon_alloc(struct ieee80211_node *ni, 2755b032f27cSSam Leffler struct ieee80211_beacon_offsets *bo) 2756b032f27cSSam Leffler { 2757b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2758b032f27cSSam Leffler struct ieee80211com *ic = ni->ni_ic; 2759b032f27cSSam Leffler struct ifnet *ifp = vap->iv_ifp; 2760b032f27cSSam Leffler struct ieee80211_frame *wh; 2761b032f27cSSam Leffler struct mbuf *m; 2762b032f27cSSam Leffler int pktlen; 2763b032f27cSSam Leffler uint8_t *frm; 2764b032f27cSSam Leffler 2765b032f27cSSam Leffler /* 2766b032f27cSSam Leffler * beacon frame format 2767b032f27cSSam Leffler * [8] time stamp 2768b032f27cSSam Leffler * [2] beacon interval 2769b032f27cSSam Leffler * [2] cabability information 2770b032f27cSSam Leffler * [tlv] ssid 2771b032f27cSSam Leffler * [tlv] supported rates 2772b032f27cSSam Leffler * [3] parameter set (DS) 2773b032f27cSSam Leffler * [8] CF parameter set (optional) 2774b032f27cSSam Leffler * [tlv] parameter set (IBSS/TIM) 2775b032f27cSSam Leffler * [tlv] country (optional) 2776b032f27cSSam Leffler * [3] power control (optional) 2777b032f27cSSam Leffler * [5] channel switch announcement (CSA) (optional) 2778b032f27cSSam Leffler * [tlv] extended rate phy (ERP) 2779b032f27cSSam Leffler * [tlv] extended supported rates 2780b032f27cSSam Leffler * [tlv] RSN parameters 2781b032f27cSSam Leffler * [tlv] HT capabilities 2782b032f27cSSam Leffler * [tlv] HT information 2783b032f27cSSam Leffler * [tlv] Vendor OUI HT capabilities (optional) 2784b032f27cSSam Leffler * [tlv] Vendor OUI HT information (optional) 2785b032f27cSSam Leffler * XXX Vendor-specific OIDs (e.g. Atheros) 2786b032f27cSSam Leffler * [tlv] WPA parameters 2787b032f27cSSam Leffler * [tlv] WME parameters 278810ad9a77SSam Leffler * [tlv] TDMA parameters (optional) 278959aa14a9SRui Paulo * [tlv] Mesh ID (MBSS) 279059aa14a9SRui Paulo * [tlv] Mesh Conf (MBSS) 2791b032f27cSSam Leffler * [tlv] application data (optional) 2792b032f27cSSam Leffler * NB: we allocate the max space required for the TIM bitmap. 2793b032f27cSSam Leffler * XXX how big is this? 2794b032f27cSSam Leffler */ 2795b032f27cSSam Leffler pktlen = 8 /* time stamp */ 2796b032f27cSSam Leffler + sizeof(uint16_t) /* beacon interval */ 2797b032f27cSSam Leffler + sizeof(uint16_t) /* capabilities */ 2798b032f27cSSam Leffler + 2 + ni->ni_esslen /* ssid */ 2799b032f27cSSam Leffler + 2 + IEEE80211_RATE_SIZE /* supported rates */ 2800b032f27cSSam Leffler + 2 + 1 /* DS parameters */ 2801b032f27cSSam Leffler + 2 + 6 /* CF parameters */ 2802b032f27cSSam Leffler + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ 2803b032f27cSSam Leffler + IEEE80211_COUNTRY_MAX_SIZE /* country */ 2804b032f27cSSam Leffler + 2 + 1 /* power control */ 2805b032f27cSSam Leffler + sizeof(struct ieee80211_csa_ie) /* CSA */ 280632b0e64bSAdrian Chadd + sizeof(struct ieee80211_quiet_ie) /* Quiet */ 2807b032f27cSSam Leffler + 2 + 1 /* ERP */ 2808b032f27cSSam Leffler + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 2809b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 2810b032f27cSSam Leffler 2*sizeof(struct ieee80211_ie_wpa) : 0) 2811b032f27cSSam Leffler /* XXX conditional? */ 2812b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ 2813b032f27cSSam Leffler + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ 2814b032f27cSSam Leffler + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ 2815b032f27cSSam Leffler sizeof(struct ieee80211_wme_param) : 0) 28164207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 28174207227cSSam Leffler + sizeof(struct ieee80211_ath_ie) /* ATH */ 28184207227cSSam Leffler #endif 281910ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 282010ad9a77SSam Leffler + (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */ 282110ad9a77SSam Leffler sizeof(struct ieee80211_tdma_param) : 0) 282210ad9a77SSam Leffler #endif 282359aa14a9SRui Paulo #ifdef IEEE80211_SUPPORT_MESH 282459aa14a9SRui Paulo + 2 + ni->ni_meshidlen 282559aa14a9SRui Paulo + sizeof(struct ieee80211_meshconf_ie) 282659aa14a9SRui Paulo #endif 2827b032f27cSSam Leffler + IEEE80211_MAX_APPIE 2828b032f27cSSam Leffler ; 2829b032f27cSSam Leffler m = ieee80211_getmgtframe(&frm, 2830b032f27cSSam Leffler ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); 2831b032f27cSSam Leffler if (m == NULL) { 2832b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 2833b032f27cSSam Leffler "%s: cannot get buf; size %u\n", __func__, pktlen); 2834b032f27cSSam Leffler vap->iv_stats.is_tx_nobuf++; 2835b032f27cSSam Leffler return NULL; 2836b032f27cSSam Leffler } 2837b032f27cSSam Leffler ieee80211_beacon_construct(m, frm, bo, ni); 28388a1b9b6aSSam Leffler 28398a1b9b6aSSam Leffler M_PREPEND(m, sizeof(struct ieee80211_frame), M_DONTWAIT); 28408a1b9b6aSSam Leffler KASSERT(m != NULL, ("no space for 802.11 header?")); 28418a1b9b6aSSam Leffler wh = mtod(m, struct ieee80211_frame *); 28428a1b9b6aSSam Leffler wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 28438a1b9b6aSSam Leffler IEEE80211_FC0_SUBTYPE_BEACON; 28448a1b9b6aSSam Leffler wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 284568e8e04eSSam Leffler *(uint16_t *)wh->i_dur = 0; 28468a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 2847b032f27cSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 28488a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 284968e8e04eSSam Leffler *(uint16_t *)wh->i_seq = 0; 28508a1b9b6aSSam Leffler 28518a1b9b6aSSam Leffler return m; 28528a1b9b6aSSam Leffler } 28538a1b9b6aSSam Leffler 28548a1b9b6aSSam Leffler /* 28558a1b9b6aSSam Leffler * Update the dynamic parts of a beacon frame based on the current state. 28568a1b9b6aSSam Leffler */ 28578a1b9b6aSSam Leffler int 2858b105a069SSam Leffler ieee80211_beacon_update(struct ieee80211_node *ni, 28598a1b9b6aSSam Leffler struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) 28608a1b9b6aSSam Leffler { 2861b032f27cSSam Leffler struct ieee80211vap *vap = ni->ni_vap; 2862b105a069SSam Leffler struct ieee80211com *ic = ni->ni_ic; 28638a1b9b6aSSam Leffler int len_changed = 0; 286468e8e04eSSam Leffler uint16_t capinfo; 2865fa3324c9SAdrian Chadd struct ieee80211_frame *wh; 2866fa3324c9SAdrian Chadd ieee80211_seq seqno; 28678a1b9b6aSSam Leffler 2868b032f27cSSam Leffler IEEE80211_LOCK(ic); 2869b032f27cSSam Leffler /* 2870b032f27cSSam Leffler * Handle 11h channel change when we've reached the count. 2871b032f27cSSam Leffler * We must recalculate the beacon frame contents to account 2872b032f27cSSam Leffler * for the new channel. Note we do this only for the first 2873b032f27cSSam Leffler * vap that reaches this point; subsequent vaps just update 2874b032f27cSSam Leffler * their beacon state to reflect the recalculated channel. 2875b032f27cSSam Leffler */ 2876b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && 2877b032f27cSSam Leffler vap->iv_csa_count == ic->ic_csa_count) { 2878b032f27cSSam Leffler vap->iv_csa_count = 0; 2879b032f27cSSam Leffler /* 2880b032f27cSSam Leffler * Effect channel change before reconstructing the beacon 2881b032f27cSSam Leffler * frame contents as many places reference ni_chan. 2882b032f27cSSam Leffler */ 2883b032f27cSSam Leffler if (ic->ic_csa_newchan != NULL) 2884b032f27cSSam Leffler ieee80211_csa_completeswitch(ic); 2885b032f27cSSam Leffler /* 2886b032f27cSSam Leffler * NB: ieee80211_beacon_construct clears all pending 2887b032f27cSSam Leffler * updates in bo_flags so we don't need to explicitly 2888b032f27cSSam Leffler * clear IEEE80211_BEACON_CSA. 2889b032f27cSSam Leffler */ 2890b032f27cSSam Leffler ieee80211_beacon_construct(m, 2891b032f27cSSam Leffler mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni); 2892b032f27cSSam Leffler 2893b032f27cSSam Leffler /* XXX do WME aggressive mode processing? */ 2894b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 2895b032f27cSSam Leffler return 1; /* just assume length changed */ 2896b032f27cSSam Leffler } 2897b032f27cSSam Leffler 2898fa3324c9SAdrian Chadd wh = mtod(m, struct ieee80211_frame *); 2899fa3324c9SAdrian Chadd seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 2900fa3324c9SAdrian Chadd *(uint16_t *)&wh->i_seq[0] = 2901fa3324c9SAdrian Chadd htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 2902fa3324c9SAdrian Chadd M_SEQNO_SET(m, seqno); 2903fa3324c9SAdrian Chadd 29048a1b9b6aSSam Leffler /* XXX faster to recalculate entirely or just changes? */ 290559aa14a9SRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 29068a1b9b6aSSam Leffler *bo->bo_caps = htole16(capinfo); 29078a1b9b6aSSam Leffler 2908b032f27cSSam Leffler if (vap->iv_flags & IEEE80211_F_WME) { 29098a1b9b6aSSam Leffler struct ieee80211_wme_state *wme = &ic->ic_wme; 29108a1b9b6aSSam Leffler 29118a1b9b6aSSam Leffler /* 29128a1b9b6aSSam Leffler * Check for agressive mode change. When there is 29138a1b9b6aSSam Leffler * significant high priority traffic in the BSS 29148a1b9b6aSSam Leffler * throttle back BE traffic by using conservative 29158a1b9b6aSSam Leffler * parameters. Otherwise BE uses agressive params 29168a1b9b6aSSam Leffler * to optimize performance of legacy/non-QoS traffic. 29178a1b9b6aSSam Leffler */ 29188a1b9b6aSSam Leffler if (wme->wme_flags & WME_F_AGGRMODE) { 29198a1b9b6aSSam Leffler if (wme->wme_hipri_traffic > 29208a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 2921b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 29228a1b9b6aSSam Leffler "%s: traffic %u, disable aggressive mode\n", 29238a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 29248a1b9b6aSSam Leffler wme->wme_flags &= ~WME_F_AGGRMODE; 2925b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 29268a1b9b6aSSam Leffler wme->wme_hipri_traffic = 29278a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 29288a1b9b6aSSam Leffler } else 29298a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 29308a1b9b6aSSam Leffler } else { 29318a1b9b6aSSam Leffler if (wme->wme_hipri_traffic <= 29328a1b9b6aSSam Leffler wme->wme_hipri_switch_thresh) { 2933b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 29348a1b9b6aSSam Leffler "%s: traffic %u, enable aggressive mode\n", 29358a1b9b6aSSam Leffler __func__, wme->wme_hipri_traffic); 29368a1b9b6aSSam Leffler wme->wme_flags |= WME_F_AGGRMODE; 2937b032f27cSSam Leffler ieee80211_wme_updateparams_locked(vap); 29388a1b9b6aSSam Leffler wme->wme_hipri_traffic = 0; 29398a1b9b6aSSam Leffler } else 29408a1b9b6aSSam Leffler wme->wme_hipri_traffic = 29418a1b9b6aSSam Leffler wme->wme_hipri_switch_hysteresis; 29428a1b9b6aSSam Leffler } 2943b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { 29448a1b9b6aSSam Leffler (void) ieee80211_add_wme_param(bo->bo_wme, wme); 2945b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_WME); 29468a1b9b6aSSam Leffler } 29478a1b9b6aSSam Leffler } 29488a1b9b6aSSam Leffler 2949b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { 2950b032f27cSSam Leffler ieee80211_ht_update_beacon(vap, bo); 2951b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); 295268e8e04eSSam Leffler } 295310ad9a77SSam Leffler #ifdef IEEE80211_SUPPORT_TDMA 295410ad9a77SSam Leffler if (vap->iv_caps & IEEE80211_C_TDMA) { 295510ad9a77SSam Leffler /* 295610ad9a77SSam Leffler * NB: the beacon is potentially updated every TBTT. 295710ad9a77SSam Leffler */ 295810ad9a77SSam Leffler ieee80211_tdma_update_beacon(vap, bo); 295910ad9a77SSam Leffler } 296010ad9a77SSam Leffler #endif 2961d093681cSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 2962d093681cSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 2963d093681cSRui Paulo ieee80211_mesh_update_beacon(vap, bo); 2964d093681cSRui Paulo #endif 2965d093681cSRui Paulo 296659aa14a9SRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP || 296759aa14a9SRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/ 29688a1b9b6aSSam Leffler struct ieee80211_tim_ie *tie = 29698a1b9b6aSSam Leffler (struct ieee80211_tim_ie *) bo->bo_tim; 2970b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { 29718a1b9b6aSSam Leffler u_int timlen, timoff, i; 29728a1b9b6aSSam Leffler /* 29738a1b9b6aSSam Leffler * ATIM/DTIM needs updating. If it fits in the 29748a1b9b6aSSam Leffler * current space allocated then just copy in the 29758a1b9b6aSSam Leffler * new bits. Otherwise we need to move any trailing 29768a1b9b6aSSam Leffler * data to make room. Note that we know there is 29778a1b9b6aSSam Leffler * contiguous space because ieee80211_beacon_allocate 29788a1b9b6aSSam Leffler * insures there is space in the mbuf to write a 2979b032f27cSSam Leffler * maximal-size virtual bitmap (based on iv_max_aid). 29808a1b9b6aSSam Leffler */ 29818a1b9b6aSSam Leffler /* 29828a1b9b6aSSam Leffler * Calculate the bitmap size and offset, copy any 29838a1b9b6aSSam Leffler * trailer out of the way, and then copy in the 29848a1b9b6aSSam Leffler * new bitmap and update the information element. 29858a1b9b6aSSam Leffler * Note that the tim bitmap must contain at least 29868a1b9b6aSSam Leffler * one byte and any offset must be even. 29878a1b9b6aSSam Leffler */ 2988b032f27cSSam Leffler if (vap->iv_ps_pending != 0) { 29898a1b9b6aSSam Leffler timoff = 128; /* impossibly large */ 2990b032f27cSSam Leffler for (i = 0; i < vap->iv_tim_len; i++) 2991b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) { 29928a1b9b6aSSam Leffler timoff = i &~ 1; 29938a1b9b6aSSam Leffler break; 29948a1b9b6aSSam Leffler } 29958a1b9b6aSSam Leffler KASSERT(timoff != 128, ("tim bitmap empty!")); 2996b032f27cSSam Leffler for (i = vap->iv_tim_len-1; i >= timoff; i--) 2997b032f27cSSam Leffler if (vap->iv_tim_bitmap[i]) 29988a1b9b6aSSam Leffler break; 29998a1b9b6aSSam Leffler timlen = 1 + (i - timoff); 30008a1b9b6aSSam Leffler } else { 30018a1b9b6aSSam Leffler timoff = 0; 30028a1b9b6aSSam Leffler timlen = 1; 30038a1b9b6aSSam Leffler } 30048a1b9b6aSSam Leffler if (timlen != bo->bo_tim_len) { 30058a1b9b6aSSam Leffler /* copy up/down trailer */ 30060912bac9SSam Leffler int adjust = tie->tim_bitmap+timlen 3007b105a069SSam Leffler - bo->bo_tim_trailer; 3008b105a069SSam Leffler ovbcopy(bo->bo_tim_trailer, 3009b105a069SSam Leffler bo->bo_tim_trailer+adjust, 3010b105a069SSam Leffler bo->bo_tim_trailer_len); 3011b105a069SSam Leffler bo->bo_tim_trailer += adjust; 30120912bac9SSam Leffler bo->bo_erp += adjust; 301368e8e04eSSam Leffler bo->bo_htinfo += adjust; 301402e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG 30154207227cSSam Leffler bo->bo_ath += adjust; 30164207227cSSam Leffler #endif 301702e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA 301892e870edSSam Leffler bo->bo_tdma += adjust; 301992e870edSSam Leffler #endif 302002e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH 3021d093681cSRui Paulo bo->bo_meshconf += adjust; 3022d093681cSRui Paulo #endif 3023b032f27cSSam Leffler bo->bo_appie += adjust; 3024b032f27cSSam Leffler bo->bo_wme += adjust; 3025b032f27cSSam Leffler bo->bo_csa += adjust; 302632b0e64bSAdrian Chadd bo->bo_quiet += adjust; 30278a1b9b6aSSam Leffler bo->bo_tim_len = timlen; 30288a1b9b6aSSam Leffler 30298a1b9b6aSSam Leffler /* update information element */ 30308a1b9b6aSSam Leffler tie->tim_len = 3 + timlen; 30318a1b9b6aSSam Leffler tie->tim_bitctl = timoff; 30328a1b9b6aSSam Leffler len_changed = 1; 30338a1b9b6aSSam Leffler } 3034b032f27cSSam Leffler memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, 30358a1b9b6aSSam Leffler bo->bo_tim_len); 30368a1b9b6aSSam Leffler 3037b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); 30388a1b9b6aSSam Leffler 3039b032f27cSSam Leffler IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 30408a1b9b6aSSam Leffler "%s: TIM updated, pending %u, off %u, len %u\n", 3041b032f27cSSam Leffler __func__, vap->iv_ps_pending, timoff, timlen); 30428a1b9b6aSSam Leffler } 30438a1b9b6aSSam Leffler /* count down DTIM period */ 30448a1b9b6aSSam Leffler if (tie->tim_count == 0) 30458a1b9b6aSSam Leffler tie->tim_count = tie->tim_period - 1; 30468a1b9b6aSSam Leffler else 30478a1b9b6aSSam Leffler tie->tim_count--; 30488a1b9b6aSSam Leffler /* update state for buffered multicast frames on DTIM */ 3049a196b35fSSam Leffler if (mcast && tie->tim_count == 0) 30508a1b9b6aSSam Leffler tie->tim_bitctl |= 1; 30518a1b9b6aSSam Leffler else 30528a1b9b6aSSam Leffler tie->tim_bitctl &= ~1; 3053b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { 3054b032f27cSSam Leffler struct ieee80211_csa_ie *csa = 3055b032f27cSSam Leffler (struct ieee80211_csa_ie *) bo->bo_csa; 3056b032f27cSSam Leffler 3057b032f27cSSam Leffler /* 3058b032f27cSSam Leffler * Insert or update CSA ie. If we're just starting 3059b032f27cSSam Leffler * to count down to the channel switch then we need 3060b032f27cSSam Leffler * to insert the CSA ie. Otherwise we just need to 3061b032f27cSSam Leffler * drop the count. The actual change happens above 3062b032f27cSSam Leffler * when the vap's count reaches the target count. 3063b032f27cSSam Leffler */ 3064b032f27cSSam Leffler if (vap->iv_csa_count == 0) { 3065b032f27cSSam Leffler memmove(&csa[1], csa, bo->bo_csa_trailer_len); 3066b032f27cSSam Leffler bo->bo_erp += sizeof(*csa); 3067d01b3c26SSam Leffler bo->bo_htinfo += sizeof(*csa); 3068b032f27cSSam Leffler bo->bo_wme += sizeof(*csa); 306902e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_SUPERG 30704207227cSSam Leffler bo->bo_ath += sizeof(*csa); 30714207227cSSam Leffler #endif 307202e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_TDMA 307392e870edSSam Leffler bo->bo_tdma += sizeof(*csa); 307492e870edSSam Leffler #endif 307502e69b54SBernhard Schmidt #ifdef IEEE80211_SUPPORT_MESH 3076d093681cSRui Paulo bo->bo_meshconf += sizeof(*csa); 3077d093681cSRui Paulo #endif 3078b032f27cSSam Leffler bo->bo_appie += sizeof(*csa); 3079b032f27cSSam Leffler bo->bo_csa_trailer_len += sizeof(*csa); 308032b0e64bSAdrian Chadd bo->bo_quiet += sizeof(*csa); 3081b032f27cSSam Leffler bo->bo_tim_trailer_len += sizeof(*csa); 3082b032f27cSSam Leffler m->m_len += sizeof(*csa); 3083b032f27cSSam Leffler m->m_pkthdr.len += sizeof(*csa); 3084b032f27cSSam Leffler 3085b032f27cSSam Leffler ieee80211_add_csa(bo->bo_csa, vap); 3086b032f27cSSam Leffler } else 3087b032f27cSSam Leffler csa->csa_count--; 3088b032f27cSSam Leffler vap->iv_csa_count++; 3089b032f27cSSam Leffler /* NB: don't clear IEEE80211_BEACON_CSA */ 3090b032f27cSSam Leffler } 309132b0e64bSAdrian Chadd if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 309232b0e64bSAdrian Chadd (vap->iv_flags_ext & IEEE80211_FEXT_DFS) ){ 309332b0e64bSAdrian Chadd if (vap->iv_quiet) 309432b0e64bSAdrian Chadd ieee80211_add_quiet(bo->bo_quiet, vap); 309532b0e64bSAdrian Chadd } 3096b105a069SSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { 30970912bac9SSam Leffler /* 30980912bac9SSam Leffler * ERP element needs updating. 30990912bac9SSam Leffler */ 31000912bac9SSam Leffler (void) ieee80211_add_erp(bo->bo_erp, ic); 3101b105a069SSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); 31020912bac9SSam Leffler } 31034207227cSSam Leffler #ifdef IEEE80211_SUPPORT_SUPERG 31044207227cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_ATH)) { 31054207227cSSam Leffler ieee80211_add_athcaps(bo->bo_ath, ni); 31064207227cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_ATH); 31074207227cSSam Leffler } 31084207227cSSam Leffler #endif 31098a1b9b6aSSam Leffler } 3110b032f27cSSam Leffler if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { 3111b032f27cSSam Leffler const struct ieee80211_appie *aie = vap->iv_appie_beacon; 3112b032f27cSSam Leffler int aielen; 3113b032f27cSSam Leffler uint8_t *frm; 3114b032f27cSSam Leffler 3115b032f27cSSam Leffler aielen = 0; 3116b032f27cSSam Leffler if (aie != NULL) 3117b032f27cSSam Leffler aielen += aie->ie_len; 3118b032f27cSSam Leffler if (aielen != bo->bo_appie_len) { 3119b032f27cSSam Leffler /* copy up/down trailer */ 3120b032f27cSSam Leffler int adjust = aielen - bo->bo_appie_len; 3121b032f27cSSam Leffler ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, 3122b032f27cSSam Leffler bo->bo_tim_trailer_len); 3123b032f27cSSam Leffler bo->bo_tim_trailer += adjust; 3124b032f27cSSam Leffler bo->bo_appie += adjust; 3125b032f27cSSam Leffler bo->bo_appie_len = aielen; 3126b032f27cSSam Leffler 3127b032f27cSSam Leffler len_changed = 1; 3128b032f27cSSam Leffler } 3129b032f27cSSam Leffler frm = bo->bo_appie; 3130b032f27cSSam Leffler if (aie != NULL) 3131b032f27cSSam Leffler frm = add_appie(frm, aie); 3132b032f27cSSam Leffler clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); 3133b032f27cSSam Leffler } 3134b032f27cSSam Leffler IEEE80211_UNLOCK(ic); 31358a1b9b6aSSam Leffler 31368a1b9b6aSSam Leffler return len_changed; 31378a1b9b6aSSam Leffler } 3138