132176cfdSRui Paulo /*- 2f186073cSJoerg Sonnenberger * Copyright (c) 2001 Atsushi Onoe 332176cfdSRui Paulo * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting 4f186073cSJoerg Sonnenberger * All rights reserved. 5f186073cSJoerg Sonnenberger * 6f186073cSJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 7f186073cSJoerg Sonnenberger * modification, are permitted provided that the following conditions 8f186073cSJoerg Sonnenberger * are met: 9f186073cSJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright 10f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer. 11f186073cSJoerg Sonnenberger * 2. Redistributions in binary form must reproduce the above copyright 12f186073cSJoerg Sonnenberger * notice, this list of conditions and the following disclaimer in the 13f186073cSJoerg Sonnenberger * documentation and/or other materials provided with the distribution. 14f186073cSJoerg Sonnenberger * 15f186073cSJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16f186073cSJoerg Sonnenberger * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17f186073cSJoerg Sonnenberger * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18f186073cSJoerg Sonnenberger * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19f186073cSJoerg Sonnenberger * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20f186073cSJoerg Sonnenberger * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21f186073cSJoerg Sonnenberger * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22f186073cSJoerg Sonnenberger * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23f186073cSJoerg Sonnenberger * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24f186073cSJoerg Sonnenberger * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25f186073cSJoerg Sonnenberger */ 26f186073cSJoerg Sonnenberger 27085ff963SMatthew Dillon #include <sys/cdefs.h> 28085ff963SMatthew Dillon __FBSDID("$FreeBSD$"); 29085ff963SMatthew Dillon 30f186073cSJoerg Sonnenberger #include "opt_inet.h" 3132176cfdSRui Paulo #include "opt_inet6.h" 3232176cfdSRui Paulo #include "opt_wlan.h" 33f186073cSJoerg Sonnenberger 34f186073cSJoerg Sonnenberger #include <sys/param.h> 35f186073cSJoerg Sonnenberger #include <sys/systm.h> 36f186073cSJoerg Sonnenberger #include <sys/mbuf.h> 37f186073cSJoerg Sonnenberger #include <sys/kernel.h> 38f186073cSJoerg Sonnenberger #include <sys/endian.h> 39f186073cSJoerg Sonnenberger 40841ab66cSSepherosa Ziehau #include <sys/socket.h> 41f186073cSJoerg Sonnenberger 42f186073cSJoerg Sonnenberger #include <net/bpf.h> 43841ab66cSSepherosa Ziehau #include <net/ethernet.h> 44841ab66cSSepherosa Ziehau #include <net/if.h> 45085ff963SMatthew Dillon #include <net/if_var.h> 46841ab66cSSepherosa Ziehau #include <net/if_llc.h> 47841ab66cSSepherosa Ziehau #include <net/if_media.h> 48085ff963SMatthew Dillon #include <net/vlan/if_vlan_var.h> 49085ff963SMatthew Dillon 50085ff963SMatthew Dillon #if defined(__DragonFly__) 5134a60cf6SRui Paulo #include <net/ifq_var.h> 52085ff963SMatthew Dillon #endif 53841ab66cSSepherosa Ziehau 54841ab66cSSepherosa Ziehau #include <netproto/802_11/ieee80211_var.h> 5532176cfdSRui Paulo #include <netproto/802_11/ieee80211_regdomain.h> 5632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 5732176cfdSRui Paulo #include <netproto/802_11/ieee80211_superg.h> 5832176cfdSRui Paulo #endif 5932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 6032176cfdSRui Paulo #include <netproto/802_11/ieee80211_tdma.h> 6132176cfdSRui Paulo #endif 6232176cfdSRui Paulo #include <netproto/802_11/ieee80211_wds.h> 6332176cfdSRui Paulo #include <netproto/802_11/ieee80211_mesh.h> 64f186073cSJoerg Sonnenberger 65085ff963SMatthew Dillon #if defined(INET) || defined(INET6) 66f186073cSJoerg Sonnenberger #include <netinet/in.h> 67085ff963SMatthew Dillon #endif 68085ff963SMatthew Dillon 69085ff963SMatthew Dillon #ifdef INET 70f186073cSJoerg Sonnenberger #include <netinet/if_ether.h> 71841ab66cSSepherosa Ziehau #include <netinet/in_systm.h> 72841ab66cSSepherosa Ziehau #include <netinet/ip.h> 73f186073cSJoerg Sonnenberger #endif 7432176cfdSRui Paulo #ifdef INET6 7532176cfdSRui Paulo #include <netinet/ip6.h> 7632176cfdSRui Paulo #endif 7732176cfdSRui Paulo 78085ff963SMatthew Dillon /*#include <security/mac/mac_framework.h>*/ 79085ff963SMatthew Dillon 8032176cfdSRui Paulo #define ETHER_HEADER_COPY(dst, src) \ 8132176cfdSRui Paulo memcpy(dst, src, sizeof(struct ether_header)) 8232176cfdSRui Paulo 8332176cfdSRui Paulo /* unalligned little endian access */ 8432176cfdSRui Paulo #define LE_WRITE_2(p, v) do { \ 8532176cfdSRui Paulo ((uint8_t *)(p))[0] = (v) & 0xff; \ 8632176cfdSRui Paulo ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 8732176cfdSRui Paulo } while (0) 8832176cfdSRui Paulo #define LE_WRITE_4(p, v) do { \ 8932176cfdSRui Paulo ((uint8_t *)(p))[0] = (v) & 0xff; \ 9032176cfdSRui Paulo ((uint8_t *)(p))[1] = ((v) >> 8) & 0xff; \ 9132176cfdSRui Paulo ((uint8_t *)(p))[2] = ((v) >> 16) & 0xff; \ 9232176cfdSRui Paulo ((uint8_t *)(p))[3] = ((v) >> 24) & 0xff; \ 9332176cfdSRui Paulo } while (0) 9432176cfdSRui Paulo 9532176cfdSRui Paulo static int ieee80211_fragment(struct ieee80211vap *, struct mbuf *, 9632176cfdSRui Paulo u_int hdrsize, u_int ciphdrsize, u_int mtu); 9732176cfdSRui Paulo static void ieee80211_tx_mgt_cb(struct ieee80211_node *, void *, int); 98f186073cSJoerg Sonnenberger 99841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 100841ab66cSSepherosa Ziehau /* 101841ab66cSSepherosa Ziehau * Decide if an outbound management frame should be 102841ab66cSSepherosa Ziehau * printed when debugging is enabled. This filters some 103841ab66cSSepherosa Ziehau * of the less interesting frames that come frequently 104841ab66cSSepherosa Ziehau * (e.g. beacons). 105841ab66cSSepherosa Ziehau */ 106841ab66cSSepherosa Ziehau static __inline int 10732176cfdSRui Paulo doprint(struct ieee80211vap *vap, int subtype) 108841ab66cSSepherosa Ziehau { 109841ab66cSSepherosa Ziehau switch (subtype) { 110841ab66cSSepherosa Ziehau case IEEE80211_FC0_SUBTYPE_PROBE_RESP: 11132176cfdSRui Paulo return (vap->iv_opmode == IEEE80211_M_IBSS); 112841ab66cSSepherosa Ziehau } 113841ab66cSSepherosa Ziehau return 1; 114841ab66cSSepherosa Ziehau } 115841ab66cSSepherosa Ziehau #endif 116841ab66cSSepherosa Ziehau 117841ab66cSSepherosa Ziehau /* 118085ff963SMatthew Dillon * Transmit a frame to the given destination on the given VAP. 119085ff963SMatthew Dillon * 120085ff963SMatthew Dillon * It's up to the caller to figure out the details of who this 121085ff963SMatthew Dillon * is going to and resolving the node. 122085ff963SMatthew Dillon * 123085ff963SMatthew Dillon * This routine takes care of queuing it for power save, 124085ff963SMatthew Dillon * A-MPDU state stuff, fast-frames state stuff, encapsulation 125085ff963SMatthew Dillon * if required, then passing it up to the driver layer. 126085ff963SMatthew Dillon * 127085ff963SMatthew Dillon * This routine (for now) consumes the mbuf and frees the node 128085ff963SMatthew Dillon * reference; it ideally will return a TX status which reflects 129085ff963SMatthew Dillon * whether the mbuf was consumed or not, so the caller can 130085ff963SMatthew Dillon * free the mbuf (if appropriate) and the node reference (again, 131085ff963SMatthew Dillon * if appropriate.) 132841ab66cSSepherosa Ziehau */ 133085ff963SMatthew Dillon int 134085ff963SMatthew Dillon ieee80211_vap_pkt_send_dest(struct ieee80211vap *vap, struct mbuf *m, 135085ff963SMatthew Dillon struct ieee80211_node *ni) 13632176cfdSRui Paulo { 13732176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 138085ff963SMatthew Dillon struct ifnet *ifp = vap->iv_ifp; 13932176cfdSRui Paulo int error; 14032176cfdSRui Paulo 14132176cfdSRui Paulo if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 14232176cfdSRui Paulo (m->m_flags & M_PWR_SAV) == 0) { 14332176cfdSRui Paulo /* 14432176cfdSRui Paulo * Station in power save mode; pass the frame 14532176cfdSRui Paulo * to the 802.11 layer and continue. We'll get 14632176cfdSRui Paulo * the frame back when the time is right. 14732176cfdSRui Paulo * XXX lose WDS vap linkage? 14832176cfdSRui Paulo */ 14932176cfdSRui Paulo (void) ieee80211_pwrsave(ni, m); 15032176cfdSRui Paulo ieee80211_free_node(ni); 151085ff963SMatthew Dillon 152085ff963SMatthew Dillon /* 153085ff963SMatthew Dillon * We queued it fine, so tell the upper layer 154085ff963SMatthew Dillon * that we consumed it. 155085ff963SMatthew Dillon */ 156085ff963SMatthew Dillon return (0); 15732176cfdSRui Paulo } 15832176cfdSRui Paulo /* calculate priority so drivers can find the tx queue */ 15932176cfdSRui Paulo if (ieee80211_classify(ni, m)) { 16032176cfdSRui Paulo IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 161085ff963SMatthew Dillon ni->ni_macaddr, NULL, 16232176cfdSRui Paulo "%s", "classification failure"); 16332176cfdSRui Paulo vap->iv_stats.is_tx_classify++; 164d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 16532176cfdSRui Paulo m_freem(m); 16632176cfdSRui Paulo ieee80211_free_node(ni); 167085ff963SMatthew Dillon 168085ff963SMatthew Dillon /* XXX better status? */ 169085ff963SMatthew Dillon return (0); 17032176cfdSRui Paulo } 17132176cfdSRui Paulo /* 17232176cfdSRui Paulo * Stash the node pointer. Note that we do this after 17332176cfdSRui Paulo * any call to ieee80211_dwds_mcast because that code 17432176cfdSRui Paulo * uses any existing value for rcvif to identify the 17532176cfdSRui Paulo * interface it (might have been) received on. 17632176cfdSRui Paulo */ 17732176cfdSRui Paulo m->m_pkthdr.rcvif = (void *)ni; 17832176cfdSRui Paulo 17932176cfdSRui Paulo BPF_MTAP(ifp, m); /* 802.3 tx */ 18032176cfdSRui Paulo 18132176cfdSRui Paulo /* 18232176cfdSRui Paulo * Check if A-MPDU tx aggregation is setup or if we 18332176cfdSRui Paulo * should try to enable it. The sta must be associated 18432176cfdSRui Paulo * with HT and A-MPDU enabled for use. When the policy 18532176cfdSRui Paulo * routine decides we should enable A-MPDU we issue an 18632176cfdSRui Paulo * ADDBA request and wait for a reply. The frame being 18732176cfdSRui Paulo * encapsulated will go out w/o using A-MPDU, or possibly 18832176cfdSRui Paulo * it might be collected by the driver and held/retransmit. 18932176cfdSRui Paulo * The default ic_ampdu_enable routine handles staggering 19032176cfdSRui Paulo * ADDBA requests in case the receiver NAK's us or we are 19132176cfdSRui Paulo * otherwise unable to establish a BA stream. 19232176cfdSRui Paulo */ 19332176cfdSRui Paulo if ((ni->ni_flags & IEEE80211_NODE_AMPDU_TX) && 19432176cfdSRui Paulo (vap->iv_flags_ht & IEEE80211_FHT_AMPDU_TX) && 19532176cfdSRui Paulo (m->m_flags & M_EAPOL) == 0) { 196085ff963SMatthew Dillon int tid = WME_AC_TO_TID(M_WME_GETAC(m)); 197085ff963SMatthew Dillon struct ieee80211_tx_ampdu *tap = &ni->ni_tx_ampdu[tid]; 19832176cfdSRui Paulo 19932176cfdSRui Paulo ieee80211_txampdu_count_packet(tap); 20032176cfdSRui Paulo if (IEEE80211_AMPDU_RUNNING(tap)) { 20132176cfdSRui Paulo /* 20232176cfdSRui Paulo * Operational, mark frame for aggregation. 20332176cfdSRui Paulo * 20432176cfdSRui Paulo * XXX do tx aggregation here 20532176cfdSRui Paulo */ 20632176cfdSRui Paulo m->m_flags |= M_AMPDU_MPDU; 20732176cfdSRui Paulo } else if (!IEEE80211_AMPDU_REQUESTED(tap) && 20832176cfdSRui Paulo ic->ic_ampdu_enable(ni, tap)) { 20932176cfdSRui Paulo /* 21032176cfdSRui Paulo * Not negotiated yet, request service. 21132176cfdSRui Paulo */ 21232176cfdSRui Paulo ieee80211_ampdu_request(ni, tap); 21332176cfdSRui Paulo /* XXX hold frame for reply? */ 21432176cfdSRui Paulo } 21532176cfdSRui Paulo } 216085ff963SMatthew Dillon 21732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 21832176cfdSRui Paulo else if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_NODE_FF)) { 21932176cfdSRui Paulo m = ieee80211_ff_check(ni, m); 22032176cfdSRui Paulo if (m == NULL) { 22132176cfdSRui Paulo /* NB: any ni ref held on stageq */ 222085ff963SMatthew Dillon return (0); 22332176cfdSRui Paulo } 22432176cfdSRui Paulo } 22532176cfdSRui Paulo #endif /* IEEE80211_SUPPORT_SUPERG */ 226085ff963SMatthew Dillon 227085ff963SMatthew Dillon /* 228085ff963SMatthew Dillon * Grab the TX lock - serialise the TX process from this 229085ff963SMatthew Dillon * point (where TX state is being checked/modified) 230085ff963SMatthew Dillon * through to driver queue. 231085ff963SMatthew Dillon */ 232085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 233085ff963SMatthew Dillon 23432176cfdSRui Paulo if (__predict_true((vap->iv_caps & IEEE80211_C_8023ENCAP) == 0)) { 23532176cfdSRui Paulo /* 23632176cfdSRui Paulo * Encapsulate the packet in prep for transmission. 23732176cfdSRui Paulo */ 23832176cfdSRui Paulo m = ieee80211_encap(vap, ni, m); 23932176cfdSRui Paulo if (m == NULL) { 24032176cfdSRui Paulo /* NB: stat+msg handled in ieee80211_encap */ 241085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 24232176cfdSRui Paulo ieee80211_free_node(ni); 243085ff963SMatthew Dillon /* XXX better status? */ 244085ff963SMatthew Dillon return (ENOBUFS); 24532176cfdSRui Paulo } 24632176cfdSRui Paulo } 247085ff963SMatthew Dillon error = ieee80211_parent_xmitpkt(ic, m); 24832176cfdSRui Paulo 249085ff963SMatthew Dillon /* 250085ff963SMatthew Dillon * Unlock at this point - no need to hold it across 251085ff963SMatthew Dillon * ieee80211_free_node() (ie, the comlock) 252085ff963SMatthew Dillon */ 253085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 25432176cfdSRui Paulo if (error != 0) { 25532176cfdSRui Paulo /* NB: IFQ_HANDOFF reclaims mbuf */ 25632176cfdSRui Paulo ieee80211_free_node(ni); 25732176cfdSRui Paulo } else { 258d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 25932176cfdSRui Paulo } 26032176cfdSRui Paulo ic->ic_lastdata = ticks; 261085ff963SMatthew Dillon 262085ff963SMatthew Dillon return (0); 26332176cfdSRui Paulo } 264085ff963SMatthew Dillon 265085ff963SMatthew Dillon 266085ff963SMatthew Dillon 267085ff963SMatthew Dillon /* 268085ff963SMatthew Dillon * Send the given mbuf through the given vap. 269085ff963SMatthew Dillon * 270085ff963SMatthew Dillon * This consumes the mbuf regardless of whether the transmit 271085ff963SMatthew Dillon * was successful or not. 272085ff963SMatthew Dillon * 273085ff963SMatthew Dillon * This does none of the initial checks that ieee80211_start() 274085ff963SMatthew Dillon * does (eg CAC timeout, interface wakeup) - the caller must 275085ff963SMatthew Dillon * do this first. 276085ff963SMatthew Dillon */ 277085ff963SMatthew Dillon static int 278085ff963SMatthew Dillon ieee80211_start_pkt(struct ieee80211vap *vap, struct mbuf *m) 279085ff963SMatthew Dillon { 280085ff963SMatthew Dillon #define IS_DWDS(vap) \ 281085ff963SMatthew Dillon (vap->iv_opmode == IEEE80211_M_WDS && \ 282085ff963SMatthew Dillon (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY) == 0) 283085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 284085ff963SMatthew Dillon struct ifnet *ifp = vap->iv_ifp; 285085ff963SMatthew Dillon struct ieee80211_node *ni; 286085ff963SMatthew Dillon struct ether_header *eh; 287085ff963SMatthew Dillon 288085ff963SMatthew Dillon /* 289085ff963SMatthew Dillon * Cancel any background scan. 290085ff963SMatthew Dillon */ 291085ff963SMatthew Dillon if (ic->ic_flags & IEEE80211_F_SCAN) 292085ff963SMatthew Dillon ieee80211_cancel_anyscan(vap); 293085ff963SMatthew Dillon /* 294085ff963SMatthew Dillon * Find the node for the destination so we can do 295085ff963SMatthew Dillon * things like power save and fast frames aggregation. 296085ff963SMatthew Dillon * 297085ff963SMatthew Dillon * NB: past this point various code assumes the first 298085ff963SMatthew Dillon * mbuf has the 802.3 header present (and contiguous). 299085ff963SMatthew Dillon */ 300085ff963SMatthew Dillon ni = NULL; 301085ff963SMatthew Dillon if (m->m_len < sizeof(struct ether_header) && 302085ff963SMatthew Dillon (m = m_pullup(m, sizeof(struct ether_header))) == NULL) { 303085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 304085ff963SMatthew Dillon "discard frame, %s\n", "m_pullup failed"); 305085ff963SMatthew Dillon vap->iv_stats.is_tx_nobuf++; /* XXX */ 306085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 307085ff963SMatthew Dillon return (ENOBUFS); 308085ff963SMatthew Dillon } 309085ff963SMatthew Dillon eh = mtod(m, struct ether_header *); 310085ff963SMatthew Dillon if (ETHER_IS_MULTICAST(eh->ether_dhost)) { 311085ff963SMatthew Dillon if (IS_DWDS(vap)) { 312085ff963SMatthew Dillon /* 313085ff963SMatthew Dillon * Only unicast frames from the above go out 314085ff963SMatthew Dillon * DWDS vaps; multicast frames are handled by 315085ff963SMatthew Dillon * dispatching the frame as it comes through 316085ff963SMatthew Dillon * the AP vap (see below). 317085ff963SMatthew Dillon */ 318085ff963SMatthew Dillon IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_WDS, 319085ff963SMatthew Dillon eh->ether_dhost, "mcast", "%s", "on DWDS"); 320085ff963SMatthew Dillon vap->iv_stats.is_dwds_mcast++; 321085ff963SMatthew Dillon m_freem(m); 322085ff963SMatthew Dillon /* XXX better status? */ 323085ff963SMatthew Dillon return (ENOBUFS); 324085ff963SMatthew Dillon } 325085ff963SMatthew Dillon if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 326085ff963SMatthew Dillon /* 327085ff963SMatthew Dillon * Spam DWDS vap's w/ multicast traffic. 328085ff963SMatthew Dillon */ 329085ff963SMatthew Dillon /* XXX only if dwds in use? */ 330085ff963SMatthew Dillon ieee80211_dwds_mcast(vap, m); 331085ff963SMatthew Dillon } 332085ff963SMatthew Dillon } 333085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 334085ff963SMatthew Dillon if (vap->iv_opmode != IEEE80211_M_MBSS) { 335085ff963SMatthew Dillon #endif 336085ff963SMatthew Dillon ni = ieee80211_find_txnode(vap, eh->ether_dhost); 337085ff963SMatthew Dillon if (ni == NULL) { 338085ff963SMatthew Dillon /* NB: ieee80211_find_txnode does stat+msg */ 339085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 340085ff963SMatthew Dillon m_freem(m); 341085ff963SMatthew Dillon /* XXX better status? */ 342085ff963SMatthew Dillon return (ENOBUFS); 343085ff963SMatthew Dillon } 344085ff963SMatthew Dillon if (ni->ni_associd == 0 && 345085ff963SMatthew Dillon (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { 346085ff963SMatthew Dillon IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 347085ff963SMatthew Dillon eh->ether_dhost, NULL, 348085ff963SMatthew Dillon "sta not associated (type 0x%04x)", 349085ff963SMatthew Dillon htons(eh->ether_type)); 350085ff963SMatthew Dillon vap->iv_stats.is_tx_notassoc++; 351085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 352085ff963SMatthew Dillon m_freem(m); 353085ff963SMatthew Dillon ieee80211_free_node(ni); 354085ff963SMatthew Dillon /* XXX better status? */ 355085ff963SMatthew Dillon return (ENOBUFS); 356085ff963SMatthew Dillon } 357085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 358085ff963SMatthew Dillon } else { 359085ff963SMatthew Dillon if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) { 360085ff963SMatthew Dillon /* 361085ff963SMatthew Dillon * Proxy station only if configured. 362085ff963SMatthew Dillon */ 363085ff963SMatthew Dillon if (!ieee80211_mesh_isproxyena(vap)) { 364085ff963SMatthew Dillon IEEE80211_DISCARD_MAC(vap, 365085ff963SMatthew Dillon IEEE80211_MSG_OUTPUT | 366085ff963SMatthew Dillon IEEE80211_MSG_MESH, 367085ff963SMatthew Dillon eh->ether_dhost, NULL, 368085ff963SMatthew Dillon "%s", "proxy not enabled"); 369085ff963SMatthew Dillon vap->iv_stats.is_mesh_notproxy++; 370085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 371085ff963SMatthew Dillon m_freem(m); 372085ff963SMatthew Dillon /* XXX better status? */ 373085ff963SMatthew Dillon return (ENOBUFS); 374085ff963SMatthew Dillon } 375085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 376f92fae3fSSascha Wildner "forward frame from DS SA(%s), DA(%s)\n", 377f92fae3fSSascha Wildner ether_sprintf(eh->ether_shost), 378f92fae3fSSascha Wildner ether_sprintf(eh->ether_dhost)); 379085ff963SMatthew Dillon ieee80211_mesh_proxy_check(vap, eh->ether_shost); 380085ff963SMatthew Dillon } 381085ff963SMatthew Dillon ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m); 382085ff963SMatthew Dillon if (ni == NULL) { 383085ff963SMatthew Dillon /* 384085ff963SMatthew Dillon * NB: ieee80211_mesh_discover holds/disposes 385085ff963SMatthew Dillon * frame (e.g. queueing on path discovery). 386085ff963SMatthew Dillon */ 387085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 388085ff963SMatthew Dillon /* XXX better status? */ 389085ff963SMatthew Dillon return (ENOBUFS); 390085ff963SMatthew Dillon } 391085ff963SMatthew Dillon } 392085ff963SMatthew Dillon #endif 393085ff963SMatthew Dillon 394085ff963SMatthew Dillon /* 395085ff963SMatthew Dillon * We've resolved the sender, so attempt to transmit it. 396085ff963SMatthew Dillon */ 397085ff963SMatthew Dillon 398085ff963SMatthew Dillon if (vap->iv_state == IEEE80211_S_SLEEP) { 399085ff963SMatthew Dillon /* 400085ff963SMatthew Dillon * In power save; queue frame and then wakeup device 401085ff963SMatthew Dillon * for transmit. 402085ff963SMatthew Dillon */ 403085ff963SMatthew Dillon ic->ic_lastdata = ticks; 404085ff963SMatthew Dillon (void) ieee80211_pwrsave(ni, m); 405085ff963SMatthew Dillon ieee80211_free_node(ni); 406085ff963SMatthew Dillon ieee80211_new_state(vap, IEEE80211_S_RUN, 0); 407085ff963SMatthew Dillon return (0); 408085ff963SMatthew Dillon } 409085ff963SMatthew Dillon 410085ff963SMatthew Dillon if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0) 411085ff963SMatthew Dillon return (ENOBUFS); 412085ff963SMatthew Dillon return (0); 41332176cfdSRui Paulo #undef IS_DWDS 41432176cfdSRui Paulo } 41532176cfdSRui Paulo 416085ff963SMatthew Dillon /* 417085ff963SMatthew Dillon * Start method for vap's. All packets from the stack come 418085ff963SMatthew Dillon * through here. We handle common processing of the packets 419085ff963SMatthew Dillon * before dispatching them to the underlying device. 420085ff963SMatthew Dillon * 421085ff963SMatthew Dillon * if_transmit() requires that the mbuf be consumed by this call 422085ff963SMatthew Dillon * regardless of the return condition. 423085ff963SMatthew Dillon */ 424085ff963SMatthew Dillon 425085ff963SMatthew Dillon #if defined(__DragonFly__) 426085ff963SMatthew Dillon 427085ff963SMatthew Dillon void 428085ff963SMatthew Dillon ieee80211_vap_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 429085ff963SMatthew Dillon { 430085ff963SMatthew Dillon struct ieee80211vap *vap = ifp->if_softc; 431085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 432085ff963SMatthew Dillon struct ifnet *parent = ic->ic_ifp; 433085ff963SMatthew Dillon struct mbuf *m = NULL; 434085ff963SMatthew Dillon 435085ff963SMatthew Dillon /* NB: parent must be up and running */ 436085ff963SMatthew Dillon if (!IFNET_IS_UP_RUNNING(parent)) { 437085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 438085ff963SMatthew Dillon "%s: ignore queue, parent %s not up+running\n", 439085ff963SMatthew Dillon __func__, parent->if_xname); 440085ff963SMatthew Dillon /* XXX stat */ 441085ff963SMatthew Dillon /*m_freem(m);*/ 442085ff963SMatthew Dillon /*return (EINVAL);*/ 443085ff963SMatthew Dillon return; 444085ff963SMatthew Dillon } 445085ff963SMatthew Dillon 446085ff963SMatthew Dillon wlan_assert_serialized(); 447085ff963SMatthew Dillon ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 448085ff963SMatthew Dillon 449085ff963SMatthew Dillon /* 450085ff963SMatthew Dillon * No data frames go out unless we're running. 451085ff963SMatthew Dillon * Note in particular this covers CAC and CSA 452085ff963SMatthew Dillon * states (though maybe we should check muting 453085ff963SMatthew Dillon * for CSA). 454085ff963SMatthew Dillon */ 455085ff963SMatthew Dillon if (vap->iv_state != IEEE80211_S_RUN && 456085ff963SMatthew Dillon vap->iv_state != IEEE80211_S_SLEEP) { 457085ff963SMatthew Dillon IEEE80211_LOCK(ic); 458085ff963SMatthew Dillon /* re-check under the com lock to avoid races */ 459085ff963SMatthew Dillon if (vap->iv_state != IEEE80211_S_RUN && 460085ff963SMatthew Dillon vap->iv_state != IEEE80211_S_SLEEP) { 461085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 462085ff963SMatthew Dillon "%s: ignore queue, in %s state\n", 463085ff963SMatthew Dillon __func__, ieee80211_state_name[vap->iv_state]); 464085ff963SMatthew Dillon vap->iv_stats.is_tx_badstate++; 465085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 466085ff963SMatthew Dillon ifsq_set_oactive(ifsq); 467085ff963SMatthew Dillon /*m_freem(m);*/ 468085ff963SMatthew Dillon /* return (EINVAL); */ 469085ff963SMatthew Dillon return; 470085ff963SMatthew Dillon } 471085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 472085ff963SMatthew Dillon } 473085ff963SMatthew Dillon 474085ff963SMatthew Dillon wlan_serialize_exit(); 475085ff963SMatthew Dillon for (;;) { 476085ff963SMatthew Dillon m = ifsq_dequeue(ifsq); 477085ff963SMatthew Dillon if (m == NULL) 478085ff963SMatthew Dillon break; 479085ff963SMatthew Dillon 480085ff963SMatthew Dillon /* 481085ff963SMatthew Dillon * Sanitize mbuf flags for net80211 use. We cannot 482085ff963SMatthew Dillon * clear M_PWR_SAV or M_MORE_DATA because these may 483085ff963SMatthew Dillon * be set for frames that are re-submitted from the 484085ff963SMatthew Dillon * power save queue. 485085ff963SMatthew Dillon * 486085ff963SMatthew Dillon * NB: This must be done before ieee80211_classify as 487085ff963SMatthew Dillon * it marks EAPOL in frames with M_EAPOL. 488085ff963SMatthew Dillon */ 489085ff963SMatthew Dillon m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); 490085ff963SMatthew Dillon 491085ff963SMatthew Dillon /* 492085ff963SMatthew Dillon * Bump to the packet transmission path. 493085ff963SMatthew Dillon * The mbuf will be consumed here. 494085ff963SMatthew Dillon */ 495085ff963SMatthew Dillon ieee80211_start_pkt(vap, m); 496085ff963SMatthew Dillon } 497085ff963SMatthew Dillon wlan_serialize_enter(); 498085ff963SMatthew Dillon } 499085ff963SMatthew Dillon 500085ff963SMatthew Dillon #else 501085ff963SMatthew Dillon 502085ff963SMatthew Dillon int 503085ff963SMatthew Dillon ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m) 504085ff963SMatthew Dillon { 505085ff963SMatthew Dillon struct ieee80211vap *vap = ifp->if_softc; 506085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 507085ff963SMatthew Dillon struct ifnet *parent = ic->ic_ifp; 508085ff963SMatthew Dillon 509085ff963SMatthew Dillon /* NB: parent must be up and running */ 510085ff963SMatthew Dillon if (!IFNET_IS_UP_RUNNING(parent)) { 511085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 512085ff963SMatthew Dillon "%s: ignore queue, parent %s not up+running\n", 513085ff963SMatthew Dillon __func__, parent->if_xname); 514085ff963SMatthew Dillon /* XXX stat */ 515085ff963SMatthew Dillon m_freem(m); 516085ff963SMatthew Dillon return (EINVAL); 517085ff963SMatthew Dillon } 518085ff963SMatthew Dillon 519085ff963SMatthew Dillon /* 520085ff963SMatthew Dillon * No data frames go out unless we're running. 521085ff963SMatthew Dillon * Note in particular this covers CAC and CSA 522085ff963SMatthew Dillon * states (though maybe we should check muting 523085ff963SMatthew Dillon * for CSA). 524085ff963SMatthew Dillon */ 525085ff963SMatthew Dillon if (vap->iv_state != IEEE80211_S_RUN && 526085ff963SMatthew Dillon vap->iv_state != IEEE80211_S_SLEEP) { 527085ff963SMatthew Dillon IEEE80211_LOCK(ic); 528085ff963SMatthew Dillon /* re-check under the com lock to avoid races */ 529085ff963SMatthew Dillon if (vap->iv_state != IEEE80211_S_RUN && 530085ff963SMatthew Dillon vap->iv_state != IEEE80211_S_SLEEP) { 531085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 532085ff963SMatthew Dillon "%s: ignore queue, in %s state\n", 533085ff963SMatthew Dillon __func__, ieee80211_state_name[vap->iv_state]); 534085ff963SMatthew Dillon vap->iv_stats.is_tx_badstate++; 535085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 536085ff963SMatthew Dillon ifp->if_drv_flags |= IFF_DRV_OACTIVE; 537085ff963SMatthew Dillon m_freem(m); 538085ff963SMatthew Dillon return (EINVAL); 539085ff963SMatthew Dillon } 540085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 541085ff963SMatthew Dillon } 542085ff963SMatthew Dillon 543085ff963SMatthew Dillon /* 544085ff963SMatthew Dillon * Sanitize mbuf flags for net80211 use. We cannot 545085ff963SMatthew Dillon * clear M_PWR_SAV or M_MORE_DATA because these may 546085ff963SMatthew Dillon * be set for frames that are re-submitted from the 547085ff963SMatthew Dillon * power save queue. 548085ff963SMatthew Dillon * 549085ff963SMatthew Dillon * NB: This must be done before ieee80211_classify as 550085ff963SMatthew Dillon * it marks EAPOL in frames with M_EAPOL. 551085ff963SMatthew Dillon */ 552085ff963SMatthew Dillon m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); 553085ff963SMatthew Dillon 554085ff963SMatthew Dillon /* 555085ff963SMatthew Dillon * Bump to the packet transmission path. 556085ff963SMatthew Dillon * The mbuf will be consumed here. 557085ff963SMatthew Dillon */ 558085ff963SMatthew Dillon return (ieee80211_start_pkt(vap, m)); 559085ff963SMatthew Dillon } 560085ff963SMatthew Dillon 561085ff963SMatthew Dillon void 562085ff963SMatthew Dillon ieee80211_vap_qflush(struct ifnet *ifp) 563085ff963SMatthew Dillon { 564085ff963SMatthew Dillon 565085ff963SMatthew Dillon /* Empty for now */ 566085ff963SMatthew Dillon } 567085ff963SMatthew Dillon 568085ff963SMatthew Dillon #endif 569085ff963SMatthew Dillon 570085ff963SMatthew Dillon /* 571085ff963SMatthew Dillon * 802.11 raw output routine. 572085ff963SMatthew Dillon * 573085ff963SMatthew Dillon * XXX TODO: this (and other send routines) should correctly 574085ff963SMatthew Dillon * XXX keep the pwr mgmt bit set if it decides to call into the 575085ff963SMatthew Dillon * XXX driver to send a frame whilst the state is SLEEP. 576085ff963SMatthew Dillon * 577085ff963SMatthew Dillon * Otherwise the peer may decide that we're awake and flood us 578085ff963SMatthew Dillon * with traffic we are still too asleep to receive! 579085ff963SMatthew Dillon */ 580085ff963SMatthew Dillon int 581085ff963SMatthew Dillon ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni, 582085ff963SMatthew Dillon struct mbuf *m, const struct ieee80211_bpf_params *params) 583085ff963SMatthew Dillon { 584085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 585085ff963SMatthew Dillon 586085ff963SMatthew Dillon return (ic->ic_raw_xmit(ni, m, params)); 587085ff963SMatthew Dillon } 588cc0d8938SRui Paulo 58932176cfdSRui Paulo /* 59032176cfdSRui Paulo * 802.11 output routine. This is (currently) used only to 59132176cfdSRui Paulo * connect bpf write calls to the 802.11 layer for injecting 59232176cfdSRui Paulo * raw 802.11 frames. 59332176cfdSRui Paulo */ 594085ff963SMatthew Dillon #if defined(__DragonFly__) 59532176cfdSRui Paulo int 59632176cfdSRui Paulo ieee80211_output(struct ifnet *ifp, struct mbuf *m, 59734a60cf6SRui Paulo struct sockaddr *dst, struct rtentry *rt) 598085ff963SMatthew Dillon #else 599085ff963SMatthew Dillon int 600085ff963SMatthew Dillon ieee80211_output(struct ifnet *ifp, struct mbuf *m, 601*294727bfSImre Vadász const struct sockaddr *dst, struct route *ro) 602085ff963SMatthew Dillon #endif 60332176cfdSRui Paulo { 60432176cfdSRui Paulo #define senderr(e) do { error = (e); goto bad;} while (0) 60532176cfdSRui Paulo struct ieee80211_node *ni = NULL; 60632176cfdSRui Paulo struct ieee80211vap *vap; 60732176cfdSRui Paulo struct ieee80211_frame *wh; 608085ff963SMatthew Dillon struct ieee80211com *ic = NULL; 60932176cfdSRui Paulo int error; 610085ff963SMatthew Dillon int ret; 61132176cfdSRui Paulo 612085ff963SMatthew Dillon #if defined(__DragonFly__) 613085ff963SMatthew Dillon struct ifaltq_subque *ifsq; 614f0a26983SSepherosa Ziehau ifsq = ifq_get_subq_default(&ifp->if_snd); 615085ff963SMatthew Dillon if (ifsq_is_oactive(ifsq)) 616085ff963SMatthew Dillon #else 617085ff963SMatthew Dillon if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 618085ff963SMatthew Dillon #endif 619085ff963SMatthew Dillon { 62032176cfdSRui Paulo /* 62132176cfdSRui Paulo * Short-circuit requests if the vap is marked OACTIVE 62232176cfdSRui Paulo * as this can happen because a packet came down through 62332176cfdSRui Paulo * ieee80211_start before the vap entered RUN state in 62432176cfdSRui Paulo * which case it's ok to just drop the frame. This 62532176cfdSRui Paulo * should not be necessary but callers of if_output don't 62632176cfdSRui Paulo * check OACTIVE. 62732176cfdSRui Paulo */ 62832176cfdSRui Paulo senderr(ENETDOWN); 62932176cfdSRui Paulo } 63032176cfdSRui Paulo vap = ifp->if_softc; 631085ff963SMatthew Dillon ic = vap->iv_ic; 63232176cfdSRui Paulo /* 63332176cfdSRui Paulo * Hand to the 802.3 code if not tagged as 63432176cfdSRui Paulo * a raw 802.11 frame. 63532176cfdSRui Paulo */ 636085ff963SMatthew Dillon #if defined(__DragonFly__) 63732176cfdSRui Paulo if (dst->sa_family != AF_IEEE80211) 63834a60cf6SRui Paulo return vap->iv_output(ifp, m, dst, rt); 639085ff963SMatthew Dillon #else 640085ff963SMatthew Dillon if (dst->sa_family != AF_IEEE80211) 641085ff963SMatthew Dillon return vap->iv_output(ifp, m, dst, ro); 642085ff963SMatthew Dillon #endif 64332176cfdSRui Paulo #ifdef MAC 64432176cfdSRui Paulo error = mac_ifnet_check_transmit(ifp, m); 64532176cfdSRui Paulo if (error) 64632176cfdSRui Paulo senderr(error); 64732176cfdSRui Paulo #endif 64832176cfdSRui Paulo if (ifp->if_flags & IFF_MONITOR) 64932176cfdSRui Paulo senderr(ENETDOWN); 65032176cfdSRui Paulo if (!IFNET_IS_UP_RUNNING(ifp)) 65132176cfdSRui Paulo senderr(ENETDOWN); 65232176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 65332176cfdSRui Paulo IEEE80211_DPRINTF(vap, 65432176cfdSRui Paulo IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 65532176cfdSRui Paulo "block %s frame in CAC state\n", "raw data"); 65632176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 65732176cfdSRui Paulo senderr(EIO); /* XXX */ 658085ff963SMatthew Dillon } else if (vap->iv_state == IEEE80211_S_SCAN) 659085ff963SMatthew Dillon senderr(EIO); 66032176cfdSRui Paulo /* XXX bypass bridge, pfil, carp, etc. */ 66132176cfdSRui Paulo 66232176cfdSRui Paulo if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) 66332176cfdSRui Paulo senderr(EIO); /* XXX */ 66432176cfdSRui Paulo wh = mtod(m, struct ieee80211_frame *); 66532176cfdSRui Paulo if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 66632176cfdSRui Paulo IEEE80211_FC0_VERSION_0) 66732176cfdSRui Paulo senderr(EIO); /* XXX */ 66832176cfdSRui Paulo 66932176cfdSRui Paulo /* locate destination node */ 67032176cfdSRui Paulo switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 67132176cfdSRui Paulo case IEEE80211_FC1_DIR_NODS: 67232176cfdSRui Paulo case IEEE80211_FC1_DIR_FROMDS: 67332176cfdSRui Paulo ni = ieee80211_find_txnode(vap, wh->i_addr1); 67432176cfdSRui Paulo break; 67532176cfdSRui Paulo case IEEE80211_FC1_DIR_TODS: 67632176cfdSRui Paulo case IEEE80211_FC1_DIR_DSTODS: 67732176cfdSRui Paulo if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) 67832176cfdSRui Paulo senderr(EIO); /* XXX */ 67932176cfdSRui Paulo ni = ieee80211_find_txnode(vap, wh->i_addr3); 68032176cfdSRui Paulo break; 68132176cfdSRui Paulo default: 68232176cfdSRui Paulo senderr(EIO); /* XXX */ 68332176cfdSRui Paulo } 68432176cfdSRui Paulo if (ni == NULL) { 68532176cfdSRui Paulo /* 68632176cfdSRui Paulo * Permit packets w/ bpf params through regardless 68732176cfdSRui Paulo * (see below about sa_len). 68832176cfdSRui Paulo */ 68932176cfdSRui Paulo if (dst->sa_len == 0) 69032176cfdSRui Paulo senderr(EHOSTUNREACH); 69132176cfdSRui Paulo ni = ieee80211_ref_node(vap->iv_bss); 69232176cfdSRui Paulo } 69332176cfdSRui Paulo 69432176cfdSRui Paulo /* 69532176cfdSRui Paulo * Sanitize mbuf for net80211 flags leaked from above. 69632176cfdSRui Paulo * 69732176cfdSRui Paulo * NB: This must be done before ieee80211_classify as 69832176cfdSRui Paulo * it marks EAPOL in frames with M_EAPOL. 69932176cfdSRui Paulo */ 70032176cfdSRui Paulo m->m_flags &= ~M_80211_TX; 70132176cfdSRui Paulo 70232176cfdSRui Paulo /* calculate priority so drivers can find the tx queue */ 70332176cfdSRui Paulo /* XXX assumes an 802.3 frame */ 70432176cfdSRui Paulo if (ieee80211_classify(ni, m)) 70532176cfdSRui Paulo senderr(EIO); /* XXX */ 70632176cfdSRui Paulo 707d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 70832176cfdSRui Paulo IEEE80211_NODE_STAT(ni, tx_data); 70932176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 71032176cfdSRui Paulo IEEE80211_NODE_STAT(ni, tx_mcast); 71132176cfdSRui Paulo m->m_flags |= M_MCAST; 71232176cfdSRui Paulo } else 71332176cfdSRui Paulo IEEE80211_NODE_STAT(ni, tx_ucast); 71432176cfdSRui Paulo /* NB: ieee80211_encap does not include 802.11 header */ 71532176cfdSRui Paulo IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len); 71632176cfdSRui Paulo 717085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 718085ff963SMatthew Dillon 71932176cfdSRui Paulo /* 72032176cfdSRui Paulo * NB: DLT_IEEE802_11_RADIO identifies the parameters are 72132176cfdSRui Paulo * present by setting the sa_len field of the sockaddr (yes, 72232176cfdSRui Paulo * this is a hack). 72332176cfdSRui Paulo * NB: we assume sa_data is suitably aligned to cast. 72432176cfdSRui Paulo */ 725085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, ni, m, 72632176cfdSRui Paulo (const struct ieee80211_bpf_params *)(dst->sa_len ? 72732176cfdSRui Paulo dst->sa_data : NULL)); 728085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 729085ff963SMatthew Dillon return (ret); 73032176cfdSRui Paulo bad: 73132176cfdSRui Paulo if (m != NULL) 73232176cfdSRui Paulo m_freem(m); 73332176cfdSRui Paulo if (ni != NULL) 73432176cfdSRui Paulo ieee80211_free_node(ni); 735d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 73632176cfdSRui Paulo return error; 73732176cfdSRui Paulo #undef senderr 73832176cfdSRui Paulo } 73932176cfdSRui Paulo 74032176cfdSRui Paulo /* 74132176cfdSRui Paulo * Set the direction field and address fields of an outgoing 74232176cfdSRui Paulo * frame. Note this should be called early on in constructing 74332176cfdSRui Paulo * a frame as it sets i_fc[1]; other bits can then be or'd in. 74432176cfdSRui Paulo */ 74532176cfdSRui Paulo void 74632176cfdSRui Paulo ieee80211_send_setup( 747841ab66cSSepherosa Ziehau struct ieee80211_node *ni, 74832176cfdSRui Paulo struct mbuf *m, 74932176cfdSRui Paulo int type, int tid, 750841ab66cSSepherosa Ziehau const uint8_t sa[IEEE80211_ADDR_LEN], 751841ab66cSSepherosa Ziehau const uint8_t da[IEEE80211_ADDR_LEN], 752841ab66cSSepherosa Ziehau const uint8_t bssid[IEEE80211_ADDR_LEN]) 753841ab66cSSepherosa Ziehau { 754841ab66cSSepherosa Ziehau #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) 75532176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 756085ff963SMatthew Dillon struct ieee80211_tx_ampdu *tap; 75732176cfdSRui Paulo struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 75832176cfdSRui Paulo ieee80211_seq seqno; 759841ab66cSSepherosa Ziehau 760085ff963SMatthew Dillon IEEE80211_TX_LOCK_ASSERT(ni->ni_ic); 761085ff963SMatthew Dillon 762841ab66cSSepherosa Ziehau wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; 763841ab66cSSepherosa Ziehau if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 76432176cfdSRui Paulo switch (vap->iv_opmode) { 765841ab66cSSepherosa Ziehau case IEEE80211_M_STA: 766841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 767841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 768841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr2, sa); 769841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, da); 770841ab66cSSepherosa Ziehau break; 771841ab66cSSepherosa Ziehau case IEEE80211_M_IBSS: 772841ab66cSSepherosa Ziehau case IEEE80211_M_AHDEMO: 773841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 774841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, da); 775841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr2, sa); 776841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 777841ab66cSSepherosa Ziehau break; 778841ab66cSSepherosa Ziehau case IEEE80211_M_HOSTAP: 779841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 780841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, da); 781841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr2, bssid); 782841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, sa); 783841ab66cSSepherosa Ziehau break; 78432176cfdSRui Paulo case IEEE80211_M_WDS: 78532176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 78632176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 78732176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 78832176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, da); 78932176cfdSRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 79032176cfdSRui Paulo break; 79132176cfdSRui Paulo case IEEE80211_M_MBSS: 79232176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 79332176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(da)) { 79432176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 79532176cfdSRui Paulo /* XXX next hop */ 79632176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 79732176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 79832176cfdSRui Paulo vap->iv_myaddr); 79932176cfdSRui Paulo } else { 80032176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 80132176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 80232176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 80332176cfdSRui Paulo vap->iv_myaddr); 80432176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, da); 80532176cfdSRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 80632176cfdSRui Paulo } 80732176cfdSRui Paulo #endif 80832176cfdSRui Paulo break; 809841ab66cSSepherosa Ziehau case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ 810841ab66cSSepherosa Ziehau break; 811841ab66cSSepherosa Ziehau } 812841ab66cSSepherosa Ziehau } else { 813841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 814841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, da); 815841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr2, sa); 81632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 81732176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 81832176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, sa); 81932176cfdSRui Paulo else 82032176cfdSRui Paulo #endif 821841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 822841ab66cSSepherosa Ziehau } 823841ab66cSSepherosa Ziehau *(uint16_t *)&wh->i_dur[0] = 0; 82432176cfdSRui Paulo 825085ff963SMatthew Dillon tap = &ni->ni_tx_ampdu[tid]; 826085ff963SMatthew Dillon if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) 827085ff963SMatthew Dillon m->m_flags |= M_AMPDU_MPDU; 828085ff963SMatthew Dillon else { 82932176cfdSRui Paulo seqno = ni->ni_txseqs[tid]++; 830085ff963SMatthew Dillon *(uint16_t *)&wh->i_seq[0] = 831085ff963SMatthew Dillon htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 83232176cfdSRui Paulo M_SEQNO_SET(m, seqno); 833085ff963SMatthew Dillon } 83432176cfdSRui Paulo 83532176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 83632176cfdSRui Paulo m->m_flags |= M_MCAST; 837841ab66cSSepherosa Ziehau #undef WH4 838841ab66cSSepherosa Ziehau } 839841ab66cSSepherosa Ziehau 840f186073cSJoerg Sonnenberger /* 841f186073cSJoerg Sonnenberger * Send a management frame to the specified node. The node pointer 842f186073cSJoerg Sonnenberger * must have a reference as the pointer will be passed to the driver 843f186073cSJoerg Sonnenberger * and potentially held for a long time. If the frame is successfully 844f186073cSJoerg Sonnenberger * dispatched to the driver, then it is responsible for freeing the 84532176cfdSRui Paulo * reference (and potentially free'ing up any associated storage); 84632176cfdSRui Paulo * otherwise deal with reclaiming any reference (on error). 847f186073cSJoerg Sonnenberger */ 84832176cfdSRui Paulo int 84932176cfdSRui Paulo ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, 85032176cfdSRui Paulo struct ieee80211_bpf_params *params) 851f186073cSJoerg Sonnenberger { 85232176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 85332176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 854f186073cSJoerg Sonnenberger struct ieee80211_frame *wh; 855085ff963SMatthew Dillon int ret; 856085ff963SMatthew Dillon 857f186073cSJoerg Sonnenberger KASSERT(ni != NULL, ("null node")); 858f186073cSJoerg Sonnenberger 85932176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 86032176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 86132176cfdSRui Paulo ni, "block %s frame in CAC state", 86232176cfdSRui Paulo ieee80211_mgt_subtype_name[ 86332176cfdSRui Paulo (type & IEEE80211_FC0_SUBTYPE_MASK) >> 86432176cfdSRui Paulo IEEE80211_FC0_SUBTYPE_SHIFT]); 86532176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 86632176cfdSRui Paulo ieee80211_free_node(ni); 86732176cfdSRui Paulo m_freem(m); 86832176cfdSRui Paulo return EIO; /* XXX */ 86932176cfdSRui Paulo } 87032176cfdSRui Paulo 871b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 87232176cfdSRui Paulo if (m == NULL) { 87332176cfdSRui Paulo ieee80211_free_node(ni); 874f186073cSJoerg Sonnenberger return ENOMEM; 87532176cfdSRui Paulo } 876f186073cSJoerg Sonnenberger 877085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 878085ff963SMatthew Dillon 879f186073cSJoerg Sonnenberger wh = mtod(m, struct ieee80211_frame *); 88032176cfdSRui Paulo ieee80211_send_setup(ni, m, 88132176cfdSRui Paulo IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, 88232176cfdSRui Paulo vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 88332176cfdSRui Paulo if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 88432176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, 88532176cfdSRui Paulo "encrypting frame (%s)", __func__); 886085ff963SMatthew Dillon wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; 887f186073cSJoerg Sonnenberger } 88832176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 88932176cfdSRui Paulo 89032176cfdSRui Paulo KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); 89132176cfdSRui Paulo M_WME_SETAC(m, params->ibp_pri); 89232176cfdSRui Paulo 893841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 894841ab66cSSepherosa Ziehau /* avoid printing too many frames */ 89532176cfdSRui Paulo if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || 89632176cfdSRui Paulo ieee80211_msg_dumppkts(vap)) { 8971e290df3SAntonio Huete Jimenez kprintf("[%s] send %s on channel %u\n", 898085ff963SMatthew Dillon ether_sprintf(wh->i_addr1), 899841ab66cSSepherosa Ziehau ieee80211_mgt_subtype_name[ 900841ab66cSSepherosa Ziehau (type & IEEE80211_FC0_SUBTYPE_MASK) >> 901841ab66cSSepherosa Ziehau IEEE80211_FC0_SUBTYPE_SHIFT], 902841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan)); 903841ab66cSSepherosa Ziehau } 904841ab66cSSepherosa Ziehau #endif 905841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_mgmt); 90632176cfdSRui Paulo 907085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, ni, m, params); 908085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 909085ff963SMatthew Dillon return (ret); 910f186073cSJoerg Sonnenberger } 911f186073cSJoerg Sonnenberger 912f186073cSJoerg Sonnenberger /* 91332176cfdSRui Paulo * Send a null data frame to the specified node. If the station 91432176cfdSRui Paulo * is setup for QoS then a QoS Null Data frame is constructed. 91532176cfdSRui Paulo * If this is a WDS station then a 4-address frame is constructed. 916f186073cSJoerg Sonnenberger * 917841ab66cSSepherosa Ziehau * NB: the caller is assumed to have setup a node reference 918841ab66cSSepherosa Ziehau * for use; this is necessary to deal with a race condition 91932176cfdSRui Paulo * when probing for inactive stations. Like ieee80211_mgmt_output 92032176cfdSRui Paulo * we must cleanup any node reference on error; however we 92132176cfdSRui Paulo * can safely just unref it as we know it will never be the 92232176cfdSRui Paulo * last reference to the node. 923841ab66cSSepherosa Ziehau */ 924841ab66cSSepherosa Ziehau int 925841ab66cSSepherosa Ziehau ieee80211_send_nulldata(struct ieee80211_node *ni) 926841ab66cSSepherosa Ziehau { 92732176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 928841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 929841ab66cSSepherosa Ziehau struct mbuf *m; 930841ab66cSSepherosa Ziehau struct ieee80211_frame *wh; 93132176cfdSRui Paulo int hdrlen; 93232176cfdSRui Paulo uint8_t *frm; 933085ff963SMatthew Dillon int ret; 934841ab66cSSepherosa Ziehau 93532176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 93632176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 93732176cfdSRui Paulo ni, "block %s frame in CAC state", "null data"); 93832176cfdSRui Paulo ieee80211_unref_node(&ni); 93932176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 94032176cfdSRui Paulo return EIO; /* XXX */ 94132176cfdSRui Paulo } 94232176cfdSRui Paulo 94332176cfdSRui Paulo if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) 94432176cfdSRui Paulo hdrlen = sizeof(struct ieee80211_qosframe); 94532176cfdSRui Paulo else 94632176cfdSRui Paulo hdrlen = sizeof(struct ieee80211_frame); 94732176cfdSRui Paulo /* NB: only WDS vap's get 4-address frames */ 94832176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_WDS) 94932176cfdSRui Paulo hdrlen += IEEE80211_ADDR_LEN; 95032176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_DATAPAD) 95132176cfdSRui Paulo hdrlen = roundup(hdrlen, sizeof(uint32_t)); 95232176cfdSRui Paulo 95332176cfdSRui Paulo m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); 954841ab66cSSepherosa Ziehau if (m == NULL) { 955841ab66cSSepherosa Ziehau /* XXX debug msg */ 956841ab66cSSepherosa Ziehau ieee80211_unref_node(&ni); 95732176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 958841ab66cSSepherosa Ziehau return ENOMEM; 959841ab66cSSepherosa Ziehau } 96032176cfdSRui Paulo KASSERT(M_LEADINGSPACE(m) >= hdrlen, 96132176cfdSRui Paulo ("leading space %zd", M_LEADINGSPACE(m))); 962b5523eacSSascha Wildner M_PREPEND(m, hdrlen, M_NOWAIT); 96332176cfdSRui Paulo if (m == NULL) { 96432176cfdSRui Paulo /* NB: cannot happen */ 96532176cfdSRui Paulo ieee80211_free_node(ni); 96632176cfdSRui Paulo return ENOMEM; 96732176cfdSRui Paulo } 968841ab66cSSepherosa Ziehau 969085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 970085ff963SMatthew Dillon 97132176cfdSRui Paulo wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ 97232176cfdSRui Paulo if (ni->ni_flags & IEEE80211_NODE_QOS) { 97332176cfdSRui Paulo const int tid = WME_AC_TO_TID(WME_AC_BE); 97432176cfdSRui Paulo uint8_t *qos; 97532176cfdSRui Paulo 97632176cfdSRui Paulo ieee80211_send_setup(ni, m, 97732176cfdSRui Paulo IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, 97832176cfdSRui Paulo tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 97932176cfdSRui Paulo 98032176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_WDS) 98132176cfdSRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 98232176cfdSRui Paulo else 98332176cfdSRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 98432176cfdSRui Paulo qos[0] = tid & IEEE80211_QOS_TID; 98532176cfdSRui Paulo if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) 98632176cfdSRui Paulo qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 98732176cfdSRui Paulo qos[1] = 0; 98832176cfdSRui Paulo } else { 98932176cfdSRui Paulo ieee80211_send_setup(ni, m, 990841ab66cSSepherosa Ziehau IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 99132176cfdSRui Paulo IEEE80211_NONQOS_TID, 99232176cfdSRui Paulo vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 99332176cfdSRui Paulo } 99432176cfdSRui Paulo if (vap->iv_opmode != IEEE80211_M_WDS) { 995841ab66cSSepherosa Ziehau /* NB: power management bit is never sent by an AP */ 996841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 99732176cfdSRui Paulo vap->iv_opmode != IEEE80211_M_HOSTAP) 998841ab66cSSepherosa Ziehau wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 99932176cfdSRui Paulo } 100032176cfdSRui Paulo m->m_len = m->m_pkthdr.len = hdrlen; 100132176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 100232176cfdSRui Paulo 100332176cfdSRui Paulo M_WME_SETAC(m, WME_AC_BE); 1004841ab66cSSepherosa Ziehau 1005841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_data); 1006841ab66cSSepherosa Ziehau 100732176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, 100832176cfdSRui Paulo "send %snull data frame on channel %u, pwr mgt %s", 100932176cfdSRui Paulo ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", 1010841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan), 1011841ab66cSSepherosa Ziehau wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 1012841ab66cSSepherosa Ziehau 1013085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, ni, m, NULL); 1014085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 1015085ff963SMatthew Dillon return (ret); 1016841ab66cSSepherosa Ziehau } 1017841ab66cSSepherosa Ziehau 1018841ab66cSSepherosa Ziehau /* 1019841ab66cSSepherosa Ziehau * Assign priority to a frame based on any vlan tag assigned 1020841ab66cSSepherosa Ziehau * to the station and/or any Diffserv setting in an IP header. 1021841ab66cSSepherosa Ziehau * Finally, if an ACM policy is setup (in station mode) it's 1022841ab66cSSepherosa Ziehau * applied. 1023841ab66cSSepherosa Ziehau */ 1024841ab66cSSepherosa Ziehau int 102532176cfdSRui Paulo ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) 1026841ab66cSSepherosa Ziehau { 102732176cfdSRui Paulo const struct ether_header *eh = mtod(m, struct ether_header *); 102832176cfdSRui Paulo int v_wme_ac, d_wme_ac, ac; 1029841ab66cSSepherosa Ziehau 103032176cfdSRui Paulo /* 103132176cfdSRui Paulo * Always promote PAE/EAPOL frames to high priority. 103232176cfdSRui Paulo */ 103332176cfdSRui Paulo if (eh->ether_type == htons(ETHERTYPE_PAE)) { 103432176cfdSRui Paulo /* NB: mark so others don't need to check header */ 103532176cfdSRui Paulo m->m_flags |= M_EAPOL; 103632176cfdSRui Paulo ac = WME_AC_VO; 103732176cfdSRui Paulo goto done; 103832176cfdSRui Paulo } 103932176cfdSRui Paulo /* 104032176cfdSRui Paulo * Non-qos traffic goes to BE. 104132176cfdSRui Paulo */ 1042841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { 1043841ab66cSSepherosa Ziehau ac = WME_AC_BE; 1044841ab66cSSepherosa Ziehau goto done; 1045841ab66cSSepherosa Ziehau } 1046841ab66cSSepherosa Ziehau 1047841ab66cSSepherosa Ziehau /* 1048841ab66cSSepherosa Ziehau * If node has a vlan tag then all traffic 1049841ab66cSSepherosa Ziehau * to it must have a matching tag. 1050841ab66cSSepherosa Ziehau */ 1051841ab66cSSepherosa Ziehau v_wme_ac = 0; 1052841ab66cSSepherosa Ziehau if (ni->ni_vlan != 0) { 105332176cfdSRui Paulo if ((m->m_flags & M_VLANTAG) == 0) { 1054841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_novlantag); 1055841ab66cSSepherosa Ziehau return 1; 1056841ab66cSSepherosa Ziehau } 1057085ff963SMatthew Dillon #if defined(__DragonFly__) 105832176cfdSRui Paulo if (EVL_VLANOFTAG(m->m_pkthdr.ether_vlantag) != 1059841ab66cSSepherosa Ziehau EVL_VLANOFTAG(ni->ni_vlan)) { 1060841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 1061841ab66cSSepherosa Ziehau return 1; 1062841ab66cSSepherosa Ziehau } 1063085ff963SMatthew Dillon #else 1064085ff963SMatthew Dillon if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 1065085ff963SMatthew Dillon EVL_VLANOFTAG(ni->ni_vlan)) { 1066085ff963SMatthew Dillon IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 1067085ff963SMatthew Dillon return 1; 1068085ff963SMatthew Dillon } 1069085ff963SMatthew Dillon #endif 1070841ab66cSSepherosa Ziehau /* map vlan priority to AC */ 107132176cfdSRui Paulo v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); 1072841ab66cSSepherosa Ziehau } 1073841ab66cSSepherosa Ziehau 107432176cfdSRui Paulo /* XXX m_copydata may be too slow for fast path */ 1075841ab66cSSepherosa Ziehau #ifdef INET 1076841ab66cSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_IP)) { 107732176cfdSRui Paulo uint8_t tos; 1078841ab66cSSepherosa Ziehau /* 107932176cfdSRui Paulo * IP frame, map the DSCP bits from the TOS field. 1080841ab66cSSepherosa Ziehau */ 108132176cfdSRui Paulo /* NB: ip header may not be in first mbuf */ 108232176cfdSRui Paulo m_copydata(m, sizeof(struct ether_header) + 108332176cfdSRui Paulo offsetof(struct ip, ip_tos), sizeof(tos), &tos); 108432176cfdSRui Paulo tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 108532176cfdSRui Paulo d_wme_ac = TID_TO_WME_AC(tos); 1086841ab66cSSepherosa Ziehau } else { 1087841ab66cSSepherosa Ziehau #endif /* INET */ 108832176cfdSRui Paulo #ifdef INET6 108932176cfdSRui Paulo if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 109032176cfdSRui Paulo uint32_t flow; 109132176cfdSRui Paulo uint8_t tos; 109232176cfdSRui Paulo /* 1093085ff963SMatthew Dillon * IPv6 frame, map the DSCP bits from the traffic class field. 109432176cfdSRui Paulo */ 109532176cfdSRui Paulo m_copydata(m, sizeof(struct ether_header) + 109632176cfdSRui Paulo offsetof(struct ip6_hdr, ip6_flow), sizeof(flow), 109732176cfdSRui Paulo (caddr_t) &flow); 109832176cfdSRui Paulo tos = (uint8_t)(ntohl(flow) >> 20); 109932176cfdSRui Paulo tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 110032176cfdSRui Paulo d_wme_ac = TID_TO_WME_AC(tos); 110132176cfdSRui Paulo } else { 110232176cfdSRui Paulo #endif /* INET6 */ 1103841ab66cSSepherosa Ziehau d_wme_ac = WME_AC_BE; 110432176cfdSRui Paulo #ifdef INET6 110532176cfdSRui Paulo } 110632176cfdSRui Paulo #endif 1107841ab66cSSepherosa Ziehau #ifdef INET 1108841ab66cSSepherosa Ziehau } 1109841ab66cSSepherosa Ziehau #endif 1110841ab66cSSepherosa Ziehau /* 1111841ab66cSSepherosa Ziehau * Use highest priority AC. 1112841ab66cSSepherosa Ziehau */ 1113841ab66cSSepherosa Ziehau if (v_wme_ac > d_wme_ac) 1114841ab66cSSepherosa Ziehau ac = v_wme_ac; 1115841ab66cSSepherosa Ziehau else 1116841ab66cSSepherosa Ziehau ac = d_wme_ac; 1117841ab66cSSepherosa Ziehau 1118841ab66cSSepherosa Ziehau /* 1119841ab66cSSepherosa Ziehau * Apply ACM policy. 1120841ab66cSSepherosa Ziehau */ 112132176cfdSRui Paulo if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { 1122841ab66cSSepherosa Ziehau static const int acmap[4] = { 1123841ab66cSSepherosa Ziehau WME_AC_BK, /* WME_AC_BE */ 1124841ab66cSSepherosa Ziehau WME_AC_BK, /* WME_AC_BK */ 1125841ab66cSSepherosa Ziehau WME_AC_BE, /* WME_AC_VI */ 1126841ab66cSSepherosa Ziehau WME_AC_VI, /* WME_AC_VO */ 1127841ab66cSSepherosa Ziehau }; 112832176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 112932176cfdSRui Paulo 1130841ab66cSSepherosa Ziehau while (ac != WME_AC_BK && 1131841ab66cSSepherosa Ziehau ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) 1132841ab66cSSepherosa Ziehau ac = acmap[ac]; 1133841ab66cSSepherosa Ziehau } 1134841ab66cSSepherosa Ziehau done: 1135841ab66cSSepherosa Ziehau M_WME_SETAC(m, ac); 1136841ab66cSSepherosa Ziehau return 0; 1137841ab66cSSepherosa Ziehau } 1138841ab66cSSepherosa Ziehau 1139841ab66cSSepherosa Ziehau /* 1140841ab66cSSepherosa Ziehau * Insure there is sufficient contiguous space to encapsulate the 1141841ab66cSSepherosa Ziehau * 802.11 data frame. If room isn't already there, arrange for it. 1142841ab66cSSepherosa Ziehau * Drivers and cipher modules assume we have done the necessary work 1143841ab66cSSepherosa Ziehau * and fail rudely if they don't find the space they need. 1144841ab66cSSepherosa Ziehau */ 114532176cfdSRui Paulo struct mbuf * 114632176cfdSRui Paulo ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, 1147841ab66cSSepherosa Ziehau struct ieee80211_key *key, struct mbuf *m) 1148841ab66cSSepherosa Ziehau { 1149841ab66cSSepherosa Ziehau #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) 115032176cfdSRui Paulo int needed_space = vap->iv_ic->ic_headroom + hdrsize; 1151841ab66cSSepherosa Ziehau 1152841ab66cSSepherosa Ziehau if (key != NULL) { 1153841ab66cSSepherosa Ziehau /* XXX belongs in crypto code? */ 1154841ab66cSSepherosa Ziehau needed_space += key->wk_cipher->ic_header; 1155841ab66cSSepherosa Ziehau /* XXX frags */ 1156841ab66cSSepherosa Ziehau /* 1157841ab66cSSepherosa Ziehau * When crypto is being done in the host we must insure 1158841ab66cSSepherosa Ziehau * the data are writable for the cipher routines; clone 1159841ab66cSSepherosa Ziehau * a writable mbuf chain. 1160841ab66cSSepherosa Ziehau * XXX handle SWMIC specially 1161841ab66cSSepherosa Ziehau */ 116232176cfdSRui Paulo if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { 1163b5523eacSSascha Wildner m = m_unshare(m, M_NOWAIT); 1164841ab66cSSepherosa Ziehau if (m == NULL) { 116532176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 1166841ab66cSSepherosa Ziehau "%s: cannot get writable mbuf\n", __func__); 116732176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ 1168841ab66cSSepherosa Ziehau return NULL; 1169841ab66cSSepherosa Ziehau } 1170841ab66cSSepherosa Ziehau } 1171841ab66cSSepherosa Ziehau } 1172841ab66cSSepherosa Ziehau /* 1173841ab66cSSepherosa Ziehau * We know we are called just before stripping an Ethernet 1174841ab66cSSepherosa Ziehau * header and prepending an LLC header. This means we know 1175841ab66cSSepherosa Ziehau * there will be 1176841ab66cSSepherosa Ziehau * sizeof(struct ether_header) - sizeof(struct llc) 1177841ab66cSSepherosa Ziehau * bytes recovered to which we need additional space for the 1178841ab66cSSepherosa Ziehau * 802.11 header and any crypto header. 1179841ab66cSSepherosa Ziehau */ 1180841ab66cSSepherosa Ziehau /* XXX check trailing space and copy instead? */ 1181841ab66cSSepherosa Ziehau if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { 1182b5523eacSSascha Wildner struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); 1183841ab66cSSepherosa Ziehau if (n == NULL) { 118432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 1185841ab66cSSepherosa Ziehau "%s: cannot expand storage\n", __func__); 118632176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 1187841ab66cSSepherosa Ziehau m_freem(m); 1188841ab66cSSepherosa Ziehau return NULL; 1189841ab66cSSepherosa Ziehau } 1190085ff963SMatthew Dillon #if defined(__DragonFly__) 1191841ab66cSSepherosa Ziehau KASSERT(needed_space <= MHLEN, 1192085ff963SMatthew Dillon ("not enough room, need %u got %zd\n", needed_space, MHLEN)); 1193085ff963SMatthew Dillon #else 1194085ff963SMatthew Dillon KASSERT(needed_space <= MHLEN, 1195085ff963SMatthew Dillon ("not enough room, need %u got %d\n", needed_space, MHLEN)); 1196085ff963SMatthew Dillon #endif 1197841ab66cSSepherosa Ziehau /* 1198841ab66cSSepherosa Ziehau * Setup new mbuf to have leading space to prepend the 1199841ab66cSSepherosa Ziehau * 802.11 header and any crypto header bits that are 1200841ab66cSSepherosa Ziehau * required (the latter are added when the driver calls 1201841ab66cSSepherosa Ziehau * back to ieee80211_crypto_encap to do crypto encapsulation). 1202841ab66cSSepherosa Ziehau */ 1203841ab66cSSepherosa Ziehau /* NB: must be first 'cuz it clobbers m_data */ 1204841ab66cSSepherosa Ziehau m_move_pkthdr(n, m); 1205841ab66cSSepherosa Ziehau n->m_len = 0; /* NB: m_gethdr does not set */ 1206841ab66cSSepherosa Ziehau n->m_data += needed_space; 1207841ab66cSSepherosa Ziehau /* 1208841ab66cSSepherosa Ziehau * Pull up Ethernet header to create the expected layout. 1209841ab66cSSepherosa Ziehau * We could use m_pullup but that's overkill (i.e. we don't 1210841ab66cSSepherosa Ziehau * need the actual data) and it cannot fail so do it inline 1211841ab66cSSepherosa Ziehau * for speed. 1212841ab66cSSepherosa Ziehau */ 1213841ab66cSSepherosa Ziehau /* NB: struct ether_header is known to be contiguous */ 1214841ab66cSSepherosa Ziehau n->m_len += sizeof(struct ether_header); 1215841ab66cSSepherosa Ziehau m->m_len -= sizeof(struct ether_header); 1216841ab66cSSepherosa Ziehau m->m_data += sizeof(struct ether_header); 1217841ab66cSSepherosa Ziehau /* 1218841ab66cSSepherosa Ziehau * Replace the head of the chain. 1219841ab66cSSepherosa Ziehau */ 1220841ab66cSSepherosa Ziehau n->m_next = m; 1221841ab66cSSepherosa Ziehau m = n; 1222841ab66cSSepherosa Ziehau } 1223841ab66cSSepherosa Ziehau return m; 1224841ab66cSSepherosa Ziehau #undef TO_BE_RECLAIMED 1225841ab66cSSepherosa Ziehau } 1226841ab66cSSepherosa Ziehau 1227841ab66cSSepherosa Ziehau /* 1228841ab66cSSepherosa Ziehau * Return the transmit key to use in sending a unicast frame. 1229841ab66cSSepherosa Ziehau * If a unicast key is set we use that. When no unicast key is set 1230841ab66cSSepherosa Ziehau * we fall back to the default transmit key. 1231841ab66cSSepherosa Ziehau */ 1232841ab66cSSepherosa Ziehau static __inline struct ieee80211_key * 123332176cfdSRui Paulo ieee80211_crypto_getucastkey(struct ieee80211vap *vap, 123432176cfdSRui Paulo struct ieee80211_node *ni) 1235841ab66cSSepherosa Ziehau { 123632176cfdSRui Paulo if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { 123732176cfdSRui Paulo if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 123832176cfdSRui Paulo IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 1239841ab66cSSepherosa Ziehau return NULL; 124032176cfdSRui Paulo return &vap->iv_nw_keys[vap->iv_def_txkey]; 1241841ab66cSSepherosa Ziehau } else { 1242841ab66cSSepherosa Ziehau return &ni->ni_ucastkey; 1243841ab66cSSepherosa Ziehau } 1244841ab66cSSepherosa Ziehau } 1245841ab66cSSepherosa Ziehau 1246841ab66cSSepherosa Ziehau /* 1247841ab66cSSepherosa Ziehau * Return the transmit key to use in sending a multicast frame. 1248841ab66cSSepherosa Ziehau * Multicast traffic always uses the group key which is installed as 1249841ab66cSSepherosa Ziehau * the default tx key. 1250841ab66cSSepherosa Ziehau */ 1251841ab66cSSepherosa Ziehau static __inline struct ieee80211_key * 125232176cfdSRui Paulo ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, 125332176cfdSRui Paulo struct ieee80211_node *ni) 1254841ab66cSSepherosa Ziehau { 125532176cfdSRui Paulo if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 125632176cfdSRui Paulo IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 1257841ab66cSSepherosa Ziehau return NULL; 125832176cfdSRui Paulo return &vap->iv_nw_keys[vap->iv_def_txkey]; 1259841ab66cSSepherosa Ziehau } 1260841ab66cSSepherosa Ziehau 1261841ab66cSSepherosa Ziehau /* 1262841ab66cSSepherosa Ziehau * Encapsulate an outbound data frame. The mbuf chain is updated. 1263841ab66cSSepherosa Ziehau * If an error is encountered NULL is returned. The caller is required 1264841ab66cSSepherosa Ziehau * to provide a node reference and pullup the ethernet header in the 1265841ab66cSSepherosa Ziehau * first mbuf. 126632176cfdSRui Paulo * 126732176cfdSRui Paulo * NB: Packet is assumed to be processed by ieee80211_classify which 126832176cfdSRui Paulo * marked EAPOL frames w/ M_EAPOL. 1269f186073cSJoerg Sonnenberger */ 1270f186073cSJoerg Sonnenberger struct mbuf * 127132176cfdSRui Paulo ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni, 127232176cfdSRui Paulo struct mbuf *m) 1273f186073cSJoerg Sonnenberger { 127432176cfdSRui Paulo #define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) 1275085ff963SMatthew Dillon #define MC01(mc) ((struct ieee80211_meshcntl_ae01 *)mc) 127632176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 127732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 127832176cfdSRui Paulo struct ieee80211_mesh_state *ms = vap->iv_mesh; 127932176cfdSRui Paulo struct ieee80211_meshcntl_ae10 *mc; 1280085ff963SMatthew Dillon struct ieee80211_mesh_route *rt = NULL; 1281085ff963SMatthew Dillon int dir = -1; 128232176cfdSRui Paulo #endif 1283f186073cSJoerg Sonnenberger struct ether_header eh; 1284f186073cSJoerg Sonnenberger struct ieee80211_frame *wh; 1285841ab66cSSepherosa Ziehau struct ieee80211_key *key; 1286f186073cSJoerg Sonnenberger struct llc *llc; 128732176cfdSRui Paulo int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr; 128832176cfdSRui Paulo ieee80211_seq seqno; 128932176cfdSRui Paulo int meshhdrsize, meshae; 129032176cfdSRui Paulo uint8_t *qos; 1291f186073cSJoerg Sonnenberger 1292085ff963SMatthew Dillon IEEE80211_TX_LOCK_ASSERT(ic); 1293085ff963SMatthew Dillon 129432176cfdSRui Paulo /* 129532176cfdSRui Paulo * Copy existing Ethernet header to a safe place. The 129632176cfdSRui Paulo * rest of the code assumes it's ok to strip it when 129732176cfdSRui Paulo * reorganizing state for the final encapsulation. 129832176cfdSRui Paulo */ 1299841ab66cSSepherosa Ziehau KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); 130032176cfdSRui Paulo ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); 1301f186073cSJoerg Sonnenberger 1302841ab66cSSepherosa Ziehau /* 1303841ab66cSSepherosa Ziehau * Insure space for additional headers. First identify 1304841ab66cSSepherosa Ziehau * transmit key to use in calculating any buffer adjustments 1305841ab66cSSepherosa Ziehau * required. This is also used below to do privacy 1306841ab66cSSepherosa Ziehau * encapsulation work. Then calculate the 802.11 header 1307841ab66cSSepherosa Ziehau * size and any padding required by the driver. 1308841ab66cSSepherosa Ziehau * 1309841ab66cSSepherosa Ziehau * Note key may be NULL if we fall back to the default 1310841ab66cSSepherosa Ziehau * transmit key and that is not set. In that case the 1311841ab66cSSepherosa Ziehau * buffer may not be expanded as needed by the cipher 1312841ab66cSSepherosa Ziehau * routines, but they will/should discard it. 1313841ab66cSSepherosa Ziehau */ 131432176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) { 131532176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA || 131632176cfdSRui Paulo !IEEE80211_IS_MULTICAST(eh.ether_dhost) || 131732176cfdSRui Paulo (vap->iv_opmode == IEEE80211_M_WDS && 131832176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) 131932176cfdSRui Paulo key = ieee80211_crypto_getucastkey(vap, ni); 1320841ab66cSSepherosa Ziehau else 132132176cfdSRui Paulo key = ieee80211_crypto_getmcastkey(vap, ni); 132232176cfdSRui Paulo if (key == NULL && (m->m_flags & M_EAPOL) == 0) { 132332176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, 132432176cfdSRui Paulo eh.ether_dhost, 132532176cfdSRui Paulo "no default transmit key (%s) deftxkey %u", 132632176cfdSRui Paulo __func__, vap->iv_def_txkey); 132732176cfdSRui Paulo vap->iv_stats.is_tx_nodefkey++; 1328a92bce5eSSepherosa Ziehau goto bad; 1329841ab66cSSepherosa Ziehau } 1330841ab66cSSepherosa Ziehau } else 1331841ab66cSSepherosa Ziehau key = NULL; 1332841ab66cSSepherosa Ziehau /* 1333841ab66cSSepherosa Ziehau * XXX Some ap's don't handle QoS-encapsulated EAPOL 1334841ab66cSSepherosa Ziehau * frames so suppress use. This may be an issue if other 1335841ab66cSSepherosa Ziehau * ap's require all data frames to be QoS-encapsulated 1336841ab66cSSepherosa Ziehau * once negotiated in which case we'll need to make this 1337841ab66cSSepherosa Ziehau * configurable. 1338085ff963SMatthew Dillon * NB: mesh data frames are QoS. 1339841ab66cSSepherosa Ziehau */ 1340085ff963SMatthew Dillon addqos = ((ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) || 1341085ff963SMatthew Dillon (vap->iv_opmode == IEEE80211_M_MBSS)) && 134232176cfdSRui Paulo (m->m_flags & M_EAPOL) == 0; 1343841ab66cSSepherosa Ziehau if (addqos) 1344841ab66cSSepherosa Ziehau hdrsize = sizeof(struct ieee80211_qosframe); 1345841ab66cSSepherosa Ziehau else 1346841ab66cSSepherosa Ziehau hdrsize = sizeof(struct ieee80211_frame); 134732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 134832176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 134932176cfdSRui Paulo /* 135032176cfdSRui Paulo * Mesh data frames are encapsulated according to the 135132176cfdSRui Paulo * rules of Section 11B.8.5 (p.139 of D3.0 spec). 135232176cfdSRui Paulo * o Group Addressed data (aka multicast) originating 135332176cfdSRui Paulo * at the local sta are sent w/ 3-address format and 135432176cfdSRui Paulo * address extension mode 00 135532176cfdSRui Paulo * o Individually Addressed data (aka unicast) originating 135632176cfdSRui Paulo * at the local sta are sent w/ 4-address format and 135732176cfdSRui Paulo * address extension mode 00 135832176cfdSRui Paulo * o Group Addressed data forwarded from a non-mesh sta are 135932176cfdSRui Paulo * sent w/ 3-address format and address extension mode 01 136032176cfdSRui Paulo * o Individually Address data from another sta are sent 136132176cfdSRui Paulo * w/ 4-address format and address extension mode 10 136232176cfdSRui Paulo */ 136332176cfdSRui Paulo is4addr = 0; /* NB: don't use, disable */ 1364085ff963SMatthew Dillon if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) { 1365085ff963SMatthew Dillon rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost); 1366085ff963SMatthew Dillon KASSERT(rt != NULL, ("route is NULL")); 1367085ff963SMatthew Dillon dir = IEEE80211_FC1_DIR_DSTODS; 1368085ff963SMatthew Dillon hdrsize += IEEE80211_ADDR_LEN; 1369085ff963SMatthew Dillon if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) { 1370085ff963SMatthew Dillon if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate, 1371085ff963SMatthew Dillon vap->iv_myaddr)) { 1372085ff963SMatthew Dillon IEEE80211_NOTE_MAC(vap, 1373085ff963SMatthew Dillon IEEE80211_MSG_MESH, 1374085ff963SMatthew Dillon eh.ether_dhost, 1375085ff963SMatthew Dillon "%s", "trying to send to ourself"); 1376085ff963SMatthew Dillon goto bad; 1377085ff963SMatthew Dillon } 1378085ff963SMatthew Dillon meshae = IEEE80211_MESH_AE_10; 1379085ff963SMatthew Dillon meshhdrsize = 1380085ff963SMatthew Dillon sizeof(struct ieee80211_meshcntl_ae10); 138132176cfdSRui Paulo } else { 1382085ff963SMatthew Dillon meshae = IEEE80211_MESH_AE_00; 1383085ff963SMatthew Dillon meshhdrsize = 1384085ff963SMatthew Dillon sizeof(struct ieee80211_meshcntl); 1385085ff963SMatthew Dillon } 1386085ff963SMatthew Dillon } else { 1387085ff963SMatthew Dillon dir = IEEE80211_FC1_DIR_FROMDS; 1388085ff963SMatthew Dillon if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { 1389085ff963SMatthew Dillon /* proxy group */ 1390085ff963SMatthew Dillon meshae = IEEE80211_MESH_AE_01; 1391085ff963SMatthew Dillon meshhdrsize = 1392085ff963SMatthew Dillon sizeof(struct ieee80211_meshcntl_ae01); 1393085ff963SMatthew Dillon } else { 1394085ff963SMatthew Dillon /* group */ 1395085ff963SMatthew Dillon meshae = IEEE80211_MESH_AE_00; 1396085ff963SMatthew Dillon meshhdrsize = sizeof(struct ieee80211_meshcntl); 1397085ff963SMatthew Dillon } 139832176cfdSRui Paulo } 139932176cfdSRui Paulo } else { 140032176cfdSRui Paulo #endif 140132176cfdSRui Paulo /* 140232176cfdSRui Paulo * 4-address frames need to be generated for: 140332176cfdSRui Paulo * o packets sent through a WDS vap (IEEE80211_M_WDS) 140432176cfdSRui Paulo * o packets sent through a vap marked for relaying 140532176cfdSRui Paulo * (e.g. a station operating with dynamic WDS) 140632176cfdSRui Paulo */ 140732176cfdSRui Paulo is4addr = vap->iv_opmode == IEEE80211_M_WDS || 140832176cfdSRui Paulo ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) && 140932176cfdSRui Paulo !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); 141032176cfdSRui Paulo if (is4addr) 141132176cfdSRui Paulo hdrsize += IEEE80211_ADDR_LEN; 141232176cfdSRui Paulo meshhdrsize = meshae = 0; 141332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 141432176cfdSRui Paulo } 141532176cfdSRui Paulo #endif 141632176cfdSRui Paulo /* 141732176cfdSRui Paulo * Honor driver DATAPAD requirement. 141832176cfdSRui Paulo */ 1419841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DATAPAD) 142032176cfdSRui Paulo hdrspace = roundup(hdrsize, sizeof(uint32_t)); 142132176cfdSRui Paulo else 142232176cfdSRui Paulo hdrspace = hdrsize; 142332176cfdSRui Paulo 142432176cfdSRui Paulo if (__predict_true((m->m_flags & M_FF) == 0)) { 142532176cfdSRui Paulo /* 142632176cfdSRui Paulo * Normal frame. 142732176cfdSRui Paulo */ 142832176cfdSRui Paulo m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m); 1429841ab66cSSepherosa Ziehau if (m == NULL) { 1430841ab66cSSepherosa Ziehau /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 1431f186073cSJoerg Sonnenberger goto bad; 1432f186073cSJoerg Sonnenberger } 143332176cfdSRui Paulo /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ 1434f186073cSJoerg Sonnenberger m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 1435f186073cSJoerg Sonnenberger llc = mtod(m, struct llc *); 1436f186073cSJoerg Sonnenberger llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 1437f186073cSJoerg Sonnenberger llc->llc_control = LLC_UI; 1438f186073cSJoerg Sonnenberger llc->llc_snap.org_code[0] = 0; 1439f186073cSJoerg Sonnenberger llc->llc_snap.org_code[1] = 0; 1440f186073cSJoerg Sonnenberger llc->llc_snap.org_code[2] = 0; 1441f186073cSJoerg Sonnenberger llc->llc_snap.ether_type = eh.ether_type; 144232176cfdSRui Paulo } else { 144332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 144432176cfdSRui Paulo /* 144532176cfdSRui Paulo * Aggregated frame. 144632176cfdSRui Paulo */ 144732176cfdSRui Paulo m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key); 144832176cfdSRui Paulo if (m == NULL) 144932176cfdSRui Paulo #endif 145032176cfdSRui Paulo goto bad; 145132176cfdSRui Paulo } 1452841ab66cSSepherosa Ziehau datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ 1453841ab66cSSepherosa Ziehau 1454b5523eacSSascha Wildner M_PREPEND(m, hdrspace + meshhdrsize, M_NOWAIT); 1455f186073cSJoerg Sonnenberger if (m == NULL) { 145632176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 1457f186073cSJoerg Sonnenberger goto bad; 1458f186073cSJoerg Sonnenberger } 1459f186073cSJoerg Sonnenberger wh = mtod(m, struct ieee80211_frame *); 1460f186073cSJoerg Sonnenberger wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 1461f186073cSJoerg Sonnenberger *(uint16_t *)wh->i_dur = 0; 146232176cfdSRui Paulo qos = NULL; /* NB: quiet compiler */ 146332176cfdSRui Paulo if (is4addr) { 146432176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 146532176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 146632176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 146732176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 146832176cfdSRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 146932176cfdSRui Paulo } else switch (vap->iv_opmode) { 1470f186073cSJoerg Sonnenberger case IEEE80211_M_STA: 1471f186073cSJoerg Sonnenberger wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 1472f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 1473f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1474f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1475f186073cSJoerg Sonnenberger break; 1476f186073cSJoerg Sonnenberger case IEEE80211_M_IBSS: 1477f186073cSJoerg Sonnenberger case IEEE80211_M_AHDEMO: 1478f186073cSJoerg Sonnenberger wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 1479f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 1480f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1481841ab66cSSepherosa Ziehau /* 148232176cfdSRui Paulo * NB: always use the bssid from iv_bss as the 1483841ab66cSSepherosa Ziehau * neighbor's may be stale after an ibss merge 1484841ab66cSSepherosa Ziehau */ 148532176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); 1486f186073cSJoerg Sonnenberger break; 1487f186073cSJoerg Sonnenberger case IEEE80211_M_HOSTAP: 1488f186073cSJoerg Sonnenberger wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 1489f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 1490f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 1491f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 1492f186073cSJoerg Sonnenberger break; 149332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 149432176cfdSRui Paulo case IEEE80211_M_MBSS: 149532176cfdSRui Paulo /* NB: offset by hdrspace to deal with DATAPAD */ 149632176cfdSRui Paulo mc = (struct ieee80211_meshcntl_ae10 *) 149732176cfdSRui Paulo (mtod(m, uint8_t *) + hdrspace); 1498085ff963SMatthew Dillon wh->i_fc[1] = dir; 149932176cfdSRui Paulo switch (meshae) { 1500085ff963SMatthew Dillon case IEEE80211_MESH_AE_00: /* no proxy */ 150132176cfdSRui Paulo mc->mc_flags = 0; 1502085ff963SMatthew Dillon if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */ 1503085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr1, 1504085ff963SMatthew Dillon ni->ni_macaddr); 1505085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr2, 1506085ff963SMatthew Dillon vap->iv_myaddr); 1507085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr3, 1508085ff963SMatthew Dillon eh.ether_dhost); 1509085ff963SMatthew Dillon IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, 1510085ff963SMatthew Dillon eh.ether_shost); 1511085ff963SMatthew Dillon qos =((struct ieee80211_qosframe_addr4 *) 1512085ff963SMatthew Dillon wh)->i_qos; 1513085ff963SMatthew Dillon } else if (dir == IEEE80211_FC1_DIR_FROMDS) { 1514085ff963SMatthew Dillon /* mcast */ 1515085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr1, 1516085ff963SMatthew Dillon eh.ether_dhost); 1517085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr2, 1518085ff963SMatthew Dillon vap->iv_myaddr); 1519085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr3, 1520085ff963SMatthew Dillon eh.ether_shost); 1521085ff963SMatthew Dillon qos = ((struct ieee80211_qosframe *) 1522085ff963SMatthew Dillon wh)->i_qos; 1523085ff963SMatthew Dillon } 152432176cfdSRui Paulo break; 1525085ff963SMatthew Dillon case IEEE80211_MESH_AE_01: /* mcast, proxy */ 152632176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 152732176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 152832176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 152932176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr); 153032176cfdSRui Paulo mc->mc_flags = 1; 1531085ff963SMatthew Dillon IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4, 1532085ff963SMatthew Dillon eh.ether_shost); 153332176cfdSRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 153432176cfdSRui Paulo break; 1535085ff963SMatthew Dillon case IEEE80211_MESH_AE_10: /* ucast, proxy */ 1536085ff963SMatthew Dillon KASSERT(rt != NULL, ("route is NULL")); 1537085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop); 153832176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1539085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate); 154032176cfdSRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr); 1541085ff963SMatthew Dillon mc->mc_flags = IEEE80211_MESH_AE_10; 1542085ff963SMatthew Dillon IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost); 1543085ff963SMatthew Dillon IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost); 154432176cfdSRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 154532176cfdSRui Paulo break; 154632176cfdSRui Paulo default: 154732176cfdSRui Paulo KASSERT(0, ("meshae %d", meshae)); 154832176cfdSRui Paulo break; 154932176cfdSRui Paulo } 155032176cfdSRui Paulo mc->mc_ttl = ms->ms_ttl; 155132176cfdSRui Paulo ms->ms_seq++; 155232176cfdSRui Paulo LE_WRITE_4(mc->mc_seq, ms->ms_seq); 155332176cfdSRui Paulo break; 155432176cfdSRui Paulo #endif 155532176cfdSRui Paulo case IEEE80211_M_WDS: /* NB: is4addr should always be true */ 155632176cfdSRui Paulo default: 1557f186073cSJoerg Sonnenberger goto bad; 1558f186073cSJoerg Sonnenberger } 1559841ab66cSSepherosa Ziehau if (m->m_flags & M_MORE_DATA) 1560841ab66cSSepherosa Ziehau wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 1561841ab66cSSepherosa Ziehau if (addqos) { 1562841ab66cSSepherosa Ziehau int ac, tid; 1563841ab66cSSepherosa Ziehau 156432176cfdSRui Paulo if (is4addr) { 156532176cfdSRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 156632176cfdSRui Paulo /* NB: mesh case handled earlier */ 156732176cfdSRui Paulo } else if (vap->iv_opmode != IEEE80211_M_MBSS) 156832176cfdSRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 1569841ab66cSSepherosa Ziehau ac = M_WME_GETAC(m); 1570841ab66cSSepherosa Ziehau /* map from access class/queue to 11e header priorty value */ 1571841ab66cSSepherosa Ziehau tid = WME_AC_TO_TID(ac); 157232176cfdSRui Paulo qos[0] = tid & IEEE80211_QOS_TID; 1573841ab66cSSepherosa Ziehau if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) 157432176cfdSRui Paulo qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 1575085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 1576085ff963SMatthew Dillon if (vap->iv_opmode == IEEE80211_M_MBSS) 1577085ff963SMatthew Dillon qos[1] = IEEE80211_QOS_MC; 1578085ff963SMatthew Dillon else 1579085ff963SMatthew Dillon #endif 158032176cfdSRui Paulo qos[1] = 0; 158132176cfdSRui Paulo wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; 1582841ab66cSSepherosa Ziehau 158332176cfdSRui Paulo if ((m->m_flags & M_AMPDU_MPDU) == 0) { 158432176cfdSRui Paulo /* 158532176cfdSRui Paulo * NB: don't assign a sequence # to potential 158632176cfdSRui Paulo * aggregates; we expect this happens at the 158732176cfdSRui Paulo * point the frame comes off any aggregation q 158832176cfdSRui Paulo * as otherwise we may introduce holes in the 158932176cfdSRui Paulo * BA sequence space and/or make window accouting 159032176cfdSRui Paulo * more difficult. 159132176cfdSRui Paulo * 159232176cfdSRui Paulo * XXX may want to control this with a driver 159332176cfdSRui Paulo * capability; this may also change when we pull 159432176cfdSRui Paulo * aggregation up into net80211 159532176cfdSRui Paulo */ 159632176cfdSRui Paulo seqno = ni->ni_txseqs[tid]++; 1597841ab66cSSepherosa Ziehau *(uint16_t *)wh->i_seq = 159832176cfdSRui Paulo htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 159932176cfdSRui Paulo M_SEQNO_SET(m, seqno); 1600841ab66cSSepherosa Ziehau } 160132176cfdSRui Paulo } else { 160232176cfdSRui Paulo seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 160332176cfdSRui Paulo *(uint16_t *)wh->i_seq = 160432176cfdSRui Paulo htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 160532176cfdSRui Paulo M_SEQNO_SET(m, seqno); 160632176cfdSRui Paulo } 160732176cfdSRui Paulo 160832176cfdSRui Paulo 160932176cfdSRui Paulo /* check if xmit fragmentation is required */ 161032176cfdSRui Paulo txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && 161132176cfdSRui Paulo !IEEE80211_IS_MULTICAST(wh->i_addr1) && 161232176cfdSRui Paulo (vap->iv_caps & IEEE80211_C_TXFRAG) && 161332176cfdSRui Paulo (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0); 1614841ab66cSSepherosa Ziehau if (key != NULL) { 1615841ab66cSSepherosa Ziehau /* 1616841ab66cSSepherosa Ziehau * IEEE 802.1X: send EAPOL frames always in the clear. 1617841ab66cSSepherosa Ziehau * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 1618841ab66cSSepherosa Ziehau */ 161932176cfdSRui Paulo if ((m->m_flags & M_EAPOL) == 0 || 162032176cfdSRui Paulo ((vap->iv_flags & IEEE80211_F_WPA) && 162132176cfdSRui Paulo (vap->iv_opmode == IEEE80211_M_STA ? 162232176cfdSRui Paulo !IEEE80211_KEY_UNDEFINED(key) : 162332176cfdSRui Paulo !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { 1624085ff963SMatthew Dillon wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; 162532176cfdSRui Paulo if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { 162632176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, 162732176cfdSRui Paulo eh.ether_dhost, 162832176cfdSRui Paulo "%s", "enmic failed, discard frame"); 162932176cfdSRui Paulo vap->iv_stats.is_crypto_enmicfail++; 1630841ab66cSSepherosa Ziehau goto bad; 1631841ab66cSSepherosa Ziehau } 1632841ab66cSSepherosa Ziehau } 1633841ab66cSSepherosa Ziehau } 163432176cfdSRui Paulo if (txfrag && !ieee80211_fragment(vap, m, hdrsize, 163532176cfdSRui Paulo key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) 163632176cfdSRui Paulo goto bad; 163732176cfdSRui Paulo 163832176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 1639841ab66cSSepherosa Ziehau 1640841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_data); 164132176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1642fb134238SSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_mcast); 164332176cfdSRui Paulo m->m_flags |= M_MCAST; 164432176cfdSRui Paulo } else 1645fb134238SSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_ucast); 1646841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); 1647841ab66cSSepherosa Ziehau 1648f186073cSJoerg Sonnenberger return m; 1649f186073cSJoerg Sonnenberger bad: 1650f186073cSJoerg Sonnenberger if (m != NULL) 1651f186073cSJoerg Sonnenberger m_freem(m); 1652f186073cSJoerg Sonnenberger return NULL; 165332176cfdSRui Paulo #undef WH4 1654085ff963SMatthew Dillon #undef MC01 165532176cfdSRui Paulo } 165632176cfdSRui Paulo 165732176cfdSRui Paulo /* 165832176cfdSRui Paulo * Fragment the frame according to the specified mtu. 165932176cfdSRui Paulo * The size of the 802.11 header (w/o padding) is provided 166032176cfdSRui Paulo * so we don't need to recalculate it. We create a new 166132176cfdSRui Paulo * mbuf for each fragment and chain it through m_nextpkt; 166232176cfdSRui Paulo * we might be able to optimize this by reusing the original 166332176cfdSRui Paulo * packet's mbufs but that is significantly more complicated. 166432176cfdSRui Paulo */ 166532176cfdSRui Paulo static int 166632176cfdSRui Paulo ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, 166732176cfdSRui Paulo u_int hdrsize, u_int ciphdrsize, u_int mtu) 166832176cfdSRui Paulo { 1669085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 167032176cfdSRui Paulo struct ieee80211_frame *wh, *whf; 167132176cfdSRui Paulo struct mbuf *m, *prev, *next; 167232176cfdSRui Paulo u_int totalhdrsize, fragno, fragsize, off, remainder, payload; 1673085ff963SMatthew Dillon u_int hdrspace; 167432176cfdSRui Paulo 167532176cfdSRui Paulo KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); 167632176cfdSRui Paulo KASSERT(m0->m_pkthdr.len > mtu, 167732176cfdSRui Paulo ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); 167832176cfdSRui Paulo 1679085ff963SMatthew Dillon /* 1680085ff963SMatthew Dillon * Honor driver DATAPAD requirement. 1681085ff963SMatthew Dillon */ 1682085ff963SMatthew Dillon if (ic->ic_flags & IEEE80211_F_DATAPAD) 1683085ff963SMatthew Dillon hdrspace = roundup(hdrsize, sizeof(uint32_t)); 1684085ff963SMatthew Dillon else 1685085ff963SMatthew Dillon hdrspace = hdrsize; 1686085ff963SMatthew Dillon 168732176cfdSRui Paulo wh = mtod(m0, struct ieee80211_frame *); 168832176cfdSRui Paulo /* NB: mark the first frag; it will be propagated below */ 168932176cfdSRui Paulo wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; 1690085ff963SMatthew Dillon totalhdrsize = hdrspace + ciphdrsize; 169132176cfdSRui Paulo fragno = 1; 169232176cfdSRui Paulo off = mtu - ciphdrsize; 169332176cfdSRui Paulo remainder = m0->m_pkthdr.len - off; 169432176cfdSRui Paulo prev = m0; 169532176cfdSRui Paulo do { 169632176cfdSRui Paulo fragsize = totalhdrsize + remainder; 169732176cfdSRui Paulo if (fragsize > mtu) 169832176cfdSRui Paulo fragsize = mtu; 169932176cfdSRui Paulo /* XXX fragsize can be >2048! */ 170032176cfdSRui Paulo KASSERT(fragsize < MCLBYTES, 170132176cfdSRui Paulo ("fragment size %u too big!", fragsize)); 170232176cfdSRui Paulo if (fragsize > MHLEN) 1703b5523eacSSascha Wildner m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 170432176cfdSRui Paulo else 1705b5523eacSSascha Wildner m = m_gethdr(M_NOWAIT, MT_DATA); 170632176cfdSRui Paulo if (m == NULL) 170732176cfdSRui Paulo goto bad; 170832176cfdSRui Paulo /* leave room to prepend any cipher header */ 170932176cfdSRui Paulo m_align(m, fragsize - ciphdrsize); 171032176cfdSRui Paulo 171132176cfdSRui Paulo /* 171232176cfdSRui Paulo * Form the header in the fragment. Note that since 171332176cfdSRui Paulo * we mark the first fragment with the MORE_FRAG bit 171432176cfdSRui Paulo * it automatically is propagated to each fragment; we 171532176cfdSRui Paulo * need only clear it on the last fragment (done below). 1716085ff963SMatthew Dillon * NB: frag 1+ dont have Mesh Control field present. 171732176cfdSRui Paulo */ 171832176cfdSRui Paulo whf = mtod(m, struct ieee80211_frame *); 171932176cfdSRui Paulo memcpy(whf, wh, hdrsize); 1720085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 1721085ff963SMatthew Dillon if (vap->iv_opmode == IEEE80211_M_MBSS) { 1722085ff963SMatthew Dillon if (IEEE80211_IS_DSTODS(wh)) 1723085ff963SMatthew Dillon ((struct ieee80211_qosframe_addr4 *) 1724085ff963SMatthew Dillon whf)->i_qos[1] &= ~IEEE80211_QOS_MC; 1725085ff963SMatthew Dillon else 1726085ff963SMatthew Dillon ((struct ieee80211_qosframe *) 1727085ff963SMatthew Dillon whf)->i_qos[1] &= ~IEEE80211_QOS_MC; 1728085ff963SMatthew Dillon } 1729085ff963SMatthew Dillon #endif 173032176cfdSRui Paulo *(uint16_t *)&whf->i_seq[0] |= htole16( 173132176cfdSRui Paulo (fragno & IEEE80211_SEQ_FRAG_MASK) << 173232176cfdSRui Paulo IEEE80211_SEQ_FRAG_SHIFT); 173332176cfdSRui Paulo fragno++; 173432176cfdSRui Paulo 173532176cfdSRui Paulo payload = fragsize - totalhdrsize; 173632176cfdSRui Paulo /* NB: destination is known to be contiguous */ 1737085ff963SMatthew Dillon 1738085ff963SMatthew Dillon m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrspace); 1739085ff963SMatthew Dillon m->m_len = hdrspace + payload; 1740085ff963SMatthew Dillon m->m_pkthdr.len = hdrspace + payload; 174132176cfdSRui Paulo m->m_flags |= M_FRAG; 174232176cfdSRui Paulo 174332176cfdSRui Paulo /* chain up the fragment */ 174432176cfdSRui Paulo prev->m_nextpkt = m; 174532176cfdSRui Paulo prev = m; 174632176cfdSRui Paulo 174732176cfdSRui Paulo /* deduct fragment just formed */ 174832176cfdSRui Paulo remainder -= payload; 174932176cfdSRui Paulo off += payload; 175032176cfdSRui Paulo } while (remainder != 0); 175132176cfdSRui Paulo 175232176cfdSRui Paulo /* set the last fragment */ 175332176cfdSRui Paulo m->m_flags |= M_LASTFRAG; 175432176cfdSRui Paulo whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; 175532176cfdSRui Paulo 175632176cfdSRui Paulo /* strip first mbuf now that everything has been copied */ 175732176cfdSRui Paulo m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); 175832176cfdSRui Paulo m0->m_flags |= M_FIRSTFRAG | M_FRAG; 175932176cfdSRui Paulo 176032176cfdSRui Paulo vap->iv_stats.is_tx_fragframes++; 176132176cfdSRui Paulo vap->iv_stats.is_tx_frags += fragno-1; 176232176cfdSRui Paulo 176332176cfdSRui Paulo return 1; 176432176cfdSRui Paulo bad: 176532176cfdSRui Paulo /* reclaim fragments but leave original frame for caller to free */ 176632176cfdSRui Paulo for (m = m0->m_nextpkt; m != NULL; m = next) { 176732176cfdSRui Paulo next = m->m_nextpkt; 176832176cfdSRui Paulo m->m_nextpkt = NULL; /* XXX paranoid */ 176932176cfdSRui Paulo m_freem(m); 177032176cfdSRui Paulo } 177132176cfdSRui Paulo m0->m_nextpkt = NULL; 177232176cfdSRui Paulo return 0; 1773f186073cSJoerg Sonnenberger } 1774f186073cSJoerg Sonnenberger 1775f186073cSJoerg Sonnenberger /* 1776f186073cSJoerg Sonnenberger * Add a supported rates element id to a frame. 1777f186073cSJoerg Sonnenberger */ 1778f186073cSJoerg Sonnenberger uint8_t * 1779f186073cSJoerg Sonnenberger ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 1780f186073cSJoerg Sonnenberger { 1781f186073cSJoerg Sonnenberger int nrates; 1782f186073cSJoerg Sonnenberger 1783f186073cSJoerg Sonnenberger *frm++ = IEEE80211_ELEMID_RATES; 1784f186073cSJoerg Sonnenberger nrates = rs->rs_nrates; 1785f186073cSJoerg Sonnenberger if (nrates > IEEE80211_RATE_SIZE) 1786f186073cSJoerg Sonnenberger nrates = IEEE80211_RATE_SIZE; 1787f186073cSJoerg Sonnenberger *frm++ = nrates; 1788f186073cSJoerg Sonnenberger memcpy(frm, rs->rs_rates, nrates); 1789f186073cSJoerg Sonnenberger return frm + nrates; 1790f186073cSJoerg Sonnenberger } 1791f186073cSJoerg Sonnenberger 1792f186073cSJoerg Sonnenberger /* 1793f186073cSJoerg Sonnenberger * Add an extended supported rates element id to a frame. 1794f186073cSJoerg Sonnenberger */ 1795f186073cSJoerg Sonnenberger uint8_t * 1796f186073cSJoerg Sonnenberger ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 1797f186073cSJoerg Sonnenberger { 1798f186073cSJoerg Sonnenberger /* 1799f186073cSJoerg Sonnenberger * Add an extended supported rates element if operating in 11g mode. 1800f186073cSJoerg Sonnenberger */ 1801f186073cSJoerg Sonnenberger if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 1802f186073cSJoerg Sonnenberger int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 1803f186073cSJoerg Sonnenberger *frm++ = IEEE80211_ELEMID_XRATES; 1804f186073cSJoerg Sonnenberger *frm++ = nrates; 1805f186073cSJoerg Sonnenberger memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 1806f186073cSJoerg Sonnenberger frm += nrates; 1807f186073cSJoerg Sonnenberger } 1808f186073cSJoerg Sonnenberger return frm; 1809f186073cSJoerg Sonnenberger } 1810f186073cSJoerg Sonnenberger 1811f186073cSJoerg Sonnenberger /* 181232176cfdSRui Paulo * Add an ssid element to a frame. 1813f186073cSJoerg Sonnenberger */ 1814e218318cSMatthew Dillon uint8_t * 1815f186073cSJoerg Sonnenberger ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) 1816f186073cSJoerg Sonnenberger { 1817f186073cSJoerg Sonnenberger *frm++ = IEEE80211_ELEMID_SSID; 1818f186073cSJoerg Sonnenberger *frm++ = len; 1819f186073cSJoerg Sonnenberger memcpy(frm, ssid, len); 1820f186073cSJoerg Sonnenberger return frm + len; 1821f186073cSJoerg Sonnenberger } 1822f186073cSJoerg Sonnenberger 1823841ab66cSSepherosa Ziehau /* 1824841ab66cSSepherosa Ziehau * Add an erp element to a frame. 1825841ab66cSSepherosa Ziehau */ 1826841ab66cSSepherosa Ziehau static uint8_t * 1827841ab66cSSepherosa Ziehau ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) 1828f186073cSJoerg Sonnenberger { 1829841ab66cSSepherosa Ziehau uint8_t erp; 1830f186073cSJoerg Sonnenberger 1831841ab66cSSepherosa Ziehau *frm++ = IEEE80211_ELEMID_ERP; 1832841ab66cSSepherosa Ziehau *frm++ = 1; 1833841ab66cSSepherosa Ziehau erp = 0; 1834841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta != 0) 1835841ab66cSSepherosa Ziehau erp |= IEEE80211_ERP_NON_ERP_PRESENT; 1836841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_USEPROT) 1837841ab66cSSepherosa Ziehau erp |= IEEE80211_ERP_USE_PROTECTION; 1838841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_USEBARKER) 1839841ab66cSSepherosa Ziehau erp |= IEEE80211_ERP_LONG_PREAMBLE; 1840841ab66cSSepherosa Ziehau *frm++ = erp; 1841841ab66cSSepherosa Ziehau return frm; 1842841ab66cSSepherosa Ziehau } 1843841ab66cSSepherosa Ziehau 1844841ab66cSSepherosa Ziehau /* 184532176cfdSRui Paulo * Add a CFParams element to a frame. 1846841ab66cSSepherosa Ziehau */ 1847841ab66cSSepherosa Ziehau static uint8_t * 184832176cfdSRui Paulo ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) 1849841ab66cSSepherosa Ziehau { 185032176cfdSRui Paulo #define ADDSHORT(frm, v) do { \ 185132176cfdSRui Paulo LE_WRITE_2(frm, v); \ 185232176cfdSRui Paulo frm += 2; \ 185332176cfdSRui Paulo } while (0) 185432176cfdSRui Paulo *frm++ = IEEE80211_ELEMID_CFPARMS; 185532176cfdSRui Paulo *frm++ = 6; 185632176cfdSRui Paulo *frm++ = 0; /* CFP count */ 185732176cfdSRui Paulo *frm++ = 2; /* CFP period */ 185832176cfdSRui Paulo ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ 185932176cfdSRui Paulo ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ 1860841ab66cSSepherosa Ziehau return frm; 186132176cfdSRui Paulo #undef ADDSHORT 186232176cfdSRui Paulo } 186332176cfdSRui Paulo 186432176cfdSRui Paulo static __inline uint8_t * 186532176cfdSRui Paulo add_appie(uint8_t *frm, const struct ieee80211_appie *ie) 186632176cfdSRui Paulo { 186732176cfdSRui Paulo memcpy(frm, ie->ie_data, ie->ie_len); 186832176cfdSRui Paulo return frm + ie->ie_len; 186932176cfdSRui Paulo } 187032176cfdSRui Paulo 187132176cfdSRui Paulo static __inline uint8_t * 187232176cfdSRui Paulo add_ie(uint8_t *frm, const uint8_t *ie) 187332176cfdSRui Paulo { 187432176cfdSRui Paulo memcpy(frm, ie, 2 + ie[1]); 187532176cfdSRui Paulo return frm + 2 + ie[1]; 1876841ab66cSSepherosa Ziehau } 1877841ab66cSSepherosa Ziehau 1878841ab66cSSepherosa Ziehau #define WME_OUI_BYTES 0x00, 0x50, 0xf2 1879841ab66cSSepherosa Ziehau /* 1880841ab66cSSepherosa Ziehau * Add a WME information element to a frame. 1881841ab66cSSepherosa Ziehau */ 1882841ab66cSSepherosa Ziehau static uint8_t * 1883841ab66cSSepherosa Ziehau ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 1884841ab66cSSepherosa Ziehau { 1885841ab66cSSepherosa Ziehau static const struct ieee80211_wme_info info = { 1886841ab66cSSepherosa Ziehau .wme_id = IEEE80211_ELEMID_VENDOR, 1887841ab66cSSepherosa Ziehau .wme_len = sizeof(struct ieee80211_wme_info) - 2, 1888841ab66cSSepherosa Ziehau .wme_oui = { WME_OUI_BYTES }, 1889841ab66cSSepherosa Ziehau .wme_type = WME_OUI_TYPE, 1890841ab66cSSepherosa Ziehau .wme_subtype = WME_INFO_OUI_SUBTYPE, 1891841ab66cSSepherosa Ziehau .wme_version = WME_VERSION, 1892841ab66cSSepherosa Ziehau .wme_info = 0, 1893841ab66cSSepherosa Ziehau }; 1894841ab66cSSepherosa Ziehau memcpy(frm, &info, sizeof(info)); 1895841ab66cSSepherosa Ziehau return frm + sizeof(info); 1896841ab66cSSepherosa Ziehau } 1897841ab66cSSepherosa Ziehau 1898841ab66cSSepherosa Ziehau /* 1899841ab66cSSepherosa Ziehau * Add a WME parameters element to a frame. 1900841ab66cSSepherosa Ziehau */ 1901841ab66cSSepherosa Ziehau static uint8_t * 1902841ab66cSSepherosa Ziehau ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 1903841ab66cSSepherosa Ziehau { 1904841ab66cSSepherosa Ziehau #define SM(_v, _f) (((_v) << _f##_S) & _f) 1905841ab66cSSepherosa Ziehau #define ADDSHORT(frm, v) do { \ 190632176cfdSRui Paulo LE_WRITE_2(frm, v); \ 1907841ab66cSSepherosa Ziehau frm += 2; \ 1908841ab66cSSepherosa Ziehau } while (0) 1909841ab66cSSepherosa Ziehau /* NB: this works 'cuz a param has an info at the front */ 1910841ab66cSSepherosa Ziehau static const struct ieee80211_wme_info param = { 1911841ab66cSSepherosa Ziehau .wme_id = IEEE80211_ELEMID_VENDOR, 1912841ab66cSSepherosa Ziehau .wme_len = sizeof(struct ieee80211_wme_param) - 2, 1913841ab66cSSepherosa Ziehau .wme_oui = { WME_OUI_BYTES }, 1914841ab66cSSepherosa Ziehau .wme_type = WME_OUI_TYPE, 1915841ab66cSSepherosa Ziehau .wme_subtype = WME_PARAM_OUI_SUBTYPE, 1916841ab66cSSepherosa Ziehau .wme_version = WME_VERSION, 1917841ab66cSSepherosa Ziehau }; 1918841ab66cSSepherosa Ziehau int i; 1919841ab66cSSepherosa Ziehau 1920841ab66cSSepherosa Ziehau memcpy(frm, ¶m, sizeof(param)); 1921841ab66cSSepherosa Ziehau frm += __offsetof(struct ieee80211_wme_info, wme_info); 1922841ab66cSSepherosa Ziehau *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 1923841ab66cSSepherosa Ziehau *frm++ = 0; /* reserved field */ 1924841ab66cSSepherosa Ziehau for (i = 0; i < WME_NUM_AC; i++) { 1925841ab66cSSepherosa Ziehau const struct wmeParams *ac = 1926841ab66cSSepherosa Ziehau &wme->wme_bssChanParams.cap_wmeParams[i]; 1927841ab66cSSepherosa Ziehau *frm++ = SM(i, WME_PARAM_ACI) 1928841ab66cSSepherosa Ziehau | SM(ac->wmep_acm, WME_PARAM_ACM) 1929841ab66cSSepherosa Ziehau | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) 1930841ab66cSSepherosa Ziehau ; 1931841ab66cSSepherosa Ziehau *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 1932841ab66cSSepherosa Ziehau | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) 1933841ab66cSSepherosa Ziehau ; 1934841ab66cSSepherosa Ziehau ADDSHORT(frm, ac->wmep_txopLimit); 1935841ab66cSSepherosa Ziehau } 1936841ab66cSSepherosa Ziehau return frm; 1937841ab66cSSepherosa Ziehau #undef SM 1938841ab66cSSepherosa Ziehau #undef ADDSHORT 1939841ab66cSSepherosa Ziehau } 1940841ab66cSSepherosa Ziehau #undef WME_OUI_BYTES 1941841ab66cSSepherosa Ziehau 1942841ab66cSSepherosa Ziehau /* 194332176cfdSRui Paulo * Add an 11h Power Constraint element to a frame. 194432176cfdSRui Paulo */ 194532176cfdSRui Paulo static uint8_t * 194632176cfdSRui Paulo ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) 194732176cfdSRui Paulo { 194832176cfdSRui Paulo const struct ieee80211_channel *c = vap->iv_bss->ni_chan; 194932176cfdSRui Paulo /* XXX per-vap tx power limit? */ 195032176cfdSRui Paulo int8_t limit = vap->iv_ic->ic_txpowlimit / 2; 195132176cfdSRui Paulo 195232176cfdSRui Paulo frm[0] = IEEE80211_ELEMID_PWRCNSTR; 195332176cfdSRui Paulo frm[1] = 1; 195432176cfdSRui Paulo frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; 195532176cfdSRui Paulo return frm + 3; 195632176cfdSRui Paulo } 195732176cfdSRui Paulo 195832176cfdSRui Paulo /* 195932176cfdSRui Paulo * Add an 11h Power Capability element to a frame. 196032176cfdSRui Paulo */ 196132176cfdSRui Paulo static uint8_t * 196232176cfdSRui Paulo ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) 196332176cfdSRui Paulo { 196432176cfdSRui Paulo frm[0] = IEEE80211_ELEMID_PWRCAP; 196532176cfdSRui Paulo frm[1] = 2; 196632176cfdSRui Paulo frm[2] = c->ic_minpower; 196732176cfdSRui Paulo frm[3] = c->ic_maxpower; 196832176cfdSRui Paulo return frm + 4; 196932176cfdSRui Paulo } 197032176cfdSRui Paulo 197132176cfdSRui Paulo /* 197232176cfdSRui Paulo * Add an 11h Supported Channels element to a frame. 197332176cfdSRui Paulo */ 197432176cfdSRui Paulo static uint8_t * 197532176cfdSRui Paulo ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) 197632176cfdSRui Paulo { 197732176cfdSRui Paulo static const int ielen = 26; 197832176cfdSRui Paulo 197932176cfdSRui Paulo frm[0] = IEEE80211_ELEMID_SUPPCHAN; 198032176cfdSRui Paulo frm[1] = ielen; 198132176cfdSRui Paulo /* XXX not correct */ 198232176cfdSRui Paulo memcpy(frm+2, ic->ic_chan_avail, ielen); 198332176cfdSRui Paulo return frm + 2 + ielen; 198432176cfdSRui Paulo } 198532176cfdSRui Paulo 198632176cfdSRui Paulo /* 1987085ff963SMatthew Dillon * Add an 11h Quiet time element to a frame. 1988085ff963SMatthew Dillon */ 1989085ff963SMatthew Dillon static uint8_t * 1990085ff963SMatthew Dillon ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap) 1991085ff963SMatthew Dillon { 1992085ff963SMatthew Dillon struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm; 1993085ff963SMatthew Dillon 1994085ff963SMatthew Dillon quiet->quiet_ie = IEEE80211_ELEMID_QUIET; 1995085ff963SMatthew Dillon quiet->len = 6; 1996085ff963SMatthew Dillon if (vap->iv_quiet_count_value == 1) 1997085ff963SMatthew Dillon vap->iv_quiet_count_value = vap->iv_quiet_count; 1998085ff963SMatthew Dillon else if (vap->iv_quiet_count_value > 1) 1999085ff963SMatthew Dillon vap->iv_quiet_count_value--; 2000085ff963SMatthew Dillon 2001085ff963SMatthew Dillon if (vap->iv_quiet_count_value == 0) { 2002085ff963SMatthew Dillon /* value 0 is reserved as per 802.11h standerd */ 2003085ff963SMatthew Dillon vap->iv_quiet_count_value = 1; 2004085ff963SMatthew Dillon } 2005085ff963SMatthew Dillon 2006085ff963SMatthew Dillon quiet->tbttcount = vap->iv_quiet_count_value; 2007085ff963SMatthew Dillon quiet->period = vap->iv_quiet_period; 2008085ff963SMatthew Dillon quiet->duration = htole16(vap->iv_quiet_duration); 2009085ff963SMatthew Dillon quiet->offset = htole16(vap->iv_quiet_offset); 2010085ff963SMatthew Dillon return frm + sizeof(*quiet); 2011085ff963SMatthew Dillon } 2012085ff963SMatthew Dillon 2013085ff963SMatthew Dillon /* 201432176cfdSRui Paulo * Add an 11h Channel Switch Announcement element to a frame. 201532176cfdSRui Paulo * Note that we use the per-vap CSA count to adjust the global 201632176cfdSRui Paulo * counter so we can use this routine to form probe response 201732176cfdSRui Paulo * frames and get the current count. 201832176cfdSRui Paulo */ 201932176cfdSRui Paulo static uint8_t * 202032176cfdSRui Paulo ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) 202132176cfdSRui Paulo { 202232176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 202332176cfdSRui Paulo struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; 202432176cfdSRui Paulo 202532176cfdSRui Paulo csa->csa_ie = IEEE80211_ELEMID_CSA; 202632176cfdSRui Paulo csa->csa_len = 3; 202732176cfdSRui Paulo csa->csa_mode = 1; /* XXX force quiet on channel */ 202832176cfdSRui Paulo csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); 202932176cfdSRui Paulo csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; 203032176cfdSRui Paulo return frm + sizeof(*csa); 203132176cfdSRui Paulo } 203232176cfdSRui Paulo 203332176cfdSRui Paulo /* 203432176cfdSRui Paulo * Add an 11h country information element to a frame. 203532176cfdSRui Paulo */ 203632176cfdSRui Paulo static uint8_t * 203732176cfdSRui Paulo ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) 203832176cfdSRui Paulo { 203932176cfdSRui Paulo 204032176cfdSRui Paulo if (ic->ic_countryie == NULL || 204132176cfdSRui Paulo ic->ic_countryie_chan != ic->ic_bsschan) { 204232176cfdSRui Paulo /* 204332176cfdSRui Paulo * Handle lazy construction of ie. This is done on 204432176cfdSRui Paulo * first use and after a channel change that requires 204532176cfdSRui Paulo * re-calculation. 204632176cfdSRui Paulo */ 204732176cfdSRui Paulo if (ic->ic_countryie != NULL) 204832176cfdSRui Paulo kfree(ic->ic_countryie, M_80211_NODE_IE); 204932176cfdSRui Paulo ic->ic_countryie = ieee80211_alloc_countryie(ic); 205032176cfdSRui Paulo if (ic->ic_countryie == NULL) 205132176cfdSRui Paulo return frm; 205232176cfdSRui Paulo ic->ic_countryie_chan = ic->ic_bsschan; 205332176cfdSRui Paulo } 205432176cfdSRui Paulo return add_appie(frm, ic->ic_countryie); 205532176cfdSRui Paulo } 205632176cfdSRui Paulo 2057085ff963SMatthew Dillon uint8_t * 2058085ff963SMatthew Dillon ieee80211_add_wpa(uint8_t *frm, const struct ieee80211vap *vap) 2059085ff963SMatthew Dillon { 2060085ff963SMatthew Dillon if (vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL) 2061085ff963SMatthew Dillon return (add_ie(frm, vap->iv_wpa_ie)); 2062085ff963SMatthew Dillon else { 2063085ff963SMatthew Dillon /* XXX else complain? */ 2064085ff963SMatthew Dillon return (frm); 2065085ff963SMatthew Dillon } 2066085ff963SMatthew Dillon } 2067085ff963SMatthew Dillon 2068085ff963SMatthew Dillon uint8_t * 2069085ff963SMatthew Dillon ieee80211_add_rsn(uint8_t *frm, const struct ieee80211vap *vap) 2070085ff963SMatthew Dillon { 2071085ff963SMatthew Dillon if (vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL) 2072085ff963SMatthew Dillon return (add_ie(frm, vap->iv_rsn_ie)); 2073085ff963SMatthew Dillon else { 2074085ff963SMatthew Dillon /* XXX else complain? */ 2075085ff963SMatthew Dillon return (frm); 2076085ff963SMatthew Dillon } 2077085ff963SMatthew Dillon } 2078085ff963SMatthew Dillon 2079085ff963SMatthew Dillon uint8_t * 2080085ff963SMatthew Dillon ieee80211_add_qos(uint8_t *frm, const struct ieee80211_node *ni) 2081085ff963SMatthew Dillon { 2082085ff963SMatthew Dillon if (ni->ni_flags & IEEE80211_NODE_QOS) { 2083085ff963SMatthew Dillon *frm++ = IEEE80211_ELEMID_QOS; 2084085ff963SMatthew Dillon *frm++ = 1; 2085085ff963SMatthew Dillon *frm++ = 0; 2086085ff963SMatthew Dillon } 2087085ff963SMatthew Dillon 2088085ff963SMatthew Dillon return (frm); 2089085ff963SMatthew Dillon } 2090085ff963SMatthew Dillon 209132176cfdSRui Paulo /* 2092841ab66cSSepherosa Ziehau * Send a probe request frame with the specified ssid 2093841ab66cSSepherosa Ziehau * and any optional information element data. 2094841ab66cSSepherosa Ziehau */ 2095841ab66cSSepherosa Ziehau int 2096841ab66cSSepherosa Ziehau ieee80211_send_probereq(struct ieee80211_node *ni, 2097841ab66cSSepherosa Ziehau const uint8_t sa[IEEE80211_ADDR_LEN], 2098841ab66cSSepherosa Ziehau const uint8_t da[IEEE80211_ADDR_LEN], 2099841ab66cSSepherosa Ziehau const uint8_t bssid[IEEE80211_ADDR_LEN], 210032176cfdSRui Paulo const uint8_t *ssid, size_t ssidlen) 2101841ab66cSSepherosa Ziehau { 210232176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 2103841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 210432176cfdSRui Paulo const struct ieee80211_txparam *tp; 210532176cfdSRui Paulo struct ieee80211_bpf_params params; 2106085ff963SMatthew Dillon struct ieee80211_frame *wh; 210732176cfdSRui Paulo const struct ieee80211_rateset *rs; 2108841ab66cSSepherosa Ziehau struct mbuf *m; 2109841ab66cSSepherosa Ziehau uint8_t *frm; 2110085ff963SMatthew Dillon int ret; 2111841ab66cSSepherosa Ziehau 211232176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 211332176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 211432176cfdSRui Paulo "block %s frame in CAC state", "probe request"); 211532176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 211632176cfdSRui Paulo return EIO; /* XXX */ 211732176cfdSRui Paulo } 211832176cfdSRui Paulo 2119841ab66cSSepherosa Ziehau /* 2120841ab66cSSepherosa Ziehau * Hold a reference on the node so it doesn't go away until after 2121841ab66cSSepherosa Ziehau * the xmit is complete all the way in the driver. On error we 2122841ab66cSSepherosa Ziehau * will remove our reference. 2123841ab66cSSepherosa Ziehau */ 212432176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 21251e290df3SAntonio Huete Jimenez "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2126841ab66cSSepherosa Ziehau __func__, __LINE__, 2127085ff963SMatthew Dillon ni, ether_sprintf(ni->ni_macaddr), 2128841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 2129841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 2130841ab66cSSepherosa Ziehau 2131841ab66cSSepherosa Ziehau /* 2132841ab66cSSepherosa Ziehau * prreq frame format 2133841ab66cSSepherosa Ziehau * [tlv] ssid 2134841ab66cSSepherosa Ziehau * [tlv] supported rates 213532176cfdSRui Paulo * [tlv] RSN (optional) 2136841ab66cSSepherosa Ziehau * [tlv] extended supported rates 213732176cfdSRui Paulo * [tlv] WPA (optional) 2138841ab66cSSepherosa Ziehau * [tlv] user-specified ie's 2139841ab66cSSepherosa Ziehau */ 2140841ab66cSSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 21414ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 2142841ab66cSSepherosa Ziehau 2 + IEEE80211_NWID_LEN 2143841ab66cSSepherosa Ziehau + 2 + IEEE80211_RATE_SIZE 214432176cfdSRui Paulo + sizeof(struct ieee80211_ie_wpa) 2145841ab66cSSepherosa Ziehau + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 214632176cfdSRui Paulo + sizeof(struct ieee80211_ie_wpa) 214732176cfdSRui Paulo + (vap->iv_appie_probereq != NULL ? 214832176cfdSRui Paulo vap->iv_appie_probereq->ie_len : 0) 2149841ab66cSSepherosa Ziehau ); 2150841ab66cSSepherosa Ziehau if (m == NULL) { 215132176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 2152841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2153841ab66cSSepherosa Ziehau return ENOMEM; 2154841ab66cSSepherosa Ziehau } 2155841ab66cSSepherosa Ziehau 2156841ab66cSSepherosa Ziehau frm = ieee80211_add_ssid(frm, ssid, ssidlen); 215732176cfdSRui Paulo rs = ieee80211_get_suprates(ic, ic->ic_curchan); 215832176cfdSRui Paulo frm = ieee80211_add_rates(frm, rs); 2159085ff963SMatthew Dillon frm = ieee80211_add_rsn(frm, vap); 216032176cfdSRui Paulo frm = ieee80211_add_xrates(frm, rs); 2161085ff963SMatthew Dillon frm = ieee80211_add_wpa(frm, vap); 216232176cfdSRui Paulo if (vap->iv_appie_probereq != NULL) 216332176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_probereq); 2164841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2165841ab66cSSepherosa Ziehau 216632176cfdSRui Paulo KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), 216732176cfdSRui Paulo ("leading space %zd", M_LEADINGSPACE(m))); 2168b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 216932176cfdSRui Paulo if (m == NULL) { 217032176cfdSRui Paulo /* NB: cannot happen */ 217132176cfdSRui Paulo ieee80211_free_node(ni); 2172841ab66cSSepherosa Ziehau return ENOMEM; 217332176cfdSRui Paulo } 2174841ab66cSSepherosa Ziehau 2175085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 2176085ff963SMatthew Dillon wh = mtod(m, struct ieee80211_frame *); 217732176cfdSRui Paulo ieee80211_send_setup(ni, m, 2178841ab66cSSepherosa Ziehau IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 217932176cfdSRui Paulo IEEE80211_NONQOS_TID, sa, da, bssid); 2180841ab66cSSepherosa Ziehau /* XXX power management? */ 218132176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 218232176cfdSRui Paulo 218332176cfdSRui Paulo M_WME_SETAC(m, WME_AC_BE); 2184841ab66cSSepherosa Ziehau 2185841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_probereq); 2186841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_mgmt); 2187841ab66cSSepherosa Ziehau 218832176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 21891e290df3SAntonio Huete Jimenez "send probe req on channel %u bssid %s ssid \"%.*s\"\n", 2190085ff963SMatthew Dillon ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid), 2191f92fae3fSSascha Wildner (int)ssidlen, ssid); 2192841ab66cSSepherosa Ziehau 219332176cfdSRui Paulo memset(¶ms, 0, sizeof(params)); 219432176cfdSRui Paulo params.ibp_pri = M_WME_GETAC(m); 219532176cfdSRui Paulo tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 219632176cfdSRui Paulo params.ibp_rate0 = tp->mgmtrate; 219732176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(da)) { 219832176cfdSRui Paulo params.ibp_flags |= IEEE80211_BPF_NOACK; 219932176cfdSRui Paulo params.ibp_try0 = 1; 220032176cfdSRui Paulo } else 220132176cfdSRui Paulo params.ibp_try0 = tp->maxretry; 220232176cfdSRui Paulo params.ibp_power = ni->ni_txpower; 2203085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, ni, m, ¶ms); 2204085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 2205085ff963SMatthew Dillon return (ret); 2206841ab66cSSepherosa Ziehau } 2207841ab66cSSepherosa Ziehau 2208841ab66cSSepherosa Ziehau /* 2209841ab66cSSepherosa Ziehau * Calculate capability information for mgt frames. 2210841ab66cSSepherosa Ziehau */ 221132176cfdSRui Paulo uint16_t 221232176cfdSRui Paulo ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) 2213841ab66cSSepherosa Ziehau { 221432176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 2215841ab66cSSepherosa Ziehau uint16_t capinfo; 2216841ab66cSSepherosa Ziehau 221732176cfdSRui Paulo KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); 2218841ab66cSSepherosa Ziehau 221932176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2220841ab66cSSepherosa Ziehau capinfo = IEEE80211_CAPINFO_ESS; 222132176cfdSRui Paulo else if (vap->iv_opmode == IEEE80211_M_IBSS) 2222841ab66cSSepherosa Ziehau capinfo = IEEE80211_CAPINFO_IBSS; 2223841ab66cSSepherosa Ziehau else 2224841ab66cSSepherosa Ziehau capinfo = 0; 222532176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) 2226841ab66cSSepherosa Ziehau capinfo |= IEEE80211_CAPINFO_PRIVACY; 222732176cfdSRui Paulo if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 222832176cfdSRui Paulo IEEE80211_IS_CHAN_2GHZ(chan)) 2229841ab66cSSepherosa Ziehau capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 2230841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_SHSLOT) 2231841ab66cSSepherosa Ziehau capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 223232176cfdSRui Paulo if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) 223332176cfdSRui Paulo capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 2234841ab66cSSepherosa Ziehau return capinfo; 2235f186073cSJoerg Sonnenberger } 2236f186073cSJoerg Sonnenberger 2237f186073cSJoerg Sonnenberger /* 2238f186073cSJoerg Sonnenberger * Send a management frame. The node is for the destination (or ic_bss 2239f186073cSJoerg Sonnenberger * when in station mode). Nodes other than ic_bss have their reference 2240f186073cSJoerg Sonnenberger * count bumped to reflect our use for an indeterminant time. 2241f186073cSJoerg Sonnenberger */ 2242f186073cSJoerg Sonnenberger int 224332176cfdSRui Paulo ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) 2244f186073cSJoerg Sonnenberger { 224532176cfdSRui Paulo #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) 224632176cfdSRui Paulo #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) 224732176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 224832176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 224932176cfdSRui Paulo struct ieee80211_node *bss = vap->iv_bss; 225032176cfdSRui Paulo struct ieee80211_bpf_params params; 2251f186073cSJoerg Sonnenberger struct mbuf *m; 2252f186073cSJoerg Sonnenberger uint8_t *frm; 2253f186073cSJoerg Sonnenberger uint16_t capinfo; 225432176cfdSRui Paulo int has_challenge, is_shared_key, ret, status; 2255f186073cSJoerg Sonnenberger 2256f186073cSJoerg Sonnenberger KASSERT(ni != NULL, ("null node")); 2257f186073cSJoerg Sonnenberger 2258f186073cSJoerg Sonnenberger /* 2259f186073cSJoerg Sonnenberger * Hold a reference on the node so it doesn't go away until after 2260f186073cSJoerg Sonnenberger * the xmit is complete all the way in the driver. On error we 2261f186073cSJoerg Sonnenberger * will remove our reference. 2262f186073cSJoerg Sonnenberger */ 226332176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 22641e290df3SAntonio Huete Jimenez "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2265841ab66cSSepherosa Ziehau __func__, __LINE__, 2266085ff963SMatthew Dillon ni, ether_sprintf(ni->ni_macaddr), 2267841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 2268f186073cSJoerg Sonnenberger ieee80211_ref_node(ni); 2269841ab66cSSepherosa Ziehau 227032176cfdSRui Paulo memset(¶ms, 0, sizeof(params)); 2271f186073cSJoerg Sonnenberger switch (type) { 2272f186073cSJoerg Sonnenberger 2273f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_AUTH: 2274841ab66cSSepherosa Ziehau status = arg >> 16; 2275841ab66cSSepherosa Ziehau arg &= 0xffff; 2276841ab66cSSepherosa Ziehau has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 2277841ab66cSSepherosa Ziehau arg == IEEE80211_AUTH_SHARED_RESPONSE) && 2278841ab66cSSepherosa Ziehau ni->ni_challenge != NULL); 2279841ab66cSSepherosa Ziehau 2280841ab66cSSepherosa Ziehau /* 2281841ab66cSSepherosa Ziehau * Deduce whether we're doing open authentication or 2282841ab66cSSepherosa Ziehau * shared key authentication. We do the latter if 2283841ab66cSSepherosa Ziehau * we're in the middle of a shared key authentication 2284841ab66cSSepherosa Ziehau * handshake or if we're initiating an authentication 2285841ab66cSSepherosa Ziehau * request and configured to use shared key. 2286841ab66cSSepherosa Ziehau */ 2287841ab66cSSepherosa Ziehau is_shared_key = has_challenge || 2288841ab66cSSepherosa Ziehau arg >= IEEE80211_AUTH_SHARED_RESPONSE || 2289841ab66cSSepherosa Ziehau (arg == IEEE80211_AUTH_SHARED_REQUEST && 229032176cfdSRui Paulo bss->ni_authmode == IEEE80211_AUTH_SHARED); 2291841ab66cSSepherosa Ziehau 2292841ab66cSSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 22934ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 2294841ab66cSSepherosa Ziehau 3 * sizeof(uint16_t) 2295841ab66cSSepherosa Ziehau + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 2296841ab66cSSepherosa Ziehau sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) 2297841ab66cSSepherosa Ziehau ); 2298f186073cSJoerg Sonnenberger if (m == NULL) 2299841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2300841ab66cSSepherosa Ziehau 2301841ab66cSSepherosa Ziehau ((uint16_t *)frm)[0] = 2302841ab66cSSepherosa Ziehau (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) 2303841ab66cSSepherosa Ziehau : htole16(IEEE80211_AUTH_ALG_OPEN); 2304f186073cSJoerg Sonnenberger ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ 2305841ab66cSSepherosa Ziehau ((uint16_t *)frm)[2] = htole16(status);/* status */ 2306841ab66cSSepherosa Ziehau 2307841ab66cSSepherosa Ziehau if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 2308841ab66cSSepherosa Ziehau ((uint16_t *)frm)[3] = 2309841ab66cSSepherosa Ziehau htole16((IEEE80211_CHALLENGE_LEN << 8) | 2310841ab66cSSepherosa Ziehau IEEE80211_ELEMID_CHALLENGE); 2311841ab66cSSepherosa Ziehau memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, 2312841ab66cSSepherosa Ziehau IEEE80211_CHALLENGE_LEN); 2313841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = 2314841ab66cSSepherosa Ziehau 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; 2315841ab66cSSepherosa Ziehau if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { 231632176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 231732176cfdSRui Paulo "request encrypt frame (%s)", __func__); 231832176cfdSRui Paulo /* mark frame for encryption */ 231932176cfdSRui Paulo params.ibp_flags |= IEEE80211_BPF_CRYPTO; 2320841ab66cSSepherosa Ziehau } 2321841ab66cSSepherosa Ziehau } else 2322841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); 2323841ab66cSSepherosa Ziehau 2324841ab66cSSepherosa Ziehau /* XXX not right for shared key */ 2325841ab66cSSepherosa Ziehau if (status == IEEE80211_STATUS_SUCCESS) 2326841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_auth); 2327841ab66cSSepherosa Ziehau else 2328841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_auth_fail); 2329841ab66cSSepherosa Ziehau 233032176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA) 233132176cfdSRui Paulo ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 233232176cfdSRui Paulo (void *) vap->iv_state); 2333f186073cSJoerg Sonnenberger break; 2334f186073cSJoerg Sonnenberger 2335f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DEAUTH: 233632176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 233732176cfdSRui Paulo "send station deauthenticate (reason %d)", arg); 23384ac84526SSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 23394ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 23404ac84526SSepherosa Ziehau sizeof(uint16_t)); 2341f186073cSJoerg Sonnenberger if (m == NULL) 2342841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2343841ab66cSSepherosa Ziehau *(uint16_t *)frm = htole16(arg); /* reason */ 2344841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 2345841ab66cSSepherosa Ziehau 2346841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_deauth); 2347841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); 2348841ab66cSSepherosa Ziehau 2349841ab66cSSepherosa Ziehau ieee80211_node_unauthorize(ni); /* port closed */ 2350f186073cSJoerg Sonnenberger break; 2351f186073cSJoerg Sonnenberger 2352f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 2353208a1285SSepherosa Ziehau case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 2354f186073cSJoerg Sonnenberger /* 2355f186073cSJoerg Sonnenberger * asreq frame format 2356f186073cSJoerg Sonnenberger * [2] capability information 2357f186073cSJoerg Sonnenberger * [2] listen interval 2358f186073cSJoerg Sonnenberger * [6*] current AP address (reassoc only) 2359f186073cSJoerg Sonnenberger * [tlv] ssid 2360f186073cSJoerg Sonnenberger * [tlv] supported rates 2361f186073cSJoerg Sonnenberger * [tlv] extended supported rates 236232176cfdSRui Paulo * [4] power capability (optional) 236332176cfdSRui Paulo * [28] supported channels (optional) 236432176cfdSRui Paulo * [tlv] HT capabilities 236532176cfdSRui Paulo * [tlv] WME (optional) 236632176cfdSRui Paulo * [tlv] Vendor OUI HT capabilities (optional) 236732176cfdSRui Paulo * [tlv] Atheros capabilities (if negotiated) 236832176cfdSRui Paulo * [tlv] AppIE's (optional) 2369f186073cSJoerg Sonnenberger */ 2370841ab66cSSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 23714ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 2372841ab66cSSepherosa Ziehau sizeof(uint16_t) 2373f186073cSJoerg Sonnenberger + sizeof(uint16_t) 2374f186073cSJoerg Sonnenberger + IEEE80211_ADDR_LEN 2375841ab66cSSepherosa Ziehau + 2 + IEEE80211_NWID_LEN 2376f186073cSJoerg Sonnenberger + 2 + IEEE80211_RATE_SIZE 2377841ab66cSSepherosa Ziehau + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 237832176cfdSRui Paulo + 4 237932176cfdSRui Paulo + 2 + 26 2380841ab66cSSepherosa Ziehau + sizeof(struct ieee80211_wme_info) 238132176cfdSRui Paulo + sizeof(struct ieee80211_ie_htcap) 238232176cfdSRui Paulo + 4 + sizeof(struct ieee80211_ie_htcap) 238332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 238432176cfdSRui Paulo + sizeof(struct ieee80211_ath_ie) 238532176cfdSRui Paulo #endif 238632176cfdSRui Paulo + (vap->iv_appie_wpa != NULL ? 238732176cfdSRui Paulo vap->iv_appie_wpa->ie_len : 0) 238832176cfdSRui Paulo + (vap->iv_appie_assocreq != NULL ? 238932176cfdSRui Paulo vap->iv_appie_assocreq->ie_len : 0) 2390841ab66cSSepherosa Ziehau ); 2391f186073cSJoerg Sonnenberger if (m == NULL) 2392841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2393f186073cSJoerg Sonnenberger 239432176cfdSRui Paulo KASSERT(vap->iv_opmode == IEEE80211_M_STA, 239532176cfdSRui Paulo ("wrong mode %u", vap->iv_opmode)); 2396841ab66cSSepherosa Ziehau capinfo = IEEE80211_CAPINFO_ESS; 239732176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) 2398f186073cSJoerg Sonnenberger capinfo |= IEEE80211_CAPINFO_PRIVACY; 2399f186073cSJoerg Sonnenberger /* 2400f186073cSJoerg Sonnenberger * NB: Some 11a AP's reject the request when 240132176cfdSRui Paulo * short premable is set. 2402f186073cSJoerg Sonnenberger */ 240332176cfdSRui Paulo if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 240432176cfdSRui Paulo IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 2405f186073cSJoerg Sonnenberger capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 240632176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 2407841ab66cSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHSLOT)) 2408f186073cSJoerg Sonnenberger capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 240932176cfdSRui Paulo if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && 241032176cfdSRui Paulo (vap->iv_flags & IEEE80211_F_DOTH)) 241132176cfdSRui Paulo capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 2412f186073cSJoerg Sonnenberger *(uint16_t *)frm = htole16(capinfo); 2413f186073cSJoerg Sonnenberger frm += 2; 2414f186073cSJoerg Sonnenberger 241532176cfdSRui Paulo KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); 241622b21df8SSepherosa Ziehau *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, 241732176cfdSRui Paulo bss->ni_intval)); 2418f186073cSJoerg Sonnenberger frm += 2; 2419f186073cSJoerg Sonnenberger 2420f186073cSJoerg Sonnenberger if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 242132176cfdSRui Paulo IEEE80211_ADDR_COPY(frm, bss->ni_bssid); 2422f186073cSJoerg Sonnenberger frm += IEEE80211_ADDR_LEN; 2423f186073cSJoerg Sonnenberger } 2424f186073cSJoerg Sonnenberger 2425f186073cSJoerg Sonnenberger frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 242632176cfdSRui Paulo frm = ieee80211_add_rates(frm, &ni->ni_rates); 2427085ff963SMatthew Dillon frm = ieee80211_add_rsn(frm, vap); 242832176cfdSRui Paulo frm = ieee80211_add_xrates(frm, &ni->ni_rates); 242932176cfdSRui Paulo if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { 243032176cfdSRui Paulo frm = ieee80211_add_powercapability(frm, 243132176cfdSRui Paulo ic->ic_curchan); 243232176cfdSRui Paulo frm = ieee80211_add_supportedchannels(frm, ic); 243332176cfdSRui Paulo } 243432176cfdSRui Paulo if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 243532176cfdSRui Paulo ni->ni_ies.htcap_ie != NULL && 243632176cfdSRui Paulo ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 243732176cfdSRui Paulo frm = ieee80211_add_htcap(frm, ni); 2438085ff963SMatthew Dillon frm = ieee80211_add_wpa(frm, vap); 243932176cfdSRui Paulo if ((ic->ic_flags & IEEE80211_F_WME) && 244032176cfdSRui Paulo ni->ni_ies.wme_ie != NULL) 244132176cfdSRui Paulo frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 244232176cfdSRui Paulo if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 244332176cfdSRui Paulo ni->ni_ies.htcap_ie != NULL && 244432176cfdSRui Paulo ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 244532176cfdSRui Paulo frm = ieee80211_add_htcap_vendor(frm, ni); 244632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 244732176cfdSRui Paulo if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { 244832176cfdSRui Paulo frm = ieee80211_add_ath(frm, 244932176cfdSRui Paulo IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 245032176cfdSRui Paulo ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 245132176cfdSRui Paulo ni->ni_authmode != IEEE80211_AUTH_8021X) ? 245232176cfdSRui Paulo vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 245332176cfdSRui Paulo } 245432176cfdSRui Paulo #endif /* IEEE80211_SUPPORT_SUPERG */ 245532176cfdSRui Paulo if (vap->iv_appie_assocreq != NULL) 245632176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_assocreq); 2457f186073cSJoerg Sonnenberger m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2458f186073cSJoerg Sonnenberger 245932176cfdSRui Paulo ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 246032176cfdSRui Paulo (void *) vap->iv_state); 2461f186073cSJoerg Sonnenberger break; 2462f186073cSJoerg Sonnenberger 2463f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 2464f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 2465f186073cSJoerg Sonnenberger /* 246632176cfdSRui Paulo * asresp frame format 2467f186073cSJoerg Sonnenberger * [2] capability information 2468f186073cSJoerg Sonnenberger * [2] status 2469f186073cSJoerg Sonnenberger * [2] association ID 2470f186073cSJoerg Sonnenberger * [tlv] supported rates 2471f186073cSJoerg Sonnenberger * [tlv] extended supported rates 247232176cfdSRui Paulo * [tlv] HT capabilities (standard, if STA enabled) 247332176cfdSRui Paulo * [tlv] HT information (standard, if STA enabled) 247432176cfdSRui Paulo * [tlv] WME (if configured and STA enabled) 247532176cfdSRui Paulo * [tlv] HT capabilities (vendor OUI, if STA enabled) 247632176cfdSRui Paulo * [tlv] HT information (vendor OUI, if STA enabled) 247732176cfdSRui Paulo * [tlv] Atheros capabilities (if STA enabled) 247832176cfdSRui Paulo * [tlv] AppIE's (optional) 2479f186073cSJoerg Sonnenberger */ 2480841ab66cSSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 24814ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 2482841ab66cSSepherosa Ziehau sizeof(uint16_t) 2483f186073cSJoerg Sonnenberger + sizeof(uint16_t) 2484f186073cSJoerg Sonnenberger + sizeof(uint16_t) 2485f186073cSJoerg Sonnenberger + 2 + IEEE80211_RATE_SIZE 2486841ab66cSSepherosa Ziehau + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 248732176cfdSRui Paulo + sizeof(struct ieee80211_ie_htcap) + 4 248832176cfdSRui Paulo + sizeof(struct ieee80211_ie_htinfo) + 4 2489841ab66cSSepherosa Ziehau + sizeof(struct ieee80211_wme_param) 249032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 249132176cfdSRui Paulo + sizeof(struct ieee80211_ath_ie) 249232176cfdSRui Paulo #endif 249332176cfdSRui Paulo + (vap->iv_appie_assocresp != NULL ? 249432176cfdSRui Paulo vap->iv_appie_assocresp->ie_len : 0) 2495841ab66cSSepherosa Ziehau ); 2496f186073cSJoerg Sonnenberger if (m == NULL) 2497841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2498f186073cSJoerg Sonnenberger 249932176cfdSRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 2500f186073cSJoerg Sonnenberger *(uint16_t *)frm = htole16(capinfo); 2501f186073cSJoerg Sonnenberger frm += 2; 2502f186073cSJoerg Sonnenberger 2503f186073cSJoerg Sonnenberger *(uint16_t *)frm = htole16(arg); /* status */ 2504f186073cSJoerg Sonnenberger frm += 2; 2505f186073cSJoerg Sonnenberger 2506841ab66cSSepherosa Ziehau if (arg == IEEE80211_STATUS_SUCCESS) { 2507f186073cSJoerg Sonnenberger *(uint16_t *)frm = htole16(ni->ni_associd); 2508841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_assoc); 2509841ab66cSSepherosa Ziehau } else 2510841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_assoc_fail); 2511f186073cSJoerg Sonnenberger frm += 2; 2512f186073cSJoerg Sonnenberger 251332176cfdSRui Paulo frm = ieee80211_add_rates(frm, &ni->ni_rates); 251432176cfdSRui Paulo frm = ieee80211_add_xrates(frm, &ni->ni_rates); 251532176cfdSRui Paulo /* NB: respond according to what we received */ 251632176cfdSRui Paulo if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { 251732176cfdSRui Paulo frm = ieee80211_add_htcap(frm, ni); 251832176cfdSRui Paulo frm = ieee80211_add_htinfo(frm, ni); 251932176cfdSRui Paulo } 252032176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_WME) && 252132176cfdSRui Paulo ni->ni_ies.wme_ie != NULL) 2522841ab66cSSepherosa Ziehau frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 252332176cfdSRui Paulo if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { 252432176cfdSRui Paulo frm = ieee80211_add_htcap_vendor(frm, ni); 252532176cfdSRui Paulo frm = ieee80211_add_htinfo_vendor(frm, ni); 252632176cfdSRui Paulo } 252732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 252832176cfdSRui Paulo if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 252932176cfdSRui Paulo frm = ieee80211_add_ath(frm, 253032176cfdSRui Paulo IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 253132176cfdSRui Paulo ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 253232176cfdSRui Paulo ni->ni_authmode != IEEE80211_AUTH_8021X) ? 253332176cfdSRui Paulo vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 253432176cfdSRui Paulo #endif /* IEEE80211_SUPPORT_SUPERG */ 253532176cfdSRui Paulo if (vap->iv_appie_assocresp != NULL) 253632176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_assocresp); 2537f186073cSJoerg Sonnenberger m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2538f186073cSJoerg Sonnenberger break; 2539f186073cSJoerg Sonnenberger 2540f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DISASSOC: 254132176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 254232176cfdSRui Paulo "send station disassociate (reason %d)", arg); 25434ac84526SSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 25444ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 25454ac84526SSepherosa Ziehau sizeof(uint16_t)); 2546f186073cSJoerg Sonnenberger if (m == NULL) 2547841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2548841ab66cSSepherosa Ziehau *(uint16_t *)frm = htole16(arg); /* reason */ 2549841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 2550841ab66cSSepherosa Ziehau 2551841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_disassoc); 2552841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); 2553f186073cSJoerg Sonnenberger break; 2554f186073cSJoerg Sonnenberger 2555f186073cSJoerg Sonnenberger default: 255632176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 255732176cfdSRui Paulo "invalid mgmt frame type %u", type); 2558f186073cSJoerg Sonnenberger senderr(EINVAL, is_tx_unknownmgt); 2559f186073cSJoerg Sonnenberger /* NOTREACHED */ 2560f186073cSJoerg Sonnenberger } 256132176cfdSRui Paulo 256232176cfdSRui Paulo /* NB: force non-ProbeResp frames to the highest queue */ 256332176cfdSRui Paulo params.ibp_pri = WME_AC_VO; 256432176cfdSRui Paulo params.ibp_rate0 = bss->ni_txparms->mgmtrate; 256532176cfdSRui Paulo /* NB: we know all frames are unicast */ 256632176cfdSRui Paulo params.ibp_try0 = bss->ni_txparms->maxretry; 256732176cfdSRui Paulo params.ibp_power = bss->ni_txpower; 256832176cfdSRui Paulo return ieee80211_mgmt_output(ni, m, type, ¶ms); 2569f186073cSJoerg Sonnenberger bad: 2570841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2571f186073cSJoerg Sonnenberger return ret; 2572f186073cSJoerg Sonnenberger #undef senderr 257332176cfdSRui Paulo #undef HTFLAGS 2574f186073cSJoerg Sonnenberger } 2575841ab66cSSepherosa Ziehau 2576841ab66cSSepherosa Ziehau /* 257732176cfdSRui Paulo * Return an mbuf with a probe response frame in it. 257832176cfdSRui Paulo * Space is left to prepend and 802.11 header at the 257932176cfdSRui Paulo * front but it's left to the caller to fill in. 25803da93495SSepherosa Ziehau */ 25813da93495SSepherosa Ziehau struct mbuf * 258232176cfdSRui Paulo ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) 25833da93495SSepherosa Ziehau { 258432176cfdSRui Paulo struct ieee80211vap *vap = bss->ni_vap; 258532176cfdSRui Paulo struct ieee80211com *ic = bss->ni_ic; 258632176cfdSRui Paulo const struct ieee80211_rateset *rs; 25873da93495SSepherosa Ziehau struct mbuf *m; 258832176cfdSRui Paulo uint16_t capinfo; 258932176cfdSRui Paulo uint8_t *frm; 25903da93495SSepherosa Ziehau 259132176cfdSRui Paulo /* 259232176cfdSRui Paulo * probe response frame format 259332176cfdSRui Paulo * [8] time stamp 259432176cfdSRui Paulo * [2] beacon interval 259532176cfdSRui Paulo * [2] cabability information 259632176cfdSRui Paulo * [tlv] ssid 259732176cfdSRui Paulo * [tlv] supported rates 259832176cfdSRui Paulo * [tlv] parameter set (FH/DS) 259932176cfdSRui Paulo * [tlv] parameter set (IBSS) 260032176cfdSRui Paulo * [tlv] country (optional) 260132176cfdSRui Paulo * [3] power control (optional) 260232176cfdSRui Paulo * [5] channel switch announcement (CSA) (optional) 260332176cfdSRui Paulo * [tlv] extended rate phy (ERP) 260432176cfdSRui Paulo * [tlv] extended supported rates 260532176cfdSRui Paulo * [tlv] RSN (optional) 260632176cfdSRui Paulo * [tlv] HT capabilities 260732176cfdSRui Paulo * [tlv] HT information 260832176cfdSRui Paulo * [tlv] WPA (optional) 260932176cfdSRui Paulo * [tlv] WME (optional) 261032176cfdSRui Paulo * [tlv] Vendor OUI HT capabilities (optional) 261132176cfdSRui Paulo * [tlv] Vendor OUI HT information (optional) 261232176cfdSRui Paulo * [tlv] Atheros capabilities 261332176cfdSRui Paulo * [tlv] AppIE's (optional) 261432176cfdSRui Paulo * [tlv] Mesh ID (MBSS) 261532176cfdSRui Paulo * [tlv] Mesh Conf (MBSS) 261632176cfdSRui Paulo */ 261732176cfdSRui Paulo m = ieee80211_getmgtframe(&frm, 261832176cfdSRui Paulo ic->ic_headroom + sizeof(struct ieee80211_frame), 261932176cfdSRui Paulo 8 262032176cfdSRui Paulo + sizeof(uint16_t) 262132176cfdSRui Paulo + sizeof(uint16_t) 262232176cfdSRui Paulo + 2 + IEEE80211_NWID_LEN 262332176cfdSRui Paulo + 2 + IEEE80211_RATE_SIZE 262432176cfdSRui Paulo + 7 /* max(7,3) */ 262532176cfdSRui Paulo + IEEE80211_COUNTRY_MAX_SIZE 262632176cfdSRui Paulo + 3 262732176cfdSRui Paulo + sizeof(struct ieee80211_csa_ie) 2628085ff963SMatthew Dillon + sizeof(struct ieee80211_quiet_ie) 262932176cfdSRui Paulo + 3 263032176cfdSRui Paulo + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 263132176cfdSRui Paulo + sizeof(struct ieee80211_ie_wpa) 263232176cfdSRui Paulo + sizeof(struct ieee80211_ie_htcap) 263332176cfdSRui Paulo + sizeof(struct ieee80211_ie_htinfo) 263432176cfdSRui Paulo + sizeof(struct ieee80211_ie_wpa) 263532176cfdSRui Paulo + sizeof(struct ieee80211_wme_param) 263632176cfdSRui Paulo + 4 + sizeof(struct ieee80211_ie_htcap) 263732176cfdSRui Paulo + 4 + sizeof(struct ieee80211_ie_htinfo) 263832176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 263932176cfdSRui Paulo + sizeof(struct ieee80211_ath_ie) 264032176cfdSRui Paulo #endif 264132176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 264232176cfdSRui Paulo + 2 + IEEE80211_MESHID_LEN 264332176cfdSRui Paulo + sizeof(struct ieee80211_meshconf_ie) 264432176cfdSRui Paulo #endif 264532176cfdSRui Paulo + (vap->iv_appie_proberesp != NULL ? 264632176cfdSRui Paulo vap->iv_appie_proberesp->ie_len : 0) 264732176cfdSRui Paulo ); 264832176cfdSRui Paulo if (m == NULL) { 264932176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 26503da93495SSepherosa Ziehau return NULL; 265132176cfdSRui Paulo } 26523da93495SSepherosa Ziehau 265332176cfdSRui Paulo memset(frm, 0, 8); /* timestamp should be filled later */ 265432176cfdSRui Paulo frm += 8; 265532176cfdSRui Paulo *(uint16_t *)frm = htole16(bss->ni_intval); 265632176cfdSRui Paulo frm += 2; 265732176cfdSRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 265832176cfdSRui Paulo *(uint16_t *)frm = htole16(capinfo); 265932176cfdSRui Paulo frm += 2; 26603da93495SSepherosa Ziehau 266132176cfdSRui Paulo frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); 266232176cfdSRui Paulo rs = ieee80211_get_suprates(ic, bss->ni_chan); 266332176cfdSRui Paulo frm = ieee80211_add_rates(frm, rs); 266432176cfdSRui Paulo 266532176cfdSRui Paulo if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { 266632176cfdSRui Paulo *frm++ = IEEE80211_ELEMID_FHPARMS; 266732176cfdSRui Paulo *frm++ = 5; 266832176cfdSRui Paulo *frm++ = bss->ni_fhdwell & 0x00ff; 266932176cfdSRui Paulo *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; 267032176cfdSRui Paulo *frm++ = IEEE80211_FH_CHANSET( 267132176cfdSRui Paulo ieee80211_chan2ieee(ic, bss->ni_chan)); 267232176cfdSRui Paulo *frm++ = IEEE80211_FH_CHANPAT( 267332176cfdSRui Paulo ieee80211_chan2ieee(ic, bss->ni_chan)); 267432176cfdSRui Paulo *frm++ = bss->ni_fhindex; 267532176cfdSRui Paulo } else { 267632176cfdSRui Paulo *frm++ = IEEE80211_ELEMID_DSPARMS; 267732176cfdSRui Paulo *frm++ = 1; 267832176cfdSRui Paulo *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); 267932176cfdSRui Paulo } 268032176cfdSRui Paulo 268132176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_IBSS) { 268232176cfdSRui Paulo *frm++ = IEEE80211_ELEMID_IBSSPARMS; 268332176cfdSRui Paulo *frm++ = 2; 268432176cfdSRui Paulo *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 268532176cfdSRui Paulo } 268632176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_DOTH) || 268732176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 268832176cfdSRui Paulo frm = ieee80211_add_countryie(frm, ic); 268932176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_DOTH) { 269032176cfdSRui Paulo if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) 269132176cfdSRui Paulo frm = ieee80211_add_powerconstraint(frm, vap); 269232176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_CSAPENDING) 269332176cfdSRui Paulo frm = ieee80211_add_csa(frm, vap); 269432176cfdSRui Paulo } 2695085ff963SMatthew Dillon if (vap->iv_flags & IEEE80211_F_DOTH) { 2696085ff963SMatthew Dillon if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 2697085ff963SMatthew Dillon (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 2698085ff963SMatthew Dillon if (vap->iv_quiet) 2699085ff963SMatthew Dillon frm = ieee80211_add_quiet(frm, vap); 2700085ff963SMatthew Dillon } 2701085ff963SMatthew Dillon } 270232176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) 270332176cfdSRui Paulo frm = ieee80211_add_erp(frm, ic); 270432176cfdSRui Paulo frm = ieee80211_add_xrates(frm, rs); 2705085ff963SMatthew Dillon frm = ieee80211_add_rsn(frm, vap); 270632176cfdSRui Paulo /* 270732176cfdSRui Paulo * NB: legacy 11b clients do not get certain ie's. 270832176cfdSRui Paulo * The caller identifies such clients by passing 270932176cfdSRui Paulo * a token in legacy to us. Could expand this to be 271032176cfdSRui Paulo * any legacy client for stuff like HT ie's. 271132176cfdSRui Paulo */ 271232176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 271332176cfdSRui Paulo legacy != IEEE80211_SEND_LEGACY_11B) { 271432176cfdSRui Paulo frm = ieee80211_add_htcap(frm, bss); 271532176cfdSRui Paulo frm = ieee80211_add_htinfo(frm, bss); 271632176cfdSRui Paulo } 2717085ff963SMatthew Dillon frm = ieee80211_add_wpa(frm, vap); 271832176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_WME) 271932176cfdSRui Paulo frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 272032176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 272132176cfdSRui Paulo (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) && 272232176cfdSRui Paulo legacy != IEEE80211_SEND_LEGACY_11B) { 272332176cfdSRui Paulo frm = ieee80211_add_htcap_vendor(frm, bss); 272432176cfdSRui Paulo frm = ieee80211_add_htinfo_vendor(frm, bss); 272532176cfdSRui Paulo } 272632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 272732176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_ATHEROS) && 272832176cfdSRui Paulo legacy != IEEE80211_SEND_LEGACY_11B) 272932176cfdSRui Paulo frm = ieee80211_add_athcaps(frm, bss); 273032176cfdSRui Paulo #endif 273132176cfdSRui Paulo if (vap->iv_appie_proberesp != NULL) 273232176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_proberesp); 273332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 273432176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 273532176cfdSRui Paulo frm = ieee80211_add_meshid(frm, vap); 273632176cfdSRui Paulo frm = ieee80211_add_meshconf(frm, vap); 273732176cfdSRui Paulo } 273832176cfdSRui Paulo #endif 273932176cfdSRui Paulo m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 27403da93495SSepherosa Ziehau 27413da93495SSepherosa Ziehau return m; 27423da93495SSepherosa Ziehau } 27433da93495SSepherosa Ziehau 27443da93495SSepherosa Ziehau /* 274532176cfdSRui Paulo * Send a probe response frame to the specified mac address. 274632176cfdSRui Paulo * This does not go through the normal mgt frame api so we 274732176cfdSRui Paulo * can specify the destination address and re-use the bss node 274832176cfdSRui Paulo * for the sta reference. 2749841ab66cSSepherosa Ziehau */ 275032176cfdSRui Paulo int 275132176cfdSRui Paulo ieee80211_send_proberesp(struct ieee80211vap *vap, 275232176cfdSRui Paulo const uint8_t da[IEEE80211_ADDR_LEN], int legacy) 2753841ab66cSSepherosa Ziehau { 275432176cfdSRui Paulo struct ieee80211_node *bss = vap->iv_bss; 275532176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 2756085ff963SMatthew Dillon struct ieee80211_frame *wh; 2757841ab66cSSepherosa Ziehau struct mbuf *m; 2758085ff963SMatthew Dillon int ret; 275932176cfdSRui Paulo 276032176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 276132176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, 276232176cfdSRui Paulo "block %s frame in CAC state", "probe response"); 276332176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 276432176cfdSRui Paulo return EIO; /* XXX */ 276532176cfdSRui Paulo } 276632176cfdSRui Paulo 276732176cfdSRui Paulo /* 276832176cfdSRui Paulo * Hold a reference on the node so it doesn't go away until after 276932176cfdSRui Paulo * the xmit is complete all the way in the driver. On error we 277032176cfdSRui Paulo * will remove our reference. 277132176cfdSRui Paulo */ 277232176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 27731e290df3SAntonio Huete Jimenez "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2774085ff963SMatthew Dillon __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), 277532176cfdSRui Paulo ieee80211_node_refcnt(bss)+1); 277632176cfdSRui Paulo ieee80211_ref_node(bss); 277732176cfdSRui Paulo 277832176cfdSRui Paulo m = ieee80211_alloc_proberesp(bss, legacy); 277932176cfdSRui Paulo if (m == NULL) { 278032176cfdSRui Paulo ieee80211_free_node(bss); 278132176cfdSRui Paulo return ENOMEM; 278232176cfdSRui Paulo } 278332176cfdSRui Paulo 2784b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 278532176cfdSRui Paulo KASSERT(m != NULL, ("no room for header")); 278632176cfdSRui Paulo 2787085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 2788085ff963SMatthew Dillon wh = mtod(m, struct ieee80211_frame *); 278932176cfdSRui Paulo ieee80211_send_setup(bss, m, 279032176cfdSRui Paulo IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, 279132176cfdSRui Paulo IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); 279232176cfdSRui Paulo /* XXX power management? */ 279332176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 279432176cfdSRui Paulo 279532176cfdSRui Paulo M_WME_SETAC(m, WME_AC_BE); 279632176cfdSRui Paulo 279732176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 27981e290df3SAntonio Huete Jimenez "send probe resp on channel %u to %s%s\n", 2799085ff963SMatthew Dillon ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), 280032176cfdSRui Paulo legacy ? " <legacy>" : ""); 280132176cfdSRui Paulo IEEE80211_NODE_STAT(bss, tx_mgmt); 280232176cfdSRui Paulo 2803085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, bss, m, NULL); 2804085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 2805085ff963SMatthew Dillon return (ret); 280632176cfdSRui Paulo } 280732176cfdSRui Paulo 280832176cfdSRui Paulo /* 280932176cfdSRui Paulo * Allocate and build a RTS (Request To Send) control frame. 281032176cfdSRui Paulo */ 281132176cfdSRui Paulo struct mbuf * 281232176cfdSRui Paulo ieee80211_alloc_rts(struct ieee80211com *ic, 281332176cfdSRui Paulo const uint8_t ra[IEEE80211_ADDR_LEN], 281432176cfdSRui Paulo const uint8_t ta[IEEE80211_ADDR_LEN], 281532176cfdSRui Paulo uint16_t dur) 281632176cfdSRui Paulo { 281732176cfdSRui Paulo struct ieee80211_frame_rts *rts; 281832176cfdSRui Paulo struct mbuf *m; 281932176cfdSRui Paulo 282032176cfdSRui Paulo /* XXX honor ic_headroom */ 2821b5523eacSSascha Wildner m = m_gethdr(M_NOWAIT, MT_DATA); 282232176cfdSRui Paulo if (m != NULL) { 282332176cfdSRui Paulo rts = mtod(m, struct ieee80211_frame_rts *); 282432176cfdSRui Paulo rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 282532176cfdSRui Paulo IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; 282632176cfdSRui Paulo rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 282732176cfdSRui Paulo *(u_int16_t *)rts->i_dur = htole16(dur); 282832176cfdSRui Paulo IEEE80211_ADDR_COPY(rts->i_ra, ra); 282932176cfdSRui Paulo IEEE80211_ADDR_COPY(rts->i_ta, ta); 283032176cfdSRui Paulo 283132176cfdSRui Paulo m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); 283232176cfdSRui Paulo } 283332176cfdSRui Paulo return m; 283432176cfdSRui Paulo } 283532176cfdSRui Paulo 283632176cfdSRui Paulo /* 283732176cfdSRui Paulo * Allocate and build a CTS (Clear To Send) control frame. 283832176cfdSRui Paulo */ 283932176cfdSRui Paulo struct mbuf * 284032176cfdSRui Paulo ieee80211_alloc_cts(struct ieee80211com *ic, 284132176cfdSRui Paulo const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) 284232176cfdSRui Paulo { 284332176cfdSRui Paulo struct ieee80211_frame_cts *cts; 284432176cfdSRui Paulo struct mbuf *m; 284532176cfdSRui Paulo 284632176cfdSRui Paulo /* XXX honor ic_headroom */ 2847b5523eacSSascha Wildner m = m_gethdr(M_NOWAIT, MT_DATA); 284832176cfdSRui Paulo if (m != NULL) { 284932176cfdSRui Paulo cts = mtod(m, struct ieee80211_frame_cts *); 285032176cfdSRui Paulo cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 285132176cfdSRui Paulo IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; 285232176cfdSRui Paulo cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 285332176cfdSRui Paulo *(u_int16_t *)cts->i_dur = htole16(dur); 285432176cfdSRui Paulo IEEE80211_ADDR_COPY(cts->i_ra, ra); 285532176cfdSRui Paulo 285632176cfdSRui Paulo m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); 285732176cfdSRui Paulo } 285832176cfdSRui Paulo return m; 285932176cfdSRui Paulo } 286032176cfdSRui Paulo 286132176cfdSRui Paulo static void 2862085ff963SMatthew Dillon ieee80211_tx_mgt_timeout(void *arg) 286332176cfdSRui Paulo { 2864085ff963SMatthew Dillon struct ieee80211vap *vap = arg; 286532176cfdSRui Paulo 2866085ff963SMatthew Dillon IEEE80211_LOCK(vap->iv_ic); 286732176cfdSRui Paulo if (vap->iv_state != IEEE80211_S_INIT && 286832176cfdSRui Paulo (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { 286932176cfdSRui Paulo /* 287032176cfdSRui Paulo * NB: it's safe to specify a timeout as the reason here; 287132176cfdSRui Paulo * it'll only be used in the right state. 287232176cfdSRui Paulo */ 2873085ff963SMatthew Dillon ieee80211_new_state_locked(vap, IEEE80211_S_SCAN, 287432176cfdSRui Paulo IEEE80211_SCAN_FAIL_TIMEOUT); 287532176cfdSRui Paulo } 2876085ff963SMatthew Dillon IEEE80211_UNLOCK(vap->iv_ic); 287732176cfdSRui Paulo } 287832176cfdSRui Paulo 2879085ff963SMatthew Dillon /* 2880085ff963SMatthew Dillon * This is the callback set on net80211-sourced transmitted 2881085ff963SMatthew Dillon * authentication request frames. 2882085ff963SMatthew Dillon * 2883085ff963SMatthew Dillon * This does a couple of things: 2884085ff963SMatthew Dillon * 2885085ff963SMatthew Dillon * + If the frame transmitted was a success, it schedules a future 2886085ff963SMatthew Dillon * event which will transition the interface to scan. 2887085ff963SMatthew Dillon * If a state transition _then_ occurs before that event occurs, 2888085ff963SMatthew Dillon * said state transition will cancel this callout. 2889085ff963SMatthew Dillon * 2890085ff963SMatthew Dillon * + If the frame transmit was a failure, it immediately schedules 2891085ff963SMatthew Dillon * the transition back to scan. 2892085ff963SMatthew Dillon */ 289332176cfdSRui Paulo static void 289432176cfdSRui Paulo ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) 289532176cfdSRui Paulo { 289632176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 289732176cfdSRui Paulo enum ieee80211_state ostate = (enum ieee80211_state) arg; 289832176cfdSRui Paulo 289932176cfdSRui Paulo /* 290032176cfdSRui Paulo * Frame transmit completed; arrange timer callback. If 290132176cfdSRui Paulo * transmit was successfuly we wait for response. Otherwise 290232176cfdSRui Paulo * we arrange an immediate callback instead of doing the 290332176cfdSRui Paulo * callback directly since we don't know what state the driver 290432176cfdSRui Paulo * is in (e.g. what locks it is holding). This work should 290532176cfdSRui Paulo * not be too time-critical and not happen too often so the 290632176cfdSRui Paulo * added overhead is acceptable. 290732176cfdSRui Paulo * 290832176cfdSRui Paulo * XXX what happens if !acked but response shows up before callback? 290932176cfdSRui Paulo */ 2910085ff963SMatthew Dillon if (vap->iv_state == ostate) { 291132176cfdSRui Paulo callout_reset(&vap->iv_mgtsend, 291232176cfdSRui Paulo status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, 2913085ff963SMatthew Dillon ieee80211_tx_mgt_timeout, vap); 2914085ff963SMatthew Dillon } 291532176cfdSRui Paulo } 291632176cfdSRui Paulo 291732176cfdSRui Paulo static void 291832176cfdSRui Paulo ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, 291932176cfdSRui Paulo struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni) 292032176cfdSRui Paulo { 292132176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 292232176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 292332176cfdSRui Paulo struct ieee80211_rateset *rs = &ni->ni_rates; 2924841ab66cSSepherosa Ziehau uint16_t capinfo; 2925841ab66cSSepherosa Ziehau 2926841ab66cSSepherosa Ziehau /* 2927841ab66cSSepherosa Ziehau * beacon frame format 2928841ab66cSSepherosa Ziehau * [8] time stamp 2929841ab66cSSepherosa Ziehau * [2] beacon interval 2930841ab66cSSepherosa Ziehau * [2] cabability information 2931841ab66cSSepherosa Ziehau * [tlv] ssid 2932841ab66cSSepherosa Ziehau * [tlv] supported rates 2933841ab66cSSepherosa Ziehau * [3] parameter set (DS) 293432176cfdSRui Paulo * [8] CF parameter set (optional) 2935841ab66cSSepherosa Ziehau * [tlv] parameter set (IBSS/TIM) 293632176cfdSRui Paulo * [tlv] country (optional) 293732176cfdSRui Paulo * [3] power control (optional) 293832176cfdSRui Paulo * [5] channel switch announcement (CSA) (optional) 2939841ab66cSSepherosa Ziehau * [tlv] extended rate phy (ERP) 2940841ab66cSSepherosa Ziehau * [tlv] extended supported rates 294132176cfdSRui Paulo * [tlv] RSN parameters 294232176cfdSRui Paulo * [tlv] HT capabilities 294332176cfdSRui Paulo * [tlv] HT information 2944841ab66cSSepherosa Ziehau * XXX Vendor-specific OIDs (e.g. Atheros) 294532176cfdSRui Paulo * [tlv] WPA parameters 294632176cfdSRui Paulo * [tlv] WME parameters 294732176cfdSRui Paulo * [tlv] Vendor OUI HT capabilities (optional) 294832176cfdSRui Paulo * [tlv] Vendor OUI HT information (optional) 294932176cfdSRui Paulo * [tlv] Atheros capabilities (optional) 295032176cfdSRui Paulo * [tlv] TDMA parameters (optional) 295132176cfdSRui Paulo * [tlv] Mesh ID (MBSS) 295232176cfdSRui Paulo * [tlv] Mesh Conf (MBSS) 295332176cfdSRui Paulo * [tlv] application data (optional) 2954841ab66cSSepherosa Ziehau */ 295532176cfdSRui Paulo 295632176cfdSRui Paulo memset(bo, 0, sizeof(*bo)); 2957841ab66cSSepherosa Ziehau 2958841ab66cSSepherosa Ziehau memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ 2959841ab66cSSepherosa Ziehau frm += 8; 2960841ab66cSSepherosa Ziehau *(uint16_t *)frm = htole16(ni->ni_intval); 2961841ab66cSSepherosa Ziehau frm += 2; 296232176cfdSRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 2963841ab66cSSepherosa Ziehau bo->bo_caps = (uint16_t *)frm; 2964841ab66cSSepherosa Ziehau *(uint16_t *)frm = htole16(capinfo); 2965841ab66cSSepherosa Ziehau frm += 2; 2966841ab66cSSepherosa Ziehau *frm++ = IEEE80211_ELEMID_SSID; 296732176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { 2968841ab66cSSepherosa Ziehau *frm++ = ni->ni_esslen; 2969841ab66cSSepherosa Ziehau memcpy(frm, ni->ni_essid, ni->ni_esslen); 2970841ab66cSSepherosa Ziehau frm += ni->ni_esslen; 2971841ab66cSSepherosa Ziehau } else 2972841ab66cSSepherosa Ziehau *frm++ = 0; 2973841ab66cSSepherosa Ziehau frm = ieee80211_add_rates(frm, rs); 297432176cfdSRui Paulo if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { 2975841ab66cSSepherosa Ziehau *frm++ = IEEE80211_ELEMID_DSPARMS; 2976841ab66cSSepherosa Ziehau *frm++ = 1; 2977841ab66cSSepherosa Ziehau *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); 2978841ab66cSSepherosa Ziehau } 297932176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_PCF) { 298032176cfdSRui Paulo bo->bo_cfp = frm; 298132176cfdSRui Paulo frm = ieee80211_add_cfparms(frm, ic); 298232176cfdSRui Paulo } 2983841ab66cSSepherosa Ziehau bo->bo_tim = frm; 298432176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_IBSS) { 2985841ab66cSSepherosa Ziehau *frm++ = IEEE80211_ELEMID_IBSSPARMS; 2986841ab66cSSepherosa Ziehau *frm++ = 2; 2987841ab66cSSepherosa Ziehau *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 2988841ab66cSSepherosa Ziehau bo->bo_tim_len = 0; 298932176cfdSRui Paulo } else if (vap->iv_opmode == IEEE80211_M_HOSTAP || 299032176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { 299132176cfdSRui Paulo /* TIM IE is the same for Mesh and Hostap */ 2992841ab66cSSepherosa Ziehau struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; 2993841ab66cSSepherosa Ziehau 2994841ab66cSSepherosa Ziehau tie->tim_ie = IEEE80211_ELEMID_TIM; 2995841ab66cSSepherosa Ziehau tie->tim_len = 4; /* length */ 2996841ab66cSSepherosa Ziehau tie->tim_count = 0; /* DTIM count */ 299732176cfdSRui Paulo tie->tim_period = vap->iv_dtim_period; /* DTIM period */ 2998841ab66cSSepherosa Ziehau tie->tim_bitctl = 0; /* bitmap control */ 2999841ab66cSSepherosa Ziehau tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 3000841ab66cSSepherosa Ziehau frm += sizeof(struct ieee80211_tim_ie); 3001841ab66cSSepherosa Ziehau bo->bo_tim_len = 1; 3002841ab66cSSepherosa Ziehau } 300332176cfdSRui Paulo bo->bo_tim_trailer = frm; 300432176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_DOTH) || 300532176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 300632176cfdSRui Paulo frm = ieee80211_add_countryie(frm, ic); 300732176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_DOTH) { 300832176cfdSRui Paulo if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 300932176cfdSRui Paulo frm = ieee80211_add_powerconstraint(frm, vap); 301032176cfdSRui Paulo bo->bo_csa = frm; 301132176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_CSAPENDING) 301232176cfdSRui Paulo frm = ieee80211_add_csa(frm, vap); 301332176cfdSRui Paulo } else 301432176cfdSRui Paulo bo->bo_csa = frm; 3015085ff963SMatthew Dillon 3016085ff963SMatthew Dillon if (vap->iv_flags & IEEE80211_F_DOTH) { 3017085ff963SMatthew Dillon bo->bo_quiet = frm; 3018085ff963SMatthew Dillon if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 3019085ff963SMatthew Dillon (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 3020085ff963SMatthew Dillon if (vap->iv_quiet) 3021085ff963SMatthew Dillon frm = ieee80211_add_quiet(frm,vap); 3022085ff963SMatthew Dillon } 3023085ff963SMatthew Dillon } else 3024085ff963SMatthew Dillon bo->bo_quiet = frm; 3025085ff963SMatthew Dillon 302632176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { 3027841ab66cSSepherosa Ziehau bo->bo_erp = frm; 3028841ab66cSSepherosa Ziehau frm = ieee80211_add_erp(frm, ic); 3029841ab66cSSepherosa Ziehau } 303032176cfdSRui Paulo frm = ieee80211_add_xrates(frm, rs); 3031085ff963SMatthew Dillon frm = ieee80211_add_rsn(frm, vap); 303232176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { 303332176cfdSRui Paulo frm = ieee80211_add_htcap(frm, ni); 303432176cfdSRui Paulo bo->bo_htinfo = frm; 303532176cfdSRui Paulo frm = ieee80211_add_htinfo(frm, ni); 303632176cfdSRui Paulo } 3037085ff963SMatthew Dillon frm = ieee80211_add_wpa(frm, vap); 303832176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_WME) { 303932176cfdSRui Paulo bo->bo_wme = frm; 304032176cfdSRui Paulo frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 304132176cfdSRui Paulo } 304232176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && 304332176cfdSRui Paulo (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) { 304432176cfdSRui Paulo frm = ieee80211_add_htcap_vendor(frm, ni); 304532176cfdSRui Paulo frm = ieee80211_add_htinfo_vendor(frm, ni); 304632176cfdSRui Paulo } 304732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 304832176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_ATHEROS) { 304932176cfdSRui Paulo bo->bo_ath = frm; 305032176cfdSRui Paulo frm = ieee80211_add_athcaps(frm, ni); 305132176cfdSRui Paulo } 305232176cfdSRui Paulo #endif 305332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 305432176cfdSRui Paulo if (vap->iv_caps & IEEE80211_C_TDMA) { 305532176cfdSRui Paulo bo->bo_tdma = frm; 305632176cfdSRui Paulo frm = ieee80211_add_tdma(frm, vap); 305732176cfdSRui Paulo } 305832176cfdSRui Paulo #endif 305932176cfdSRui Paulo if (vap->iv_appie_beacon != NULL) { 306032176cfdSRui Paulo bo->bo_appie = frm; 306132176cfdSRui Paulo bo->bo_appie_len = vap->iv_appie_beacon->ie_len; 306232176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_beacon); 306332176cfdSRui Paulo } 306432176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 306532176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 306632176cfdSRui Paulo frm = ieee80211_add_meshid(frm, vap); 306732176cfdSRui Paulo bo->bo_meshconf = frm; 306832176cfdSRui Paulo frm = ieee80211_add_meshconf(frm, vap); 306932176cfdSRui Paulo } 307032176cfdSRui Paulo #endif 307132176cfdSRui Paulo bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; 307232176cfdSRui Paulo bo->bo_csa_trailer_len = frm - bo->bo_csa; 307332176cfdSRui Paulo m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 307432176cfdSRui Paulo } 307532176cfdSRui Paulo 307632176cfdSRui Paulo /* 307732176cfdSRui Paulo * Allocate a beacon frame and fillin the appropriate bits. 307832176cfdSRui Paulo */ 307932176cfdSRui Paulo struct mbuf * 308032176cfdSRui Paulo ieee80211_beacon_alloc(struct ieee80211_node *ni, 308132176cfdSRui Paulo struct ieee80211_beacon_offsets *bo) 308232176cfdSRui Paulo { 308332176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 308432176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 308532176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp; 308632176cfdSRui Paulo struct ieee80211_frame *wh; 308732176cfdSRui Paulo struct mbuf *m; 308832176cfdSRui Paulo int pktlen; 308932176cfdSRui Paulo uint8_t *frm; 309032176cfdSRui Paulo 309132176cfdSRui Paulo /* 309232176cfdSRui Paulo * beacon frame format 309332176cfdSRui Paulo * [8] time stamp 309432176cfdSRui Paulo * [2] beacon interval 309532176cfdSRui Paulo * [2] cabability information 309632176cfdSRui Paulo * [tlv] ssid 309732176cfdSRui Paulo * [tlv] supported rates 309832176cfdSRui Paulo * [3] parameter set (DS) 309932176cfdSRui Paulo * [8] CF parameter set (optional) 310032176cfdSRui Paulo * [tlv] parameter set (IBSS/TIM) 310132176cfdSRui Paulo * [tlv] country (optional) 310232176cfdSRui Paulo * [3] power control (optional) 310332176cfdSRui Paulo * [5] channel switch announcement (CSA) (optional) 310432176cfdSRui Paulo * [tlv] extended rate phy (ERP) 310532176cfdSRui Paulo * [tlv] extended supported rates 310632176cfdSRui Paulo * [tlv] RSN parameters 310732176cfdSRui Paulo * [tlv] HT capabilities 310832176cfdSRui Paulo * [tlv] HT information 310932176cfdSRui Paulo * [tlv] Vendor OUI HT capabilities (optional) 311032176cfdSRui Paulo * [tlv] Vendor OUI HT information (optional) 311132176cfdSRui Paulo * XXX Vendor-specific OIDs (e.g. Atheros) 311232176cfdSRui Paulo * [tlv] WPA parameters 311332176cfdSRui Paulo * [tlv] WME parameters 311432176cfdSRui Paulo * [tlv] TDMA parameters (optional) 311532176cfdSRui Paulo * [tlv] Mesh ID (MBSS) 311632176cfdSRui Paulo * [tlv] Mesh Conf (MBSS) 311732176cfdSRui Paulo * [tlv] application data (optional) 311832176cfdSRui Paulo * NB: we allocate the max space required for the TIM bitmap. 311932176cfdSRui Paulo * XXX how big is this? 312032176cfdSRui Paulo */ 312132176cfdSRui Paulo pktlen = 8 /* time stamp */ 312232176cfdSRui Paulo + sizeof(uint16_t) /* beacon interval */ 312332176cfdSRui Paulo + sizeof(uint16_t) /* capabilities */ 312432176cfdSRui Paulo + 2 + ni->ni_esslen /* ssid */ 312532176cfdSRui Paulo + 2 + IEEE80211_RATE_SIZE /* supported rates */ 312632176cfdSRui Paulo + 2 + 1 /* DS parameters */ 312732176cfdSRui Paulo + 2 + 6 /* CF parameters */ 312832176cfdSRui Paulo + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ 312932176cfdSRui Paulo + IEEE80211_COUNTRY_MAX_SIZE /* country */ 313032176cfdSRui Paulo + 2 + 1 /* power control */ 313132176cfdSRui Paulo + sizeof(struct ieee80211_csa_ie) /* CSA */ 3132085ff963SMatthew Dillon + sizeof(struct ieee80211_quiet_ie) /* Quiet */ 313332176cfdSRui Paulo + 2 + 1 /* ERP */ 313432176cfdSRui Paulo + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 313532176cfdSRui Paulo + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 313632176cfdSRui Paulo 2*sizeof(struct ieee80211_ie_wpa) : 0) 313732176cfdSRui Paulo /* XXX conditional? */ 313832176cfdSRui Paulo + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ 313932176cfdSRui Paulo + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ 314032176cfdSRui Paulo + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ 314132176cfdSRui Paulo sizeof(struct ieee80211_wme_param) : 0) 314232176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 314332176cfdSRui Paulo + sizeof(struct ieee80211_ath_ie) /* ATH */ 314432176cfdSRui Paulo #endif 314532176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 314632176cfdSRui Paulo + (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */ 314732176cfdSRui Paulo sizeof(struct ieee80211_tdma_param) : 0) 314832176cfdSRui Paulo #endif 314932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 315032176cfdSRui Paulo + 2 + ni->ni_meshidlen 315132176cfdSRui Paulo + sizeof(struct ieee80211_meshconf_ie) 315232176cfdSRui Paulo #endif 315332176cfdSRui Paulo + IEEE80211_MAX_APPIE 315432176cfdSRui Paulo ; 315532176cfdSRui Paulo m = ieee80211_getmgtframe(&frm, 315632176cfdSRui Paulo ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); 315732176cfdSRui Paulo if (m == NULL) { 315832176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 315932176cfdSRui Paulo "%s: cannot get buf; size %u\n", __func__, pktlen); 316032176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 316132176cfdSRui Paulo return NULL; 316232176cfdSRui Paulo } 316332176cfdSRui Paulo ieee80211_beacon_construct(m, frm, bo, ni); 3164841ab66cSSepherosa Ziehau 3165b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 3166841ab66cSSepherosa Ziehau KASSERT(m != NULL, ("no space for 802.11 header?")); 3167841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *); 3168841ab66cSSepherosa Ziehau wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 3169841ab66cSSepherosa Ziehau IEEE80211_FC0_SUBTYPE_BEACON; 3170841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 3171841ab66cSSepherosa Ziehau *(uint16_t *)wh->i_dur = 0; 3172841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 317332176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 3174841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 3175841ab66cSSepherosa Ziehau *(uint16_t *)wh->i_seq = 0; 3176841ab66cSSepherosa Ziehau 3177841ab66cSSepherosa Ziehau return m; 3178841ab66cSSepherosa Ziehau } 3179841ab66cSSepherosa Ziehau 3180841ab66cSSepherosa Ziehau /* 3181841ab66cSSepherosa Ziehau * Update the dynamic parts of a beacon frame based on the current state. 3182841ab66cSSepherosa Ziehau */ 3183841ab66cSSepherosa Ziehau int 318432176cfdSRui Paulo ieee80211_beacon_update(struct ieee80211_node *ni, 3185841ab66cSSepherosa Ziehau struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) 3186841ab66cSSepherosa Ziehau { 318732176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 318832176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 3189841ab66cSSepherosa Ziehau int len_changed = 0; 3190841ab66cSSepherosa Ziehau uint16_t capinfo; 3191085ff963SMatthew Dillon struct ieee80211_frame *wh; 3192085ff963SMatthew Dillon ieee80211_seq seqno; 3193841ab66cSSepherosa Ziehau 3194085ff963SMatthew Dillon IEEE80211_LOCK(ic); 319532176cfdSRui Paulo /* 319632176cfdSRui Paulo * Handle 11h channel change when we've reached the count. 319732176cfdSRui Paulo * We must recalculate the beacon frame contents to account 319832176cfdSRui Paulo * for the new channel. Note we do this only for the first 319932176cfdSRui Paulo * vap that reaches this point; subsequent vaps just update 320032176cfdSRui Paulo * their beacon state to reflect the recalculated channel. 320132176cfdSRui Paulo */ 320232176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && 320332176cfdSRui Paulo vap->iv_csa_count == ic->ic_csa_count) { 320432176cfdSRui Paulo vap->iv_csa_count = 0; 320532176cfdSRui Paulo /* 320632176cfdSRui Paulo * Effect channel change before reconstructing the beacon 320732176cfdSRui Paulo * frame contents as many places reference ni_chan. 320832176cfdSRui Paulo */ 320932176cfdSRui Paulo if (ic->ic_csa_newchan != NULL) 321032176cfdSRui Paulo ieee80211_csa_completeswitch(ic); 321132176cfdSRui Paulo /* 321232176cfdSRui Paulo * NB: ieee80211_beacon_construct clears all pending 321332176cfdSRui Paulo * updates in bo_flags so we don't need to explicitly 321432176cfdSRui Paulo * clear IEEE80211_BEACON_CSA. 321532176cfdSRui Paulo */ 321632176cfdSRui Paulo ieee80211_beacon_construct(m, 321732176cfdSRui Paulo mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni); 321832176cfdSRui Paulo 321932176cfdSRui Paulo /* XXX do WME aggressive mode processing? */ 3220085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 322132176cfdSRui Paulo return 1; /* just assume length changed */ 322232176cfdSRui Paulo } 3223841ab66cSSepherosa Ziehau 3224085ff963SMatthew Dillon wh = mtod(m, struct ieee80211_frame *); 3225085ff963SMatthew Dillon seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 3226085ff963SMatthew Dillon *(uint16_t *)&wh->i_seq[0] = 3227085ff963SMatthew Dillon htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 3228085ff963SMatthew Dillon M_SEQNO_SET(m, seqno); 3229085ff963SMatthew Dillon 3230841ab66cSSepherosa Ziehau /* XXX faster to recalculate entirely or just changes? */ 323132176cfdSRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 3232841ab66cSSepherosa Ziehau *bo->bo_caps = htole16(capinfo); 3233841ab66cSSepherosa Ziehau 323432176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_WME) { 3235841ab66cSSepherosa Ziehau struct ieee80211_wme_state *wme = &ic->ic_wme; 3236841ab66cSSepherosa Ziehau 3237841ab66cSSepherosa Ziehau /* 3238841ab66cSSepherosa Ziehau * Check for agressive mode change. When there is 3239841ab66cSSepherosa Ziehau * significant high priority traffic in the BSS 3240841ab66cSSepherosa Ziehau * throttle back BE traffic by using conservative 3241841ab66cSSepherosa Ziehau * parameters. Otherwise BE uses agressive params 3242841ab66cSSepherosa Ziehau * to optimize performance of legacy/non-QoS traffic. 3243841ab66cSSepherosa Ziehau */ 3244841ab66cSSepherosa Ziehau if (wme->wme_flags & WME_F_AGGRMODE) { 3245841ab66cSSepherosa Ziehau if (wme->wme_hipri_traffic > 3246841ab66cSSepherosa Ziehau wme->wme_hipri_switch_thresh) { 324732176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 3248841ab66cSSepherosa Ziehau "%s: traffic %u, disable aggressive mode\n", 3249841ab66cSSepherosa Ziehau __func__, wme->wme_hipri_traffic); 3250841ab66cSSepherosa Ziehau wme->wme_flags &= ~WME_F_AGGRMODE; 325132176cfdSRui Paulo ieee80211_wme_updateparams_locked(vap); 3252841ab66cSSepherosa Ziehau wme->wme_hipri_traffic = 3253841ab66cSSepherosa Ziehau wme->wme_hipri_switch_hysteresis; 3254841ab66cSSepherosa Ziehau } else 3255841ab66cSSepherosa Ziehau wme->wme_hipri_traffic = 0; 3256841ab66cSSepherosa Ziehau } else { 3257841ab66cSSepherosa Ziehau if (wme->wme_hipri_traffic <= 3258841ab66cSSepherosa Ziehau wme->wme_hipri_switch_thresh) { 325932176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 3260841ab66cSSepherosa Ziehau "%s: traffic %u, enable aggressive mode\n", 3261841ab66cSSepherosa Ziehau __func__, wme->wme_hipri_traffic); 3262841ab66cSSepherosa Ziehau wme->wme_flags |= WME_F_AGGRMODE; 326332176cfdSRui Paulo ieee80211_wme_updateparams_locked(vap); 3264841ab66cSSepherosa Ziehau wme->wme_hipri_traffic = 0; 3265841ab66cSSepherosa Ziehau } else 3266841ab66cSSepherosa Ziehau wme->wme_hipri_traffic = 3267841ab66cSSepherosa Ziehau wme->wme_hipri_switch_hysteresis; 3268841ab66cSSepherosa Ziehau } 326932176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { 3270841ab66cSSepherosa Ziehau (void) ieee80211_add_wme_param(bo->bo_wme, wme); 327132176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_WME); 3272841ab66cSSepherosa Ziehau } 3273841ab66cSSepherosa Ziehau } 3274841ab66cSSepherosa Ziehau 327532176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { 327632176cfdSRui Paulo ieee80211_ht_update_beacon(vap, bo); 327732176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); 327832176cfdSRui Paulo } 327932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 328032176cfdSRui Paulo if (vap->iv_caps & IEEE80211_C_TDMA) { 328132176cfdSRui Paulo /* 328232176cfdSRui Paulo * NB: the beacon is potentially updated every TBTT. 328332176cfdSRui Paulo */ 328432176cfdSRui Paulo ieee80211_tdma_update_beacon(vap, bo); 328532176cfdSRui Paulo } 328632176cfdSRui Paulo #endif 328732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 328832176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 328932176cfdSRui Paulo ieee80211_mesh_update_beacon(vap, bo); 329032176cfdSRui Paulo #endif 329132176cfdSRui Paulo 329232176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP || 329332176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/ 3294841ab66cSSepherosa Ziehau struct ieee80211_tim_ie *tie = 3295841ab66cSSepherosa Ziehau (struct ieee80211_tim_ie *) bo->bo_tim; 329632176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { 3297841ab66cSSepherosa Ziehau u_int timlen, timoff, i; 3298841ab66cSSepherosa Ziehau /* 3299841ab66cSSepherosa Ziehau * ATIM/DTIM needs updating. If it fits in the 3300841ab66cSSepherosa Ziehau * current space allocated then just copy in the 3301841ab66cSSepherosa Ziehau * new bits. Otherwise we need to move any trailing 3302841ab66cSSepherosa Ziehau * data to make room. Note that we know there is 3303841ab66cSSepherosa Ziehau * contiguous space because ieee80211_beacon_allocate 3304841ab66cSSepherosa Ziehau * insures there is space in the mbuf to write a 330532176cfdSRui Paulo * maximal-size virtual bitmap (based on iv_max_aid). 3306841ab66cSSepherosa Ziehau */ 3307841ab66cSSepherosa Ziehau /* 3308841ab66cSSepherosa Ziehau * Calculate the bitmap size and offset, copy any 3309841ab66cSSepherosa Ziehau * trailer out of the way, and then copy in the 3310841ab66cSSepherosa Ziehau * new bitmap and update the information element. 3311841ab66cSSepherosa Ziehau * Note that the tim bitmap must contain at least 3312841ab66cSSepherosa Ziehau * one byte and any offset must be even. 3313841ab66cSSepherosa Ziehau */ 331432176cfdSRui Paulo if (vap->iv_ps_pending != 0) { 3315841ab66cSSepherosa Ziehau timoff = 128; /* impossibly large */ 331632176cfdSRui Paulo for (i = 0; i < vap->iv_tim_len; i++) 331732176cfdSRui Paulo if (vap->iv_tim_bitmap[i]) { 3318841ab66cSSepherosa Ziehau timoff = i &~ 1; 3319841ab66cSSepherosa Ziehau break; 3320841ab66cSSepherosa Ziehau } 3321841ab66cSSepherosa Ziehau KASSERT(timoff != 128, ("tim bitmap empty!")); 332232176cfdSRui Paulo for (i = vap->iv_tim_len-1; i >= timoff; i--) 332332176cfdSRui Paulo if (vap->iv_tim_bitmap[i]) 3324841ab66cSSepherosa Ziehau break; 3325841ab66cSSepherosa Ziehau timlen = 1 + (i - timoff); 3326841ab66cSSepherosa Ziehau } else { 3327841ab66cSSepherosa Ziehau timoff = 0; 3328841ab66cSSepherosa Ziehau timlen = 1; 3329841ab66cSSepherosa Ziehau } 3330841ab66cSSepherosa Ziehau if (timlen != bo->bo_tim_len) { 3331841ab66cSSepherosa Ziehau /* copy up/down trailer */ 3332841ab66cSSepherosa Ziehau int adjust = tie->tim_bitmap+timlen 333332176cfdSRui Paulo - bo->bo_tim_trailer; 333432176cfdSRui Paulo ovbcopy(bo->bo_tim_trailer, 333532176cfdSRui Paulo bo->bo_tim_trailer+adjust, 333632176cfdSRui Paulo bo->bo_tim_trailer_len); 333732176cfdSRui Paulo bo->bo_tim_trailer += adjust; 3338841ab66cSSepherosa Ziehau bo->bo_erp += adjust; 333932176cfdSRui Paulo bo->bo_htinfo += adjust; 3340085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_SUPERG 334132176cfdSRui Paulo bo->bo_ath += adjust; 334232176cfdSRui Paulo #endif 3343085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_TDMA 334432176cfdSRui Paulo bo->bo_tdma += adjust; 334532176cfdSRui Paulo #endif 3346085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 334732176cfdSRui Paulo bo->bo_meshconf += adjust; 334832176cfdSRui Paulo #endif 334932176cfdSRui Paulo bo->bo_appie += adjust; 335032176cfdSRui Paulo bo->bo_wme += adjust; 335132176cfdSRui Paulo bo->bo_csa += adjust; 3352085ff963SMatthew Dillon bo->bo_quiet += adjust; 3353841ab66cSSepherosa Ziehau bo->bo_tim_len = timlen; 3354841ab66cSSepherosa Ziehau 3355841ab66cSSepherosa Ziehau /* update information element */ 3356841ab66cSSepherosa Ziehau tie->tim_len = 3 + timlen; 3357841ab66cSSepherosa Ziehau tie->tim_bitctl = timoff; 3358841ab66cSSepherosa Ziehau len_changed = 1; 3359841ab66cSSepherosa Ziehau } 336032176cfdSRui Paulo memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, 3361841ab66cSSepherosa Ziehau bo->bo_tim_len); 3362841ab66cSSepherosa Ziehau 336332176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); 3364841ab66cSSepherosa Ziehau 336532176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 3366841ab66cSSepherosa Ziehau "%s: TIM updated, pending %u, off %u, len %u\n", 336732176cfdSRui Paulo __func__, vap->iv_ps_pending, timoff, timlen); 3368841ab66cSSepherosa Ziehau } 3369841ab66cSSepherosa Ziehau /* count down DTIM period */ 3370841ab66cSSepherosa Ziehau if (tie->tim_count == 0) 3371841ab66cSSepherosa Ziehau tie->tim_count = tie->tim_period - 1; 3372841ab66cSSepherosa Ziehau else 3373841ab66cSSepherosa Ziehau tie->tim_count--; 3374841ab66cSSepherosa Ziehau /* update state for buffered multicast frames on DTIM */ 3375841ab66cSSepherosa Ziehau if (mcast && tie->tim_count == 0) 3376841ab66cSSepherosa Ziehau tie->tim_bitctl |= 1; 3377841ab66cSSepherosa Ziehau else 3378841ab66cSSepherosa Ziehau tie->tim_bitctl &= ~1; 337932176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { 338032176cfdSRui Paulo struct ieee80211_csa_ie *csa = 338132176cfdSRui Paulo (struct ieee80211_csa_ie *) bo->bo_csa; 338232176cfdSRui Paulo 338332176cfdSRui Paulo /* 338432176cfdSRui Paulo * Insert or update CSA ie. If we're just starting 338532176cfdSRui Paulo * to count down to the channel switch then we need 338632176cfdSRui Paulo * to insert the CSA ie. Otherwise we just need to 338732176cfdSRui Paulo * drop the count. The actual change happens above 338832176cfdSRui Paulo * when the vap's count reaches the target count. 338932176cfdSRui Paulo */ 339032176cfdSRui Paulo if (vap->iv_csa_count == 0) { 339132176cfdSRui Paulo memmove(&csa[1], csa, bo->bo_csa_trailer_len); 339232176cfdSRui Paulo bo->bo_erp += sizeof(*csa); 339332176cfdSRui Paulo bo->bo_htinfo += sizeof(*csa); 339432176cfdSRui Paulo bo->bo_wme += sizeof(*csa); 3395085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_SUPERG 339632176cfdSRui Paulo bo->bo_ath += sizeof(*csa); 339732176cfdSRui Paulo #endif 3398085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_TDMA 339932176cfdSRui Paulo bo->bo_tdma += sizeof(*csa); 340032176cfdSRui Paulo #endif 3401085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 340232176cfdSRui Paulo bo->bo_meshconf += sizeof(*csa); 340332176cfdSRui Paulo #endif 340432176cfdSRui Paulo bo->bo_appie += sizeof(*csa); 340532176cfdSRui Paulo bo->bo_csa_trailer_len += sizeof(*csa); 3406085ff963SMatthew Dillon bo->bo_quiet += sizeof(*csa); 340732176cfdSRui Paulo bo->bo_tim_trailer_len += sizeof(*csa); 340832176cfdSRui Paulo m->m_len += sizeof(*csa); 340932176cfdSRui Paulo m->m_pkthdr.len += sizeof(*csa); 341032176cfdSRui Paulo 341132176cfdSRui Paulo ieee80211_add_csa(bo->bo_csa, vap); 341232176cfdSRui Paulo } else 341332176cfdSRui Paulo csa->csa_count--; 341432176cfdSRui Paulo vap->iv_csa_count++; 341532176cfdSRui Paulo /* NB: don't clear IEEE80211_BEACON_CSA */ 341632176cfdSRui Paulo } 3417085ff963SMatthew Dillon if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 3418085ff963SMatthew Dillon (vap->iv_flags_ext & IEEE80211_FEXT_DFS) ){ 3419085ff963SMatthew Dillon if (vap->iv_quiet) 3420085ff963SMatthew Dillon ieee80211_add_quiet(bo->bo_quiet, vap); 3421085ff963SMatthew Dillon } 342232176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { 3423841ab66cSSepherosa Ziehau /* 3424841ab66cSSepherosa Ziehau * ERP element needs updating. 3425841ab66cSSepherosa Ziehau */ 3426841ab66cSSepherosa Ziehau (void) ieee80211_add_erp(bo->bo_erp, ic); 342732176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); 3428841ab66cSSepherosa Ziehau } 342932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 343032176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_ATH)) { 343132176cfdSRui Paulo ieee80211_add_athcaps(bo->bo_ath, ni); 343232176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_ATH); 34336dd1c373SSepherosa Ziehau } 3434841ab66cSSepherosa Ziehau #endif 3435841ab66cSSepherosa Ziehau } 343632176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { 343732176cfdSRui Paulo const struct ieee80211_appie *aie = vap->iv_appie_beacon; 343832176cfdSRui Paulo int aielen; 343932176cfdSRui Paulo uint8_t *frm; 3440841ab66cSSepherosa Ziehau 344132176cfdSRui Paulo aielen = 0; 344232176cfdSRui Paulo if (aie != NULL) 344332176cfdSRui Paulo aielen += aie->ie_len; 344432176cfdSRui Paulo if (aielen != bo->bo_appie_len) { 344532176cfdSRui Paulo /* copy up/down trailer */ 344632176cfdSRui Paulo int adjust = aielen - bo->bo_appie_len; 344732176cfdSRui Paulo ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, 344832176cfdSRui Paulo bo->bo_tim_trailer_len); 344932176cfdSRui Paulo bo->bo_tim_trailer += adjust; 345032176cfdSRui Paulo bo->bo_appie += adjust; 345132176cfdSRui Paulo bo->bo_appie_len = aielen; 3452841ab66cSSepherosa Ziehau 345332176cfdSRui Paulo len_changed = 1; 3454841ab66cSSepherosa Ziehau } 345532176cfdSRui Paulo frm = bo->bo_appie; 345632176cfdSRui Paulo if (aie != NULL) 345732176cfdSRui Paulo frm = add_appie(frm, aie); 345832176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); 34592d7dda79SSepherosa Ziehau } 3460085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 34612d7dda79SSepherosa Ziehau 346232176cfdSRui Paulo return len_changed; 3463322b19a8SSepherosa Ziehau } 3464085ff963SMatthew Dillon 3465085ff963SMatthew Dillon /* 3466085ff963SMatthew Dillon * Do Ethernet-LLC encapsulation for each payload in a fast frame 3467085ff963SMatthew Dillon * tunnel encapsulation. The frame is assumed to have an Ethernet 3468085ff963SMatthew Dillon * header at the front that must be stripped before prepending the 3469085ff963SMatthew Dillon * LLC followed by the Ethernet header passed in (with an Ethernet 3470085ff963SMatthew Dillon * type that specifies the payload size). 3471085ff963SMatthew Dillon */ 3472085ff963SMatthew Dillon struct mbuf * 3473085ff963SMatthew Dillon ieee80211_ff_encap1(struct ieee80211vap *vap, struct mbuf *m, 3474085ff963SMatthew Dillon const struct ether_header *eh) 3475085ff963SMatthew Dillon { 3476085ff963SMatthew Dillon struct llc *llc; 3477085ff963SMatthew Dillon uint16_t payload; 3478085ff963SMatthew Dillon 3479085ff963SMatthew Dillon /* XXX optimize by combining m_adj+M_PREPEND */ 3480085ff963SMatthew Dillon m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 3481085ff963SMatthew Dillon llc = mtod(m, struct llc *); 3482085ff963SMatthew Dillon llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 3483085ff963SMatthew Dillon llc->llc_control = LLC_UI; 3484085ff963SMatthew Dillon llc->llc_snap.org_code[0] = 0; 3485085ff963SMatthew Dillon llc->llc_snap.org_code[1] = 0; 3486085ff963SMatthew Dillon llc->llc_snap.org_code[2] = 0; 3487085ff963SMatthew Dillon llc->llc_snap.ether_type = eh->ether_type; 3488085ff963SMatthew Dillon payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */ 3489085ff963SMatthew Dillon 3490b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ether_header), M_NOWAIT); 3491085ff963SMatthew Dillon if (m == NULL) { /* XXX cannot happen */ 3492085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 3493085ff963SMatthew Dillon "%s: no space for ether_header\n", __func__); 3494085ff963SMatthew Dillon vap->iv_stats.is_tx_nobuf++; 3495085ff963SMatthew Dillon return NULL; 3496085ff963SMatthew Dillon } 3497085ff963SMatthew Dillon ETHER_HEADER_COPY(mtod(m, void *), eh); 3498085ff963SMatthew Dillon mtod(m, struct ether_header *)->ether_type = htons(payload); 3499085ff963SMatthew Dillon return m; 3500085ff963SMatthew Dillon } 3501085ff963SMatthew Dillon 3502085ff963SMatthew Dillon /* 3503085ff963SMatthew Dillon * Complete an mbuf transmission. 3504085ff963SMatthew Dillon * 3505085ff963SMatthew Dillon * For now, this simply processes a completed frame after the 3506085ff963SMatthew Dillon * driver has completed it's transmission and/or retransmission. 3507085ff963SMatthew Dillon * It assumes the frame is an 802.11 encapsulated frame. 3508085ff963SMatthew Dillon * 3509085ff963SMatthew Dillon * Later on it will grow to become the exit path for a given frame 3510085ff963SMatthew Dillon * from the driver and, depending upon how it's been encapsulated 3511085ff963SMatthew Dillon * and already transmitted, it may end up doing A-MPDU retransmission, 3512085ff963SMatthew Dillon * power save requeuing, etc. 3513085ff963SMatthew Dillon * 3514085ff963SMatthew Dillon * In order for the above to work, the driver entry point to this 3515085ff963SMatthew Dillon * must not hold any driver locks. Thus, the driver needs to delay 3516085ff963SMatthew Dillon * any actual mbuf completion until it can release said locks. 3517085ff963SMatthew Dillon * 3518085ff963SMatthew Dillon * This frees the mbuf and if the mbuf has a node reference, 3519085ff963SMatthew Dillon * the node reference will be freed. 3520085ff963SMatthew Dillon */ 3521085ff963SMatthew Dillon void 3522085ff963SMatthew Dillon ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status) 3523085ff963SMatthew Dillon { 3524085ff963SMatthew Dillon 3525085ff963SMatthew Dillon if (ni != NULL) { 3526085ff963SMatthew Dillon if (m->m_flags & M_TXCB) 3527085ff963SMatthew Dillon ieee80211_process_callback(ni, m, status); 3528085ff963SMatthew Dillon ieee80211_free_node(ni); 3529085ff963SMatthew Dillon } 3530085ff963SMatthew Dillon m_freem(m); 3531085ff963SMatthew Dillon } 3532