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 /* XXX better status? */ 331085ff963SMatthew Dillon return (ENOBUFS); 332085ff963SMatthew Dillon } 333085ff963SMatthew Dillon if (vap->iv_opmode == IEEE80211_M_HOSTAP) { 334085ff963SMatthew Dillon /* 335085ff963SMatthew Dillon * Spam DWDS vap's w/ multicast traffic. 336085ff963SMatthew Dillon */ 337085ff963SMatthew Dillon /* XXX only if dwds in use? */ 338085ff963SMatthew Dillon ieee80211_dwds_mcast(vap, m); 339085ff963SMatthew Dillon ieee80211_dwds_mcast(vap, m); 340085ff963SMatthew Dillon } 341085ff963SMatthew Dillon } 342085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 343085ff963SMatthew Dillon if (vap->iv_opmode != IEEE80211_M_MBSS) { 344085ff963SMatthew Dillon #endif 345085ff963SMatthew Dillon ni = ieee80211_find_txnode(vap, eh->ether_dhost); 346085ff963SMatthew Dillon if (ni == NULL) { 347085ff963SMatthew Dillon /* NB: ieee80211_find_txnode does stat+msg */ 348085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 349085ff963SMatthew Dillon m_freem(m); 350085ff963SMatthew Dillon /* XXX better status? */ 351085ff963SMatthew Dillon return (ENOBUFS); 352085ff963SMatthew Dillon } 353085ff963SMatthew Dillon if (ni->ni_associd == 0 && 354085ff963SMatthew Dillon (ni->ni_flags & IEEE80211_NODE_ASSOCID)) { 355085ff963SMatthew Dillon IEEE80211_DISCARD_MAC(vap, IEEE80211_MSG_OUTPUT, 356085ff963SMatthew Dillon eh->ether_dhost, NULL, 357085ff963SMatthew Dillon "sta not associated (type 0x%04x)", 358085ff963SMatthew Dillon htons(eh->ether_type)); 359085ff963SMatthew Dillon vap->iv_stats.is_tx_notassoc++; 360085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 361085ff963SMatthew Dillon m_freem(m); 362085ff963SMatthew Dillon ieee80211_free_node(ni); 363085ff963SMatthew Dillon /* XXX better status? */ 364085ff963SMatthew Dillon return (ENOBUFS); 365085ff963SMatthew Dillon } 366085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 367085ff963SMatthew Dillon } else { 368085ff963SMatthew Dillon if (!IEEE80211_ADDR_EQ(eh->ether_shost, vap->iv_myaddr)) { 369085ff963SMatthew Dillon /* 370085ff963SMatthew Dillon * Proxy station only if configured. 371085ff963SMatthew Dillon */ 372085ff963SMatthew Dillon if (!ieee80211_mesh_isproxyena(vap)) { 373085ff963SMatthew Dillon IEEE80211_DISCARD_MAC(vap, 374085ff963SMatthew Dillon IEEE80211_MSG_OUTPUT | 375085ff963SMatthew Dillon IEEE80211_MSG_MESH, 376085ff963SMatthew Dillon eh->ether_dhost, NULL, 377085ff963SMatthew Dillon "%s", "proxy not enabled"); 378085ff963SMatthew Dillon vap->iv_stats.is_mesh_notproxy++; 379085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 380085ff963SMatthew Dillon m_freem(m); 381085ff963SMatthew Dillon /* XXX better status? */ 382085ff963SMatthew Dillon return (ENOBUFS); 383085ff963SMatthew Dillon } 384085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 385*f92fae3fSSascha Wildner "forward frame from DS SA(%s), DA(%s)\n", 386*f92fae3fSSascha Wildner ether_sprintf(eh->ether_shost), 387*f92fae3fSSascha Wildner ether_sprintf(eh->ether_dhost)); 388085ff963SMatthew Dillon ieee80211_mesh_proxy_check(vap, eh->ether_shost); 389085ff963SMatthew Dillon } 390085ff963SMatthew Dillon ni = ieee80211_mesh_discover(vap, eh->ether_dhost, m); 391085ff963SMatthew Dillon if (ni == NULL) { 392085ff963SMatthew Dillon /* 393085ff963SMatthew Dillon * NB: ieee80211_mesh_discover holds/disposes 394085ff963SMatthew Dillon * frame (e.g. queueing on path discovery). 395085ff963SMatthew Dillon */ 396085ff963SMatthew Dillon IFNET_STAT_INC(ifp, oerrors, 1); 397085ff963SMatthew Dillon /* XXX better status? */ 398085ff963SMatthew Dillon return (ENOBUFS); 399085ff963SMatthew Dillon } 400085ff963SMatthew Dillon } 401085ff963SMatthew Dillon #endif 402085ff963SMatthew Dillon 403085ff963SMatthew Dillon /* 404085ff963SMatthew Dillon * We've resolved the sender, so attempt to transmit it. 405085ff963SMatthew Dillon */ 406085ff963SMatthew Dillon 407085ff963SMatthew Dillon if (vap->iv_state == IEEE80211_S_SLEEP) { 408085ff963SMatthew Dillon /* 409085ff963SMatthew Dillon * In power save; queue frame and then wakeup device 410085ff963SMatthew Dillon * for transmit. 411085ff963SMatthew Dillon */ 412085ff963SMatthew Dillon ic->ic_lastdata = ticks; 413085ff963SMatthew Dillon (void) ieee80211_pwrsave(ni, m); 414085ff963SMatthew Dillon ieee80211_free_node(ni); 415085ff963SMatthew Dillon ieee80211_new_state(vap, IEEE80211_S_RUN, 0); 416085ff963SMatthew Dillon return (0); 417085ff963SMatthew Dillon } 418085ff963SMatthew Dillon 419085ff963SMatthew Dillon if (ieee80211_vap_pkt_send_dest(vap, m, ni) != 0) 420085ff963SMatthew Dillon return (ENOBUFS); 421085ff963SMatthew Dillon return (0); 42232176cfdSRui Paulo #undef IS_DWDS 42332176cfdSRui Paulo } 42432176cfdSRui Paulo 425085ff963SMatthew Dillon /* 426085ff963SMatthew Dillon * Start method for vap's. All packets from the stack come 427085ff963SMatthew Dillon * through here. We handle common processing of the packets 428085ff963SMatthew Dillon * before dispatching them to the underlying device. 429085ff963SMatthew Dillon * 430085ff963SMatthew Dillon * if_transmit() requires that the mbuf be consumed by this call 431085ff963SMatthew Dillon * regardless of the return condition. 432085ff963SMatthew Dillon */ 433085ff963SMatthew Dillon 434085ff963SMatthew Dillon #if defined(__DragonFly__) 435085ff963SMatthew Dillon 436085ff963SMatthew Dillon void 437085ff963SMatthew Dillon ieee80211_vap_start(struct ifnet *ifp, struct ifaltq_subque *ifsq) 438085ff963SMatthew Dillon { 439085ff963SMatthew Dillon struct ieee80211vap *vap = ifp->if_softc; 440085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 441085ff963SMatthew Dillon struct ifnet *parent = ic->ic_ifp; 442085ff963SMatthew Dillon struct mbuf *m = NULL; 443085ff963SMatthew Dillon 444085ff963SMatthew Dillon /* NB: parent must be up and running */ 445085ff963SMatthew Dillon if (!IFNET_IS_UP_RUNNING(parent)) { 446085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 447085ff963SMatthew Dillon "%s: ignore queue, parent %s not up+running\n", 448085ff963SMatthew Dillon __func__, parent->if_xname); 449085ff963SMatthew Dillon /* XXX stat */ 450085ff963SMatthew Dillon /*m_freem(m);*/ 451085ff963SMatthew Dillon /*return (EINVAL);*/ 452085ff963SMatthew Dillon return; 453085ff963SMatthew Dillon } 454085ff963SMatthew Dillon 455085ff963SMatthew Dillon wlan_assert_serialized(); 456085ff963SMatthew Dillon ASSERT_ALTQ_SQ_DEFAULT(ifp, ifsq); 457085ff963SMatthew Dillon 458085ff963SMatthew Dillon /* 459085ff963SMatthew Dillon * No data frames go out unless we're running. 460085ff963SMatthew Dillon * Note in particular this covers CAC and CSA 461085ff963SMatthew Dillon * states (though maybe we should check muting 462085ff963SMatthew Dillon * for CSA). 463085ff963SMatthew Dillon */ 464085ff963SMatthew Dillon if (vap->iv_state != IEEE80211_S_RUN && 465085ff963SMatthew Dillon vap->iv_state != IEEE80211_S_SLEEP) { 466085ff963SMatthew Dillon IEEE80211_LOCK(ic); 467085ff963SMatthew Dillon /* re-check under the com lock to avoid races */ 468085ff963SMatthew Dillon if (vap->iv_state != IEEE80211_S_RUN && 469085ff963SMatthew Dillon vap->iv_state != IEEE80211_S_SLEEP) { 470085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 471085ff963SMatthew Dillon "%s: ignore queue, in %s state\n", 472085ff963SMatthew Dillon __func__, ieee80211_state_name[vap->iv_state]); 473085ff963SMatthew Dillon vap->iv_stats.is_tx_badstate++; 474085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 475085ff963SMatthew Dillon ifsq_set_oactive(ifsq); 476085ff963SMatthew Dillon /*m_freem(m);*/ 477085ff963SMatthew Dillon /* return (EINVAL); */ 478085ff963SMatthew Dillon return; 479085ff963SMatthew Dillon } 480085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 481085ff963SMatthew Dillon } 482085ff963SMatthew Dillon 483085ff963SMatthew Dillon wlan_serialize_exit(); 484085ff963SMatthew Dillon for (;;) { 485085ff963SMatthew Dillon m = ifsq_dequeue(ifsq); 486085ff963SMatthew Dillon if (m == NULL) 487085ff963SMatthew Dillon break; 488085ff963SMatthew Dillon 489085ff963SMatthew Dillon /* 490085ff963SMatthew Dillon * Sanitize mbuf flags for net80211 use. We cannot 491085ff963SMatthew Dillon * clear M_PWR_SAV or M_MORE_DATA because these may 492085ff963SMatthew Dillon * be set for frames that are re-submitted from the 493085ff963SMatthew Dillon * power save queue. 494085ff963SMatthew Dillon * 495085ff963SMatthew Dillon * NB: This must be done before ieee80211_classify as 496085ff963SMatthew Dillon * it marks EAPOL in frames with M_EAPOL. 497085ff963SMatthew Dillon */ 498085ff963SMatthew Dillon m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); 499085ff963SMatthew Dillon 500085ff963SMatthew Dillon /* 501085ff963SMatthew Dillon * Bump to the packet transmission path. 502085ff963SMatthew Dillon * The mbuf will be consumed here. 503085ff963SMatthew Dillon */ 504085ff963SMatthew Dillon ieee80211_start_pkt(vap, m); 505085ff963SMatthew Dillon } 506085ff963SMatthew Dillon wlan_serialize_enter(); 507085ff963SMatthew Dillon } 508085ff963SMatthew Dillon 509085ff963SMatthew Dillon #else 510085ff963SMatthew Dillon 511085ff963SMatthew Dillon int 512085ff963SMatthew Dillon ieee80211_vap_transmit(struct ifnet *ifp, struct mbuf *m) 513085ff963SMatthew Dillon { 514085ff963SMatthew Dillon struct ieee80211vap *vap = ifp->if_softc; 515085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 516085ff963SMatthew Dillon struct ifnet *parent = ic->ic_ifp; 517085ff963SMatthew Dillon 518085ff963SMatthew Dillon /* NB: parent must be up and running */ 519085ff963SMatthew Dillon if (!IFNET_IS_UP_RUNNING(parent)) { 520085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 521085ff963SMatthew Dillon "%s: ignore queue, parent %s not up+running\n", 522085ff963SMatthew Dillon __func__, parent->if_xname); 523085ff963SMatthew Dillon /* XXX stat */ 524085ff963SMatthew Dillon m_freem(m); 525085ff963SMatthew Dillon return (EINVAL); 526085ff963SMatthew Dillon } 527085ff963SMatthew Dillon 528085ff963SMatthew Dillon /* 529085ff963SMatthew Dillon * No data frames go out unless we're running. 530085ff963SMatthew Dillon * Note in particular this covers CAC and CSA 531085ff963SMatthew Dillon * states (though maybe we should check muting 532085ff963SMatthew Dillon * for CSA). 533085ff963SMatthew Dillon */ 534085ff963SMatthew Dillon if (vap->iv_state != IEEE80211_S_RUN && 535085ff963SMatthew Dillon vap->iv_state != IEEE80211_S_SLEEP) { 536085ff963SMatthew Dillon IEEE80211_LOCK(ic); 537085ff963SMatthew Dillon /* re-check under the com lock to avoid races */ 538085ff963SMatthew Dillon if (vap->iv_state != IEEE80211_S_RUN && 539085ff963SMatthew Dillon vap->iv_state != IEEE80211_S_SLEEP) { 540085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 541085ff963SMatthew Dillon "%s: ignore queue, in %s state\n", 542085ff963SMatthew Dillon __func__, ieee80211_state_name[vap->iv_state]); 543085ff963SMatthew Dillon vap->iv_stats.is_tx_badstate++; 544085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 545085ff963SMatthew Dillon ifp->if_drv_flags |= IFF_DRV_OACTIVE; 546085ff963SMatthew Dillon m_freem(m); 547085ff963SMatthew Dillon return (EINVAL); 548085ff963SMatthew Dillon } 549085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 550085ff963SMatthew Dillon } 551085ff963SMatthew Dillon 552085ff963SMatthew Dillon /* 553085ff963SMatthew Dillon * Sanitize mbuf flags for net80211 use. We cannot 554085ff963SMatthew Dillon * clear M_PWR_SAV or M_MORE_DATA because these may 555085ff963SMatthew Dillon * be set for frames that are re-submitted from the 556085ff963SMatthew Dillon * power save queue. 557085ff963SMatthew Dillon * 558085ff963SMatthew Dillon * NB: This must be done before ieee80211_classify as 559085ff963SMatthew Dillon * it marks EAPOL in frames with M_EAPOL. 560085ff963SMatthew Dillon */ 561085ff963SMatthew Dillon m->m_flags &= ~(M_80211_TX - M_PWR_SAV - M_MORE_DATA); 562085ff963SMatthew Dillon 563085ff963SMatthew Dillon /* 564085ff963SMatthew Dillon * Bump to the packet transmission path. 565085ff963SMatthew Dillon * The mbuf will be consumed here. 566085ff963SMatthew Dillon */ 567085ff963SMatthew Dillon return (ieee80211_start_pkt(vap, m)); 568085ff963SMatthew Dillon } 569085ff963SMatthew Dillon 570085ff963SMatthew Dillon void 571085ff963SMatthew Dillon ieee80211_vap_qflush(struct ifnet *ifp) 572085ff963SMatthew Dillon { 573085ff963SMatthew Dillon 574085ff963SMatthew Dillon /* Empty for now */ 575085ff963SMatthew Dillon } 576085ff963SMatthew Dillon 577085ff963SMatthew Dillon #endif 578085ff963SMatthew Dillon 579085ff963SMatthew Dillon /* 580085ff963SMatthew Dillon * 802.11 raw output routine. 581085ff963SMatthew Dillon * 582085ff963SMatthew Dillon * XXX TODO: this (and other send routines) should correctly 583085ff963SMatthew Dillon * XXX keep the pwr mgmt bit set if it decides to call into the 584085ff963SMatthew Dillon * XXX driver to send a frame whilst the state is SLEEP. 585085ff963SMatthew Dillon * 586085ff963SMatthew Dillon * Otherwise the peer may decide that we're awake and flood us 587085ff963SMatthew Dillon * with traffic we are still too asleep to receive! 588085ff963SMatthew Dillon */ 589085ff963SMatthew Dillon int 590085ff963SMatthew Dillon ieee80211_raw_output(struct ieee80211vap *vap, struct ieee80211_node *ni, 591085ff963SMatthew Dillon struct mbuf *m, const struct ieee80211_bpf_params *params) 592085ff963SMatthew Dillon { 593085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 594085ff963SMatthew Dillon 595085ff963SMatthew Dillon return (ic->ic_raw_xmit(ni, m, params)); 596085ff963SMatthew Dillon } 597cc0d8938SRui Paulo 59832176cfdSRui Paulo /* 59932176cfdSRui Paulo * 802.11 output routine. This is (currently) used only to 60032176cfdSRui Paulo * connect bpf write calls to the 802.11 layer for injecting 60132176cfdSRui Paulo * raw 802.11 frames. 60232176cfdSRui Paulo */ 603085ff963SMatthew Dillon #if defined(__DragonFly__) 60432176cfdSRui Paulo int 60532176cfdSRui Paulo ieee80211_output(struct ifnet *ifp, struct mbuf *m, 60634a60cf6SRui Paulo struct sockaddr *dst, struct rtentry *rt) 607085ff963SMatthew Dillon #elif __FreeBSD_version >= 1000031 608085ff963SMatthew Dillon int 609085ff963SMatthew Dillon ieee80211_output(struct ifnet *ifp, struct mbuf *m, 610085ff963SMatthew Dillon const struct sockaddr *dst, struct route *ro) 611085ff963SMatthew Dillon #else 612085ff963SMatthew Dillon int 613085ff963SMatthew Dillon ieee80211_output(struct ifnet *ifp, struct mbuf *m, 614085ff963SMatthew Dillon struct sockaddr *dst, struct route *ro) 615085ff963SMatthew Dillon #endif 61632176cfdSRui Paulo { 61732176cfdSRui Paulo #define senderr(e) do { error = (e); goto bad;} while (0) 61832176cfdSRui Paulo struct ieee80211_node *ni = NULL; 61932176cfdSRui Paulo struct ieee80211vap *vap; 62032176cfdSRui Paulo struct ieee80211_frame *wh; 621085ff963SMatthew Dillon struct ieee80211com *ic = NULL; 62232176cfdSRui Paulo int error; 623085ff963SMatthew Dillon int ret; 62432176cfdSRui Paulo 625085ff963SMatthew Dillon #if defined(__DragonFly__) 626085ff963SMatthew Dillon struct ifaltq_subque *ifsq; 627f0a26983SSepherosa Ziehau ifsq = ifq_get_subq_default(&ifp->if_snd); 628085ff963SMatthew Dillon if (ifsq_is_oactive(ifsq)) 629085ff963SMatthew Dillon #else 630085ff963SMatthew Dillon if (ifp->if_drv_flags & IFF_DRV_OACTIVE) 631085ff963SMatthew Dillon #endif 632085ff963SMatthew Dillon { 63332176cfdSRui Paulo /* 63432176cfdSRui Paulo * Short-circuit requests if the vap is marked OACTIVE 63532176cfdSRui Paulo * as this can happen because a packet came down through 63632176cfdSRui Paulo * ieee80211_start before the vap entered RUN state in 63732176cfdSRui Paulo * which case it's ok to just drop the frame. This 63832176cfdSRui Paulo * should not be necessary but callers of if_output don't 63932176cfdSRui Paulo * check OACTIVE. 64032176cfdSRui Paulo */ 64132176cfdSRui Paulo senderr(ENETDOWN); 64232176cfdSRui Paulo } 64332176cfdSRui Paulo vap = ifp->if_softc; 644085ff963SMatthew Dillon ic = vap->iv_ic; 64532176cfdSRui Paulo /* 64632176cfdSRui Paulo * Hand to the 802.3 code if not tagged as 64732176cfdSRui Paulo * a raw 802.11 frame. 64832176cfdSRui Paulo */ 649085ff963SMatthew Dillon #if defined(__DragonFly__) 65032176cfdSRui Paulo if (dst->sa_family != AF_IEEE80211) 65134a60cf6SRui Paulo return vap->iv_output(ifp, m, dst, rt); 652085ff963SMatthew Dillon #else 653085ff963SMatthew Dillon if (dst->sa_family != AF_IEEE80211) 654085ff963SMatthew Dillon return vap->iv_output(ifp, m, dst, ro); 655085ff963SMatthew Dillon #endif 65632176cfdSRui Paulo #ifdef MAC 65732176cfdSRui Paulo error = mac_ifnet_check_transmit(ifp, m); 65832176cfdSRui Paulo if (error) 65932176cfdSRui Paulo senderr(error); 66032176cfdSRui Paulo #endif 66132176cfdSRui Paulo if (ifp->if_flags & IFF_MONITOR) 66232176cfdSRui Paulo senderr(ENETDOWN); 66332176cfdSRui Paulo if (!IFNET_IS_UP_RUNNING(ifp)) 66432176cfdSRui Paulo senderr(ENETDOWN); 66532176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 66632176cfdSRui Paulo IEEE80211_DPRINTF(vap, 66732176cfdSRui Paulo IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 66832176cfdSRui Paulo "block %s frame in CAC state\n", "raw data"); 66932176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 67032176cfdSRui Paulo senderr(EIO); /* XXX */ 671085ff963SMatthew Dillon } else if (vap->iv_state == IEEE80211_S_SCAN) 672085ff963SMatthew Dillon senderr(EIO); 67332176cfdSRui Paulo /* XXX bypass bridge, pfil, carp, etc. */ 67432176cfdSRui Paulo 67532176cfdSRui Paulo if (m->m_pkthdr.len < sizeof(struct ieee80211_frame_ack)) 67632176cfdSRui Paulo senderr(EIO); /* XXX */ 67732176cfdSRui Paulo wh = mtod(m, struct ieee80211_frame *); 67832176cfdSRui Paulo if ((wh->i_fc[0] & IEEE80211_FC0_VERSION_MASK) != 67932176cfdSRui Paulo IEEE80211_FC0_VERSION_0) 68032176cfdSRui Paulo senderr(EIO); /* XXX */ 68132176cfdSRui Paulo 68232176cfdSRui Paulo /* locate destination node */ 68332176cfdSRui Paulo switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) { 68432176cfdSRui Paulo case IEEE80211_FC1_DIR_NODS: 68532176cfdSRui Paulo case IEEE80211_FC1_DIR_FROMDS: 68632176cfdSRui Paulo ni = ieee80211_find_txnode(vap, wh->i_addr1); 68732176cfdSRui Paulo break; 68832176cfdSRui Paulo case IEEE80211_FC1_DIR_TODS: 68932176cfdSRui Paulo case IEEE80211_FC1_DIR_DSTODS: 69032176cfdSRui Paulo if (m->m_pkthdr.len < sizeof(struct ieee80211_frame)) 69132176cfdSRui Paulo senderr(EIO); /* XXX */ 69232176cfdSRui Paulo ni = ieee80211_find_txnode(vap, wh->i_addr3); 69332176cfdSRui Paulo break; 69432176cfdSRui Paulo default: 69532176cfdSRui Paulo senderr(EIO); /* XXX */ 69632176cfdSRui Paulo } 69732176cfdSRui Paulo if (ni == NULL) { 69832176cfdSRui Paulo /* 69932176cfdSRui Paulo * Permit packets w/ bpf params through regardless 70032176cfdSRui Paulo * (see below about sa_len). 70132176cfdSRui Paulo */ 70232176cfdSRui Paulo if (dst->sa_len == 0) 70332176cfdSRui Paulo senderr(EHOSTUNREACH); 70432176cfdSRui Paulo ni = ieee80211_ref_node(vap->iv_bss); 70532176cfdSRui Paulo } 70632176cfdSRui Paulo 70732176cfdSRui Paulo /* 70832176cfdSRui Paulo * Sanitize mbuf for net80211 flags leaked from above. 70932176cfdSRui Paulo * 71032176cfdSRui Paulo * NB: This must be done before ieee80211_classify as 71132176cfdSRui Paulo * it marks EAPOL in frames with M_EAPOL. 71232176cfdSRui Paulo */ 71332176cfdSRui Paulo m->m_flags &= ~M_80211_TX; 71432176cfdSRui Paulo 71532176cfdSRui Paulo /* calculate priority so drivers can find the tx queue */ 71632176cfdSRui Paulo /* XXX assumes an 802.3 frame */ 71732176cfdSRui Paulo if (ieee80211_classify(ni, m)) 71832176cfdSRui Paulo senderr(EIO); /* XXX */ 71932176cfdSRui Paulo 720d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, opackets, 1); 72132176cfdSRui Paulo IEEE80211_NODE_STAT(ni, tx_data); 72232176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 72332176cfdSRui Paulo IEEE80211_NODE_STAT(ni, tx_mcast); 72432176cfdSRui Paulo m->m_flags |= M_MCAST; 72532176cfdSRui Paulo } else 72632176cfdSRui Paulo IEEE80211_NODE_STAT(ni, tx_ucast); 72732176cfdSRui Paulo /* NB: ieee80211_encap does not include 802.11 header */ 72832176cfdSRui Paulo IEEE80211_NODE_STAT_ADD(ni, tx_bytes, m->m_pkthdr.len); 72932176cfdSRui Paulo 730085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 731085ff963SMatthew Dillon 73232176cfdSRui Paulo /* 73332176cfdSRui Paulo * NB: DLT_IEEE802_11_RADIO identifies the parameters are 73432176cfdSRui Paulo * present by setting the sa_len field of the sockaddr (yes, 73532176cfdSRui Paulo * this is a hack). 73632176cfdSRui Paulo * NB: we assume sa_data is suitably aligned to cast. 73732176cfdSRui Paulo */ 738085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, ni, m, 73932176cfdSRui Paulo (const struct ieee80211_bpf_params *)(dst->sa_len ? 74032176cfdSRui Paulo dst->sa_data : NULL)); 741085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 742085ff963SMatthew Dillon return (ret); 74332176cfdSRui Paulo bad: 74432176cfdSRui Paulo if (m != NULL) 74532176cfdSRui Paulo m_freem(m); 74632176cfdSRui Paulo if (ni != NULL) 74732176cfdSRui Paulo ieee80211_free_node(ni); 748d40991efSSepherosa Ziehau IFNET_STAT_INC(ifp, oerrors, 1); 74932176cfdSRui Paulo return error; 75032176cfdSRui Paulo #undef senderr 75132176cfdSRui Paulo } 75232176cfdSRui Paulo 75332176cfdSRui Paulo /* 75432176cfdSRui Paulo * Set the direction field and address fields of an outgoing 75532176cfdSRui Paulo * frame. Note this should be called early on in constructing 75632176cfdSRui Paulo * a frame as it sets i_fc[1]; other bits can then be or'd in. 75732176cfdSRui Paulo */ 75832176cfdSRui Paulo void 75932176cfdSRui Paulo ieee80211_send_setup( 760841ab66cSSepherosa Ziehau struct ieee80211_node *ni, 76132176cfdSRui Paulo struct mbuf *m, 76232176cfdSRui Paulo int type, int tid, 763841ab66cSSepherosa Ziehau const uint8_t sa[IEEE80211_ADDR_LEN], 764841ab66cSSepherosa Ziehau const uint8_t da[IEEE80211_ADDR_LEN], 765841ab66cSSepherosa Ziehau const uint8_t bssid[IEEE80211_ADDR_LEN]) 766841ab66cSSepherosa Ziehau { 767841ab66cSSepherosa Ziehau #define WH4(wh) ((struct ieee80211_frame_addr4 *)wh) 76832176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 769085ff963SMatthew Dillon struct ieee80211_tx_ampdu *tap; 77032176cfdSRui Paulo struct ieee80211_frame *wh = mtod(m, struct ieee80211_frame *); 77132176cfdSRui Paulo ieee80211_seq seqno; 772841ab66cSSepherosa Ziehau 773085ff963SMatthew Dillon IEEE80211_TX_LOCK_ASSERT(ni->ni_ic); 774085ff963SMatthew Dillon 775841ab66cSSepherosa Ziehau wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | type; 776841ab66cSSepherosa Ziehau if ((type & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_DATA) { 77732176cfdSRui Paulo switch (vap->iv_opmode) { 778841ab66cSSepherosa Ziehau case IEEE80211_M_STA: 779841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 780841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, bssid); 781841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr2, sa); 782841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, da); 783841ab66cSSepherosa Ziehau break; 784841ab66cSSepherosa Ziehau case IEEE80211_M_IBSS: 785841ab66cSSepherosa Ziehau case IEEE80211_M_AHDEMO: 786841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 787841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, da); 788841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr2, sa); 789841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 790841ab66cSSepherosa Ziehau break; 791841ab66cSSepherosa Ziehau case IEEE80211_M_HOSTAP: 792841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 793841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, da); 794841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr2, bssid); 795841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, sa); 796841ab66cSSepherosa Ziehau break; 79732176cfdSRui Paulo case IEEE80211_M_WDS: 79832176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 79932176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 80032176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 80132176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, da); 80232176cfdSRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 80332176cfdSRui Paulo break; 80432176cfdSRui Paulo case IEEE80211_M_MBSS: 80532176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 80632176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(da)) { 80732176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 80832176cfdSRui Paulo /* XXX next hop */ 80932176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 81032176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 81132176cfdSRui Paulo vap->iv_myaddr); 81232176cfdSRui Paulo } else { 81332176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 81432176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, da); 81532176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, 81632176cfdSRui Paulo vap->iv_myaddr); 81732176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, da); 81832176cfdSRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, sa); 81932176cfdSRui Paulo } 82032176cfdSRui Paulo #endif 82132176cfdSRui Paulo break; 822841ab66cSSepherosa Ziehau case IEEE80211_M_MONITOR: /* NB: to quiet compiler */ 823841ab66cSSepherosa Ziehau break; 824841ab66cSSepherosa Ziehau } 825841ab66cSSepherosa Ziehau } else { 826841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 827841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, da); 828841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr2, sa); 82932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 83032176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 83132176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, sa); 83232176cfdSRui Paulo else 83332176cfdSRui Paulo #endif 834841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, bssid); 835841ab66cSSepherosa Ziehau } 836841ab66cSSepherosa Ziehau *(uint16_t *)&wh->i_dur[0] = 0; 83732176cfdSRui Paulo 838085ff963SMatthew Dillon tap = &ni->ni_tx_ampdu[tid]; 839085ff963SMatthew Dillon if (tid != IEEE80211_NONQOS_TID && IEEE80211_AMPDU_RUNNING(tap)) 840085ff963SMatthew Dillon m->m_flags |= M_AMPDU_MPDU; 841085ff963SMatthew Dillon else { 84232176cfdSRui Paulo seqno = ni->ni_txseqs[tid]++; 843085ff963SMatthew Dillon *(uint16_t *)&wh->i_seq[0] = 844085ff963SMatthew Dillon htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 84532176cfdSRui Paulo M_SEQNO_SET(m, seqno); 846085ff963SMatthew Dillon } 84732176cfdSRui Paulo 84832176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) 84932176cfdSRui Paulo m->m_flags |= M_MCAST; 850841ab66cSSepherosa Ziehau #undef WH4 851841ab66cSSepherosa Ziehau } 852841ab66cSSepherosa Ziehau 853f186073cSJoerg Sonnenberger /* 854f186073cSJoerg Sonnenberger * Send a management frame to the specified node. The node pointer 855f186073cSJoerg Sonnenberger * must have a reference as the pointer will be passed to the driver 856f186073cSJoerg Sonnenberger * and potentially held for a long time. If the frame is successfully 857f186073cSJoerg Sonnenberger * dispatched to the driver, then it is responsible for freeing the 85832176cfdSRui Paulo * reference (and potentially free'ing up any associated storage); 85932176cfdSRui Paulo * otherwise deal with reclaiming any reference (on error). 860f186073cSJoerg Sonnenberger */ 86132176cfdSRui Paulo int 86232176cfdSRui Paulo ieee80211_mgmt_output(struct ieee80211_node *ni, struct mbuf *m, int type, 86332176cfdSRui Paulo struct ieee80211_bpf_params *params) 864f186073cSJoerg Sonnenberger { 86532176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 86632176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 867f186073cSJoerg Sonnenberger struct ieee80211_frame *wh; 868085ff963SMatthew Dillon int ret; 869085ff963SMatthew Dillon 870f186073cSJoerg Sonnenberger KASSERT(ni != NULL, ("null node")); 871f186073cSJoerg Sonnenberger 87232176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 87332176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 87432176cfdSRui Paulo ni, "block %s frame in CAC state", 87532176cfdSRui Paulo ieee80211_mgt_subtype_name[ 87632176cfdSRui Paulo (type & IEEE80211_FC0_SUBTYPE_MASK) >> 87732176cfdSRui Paulo IEEE80211_FC0_SUBTYPE_SHIFT]); 87832176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 87932176cfdSRui Paulo ieee80211_free_node(ni); 88032176cfdSRui Paulo m_freem(m); 88132176cfdSRui Paulo return EIO; /* XXX */ 88232176cfdSRui Paulo } 88332176cfdSRui Paulo 884b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 88532176cfdSRui Paulo if (m == NULL) { 88632176cfdSRui Paulo ieee80211_free_node(ni); 887f186073cSJoerg Sonnenberger return ENOMEM; 88832176cfdSRui Paulo } 889f186073cSJoerg Sonnenberger 890085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 891085ff963SMatthew Dillon 892f186073cSJoerg Sonnenberger wh = mtod(m, struct ieee80211_frame *); 89332176cfdSRui Paulo ieee80211_send_setup(ni, m, 89432176cfdSRui Paulo IEEE80211_FC0_TYPE_MGT | type, IEEE80211_NONQOS_TID, 89532176cfdSRui Paulo vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 89632176cfdSRui Paulo if (params->ibp_flags & IEEE80211_BPF_CRYPTO) { 89732176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_AUTH, wh->i_addr1, 89832176cfdSRui Paulo "encrypting frame (%s)", __func__); 899085ff963SMatthew Dillon wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; 900f186073cSJoerg Sonnenberger } 90132176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 90232176cfdSRui Paulo 90332176cfdSRui Paulo KASSERT(type != IEEE80211_FC0_SUBTYPE_PROBE_RESP, ("probe response?")); 90432176cfdSRui Paulo M_WME_SETAC(m, params->ibp_pri); 90532176cfdSRui Paulo 906841ab66cSSepherosa Ziehau #ifdef IEEE80211_DEBUG 907841ab66cSSepherosa Ziehau /* avoid printing too many frames */ 90832176cfdSRui Paulo if ((ieee80211_msg_debug(vap) && doprint(vap, type)) || 90932176cfdSRui Paulo ieee80211_msg_dumppkts(vap)) { 9101e290df3SAntonio Huete Jimenez kprintf("[%s] send %s on channel %u\n", 911085ff963SMatthew Dillon ether_sprintf(wh->i_addr1), 912841ab66cSSepherosa Ziehau ieee80211_mgt_subtype_name[ 913841ab66cSSepherosa Ziehau (type & IEEE80211_FC0_SUBTYPE_MASK) >> 914841ab66cSSepherosa Ziehau IEEE80211_FC0_SUBTYPE_SHIFT], 915841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan)); 916841ab66cSSepherosa Ziehau } 917841ab66cSSepherosa Ziehau #endif 918841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_mgmt); 91932176cfdSRui Paulo 920085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, ni, m, params); 921085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 922085ff963SMatthew Dillon return (ret); 923f186073cSJoerg Sonnenberger } 924f186073cSJoerg Sonnenberger 925f186073cSJoerg Sonnenberger /* 92632176cfdSRui Paulo * Send a null data frame to the specified node. If the station 92732176cfdSRui Paulo * is setup for QoS then a QoS Null Data frame is constructed. 92832176cfdSRui Paulo * If this is a WDS station then a 4-address frame is constructed. 929f186073cSJoerg Sonnenberger * 930841ab66cSSepherosa Ziehau * NB: the caller is assumed to have setup a node reference 931841ab66cSSepherosa Ziehau * for use; this is necessary to deal with a race condition 93232176cfdSRui Paulo * when probing for inactive stations. Like ieee80211_mgmt_output 93332176cfdSRui Paulo * we must cleanup any node reference on error; however we 93432176cfdSRui Paulo * can safely just unref it as we know it will never be the 93532176cfdSRui Paulo * last reference to the node. 936841ab66cSSepherosa Ziehau */ 937841ab66cSSepherosa Ziehau int 938841ab66cSSepherosa Ziehau ieee80211_send_nulldata(struct ieee80211_node *ni) 939841ab66cSSepherosa Ziehau { 94032176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 941841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 942841ab66cSSepherosa Ziehau struct mbuf *m; 943841ab66cSSepherosa Ziehau struct ieee80211_frame *wh; 94432176cfdSRui Paulo int hdrlen; 94532176cfdSRui Paulo uint8_t *frm; 946085ff963SMatthew Dillon int ret; 947841ab66cSSepherosa Ziehau 94832176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 94932176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT | IEEE80211_MSG_DOTH, 95032176cfdSRui Paulo ni, "block %s frame in CAC state", "null data"); 95132176cfdSRui Paulo ieee80211_unref_node(&ni); 95232176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 95332176cfdSRui Paulo return EIO; /* XXX */ 95432176cfdSRui Paulo } 95532176cfdSRui Paulo 95632176cfdSRui Paulo if (ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) 95732176cfdSRui Paulo hdrlen = sizeof(struct ieee80211_qosframe); 95832176cfdSRui Paulo else 95932176cfdSRui Paulo hdrlen = sizeof(struct ieee80211_frame); 96032176cfdSRui Paulo /* NB: only WDS vap's get 4-address frames */ 96132176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_WDS) 96232176cfdSRui Paulo hdrlen += IEEE80211_ADDR_LEN; 96332176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_DATAPAD) 96432176cfdSRui Paulo hdrlen = roundup(hdrlen, sizeof(uint32_t)); 96532176cfdSRui Paulo 96632176cfdSRui Paulo m = ieee80211_getmgtframe(&frm, ic->ic_headroom + hdrlen, 0); 967841ab66cSSepherosa Ziehau if (m == NULL) { 968841ab66cSSepherosa Ziehau /* XXX debug msg */ 969841ab66cSSepherosa Ziehau ieee80211_unref_node(&ni); 97032176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 971841ab66cSSepherosa Ziehau return ENOMEM; 972841ab66cSSepherosa Ziehau } 97332176cfdSRui Paulo KASSERT(M_LEADINGSPACE(m) >= hdrlen, 97432176cfdSRui Paulo ("leading space %zd", M_LEADINGSPACE(m))); 975b5523eacSSascha Wildner M_PREPEND(m, hdrlen, M_NOWAIT); 97632176cfdSRui Paulo if (m == NULL) { 97732176cfdSRui Paulo /* NB: cannot happen */ 97832176cfdSRui Paulo ieee80211_free_node(ni); 97932176cfdSRui Paulo return ENOMEM; 98032176cfdSRui Paulo } 981841ab66cSSepherosa Ziehau 982085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 983085ff963SMatthew Dillon 98432176cfdSRui Paulo wh = mtod(m, struct ieee80211_frame *); /* NB: a little lie */ 98532176cfdSRui Paulo if (ni->ni_flags & IEEE80211_NODE_QOS) { 98632176cfdSRui Paulo const int tid = WME_AC_TO_TID(WME_AC_BE); 98732176cfdSRui Paulo uint8_t *qos; 98832176cfdSRui Paulo 98932176cfdSRui Paulo ieee80211_send_setup(ni, m, 99032176cfdSRui Paulo IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS_NULL, 99132176cfdSRui Paulo tid, vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 99232176cfdSRui Paulo 99332176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_WDS) 99432176cfdSRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 99532176cfdSRui Paulo else 99632176cfdSRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 99732176cfdSRui Paulo qos[0] = tid & IEEE80211_QOS_TID; 99832176cfdSRui Paulo if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[WME_AC_BE].wmep_noackPolicy) 99932176cfdSRui Paulo qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 100032176cfdSRui Paulo qos[1] = 0; 100132176cfdSRui Paulo } else { 100232176cfdSRui Paulo ieee80211_send_setup(ni, m, 1003841ab66cSSepherosa Ziehau IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_NODATA, 100432176cfdSRui Paulo IEEE80211_NONQOS_TID, 100532176cfdSRui Paulo vap->iv_myaddr, ni->ni_macaddr, ni->ni_bssid); 100632176cfdSRui Paulo } 100732176cfdSRui Paulo if (vap->iv_opmode != IEEE80211_M_WDS) { 1008841ab66cSSepherosa Ziehau /* NB: power management bit is never sent by an AP */ 1009841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_PWR_MGT) && 101032176cfdSRui Paulo vap->iv_opmode != IEEE80211_M_HOSTAP) 1011841ab66cSSepherosa Ziehau wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; 101232176cfdSRui Paulo } 101332176cfdSRui Paulo m->m_len = m->m_pkthdr.len = hdrlen; 101432176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 101532176cfdSRui Paulo 101632176cfdSRui Paulo M_WME_SETAC(m, WME_AC_BE); 1017841ab66cSSepherosa Ziehau 1018841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_data); 1019841ab66cSSepherosa Ziehau 102032176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, ni, 102132176cfdSRui Paulo "send %snull data frame on channel %u, pwr mgt %s", 102232176cfdSRui Paulo ni->ni_flags & IEEE80211_NODE_QOS ? "QoS " : "", 1023841ab66cSSepherosa Ziehau ieee80211_chan2ieee(ic, ic->ic_curchan), 1024841ab66cSSepherosa Ziehau wh->i_fc[1] & IEEE80211_FC1_PWR_MGT ? "ena" : "dis"); 1025841ab66cSSepherosa Ziehau 1026085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, ni, m, NULL); 1027085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 1028085ff963SMatthew Dillon return (ret); 1029841ab66cSSepherosa Ziehau } 1030841ab66cSSepherosa Ziehau 1031841ab66cSSepherosa Ziehau /* 1032841ab66cSSepherosa Ziehau * Assign priority to a frame based on any vlan tag assigned 1033841ab66cSSepherosa Ziehau * to the station and/or any Diffserv setting in an IP header. 1034841ab66cSSepherosa Ziehau * Finally, if an ACM policy is setup (in station mode) it's 1035841ab66cSSepherosa Ziehau * applied. 1036841ab66cSSepherosa Ziehau */ 1037841ab66cSSepherosa Ziehau int 103832176cfdSRui Paulo ieee80211_classify(struct ieee80211_node *ni, struct mbuf *m) 1039841ab66cSSepherosa Ziehau { 104032176cfdSRui Paulo const struct ether_header *eh = mtod(m, struct ether_header *); 104132176cfdSRui Paulo int v_wme_ac, d_wme_ac, ac; 1042841ab66cSSepherosa Ziehau 104332176cfdSRui Paulo /* 104432176cfdSRui Paulo * Always promote PAE/EAPOL frames to high priority. 104532176cfdSRui Paulo */ 104632176cfdSRui Paulo if (eh->ether_type == htons(ETHERTYPE_PAE)) { 104732176cfdSRui Paulo /* NB: mark so others don't need to check header */ 104832176cfdSRui Paulo m->m_flags |= M_EAPOL; 104932176cfdSRui Paulo ac = WME_AC_VO; 105032176cfdSRui Paulo goto done; 105132176cfdSRui Paulo } 105232176cfdSRui Paulo /* 105332176cfdSRui Paulo * Non-qos traffic goes to BE. 105432176cfdSRui Paulo */ 1055841ab66cSSepherosa Ziehau if ((ni->ni_flags & IEEE80211_NODE_QOS) == 0) { 1056841ab66cSSepherosa Ziehau ac = WME_AC_BE; 1057841ab66cSSepherosa Ziehau goto done; 1058841ab66cSSepherosa Ziehau } 1059841ab66cSSepherosa Ziehau 1060841ab66cSSepherosa Ziehau /* 1061841ab66cSSepherosa Ziehau * If node has a vlan tag then all traffic 1062841ab66cSSepherosa Ziehau * to it must have a matching tag. 1063841ab66cSSepherosa Ziehau */ 1064841ab66cSSepherosa Ziehau v_wme_ac = 0; 1065841ab66cSSepherosa Ziehau if (ni->ni_vlan != 0) { 106632176cfdSRui Paulo if ((m->m_flags & M_VLANTAG) == 0) { 1067841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_novlantag); 1068841ab66cSSepherosa Ziehau return 1; 1069841ab66cSSepherosa Ziehau } 1070085ff963SMatthew Dillon #if defined(__DragonFly__) 107132176cfdSRui Paulo if (EVL_VLANOFTAG(m->m_pkthdr.ether_vlantag) != 1072841ab66cSSepherosa Ziehau EVL_VLANOFTAG(ni->ni_vlan)) { 1073841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 1074841ab66cSSepherosa Ziehau return 1; 1075841ab66cSSepherosa Ziehau } 1076085ff963SMatthew Dillon #else 1077085ff963SMatthew Dillon if (EVL_VLANOFTAG(m->m_pkthdr.ether_vtag) != 1078085ff963SMatthew Dillon EVL_VLANOFTAG(ni->ni_vlan)) { 1079085ff963SMatthew Dillon IEEE80211_NODE_STAT(ni, tx_vlanmismatch); 1080085ff963SMatthew Dillon return 1; 1081085ff963SMatthew Dillon } 1082085ff963SMatthew Dillon #endif 1083841ab66cSSepherosa Ziehau /* map vlan priority to AC */ 108432176cfdSRui Paulo v_wme_ac = TID_TO_WME_AC(EVL_PRIOFTAG(ni->ni_vlan)); 1085841ab66cSSepherosa Ziehau } 1086841ab66cSSepherosa Ziehau 108732176cfdSRui Paulo /* XXX m_copydata may be too slow for fast path */ 1088841ab66cSSepherosa Ziehau #ifdef INET 1089841ab66cSSepherosa Ziehau if (eh->ether_type == htons(ETHERTYPE_IP)) { 109032176cfdSRui Paulo uint8_t tos; 1091841ab66cSSepherosa Ziehau /* 109232176cfdSRui Paulo * IP frame, map the DSCP bits from the TOS field. 1093841ab66cSSepherosa Ziehau */ 109432176cfdSRui Paulo /* NB: ip header may not be in first mbuf */ 109532176cfdSRui Paulo m_copydata(m, sizeof(struct ether_header) + 109632176cfdSRui Paulo offsetof(struct ip, ip_tos), sizeof(tos), &tos); 109732176cfdSRui Paulo tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 109832176cfdSRui Paulo d_wme_ac = TID_TO_WME_AC(tos); 1099841ab66cSSepherosa Ziehau } else { 1100841ab66cSSepherosa Ziehau #endif /* INET */ 110132176cfdSRui Paulo #ifdef INET6 110232176cfdSRui Paulo if (eh->ether_type == htons(ETHERTYPE_IPV6)) { 110332176cfdSRui Paulo uint32_t flow; 110432176cfdSRui Paulo uint8_t tos; 110532176cfdSRui Paulo /* 1106085ff963SMatthew Dillon * IPv6 frame, map the DSCP bits from the traffic class field. 110732176cfdSRui Paulo */ 110832176cfdSRui Paulo m_copydata(m, sizeof(struct ether_header) + 110932176cfdSRui Paulo offsetof(struct ip6_hdr, ip6_flow), sizeof(flow), 111032176cfdSRui Paulo (caddr_t) &flow); 111132176cfdSRui Paulo tos = (uint8_t)(ntohl(flow) >> 20); 111232176cfdSRui Paulo tos >>= 5; /* NB: ECN + low 3 bits of DSCP */ 111332176cfdSRui Paulo d_wme_ac = TID_TO_WME_AC(tos); 111432176cfdSRui Paulo } else { 111532176cfdSRui Paulo #endif /* INET6 */ 1116841ab66cSSepherosa Ziehau d_wme_ac = WME_AC_BE; 111732176cfdSRui Paulo #ifdef INET6 111832176cfdSRui Paulo } 111932176cfdSRui Paulo #endif 1120841ab66cSSepherosa Ziehau #ifdef INET 1121841ab66cSSepherosa Ziehau } 1122841ab66cSSepherosa Ziehau #endif 1123841ab66cSSepherosa Ziehau /* 1124841ab66cSSepherosa Ziehau * Use highest priority AC. 1125841ab66cSSepherosa Ziehau */ 1126841ab66cSSepherosa Ziehau if (v_wme_ac > d_wme_ac) 1127841ab66cSSepherosa Ziehau ac = v_wme_ac; 1128841ab66cSSepherosa Ziehau else 1129841ab66cSSepherosa Ziehau ac = d_wme_ac; 1130841ab66cSSepherosa Ziehau 1131841ab66cSSepherosa Ziehau /* 1132841ab66cSSepherosa Ziehau * Apply ACM policy. 1133841ab66cSSepherosa Ziehau */ 113432176cfdSRui Paulo if (ni->ni_vap->iv_opmode == IEEE80211_M_STA) { 1135841ab66cSSepherosa Ziehau static const int acmap[4] = { 1136841ab66cSSepherosa Ziehau WME_AC_BK, /* WME_AC_BE */ 1137841ab66cSSepherosa Ziehau WME_AC_BK, /* WME_AC_BK */ 1138841ab66cSSepherosa Ziehau WME_AC_BE, /* WME_AC_VI */ 1139841ab66cSSepherosa Ziehau WME_AC_VI, /* WME_AC_VO */ 1140841ab66cSSepherosa Ziehau }; 114132176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 114232176cfdSRui Paulo 1143841ab66cSSepherosa Ziehau while (ac != WME_AC_BK && 1144841ab66cSSepherosa Ziehau ic->ic_wme.wme_wmeBssChanParams.cap_wmeParams[ac].wmep_acm) 1145841ab66cSSepherosa Ziehau ac = acmap[ac]; 1146841ab66cSSepherosa Ziehau } 1147841ab66cSSepherosa Ziehau done: 1148841ab66cSSepherosa Ziehau M_WME_SETAC(m, ac); 1149841ab66cSSepherosa Ziehau return 0; 1150841ab66cSSepherosa Ziehau } 1151841ab66cSSepherosa Ziehau 1152841ab66cSSepherosa Ziehau /* 1153841ab66cSSepherosa Ziehau * Insure there is sufficient contiguous space to encapsulate the 1154841ab66cSSepherosa Ziehau * 802.11 data frame. If room isn't already there, arrange for it. 1155841ab66cSSepherosa Ziehau * Drivers and cipher modules assume we have done the necessary work 1156841ab66cSSepherosa Ziehau * and fail rudely if they don't find the space they need. 1157841ab66cSSepherosa Ziehau */ 115832176cfdSRui Paulo struct mbuf * 115932176cfdSRui Paulo ieee80211_mbuf_adjust(struct ieee80211vap *vap, int hdrsize, 1160841ab66cSSepherosa Ziehau struct ieee80211_key *key, struct mbuf *m) 1161841ab66cSSepherosa Ziehau { 1162841ab66cSSepherosa Ziehau #define TO_BE_RECLAIMED (sizeof(struct ether_header) - sizeof(struct llc)) 116332176cfdSRui Paulo int needed_space = vap->iv_ic->ic_headroom + hdrsize; 1164841ab66cSSepherosa Ziehau 1165841ab66cSSepherosa Ziehau if (key != NULL) { 1166841ab66cSSepherosa Ziehau /* XXX belongs in crypto code? */ 1167841ab66cSSepherosa Ziehau needed_space += key->wk_cipher->ic_header; 1168841ab66cSSepherosa Ziehau /* XXX frags */ 1169841ab66cSSepherosa Ziehau /* 1170841ab66cSSepherosa Ziehau * When crypto is being done in the host we must insure 1171841ab66cSSepherosa Ziehau * the data are writable for the cipher routines; clone 1172841ab66cSSepherosa Ziehau * a writable mbuf chain. 1173841ab66cSSepherosa Ziehau * XXX handle SWMIC specially 1174841ab66cSSepherosa Ziehau */ 117532176cfdSRui Paulo if (key->wk_flags & (IEEE80211_KEY_SWENCRYPT|IEEE80211_KEY_SWENMIC)) { 1176b5523eacSSascha Wildner m = m_unshare(m, M_NOWAIT); 1177841ab66cSSepherosa Ziehau if (m == NULL) { 117832176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 1179841ab66cSSepherosa Ziehau "%s: cannot get writable mbuf\n", __func__); 118032176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; /* XXX new stat */ 1181841ab66cSSepherosa Ziehau return NULL; 1182841ab66cSSepherosa Ziehau } 1183841ab66cSSepherosa Ziehau } 1184841ab66cSSepherosa Ziehau } 1185841ab66cSSepherosa Ziehau /* 1186841ab66cSSepherosa Ziehau * We know we are called just before stripping an Ethernet 1187841ab66cSSepherosa Ziehau * header and prepending an LLC header. This means we know 1188841ab66cSSepherosa Ziehau * there will be 1189841ab66cSSepherosa Ziehau * sizeof(struct ether_header) - sizeof(struct llc) 1190841ab66cSSepherosa Ziehau * bytes recovered to which we need additional space for the 1191841ab66cSSepherosa Ziehau * 802.11 header and any crypto header. 1192841ab66cSSepherosa Ziehau */ 1193841ab66cSSepherosa Ziehau /* XXX check trailing space and copy instead? */ 1194841ab66cSSepherosa Ziehau if (M_LEADINGSPACE(m) < needed_space - TO_BE_RECLAIMED) { 1195b5523eacSSascha Wildner struct mbuf *n = m_gethdr(M_NOWAIT, m->m_type); 1196841ab66cSSepherosa Ziehau if (n == NULL) { 119732176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_OUTPUT, 1198841ab66cSSepherosa Ziehau "%s: cannot expand storage\n", __func__); 119932176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 1200841ab66cSSepherosa Ziehau m_freem(m); 1201841ab66cSSepherosa Ziehau return NULL; 1202841ab66cSSepherosa Ziehau } 1203085ff963SMatthew Dillon #if defined(__DragonFly__) 1204841ab66cSSepherosa Ziehau KASSERT(needed_space <= MHLEN, 1205085ff963SMatthew Dillon ("not enough room, need %u got %zd\n", needed_space, MHLEN)); 1206085ff963SMatthew Dillon #else 1207085ff963SMatthew Dillon KASSERT(needed_space <= MHLEN, 1208085ff963SMatthew Dillon ("not enough room, need %u got %d\n", needed_space, MHLEN)); 1209085ff963SMatthew Dillon #endif 1210841ab66cSSepherosa Ziehau /* 1211841ab66cSSepherosa Ziehau * Setup new mbuf to have leading space to prepend the 1212841ab66cSSepherosa Ziehau * 802.11 header and any crypto header bits that are 1213841ab66cSSepherosa Ziehau * required (the latter are added when the driver calls 1214841ab66cSSepherosa Ziehau * back to ieee80211_crypto_encap to do crypto encapsulation). 1215841ab66cSSepherosa Ziehau */ 1216841ab66cSSepherosa Ziehau /* NB: must be first 'cuz it clobbers m_data */ 1217841ab66cSSepherosa Ziehau m_move_pkthdr(n, m); 1218841ab66cSSepherosa Ziehau n->m_len = 0; /* NB: m_gethdr does not set */ 1219841ab66cSSepherosa Ziehau n->m_data += needed_space; 1220841ab66cSSepherosa Ziehau /* 1221841ab66cSSepherosa Ziehau * Pull up Ethernet header to create the expected layout. 1222841ab66cSSepherosa Ziehau * We could use m_pullup but that's overkill (i.e. we don't 1223841ab66cSSepherosa Ziehau * need the actual data) and it cannot fail so do it inline 1224841ab66cSSepherosa Ziehau * for speed. 1225841ab66cSSepherosa Ziehau */ 1226841ab66cSSepherosa Ziehau /* NB: struct ether_header is known to be contiguous */ 1227841ab66cSSepherosa Ziehau n->m_len += sizeof(struct ether_header); 1228841ab66cSSepherosa Ziehau m->m_len -= sizeof(struct ether_header); 1229841ab66cSSepherosa Ziehau m->m_data += sizeof(struct ether_header); 1230841ab66cSSepherosa Ziehau /* 1231841ab66cSSepherosa Ziehau * Replace the head of the chain. 1232841ab66cSSepherosa Ziehau */ 1233841ab66cSSepherosa Ziehau n->m_next = m; 1234841ab66cSSepherosa Ziehau m = n; 1235841ab66cSSepherosa Ziehau } 1236841ab66cSSepherosa Ziehau return m; 1237841ab66cSSepherosa Ziehau #undef TO_BE_RECLAIMED 1238841ab66cSSepherosa Ziehau } 1239841ab66cSSepherosa Ziehau 1240841ab66cSSepherosa Ziehau /* 1241841ab66cSSepherosa Ziehau * Return the transmit key to use in sending a unicast frame. 1242841ab66cSSepherosa Ziehau * If a unicast key is set we use that. When no unicast key is set 1243841ab66cSSepherosa Ziehau * we fall back to the default transmit key. 1244841ab66cSSepherosa Ziehau */ 1245841ab66cSSepherosa Ziehau static __inline struct ieee80211_key * 124632176cfdSRui Paulo ieee80211_crypto_getucastkey(struct ieee80211vap *vap, 124732176cfdSRui Paulo struct ieee80211_node *ni) 1248841ab66cSSepherosa Ziehau { 124932176cfdSRui Paulo if (IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)) { 125032176cfdSRui Paulo if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 125132176cfdSRui Paulo IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 1252841ab66cSSepherosa Ziehau return NULL; 125332176cfdSRui Paulo return &vap->iv_nw_keys[vap->iv_def_txkey]; 1254841ab66cSSepherosa Ziehau } else { 1255841ab66cSSepherosa Ziehau return &ni->ni_ucastkey; 1256841ab66cSSepherosa Ziehau } 1257841ab66cSSepherosa Ziehau } 1258841ab66cSSepherosa Ziehau 1259841ab66cSSepherosa Ziehau /* 1260841ab66cSSepherosa Ziehau * Return the transmit key to use in sending a multicast frame. 1261841ab66cSSepherosa Ziehau * Multicast traffic always uses the group key which is installed as 1262841ab66cSSepherosa Ziehau * the default tx key. 1263841ab66cSSepherosa Ziehau */ 1264841ab66cSSepherosa Ziehau static __inline struct ieee80211_key * 126532176cfdSRui Paulo ieee80211_crypto_getmcastkey(struct ieee80211vap *vap, 126632176cfdSRui Paulo struct ieee80211_node *ni) 1267841ab66cSSepherosa Ziehau { 126832176cfdSRui Paulo if (vap->iv_def_txkey == IEEE80211_KEYIX_NONE || 126932176cfdSRui Paulo IEEE80211_KEY_UNDEFINED(&vap->iv_nw_keys[vap->iv_def_txkey])) 1270841ab66cSSepherosa Ziehau return NULL; 127132176cfdSRui Paulo return &vap->iv_nw_keys[vap->iv_def_txkey]; 1272841ab66cSSepherosa Ziehau } 1273841ab66cSSepherosa Ziehau 1274841ab66cSSepherosa Ziehau /* 1275841ab66cSSepherosa Ziehau * Encapsulate an outbound data frame. The mbuf chain is updated. 1276841ab66cSSepherosa Ziehau * If an error is encountered NULL is returned. The caller is required 1277841ab66cSSepherosa Ziehau * to provide a node reference and pullup the ethernet header in the 1278841ab66cSSepherosa Ziehau * first mbuf. 127932176cfdSRui Paulo * 128032176cfdSRui Paulo * NB: Packet is assumed to be processed by ieee80211_classify which 128132176cfdSRui Paulo * marked EAPOL frames w/ M_EAPOL. 1282f186073cSJoerg Sonnenberger */ 1283f186073cSJoerg Sonnenberger struct mbuf * 128432176cfdSRui Paulo ieee80211_encap(struct ieee80211vap *vap, struct ieee80211_node *ni, 128532176cfdSRui Paulo struct mbuf *m) 1286f186073cSJoerg Sonnenberger { 128732176cfdSRui Paulo #define WH4(wh) ((struct ieee80211_frame_addr4 *)(wh)) 1288085ff963SMatthew Dillon #define MC01(mc) ((struct ieee80211_meshcntl_ae01 *)mc) 128932176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 129032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 129132176cfdSRui Paulo struct ieee80211_mesh_state *ms = vap->iv_mesh; 129232176cfdSRui Paulo struct ieee80211_meshcntl_ae10 *mc; 1293085ff963SMatthew Dillon struct ieee80211_mesh_route *rt = NULL; 1294085ff963SMatthew Dillon int dir = -1; 129532176cfdSRui Paulo #endif 1296f186073cSJoerg Sonnenberger struct ether_header eh; 1297f186073cSJoerg Sonnenberger struct ieee80211_frame *wh; 1298841ab66cSSepherosa Ziehau struct ieee80211_key *key; 1299f186073cSJoerg Sonnenberger struct llc *llc; 130032176cfdSRui Paulo int hdrsize, hdrspace, datalen, addqos, txfrag, is4addr; 130132176cfdSRui Paulo ieee80211_seq seqno; 130232176cfdSRui Paulo int meshhdrsize, meshae; 130332176cfdSRui Paulo uint8_t *qos; 1304f186073cSJoerg Sonnenberger 1305085ff963SMatthew Dillon IEEE80211_TX_LOCK_ASSERT(ic); 1306085ff963SMatthew Dillon 130732176cfdSRui Paulo /* 130832176cfdSRui Paulo * Copy existing Ethernet header to a safe place. The 130932176cfdSRui Paulo * rest of the code assumes it's ok to strip it when 131032176cfdSRui Paulo * reorganizing state for the final encapsulation. 131132176cfdSRui Paulo */ 1312841ab66cSSepherosa Ziehau KASSERT(m->m_len >= sizeof(eh), ("no ethernet header!")); 131332176cfdSRui Paulo ETHER_HEADER_COPY(&eh, mtod(m, caddr_t)); 1314f186073cSJoerg Sonnenberger 1315841ab66cSSepherosa Ziehau /* 1316841ab66cSSepherosa Ziehau * Insure space for additional headers. First identify 1317841ab66cSSepherosa Ziehau * transmit key to use in calculating any buffer adjustments 1318841ab66cSSepherosa Ziehau * required. This is also used below to do privacy 1319841ab66cSSepherosa Ziehau * encapsulation work. Then calculate the 802.11 header 1320841ab66cSSepherosa Ziehau * size and any padding required by the driver. 1321841ab66cSSepherosa Ziehau * 1322841ab66cSSepherosa Ziehau * Note key may be NULL if we fall back to the default 1323841ab66cSSepherosa Ziehau * transmit key and that is not set. In that case the 1324841ab66cSSepherosa Ziehau * buffer may not be expanded as needed by the cipher 1325841ab66cSSepherosa Ziehau * routines, but they will/should discard it. 1326841ab66cSSepherosa Ziehau */ 132732176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) { 132832176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA || 132932176cfdSRui Paulo !IEEE80211_IS_MULTICAST(eh.ether_dhost) || 133032176cfdSRui Paulo (vap->iv_opmode == IEEE80211_M_WDS && 133132176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_WDSLEGACY))) 133232176cfdSRui Paulo key = ieee80211_crypto_getucastkey(vap, ni); 1333841ab66cSSepherosa Ziehau else 133432176cfdSRui Paulo key = ieee80211_crypto_getmcastkey(vap, ni); 133532176cfdSRui Paulo if (key == NULL && (m->m_flags & M_EAPOL) == 0) { 133632176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, 133732176cfdSRui Paulo eh.ether_dhost, 133832176cfdSRui Paulo "no default transmit key (%s) deftxkey %u", 133932176cfdSRui Paulo __func__, vap->iv_def_txkey); 134032176cfdSRui Paulo vap->iv_stats.is_tx_nodefkey++; 1341a92bce5eSSepherosa Ziehau goto bad; 1342841ab66cSSepherosa Ziehau } 1343841ab66cSSepherosa Ziehau } else 1344841ab66cSSepherosa Ziehau key = NULL; 1345841ab66cSSepherosa Ziehau /* 1346841ab66cSSepherosa Ziehau * XXX Some ap's don't handle QoS-encapsulated EAPOL 1347841ab66cSSepherosa Ziehau * frames so suppress use. This may be an issue if other 1348841ab66cSSepherosa Ziehau * ap's require all data frames to be QoS-encapsulated 1349841ab66cSSepherosa Ziehau * once negotiated in which case we'll need to make this 1350841ab66cSSepherosa Ziehau * configurable. 1351085ff963SMatthew Dillon * NB: mesh data frames are QoS. 1352841ab66cSSepherosa Ziehau */ 1353085ff963SMatthew Dillon addqos = ((ni->ni_flags & (IEEE80211_NODE_QOS|IEEE80211_NODE_HT)) || 1354085ff963SMatthew Dillon (vap->iv_opmode == IEEE80211_M_MBSS)) && 135532176cfdSRui Paulo (m->m_flags & M_EAPOL) == 0; 1356841ab66cSSepherosa Ziehau if (addqos) 1357841ab66cSSepherosa Ziehau hdrsize = sizeof(struct ieee80211_qosframe); 1358841ab66cSSepherosa Ziehau else 1359841ab66cSSepherosa Ziehau hdrsize = sizeof(struct ieee80211_frame); 136032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 136132176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 136232176cfdSRui Paulo /* 136332176cfdSRui Paulo * Mesh data frames are encapsulated according to the 136432176cfdSRui Paulo * rules of Section 11B.8.5 (p.139 of D3.0 spec). 136532176cfdSRui Paulo * o Group Addressed data (aka multicast) originating 136632176cfdSRui Paulo * at the local sta are sent w/ 3-address format and 136732176cfdSRui Paulo * address extension mode 00 136832176cfdSRui Paulo * o Individually Addressed data (aka unicast) originating 136932176cfdSRui Paulo * at the local sta are sent w/ 4-address format and 137032176cfdSRui Paulo * address extension mode 00 137132176cfdSRui Paulo * o Group Addressed data forwarded from a non-mesh sta are 137232176cfdSRui Paulo * sent w/ 3-address format and address extension mode 01 137332176cfdSRui Paulo * o Individually Address data from another sta are sent 137432176cfdSRui Paulo * w/ 4-address format and address extension mode 10 137532176cfdSRui Paulo */ 137632176cfdSRui Paulo is4addr = 0; /* NB: don't use, disable */ 1377085ff963SMatthew Dillon if (!IEEE80211_IS_MULTICAST(eh.ether_dhost)) { 1378085ff963SMatthew Dillon rt = ieee80211_mesh_rt_find(vap, eh.ether_dhost); 1379085ff963SMatthew Dillon KASSERT(rt != NULL, ("route is NULL")); 1380085ff963SMatthew Dillon dir = IEEE80211_FC1_DIR_DSTODS; 1381085ff963SMatthew Dillon hdrsize += IEEE80211_ADDR_LEN; 1382085ff963SMatthew Dillon if (rt->rt_flags & IEEE80211_MESHRT_FLAGS_PROXY) { 1383085ff963SMatthew Dillon if (IEEE80211_ADDR_EQ(rt->rt_mesh_gate, 1384085ff963SMatthew Dillon vap->iv_myaddr)) { 1385085ff963SMatthew Dillon IEEE80211_NOTE_MAC(vap, 1386085ff963SMatthew Dillon IEEE80211_MSG_MESH, 1387085ff963SMatthew Dillon eh.ether_dhost, 1388085ff963SMatthew Dillon "%s", "trying to send to ourself"); 1389085ff963SMatthew Dillon goto bad; 1390085ff963SMatthew Dillon } 1391085ff963SMatthew Dillon meshae = IEEE80211_MESH_AE_10; 1392085ff963SMatthew Dillon meshhdrsize = 1393085ff963SMatthew Dillon sizeof(struct ieee80211_meshcntl_ae10); 139432176cfdSRui Paulo } else { 1395085ff963SMatthew Dillon meshae = IEEE80211_MESH_AE_00; 1396085ff963SMatthew Dillon meshhdrsize = 1397085ff963SMatthew Dillon sizeof(struct ieee80211_meshcntl); 1398085ff963SMatthew Dillon } 1399085ff963SMatthew Dillon } else { 1400085ff963SMatthew Dillon dir = IEEE80211_FC1_DIR_FROMDS; 1401085ff963SMatthew Dillon if (!IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)) { 1402085ff963SMatthew Dillon /* proxy group */ 1403085ff963SMatthew Dillon meshae = IEEE80211_MESH_AE_01; 1404085ff963SMatthew Dillon meshhdrsize = 1405085ff963SMatthew Dillon sizeof(struct ieee80211_meshcntl_ae01); 1406085ff963SMatthew Dillon } else { 1407085ff963SMatthew Dillon /* group */ 1408085ff963SMatthew Dillon meshae = IEEE80211_MESH_AE_00; 1409085ff963SMatthew Dillon meshhdrsize = sizeof(struct ieee80211_meshcntl); 1410085ff963SMatthew Dillon } 141132176cfdSRui Paulo } 141232176cfdSRui Paulo } else { 141332176cfdSRui Paulo #endif 141432176cfdSRui Paulo /* 141532176cfdSRui Paulo * 4-address frames need to be generated for: 141632176cfdSRui Paulo * o packets sent through a WDS vap (IEEE80211_M_WDS) 141732176cfdSRui Paulo * o packets sent through a vap marked for relaying 141832176cfdSRui Paulo * (e.g. a station operating with dynamic WDS) 141932176cfdSRui Paulo */ 142032176cfdSRui Paulo is4addr = vap->iv_opmode == IEEE80211_M_WDS || 142132176cfdSRui Paulo ((vap->iv_flags_ext & IEEE80211_FEXT_4ADDR) && 142232176cfdSRui Paulo !IEEE80211_ADDR_EQ(eh.ether_shost, vap->iv_myaddr)); 142332176cfdSRui Paulo if (is4addr) 142432176cfdSRui Paulo hdrsize += IEEE80211_ADDR_LEN; 142532176cfdSRui Paulo meshhdrsize = meshae = 0; 142632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 142732176cfdSRui Paulo } 142832176cfdSRui Paulo #endif 142932176cfdSRui Paulo /* 143032176cfdSRui Paulo * Honor driver DATAPAD requirement. 143132176cfdSRui Paulo */ 1432841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_DATAPAD) 143332176cfdSRui Paulo hdrspace = roundup(hdrsize, sizeof(uint32_t)); 143432176cfdSRui Paulo else 143532176cfdSRui Paulo hdrspace = hdrsize; 143632176cfdSRui Paulo 143732176cfdSRui Paulo if (__predict_true((m->m_flags & M_FF) == 0)) { 143832176cfdSRui Paulo /* 143932176cfdSRui Paulo * Normal frame. 144032176cfdSRui Paulo */ 144132176cfdSRui Paulo m = ieee80211_mbuf_adjust(vap, hdrspace + meshhdrsize, key, m); 1442841ab66cSSepherosa Ziehau if (m == NULL) { 1443841ab66cSSepherosa Ziehau /* NB: ieee80211_mbuf_adjust handles msgs+statistics */ 1444f186073cSJoerg Sonnenberger goto bad; 1445f186073cSJoerg Sonnenberger } 144632176cfdSRui Paulo /* NB: this could be optimized 'cuz of ieee80211_mbuf_adjust */ 1447f186073cSJoerg Sonnenberger m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 1448f186073cSJoerg Sonnenberger llc = mtod(m, struct llc *); 1449f186073cSJoerg Sonnenberger llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 1450f186073cSJoerg Sonnenberger llc->llc_control = LLC_UI; 1451f186073cSJoerg Sonnenberger llc->llc_snap.org_code[0] = 0; 1452f186073cSJoerg Sonnenberger llc->llc_snap.org_code[1] = 0; 1453f186073cSJoerg Sonnenberger llc->llc_snap.org_code[2] = 0; 1454f186073cSJoerg Sonnenberger llc->llc_snap.ether_type = eh.ether_type; 145532176cfdSRui Paulo } else { 145632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 145732176cfdSRui Paulo /* 145832176cfdSRui Paulo * Aggregated frame. 145932176cfdSRui Paulo */ 146032176cfdSRui Paulo m = ieee80211_ff_encap(vap, m, hdrspace + meshhdrsize, key); 146132176cfdSRui Paulo if (m == NULL) 146232176cfdSRui Paulo #endif 146332176cfdSRui Paulo goto bad; 146432176cfdSRui Paulo } 1465841ab66cSSepherosa Ziehau datalen = m->m_pkthdr.len; /* NB: w/o 802.11 header */ 1466841ab66cSSepherosa Ziehau 1467b5523eacSSascha Wildner M_PREPEND(m, hdrspace + meshhdrsize, M_NOWAIT); 1468f186073cSJoerg Sonnenberger if (m == NULL) { 146932176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 1470f186073cSJoerg Sonnenberger goto bad; 1471f186073cSJoerg Sonnenberger } 1472f186073cSJoerg Sonnenberger wh = mtod(m, struct ieee80211_frame *); 1473f186073cSJoerg Sonnenberger wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_DATA; 1474f186073cSJoerg Sonnenberger *(uint16_t *)wh->i_dur = 0; 147532176cfdSRui Paulo qos = NULL; /* NB: quiet compiler */ 147632176cfdSRui Paulo if (is4addr) { 147732176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_DSTODS; 147832176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_macaddr); 147932176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 148032176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 148132176cfdSRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, eh.ether_shost); 148232176cfdSRui Paulo } else switch (vap->iv_opmode) { 1483f186073cSJoerg Sonnenberger case IEEE80211_M_STA: 1484f186073cSJoerg Sonnenberger wh->i_fc[1] = IEEE80211_FC1_DIR_TODS; 1485f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr1, ni->ni_bssid); 1486f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1487f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_dhost); 1488f186073cSJoerg Sonnenberger break; 1489f186073cSJoerg Sonnenberger case IEEE80211_M_IBSS: 1490f186073cSJoerg Sonnenberger case IEEE80211_M_AHDEMO: 1491f186073cSJoerg Sonnenberger wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 1492f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 1493f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr2, eh.ether_shost); 1494841ab66cSSepherosa Ziehau /* 149532176cfdSRui Paulo * NB: always use the bssid from iv_bss as the 1496841ab66cSSepherosa Ziehau * neighbor's may be stale after an ibss merge 1497841ab66cSSepherosa Ziehau */ 149832176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_bss->ni_bssid); 1499f186073cSJoerg Sonnenberger break; 1500f186073cSJoerg Sonnenberger case IEEE80211_M_HOSTAP: 1501f186073cSJoerg Sonnenberger wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 1502f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 1503f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr2, ni->ni_bssid); 1504f186073cSJoerg Sonnenberger IEEE80211_ADDR_COPY(wh->i_addr3, eh.ether_shost); 1505f186073cSJoerg Sonnenberger break; 150632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 150732176cfdSRui Paulo case IEEE80211_M_MBSS: 150832176cfdSRui Paulo /* NB: offset by hdrspace to deal with DATAPAD */ 150932176cfdSRui Paulo mc = (struct ieee80211_meshcntl_ae10 *) 151032176cfdSRui Paulo (mtod(m, uint8_t *) + hdrspace); 1511085ff963SMatthew Dillon wh->i_fc[1] = dir; 151232176cfdSRui Paulo switch (meshae) { 1513085ff963SMatthew Dillon case IEEE80211_MESH_AE_00: /* no proxy */ 151432176cfdSRui Paulo mc->mc_flags = 0; 1515085ff963SMatthew Dillon if (dir == IEEE80211_FC1_DIR_DSTODS) { /* ucast */ 1516085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr1, 1517085ff963SMatthew Dillon ni->ni_macaddr); 1518085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr2, 1519085ff963SMatthew Dillon vap->iv_myaddr); 1520085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr3, 1521085ff963SMatthew Dillon eh.ether_dhost); 1522085ff963SMatthew Dillon IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, 1523085ff963SMatthew Dillon eh.ether_shost); 1524085ff963SMatthew Dillon qos =((struct ieee80211_qosframe_addr4 *) 1525085ff963SMatthew Dillon wh)->i_qos; 1526085ff963SMatthew Dillon } else if (dir == IEEE80211_FC1_DIR_FROMDS) { 1527085ff963SMatthew Dillon /* mcast */ 1528085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr1, 1529085ff963SMatthew Dillon eh.ether_dhost); 1530085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr2, 1531085ff963SMatthew Dillon vap->iv_myaddr); 1532085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr3, 1533085ff963SMatthew Dillon eh.ether_shost); 1534085ff963SMatthew Dillon qos = ((struct ieee80211_qosframe *) 1535085ff963SMatthew Dillon wh)->i_qos; 1536085ff963SMatthew Dillon } 153732176cfdSRui Paulo break; 1538085ff963SMatthew Dillon case IEEE80211_MESH_AE_01: /* mcast, proxy */ 153932176cfdSRui Paulo wh->i_fc[1] = IEEE80211_FC1_DIR_FROMDS; 154032176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr1, eh.ether_dhost); 154132176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 154232176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr3, vap->iv_myaddr); 154332176cfdSRui Paulo mc->mc_flags = 1; 1544085ff963SMatthew Dillon IEEE80211_ADDR_COPY(MC01(mc)->mc_addr4, 1545085ff963SMatthew Dillon eh.ether_shost); 154632176cfdSRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 154732176cfdSRui Paulo break; 1548085ff963SMatthew Dillon case IEEE80211_MESH_AE_10: /* ucast, proxy */ 1549085ff963SMatthew Dillon KASSERT(rt != NULL, ("route is NULL")); 1550085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr1, rt->rt_nexthop); 155132176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 1552085ff963SMatthew Dillon IEEE80211_ADDR_COPY(wh->i_addr3, rt->rt_mesh_gate); 155332176cfdSRui Paulo IEEE80211_ADDR_COPY(WH4(wh)->i_addr4, vap->iv_myaddr); 1554085ff963SMatthew Dillon mc->mc_flags = IEEE80211_MESH_AE_10; 1555085ff963SMatthew Dillon IEEE80211_ADDR_COPY(mc->mc_addr5, eh.ether_dhost); 1556085ff963SMatthew Dillon IEEE80211_ADDR_COPY(mc->mc_addr6, eh.ether_shost); 155732176cfdSRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 155832176cfdSRui Paulo break; 155932176cfdSRui Paulo default: 156032176cfdSRui Paulo KASSERT(0, ("meshae %d", meshae)); 156132176cfdSRui Paulo break; 156232176cfdSRui Paulo } 156332176cfdSRui Paulo mc->mc_ttl = ms->ms_ttl; 156432176cfdSRui Paulo ms->ms_seq++; 156532176cfdSRui Paulo LE_WRITE_4(mc->mc_seq, ms->ms_seq); 156632176cfdSRui Paulo break; 156732176cfdSRui Paulo #endif 156832176cfdSRui Paulo case IEEE80211_M_WDS: /* NB: is4addr should always be true */ 156932176cfdSRui Paulo default: 1570f186073cSJoerg Sonnenberger goto bad; 1571f186073cSJoerg Sonnenberger } 1572841ab66cSSepherosa Ziehau if (m->m_flags & M_MORE_DATA) 1573841ab66cSSepherosa Ziehau wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; 1574841ab66cSSepherosa Ziehau if (addqos) { 1575841ab66cSSepherosa Ziehau int ac, tid; 1576841ab66cSSepherosa Ziehau 157732176cfdSRui Paulo if (is4addr) { 157832176cfdSRui Paulo qos = ((struct ieee80211_qosframe_addr4 *) wh)->i_qos; 157932176cfdSRui Paulo /* NB: mesh case handled earlier */ 158032176cfdSRui Paulo } else if (vap->iv_opmode != IEEE80211_M_MBSS) 158132176cfdSRui Paulo qos = ((struct ieee80211_qosframe *) wh)->i_qos; 1582841ab66cSSepherosa Ziehau ac = M_WME_GETAC(m); 1583841ab66cSSepherosa Ziehau /* map from access class/queue to 11e header priorty value */ 1584841ab66cSSepherosa Ziehau tid = WME_AC_TO_TID(ac); 158532176cfdSRui Paulo qos[0] = tid & IEEE80211_QOS_TID; 1586841ab66cSSepherosa Ziehau if (ic->ic_wme.wme_wmeChanParams.cap_wmeParams[ac].wmep_noackPolicy) 158732176cfdSRui Paulo qos[0] |= IEEE80211_QOS_ACKPOLICY_NOACK; 1588085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 1589085ff963SMatthew Dillon if (vap->iv_opmode == IEEE80211_M_MBSS) 1590085ff963SMatthew Dillon qos[1] = IEEE80211_QOS_MC; 1591085ff963SMatthew Dillon else 1592085ff963SMatthew Dillon #endif 159332176cfdSRui Paulo qos[1] = 0; 159432176cfdSRui Paulo wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_QOS; 1595841ab66cSSepherosa Ziehau 159632176cfdSRui Paulo if ((m->m_flags & M_AMPDU_MPDU) == 0) { 159732176cfdSRui Paulo /* 159832176cfdSRui Paulo * NB: don't assign a sequence # to potential 159932176cfdSRui Paulo * aggregates; we expect this happens at the 160032176cfdSRui Paulo * point the frame comes off any aggregation q 160132176cfdSRui Paulo * as otherwise we may introduce holes in the 160232176cfdSRui Paulo * BA sequence space and/or make window accouting 160332176cfdSRui Paulo * more difficult. 160432176cfdSRui Paulo * 160532176cfdSRui Paulo * XXX may want to control this with a driver 160632176cfdSRui Paulo * capability; this may also change when we pull 160732176cfdSRui Paulo * aggregation up into net80211 160832176cfdSRui Paulo */ 160932176cfdSRui Paulo seqno = ni->ni_txseqs[tid]++; 1610841ab66cSSepherosa Ziehau *(uint16_t *)wh->i_seq = 161132176cfdSRui Paulo htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 161232176cfdSRui Paulo M_SEQNO_SET(m, seqno); 1613841ab66cSSepherosa Ziehau } 161432176cfdSRui Paulo } else { 161532176cfdSRui Paulo seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 161632176cfdSRui Paulo *(uint16_t *)wh->i_seq = 161732176cfdSRui Paulo htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 161832176cfdSRui Paulo M_SEQNO_SET(m, seqno); 161932176cfdSRui Paulo } 162032176cfdSRui Paulo 162132176cfdSRui Paulo 162232176cfdSRui Paulo /* check if xmit fragmentation is required */ 162332176cfdSRui Paulo txfrag = (m->m_pkthdr.len > vap->iv_fragthreshold && 162432176cfdSRui Paulo !IEEE80211_IS_MULTICAST(wh->i_addr1) && 162532176cfdSRui Paulo (vap->iv_caps & IEEE80211_C_TXFRAG) && 162632176cfdSRui Paulo (m->m_flags & (M_FF | M_AMPDU_MPDU)) == 0); 1627841ab66cSSepherosa Ziehau if (key != NULL) { 1628841ab66cSSepherosa Ziehau /* 1629841ab66cSSepherosa Ziehau * IEEE 802.1X: send EAPOL frames always in the clear. 1630841ab66cSSepherosa Ziehau * WPA/WPA2: encrypt EAPOL keys when pairwise keys are set. 1631841ab66cSSepherosa Ziehau */ 163232176cfdSRui Paulo if ((m->m_flags & M_EAPOL) == 0 || 163332176cfdSRui Paulo ((vap->iv_flags & IEEE80211_F_WPA) && 163432176cfdSRui Paulo (vap->iv_opmode == IEEE80211_M_STA ? 163532176cfdSRui Paulo !IEEE80211_KEY_UNDEFINED(key) : 163632176cfdSRui Paulo !IEEE80211_KEY_UNDEFINED(&ni->ni_ucastkey)))) { 1637085ff963SMatthew Dillon wh->i_fc[1] |= IEEE80211_FC1_PROTECTED; 163832176cfdSRui Paulo if (!ieee80211_crypto_enmic(vap, key, m, txfrag)) { 163932176cfdSRui Paulo IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_OUTPUT, 164032176cfdSRui Paulo eh.ether_dhost, 164132176cfdSRui Paulo "%s", "enmic failed, discard frame"); 164232176cfdSRui Paulo vap->iv_stats.is_crypto_enmicfail++; 1643841ab66cSSepherosa Ziehau goto bad; 1644841ab66cSSepherosa Ziehau } 1645841ab66cSSepherosa Ziehau } 1646841ab66cSSepherosa Ziehau } 164732176cfdSRui Paulo if (txfrag && !ieee80211_fragment(vap, m, hdrsize, 164832176cfdSRui Paulo key != NULL ? key->wk_cipher->ic_header : 0, vap->iv_fragthreshold)) 164932176cfdSRui Paulo goto bad; 165032176cfdSRui Paulo 165132176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 1652841ab66cSSepherosa Ziehau 1653841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_data); 165432176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(wh->i_addr1)) { 1655fb134238SSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_mcast); 165632176cfdSRui Paulo m->m_flags |= M_MCAST; 165732176cfdSRui Paulo } else 1658fb134238SSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_ucast); 1659841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_ADD(ni, tx_bytes, datalen); 1660841ab66cSSepherosa Ziehau 1661f186073cSJoerg Sonnenberger return m; 1662f186073cSJoerg Sonnenberger bad: 1663f186073cSJoerg Sonnenberger if (m != NULL) 1664f186073cSJoerg Sonnenberger m_freem(m); 1665f186073cSJoerg Sonnenberger return NULL; 166632176cfdSRui Paulo #undef WH4 1667085ff963SMatthew Dillon #undef MC01 166832176cfdSRui Paulo } 166932176cfdSRui Paulo 167032176cfdSRui Paulo /* 167132176cfdSRui Paulo * Fragment the frame according to the specified mtu. 167232176cfdSRui Paulo * The size of the 802.11 header (w/o padding) is provided 167332176cfdSRui Paulo * so we don't need to recalculate it. We create a new 167432176cfdSRui Paulo * mbuf for each fragment and chain it through m_nextpkt; 167532176cfdSRui Paulo * we might be able to optimize this by reusing the original 167632176cfdSRui Paulo * packet's mbufs but that is significantly more complicated. 167732176cfdSRui Paulo */ 167832176cfdSRui Paulo static int 167932176cfdSRui Paulo ieee80211_fragment(struct ieee80211vap *vap, struct mbuf *m0, 168032176cfdSRui Paulo u_int hdrsize, u_int ciphdrsize, u_int mtu) 168132176cfdSRui Paulo { 1682085ff963SMatthew Dillon struct ieee80211com *ic = vap->iv_ic; 168332176cfdSRui Paulo struct ieee80211_frame *wh, *whf; 168432176cfdSRui Paulo struct mbuf *m, *prev, *next; 168532176cfdSRui Paulo u_int totalhdrsize, fragno, fragsize, off, remainder, payload; 1686085ff963SMatthew Dillon u_int hdrspace; 168732176cfdSRui Paulo 168832176cfdSRui Paulo KASSERT(m0->m_nextpkt == NULL, ("mbuf already chained?")); 168932176cfdSRui Paulo KASSERT(m0->m_pkthdr.len > mtu, 169032176cfdSRui Paulo ("pktlen %u mtu %u", m0->m_pkthdr.len, mtu)); 169132176cfdSRui Paulo 1692085ff963SMatthew Dillon /* 1693085ff963SMatthew Dillon * Honor driver DATAPAD requirement. 1694085ff963SMatthew Dillon */ 1695085ff963SMatthew Dillon if (ic->ic_flags & IEEE80211_F_DATAPAD) 1696085ff963SMatthew Dillon hdrspace = roundup(hdrsize, sizeof(uint32_t)); 1697085ff963SMatthew Dillon else 1698085ff963SMatthew Dillon hdrspace = hdrsize; 1699085ff963SMatthew Dillon 170032176cfdSRui Paulo wh = mtod(m0, struct ieee80211_frame *); 170132176cfdSRui Paulo /* NB: mark the first frag; it will be propagated below */ 170232176cfdSRui Paulo wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; 1703085ff963SMatthew Dillon totalhdrsize = hdrspace + ciphdrsize; 170432176cfdSRui Paulo fragno = 1; 170532176cfdSRui Paulo off = mtu - ciphdrsize; 170632176cfdSRui Paulo remainder = m0->m_pkthdr.len - off; 170732176cfdSRui Paulo prev = m0; 170832176cfdSRui Paulo do { 170932176cfdSRui Paulo fragsize = totalhdrsize + remainder; 171032176cfdSRui Paulo if (fragsize > mtu) 171132176cfdSRui Paulo fragsize = mtu; 171232176cfdSRui Paulo /* XXX fragsize can be >2048! */ 171332176cfdSRui Paulo KASSERT(fragsize < MCLBYTES, 171432176cfdSRui Paulo ("fragment size %u too big!", fragsize)); 171532176cfdSRui Paulo if (fragsize > MHLEN) 1716b5523eacSSascha Wildner m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 171732176cfdSRui Paulo else 1718b5523eacSSascha Wildner m = m_gethdr(M_NOWAIT, MT_DATA); 171932176cfdSRui Paulo if (m == NULL) 172032176cfdSRui Paulo goto bad; 172132176cfdSRui Paulo /* leave room to prepend any cipher header */ 172232176cfdSRui Paulo m_align(m, fragsize - ciphdrsize); 172332176cfdSRui Paulo 172432176cfdSRui Paulo /* 172532176cfdSRui Paulo * Form the header in the fragment. Note that since 172632176cfdSRui Paulo * we mark the first fragment with the MORE_FRAG bit 172732176cfdSRui Paulo * it automatically is propagated to each fragment; we 172832176cfdSRui Paulo * need only clear it on the last fragment (done below). 1729085ff963SMatthew Dillon * NB: frag 1+ dont have Mesh Control field present. 173032176cfdSRui Paulo */ 173132176cfdSRui Paulo whf = mtod(m, struct ieee80211_frame *); 173232176cfdSRui Paulo memcpy(whf, wh, hdrsize); 1733085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 1734085ff963SMatthew Dillon if (vap->iv_opmode == IEEE80211_M_MBSS) { 1735085ff963SMatthew Dillon if (IEEE80211_IS_DSTODS(wh)) 1736085ff963SMatthew Dillon ((struct ieee80211_qosframe_addr4 *) 1737085ff963SMatthew Dillon whf)->i_qos[1] &= ~IEEE80211_QOS_MC; 1738085ff963SMatthew Dillon else 1739085ff963SMatthew Dillon ((struct ieee80211_qosframe *) 1740085ff963SMatthew Dillon whf)->i_qos[1] &= ~IEEE80211_QOS_MC; 1741085ff963SMatthew Dillon } 1742085ff963SMatthew Dillon #endif 174332176cfdSRui Paulo *(uint16_t *)&whf->i_seq[0] |= htole16( 174432176cfdSRui Paulo (fragno & IEEE80211_SEQ_FRAG_MASK) << 174532176cfdSRui Paulo IEEE80211_SEQ_FRAG_SHIFT); 174632176cfdSRui Paulo fragno++; 174732176cfdSRui Paulo 174832176cfdSRui Paulo payload = fragsize - totalhdrsize; 174932176cfdSRui Paulo /* NB: destination is known to be contiguous */ 1750085ff963SMatthew Dillon 1751085ff963SMatthew Dillon m_copydata(m0, off, payload, mtod(m, uint8_t *) + hdrspace); 1752085ff963SMatthew Dillon m->m_len = hdrspace + payload; 1753085ff963SMatthew Dillon m->m_pkthdr.len = hdrspace + payload; 175432176cfdSRui Paulo m->m_flags |= M_FRAG; 175532176cfdSRui Paulo 175632176cfdSRui Paulo /* chain up the fragment */ 175732176cfdSRui Paulo prev->m_nextpkt = m; 175832176cfdSRui Paulo prev = m; 175932176cfdSRui Paulo 176032176cfdSRui Paulo /* deduct fragment just formed */ 176132176cfdSRui Paulo remainder -= payload; 176232176cfdSRui Paulo off += payload; 176332176cfdSRui Paulo } while (remainder != 0); 176432176cfdSRui Paulo 176532176cfdSRui Paulo /* set the last fragment */ 176632176cfdSRui Paulo m->m_flags |= M_LASTFRAG; 176732176cfdSRui Paulo whf->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG; 176832176cfdSRui Paulo 176932176cfdSRui Paulo /* strip first mbuf now that everything has been copied */ 177032176cfdSRui Paulo m_adj(m0, -(m0->m_pkthdr.len - (mtu - ciphdrsize))); 177132176cfdSRui Paulo m0->m_flags |= M_FIRSTFRAG | M_FRAG; 177232176cfdSRui Paulo 177332176cfdSRui Paulo vap->iv_stats.is_tx_fragframes++; 177432176cfdSRui Paulo vap->iv_stats.is_tx_frags += fragno-1; 177532176cfdSRui Paulo 177632176cfdSRui Paulo return 1; 177732176cfdSRui Paulo bad: 177832176cfdSRui Paulo /* reclaim fragments but leave original frame for caller to free */ 177932176cfdSRui Paulo for (m = m0->m_nextpkt; m != NULL; m = next) { 178032176cfdSRui Paulo next = m->m_nextpkt; 178132176cfdSRui Paulo m->m_nextpkt = NULL; /* XXX paranoid */ 178232176cfdSRui Paulo m_freem(m); 178332176cfdSRui Paulo } 178432176cfdSRui Paulo m0->m_nextpkt = NULL; 178532176cfdSRui Paulo return 0; 1786f186073cSJoerg Sonnenberger } 1787f186073cSJoerg Sonnenberger 1788f186073cSJoerg Sonnenberger /* 1789f186073cSJoerg Sonnenberger * Add a supported rates element id to a frame. 1790f186073cSJoerg Sonnenberger */ 1791f186073cSJoerg Sonnenberger uint8_t * 1792f186073cSJoerg Sonnenberger ieee80211_add_rates(uint8_t *frm, const struct ieee80211_rateset *rs) 1793f186073cSJoerg Sonnenberger { 1794f186073cSJoerg Sonnenberger int nrates; 1795f186073cSJoerg Sonnenberger 1796f186073cSJoerg Sonnenberger *frm++ = IEEE80211_ELEMID_RATES; 1797f186073cSJoerg Sonnenberger nrates = rs->rs_nrates; 1798f186073cSJoerg Sonnenberger if (nrates > IEEE80211_RATE_SIZE) 1799f186073cSJoerg Sonnenberger nrates = IEEE80211_RATE_SIZE; 1800f186073cSJoerg Sonnenberger *frm++ = nrates; 1801f186073cSJoerg Sonnenberger memcpy(frm, rs->rs_rates, nrates); 1802f186073cSJoerg Sonnenberger return frm + nrates; 1803f186073cSJoerg Sonnenberger } 1804f186073cSJoerg Sonnenberger 1805f186073cSJoerg Sonnenberger /* 1806f186073cSJoerg Sonnenberger * Add an extended supported rates element id to a frame. 1807f186073cSJoerg Sonnenberger */ 1808f186073cSJoerg Sonnenberger uint8_t * 1809f186073cSJoerg Sonnenberger ieee80211_add_xrates(uint8_t *frm, const struct ieee80211_rateset *rs) 1810f186073cSJoerg Sonnenberger { 1811f186073cSJoerg Sonnenberger /* 1812f186073cSJoerg Sonnenberger * Add an extended supported rates element if operating in 11g mode. 1813f186073cSJoerg Sonnenberger */ 1814f186073cSJoerg Sonnenberger if (rs->rs_nrates > IEEE80211_RATE_SIZE) { 1815f186073cSJoerg Sonnenberger int nrates = rs->rs_nrates - IEEE80211_RATE_SIZE; 1816f186073cSJoerg Sonnenberger *frm++ = IEEE80211_ELEMID_XRATES; 1817f186073cSJoerg Sonnenberger *frm++ = nrates; 1818f186073cSJoerg Sonnenberger memcpy(frm, rs->rs_rates + IEEE80211_RATE_SIZE, nrates); 1819f186073cSJoerg Sonnenberger frm += nrates; 1820f186073cSJoerg Sonnenberger } 1821f186073cSJoerg Sonnenberger return frm; 1822f186073cSJoerg Sonnenberger } 1823f186073cSJoerg Sonnenberger 1824f186073cSJoerg Sonnenberger /* 182532176cfdSRui Paulo * Add an ssid element to a frame. 1826f186073cSJoerg Sonnenberger */ 1827e218318cSMatthew Dillon uint8_t * 1828f186073cSJoerg Sonnenberger ieee80211_add_ssid(uint8_t *frm, const uint8_t *ssid, u_int len) 1829f186073cSJoerg Sonnenberger { 1830f186073cSJoerg Sonnenberger *frm++ = IEEE80211_ELEMID_SSID; 1831f186073cSJoerg Sonnenberger *frm++ = len; 1832f186073cSJoerg Sonnenberger memcpy(frm, ssid, len); 1833f186073cSJoerg Sonnenberger return frm + len; 1834f186073cSJoerg Sonnenberger } 1835f186073cSJoerg Sonnenberger 1836841ab66cSSepherosa Ziehau /* 1837841ab66cSSepherosa Ziehau * Add an erp element to a frame. 1838841ab66cSSepherosa Ziehau */ 1839841ab66cSSepherosa Ziehau static uint8_t * 1840841ab66cSSepherosa Ziehau ieee80211_add_erp(uint8_t *frm, struct ieee80211com *ic) 1841f186073cSJoerg Sonnenberger { 1842841ab66cSSepherosa Ziehau uint8_t erp; 1843f186073cSJoerg Sonnenberger 1844841ab66cSSepherosa Ziehau *frm++ = IEEE80211_ELEMID_ERP; 1845841ab66cSSepherosa Ziehau *frm++ = 1; 1846841ab66cSSepherosa Ziehau erp = 0; 1847841ab66cSSepherosa Ziehau if (ic->ic_nonerpsta != 0) 1848841ab66cSSepherosa Ziehau erp |= IEEE80211_ERP_NON_ERP_PRESENT; 1849841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_USEPROT) 1850841ab66cSSepherosa Ziehau erp |= IEEE80211_ERP_USE_PROTECTION; 1851841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_USEBARKER) 1852841ab66cSSepherosa Ziehau erp |= IEEE80211_ERP_LONG_PREAMBLE; 1853841ab66cSSepherosa Ziehau *frm++ = erp; 1854841ab66cSSepherosa Ziehau return frm; 1855841ab66cSSepherosa Ziehau } 1856841ab66cSSepherosa Ziehau 1857841ab66cSSepherosa Ziehau /* 185832176cfdSRui Paulo * Add a CFParams element to a frame. 1859841ab66cSSepherosa Ziehau */ 1860841ab66cSSepherosa Ziehau static uint8_t * 186132176cfdSRui Paulo ieee80211_add_cfparms(uint8_t *frm, struct ieee80211com *ic) 1862841ab66cSSepherosa Ziehau { 186332176cfdSRui Paulo #define ADDSHORT(frm, v) do { \ 186432176cfdSRui Paulo LE_WRITE_2(frm, v); \ 186532176cfdSRui Paulo frm += 2; \ 186632176cfdSRui Paulo } while (0) 186732176cfdSRui Paulo *frm++ = IEEE80211_ELEMID_CFPARMS; 186832176cfdSRui Paulo *frm++ = 6; 186932176cfdSRui Paulo *frm++ = 0; /* CFP count */ 187032176cfdSRui Paulo *frm++ = 2; /* CFP period */ 187132176cfdSRui Paulo ADDSHORT(frm, 0); /* CFP MaxDuration (TU) */ 187232176cfdSRui Paulo ADDSHORT(frm, 0); /* CFP CurRemaining (TU) */ 1873841ab66cSSepherosa Ziehau return frm; 187432176cfdSRui Paulo #undef ADDSHORT 187532176cfdSRui Paulo } 187632176cfdSRui Paulo 187732176cfdSRui Paulo static __inline uint8_t * 187832176cfdSRui Paulo add_appie(uint8_t *frm, const struct ieee80211_appie *ie) 187932176cfdSRui Paulo { 188032176cfdSRui Paulo memcpy(frm, ie->ie_data, ie->ie_len); 188132176cfdSRui Paulo return frm + ie->ie_len; 188232176cfdSRui Paulo } 188332176cfdSRui Paulo 188432176cfdSRui Paulo static __inline uint8_t * 188532176cfdSRui Paulo add_ie(uint8_t *frm, const uint8_t *ie) 188632176cfdSRui Paulo { 188732176cfdSRui Paulo memcpy(frm, ie, 2 + ie[1]); 188832176cfdSRui Paulo return frm + 2 + ie[1]; 1889841ab66cSSepherosa Ziehau } 1890841ab66cSSepherosa Ziehau 1891841ab66cSSepherosa Ziehau #define WME_OUI_BYTES 0x00, 0x50, 0xf2 1892841ab66cSSepherosa Ziehau /* 1893841ab66cSSepherosa Ziehau * Add a WME information element to a frame. 1894841ab66cSSepherosa Ziehau */ 1895841ab66cSSepherosa Ziehau static uint8_t * 1896841ab66cSSepherosa Ziehau ieee80211_add_wme_info(uint8_t *frm, struct ieee80211_wme_state *wme) 1897841ab66cSSepherosa Ziehau { 1898841ab66cSSepherosa Ziehau static const struct ieee80211_wme_info info = { 1899841ab66cSSepherosa Ziehau .wme_id = IEEE80211_ELEMID_VENDOR, 1900841ab66cSSepherosa Ziehau .wme_len = sizeof(struct ieee80211_wme_info) - 2, 1901841ab66cSSepherosa Ziehau .wme_oui = { WME_OUI_BYTES }, 1902841ab66cSSepherosa Ziehau .wme_type = WME_OUI_TYPE, 1903841ab66cSSepherosa Ziehau .wme_subtype = WME_INFO_OUI_SUBTYPE, 1904841ab66cSSepherosa Ziehau .wme_version = WME_VERSION, 1905841ab66cSSepherosa Ziehau .wme_info = 0, 1906841ab66cSSepherosa Ziehau }; 1907841ab66cSSepherosa Ziehau memcpy(frm, &info, sizeof(info)); 1908841ab66cSSepherosa Ziehau return frm + sizeof(info); 1909841ab66cSSepherosa Ziehau } 1910841ab66cSSepherosa Ziehau 1911841ab66cSSepherosa Ziehau /* 1912841ab66cSSepherosa Ziehau * Add a WME parameters element to a frame. 1913841ab66cSSepherosa Ziehau */ 1914841ab66cSSepherosa Ziehau static uint8_t * 1915841ab66cSSepherosa Ziehau ieee80211_add_wme_param(uint8_t *frm, struct ieee80211_wme_state *wme) 1916841ab66cSSepherosa Ziehau { 1917841ab66cSSepherosa Ziehau #define SM(_v, _f) (((_v) << _f##_S) & _f) 1918841ab66cSSepherosa Ziehau #define ADDSHORT(frm, v) do { \ 191932176cfdSRui Paulo LE_WRITE_2(frm, v); \ 1920841ab66cSSepherosa Ziehau frm += 2; \ 1921841ab66cSSepherosa Ziehau } while (0) 1922841ab66cSSepherosa Ziehau /* NB: this works 'cuz a param has an info at the front */ 1923841ab66cSSepherosa Ziehau static const struct ieee80211_wme_info param = { 1924841ab66cSSepherosa Ziehau .wme_id = IEEE80211_ELEMID_VENDOR, 1925841ab66cSSepherosa Ziehau .wme_len = sizeof(struct ieee80211_wme_param) - 2, 1926841ab66cSSepherosa Ziehau .wme_oui = { WME_OUI_BYTES }, 1927841ab66cSSepherosa Ziehau .wme_type = WME_OUI_TYPE, 1928841ab66cSSepherosa Ziehau .wme_subtype = WME_PARAM_OUI_SUBTYPE, 1929841ab66cSSepherosa Ziehau .wme_version = WME_VERSION, 1930841ab66cSSepherosa Ziehau }; 1931841ab66cSSepherosa Ziehau int i; 1932841ab66cSSepherosa Ziehau 1933841ab66cSSepherosa Ziehau memcpy(frm, ¶m, sizeof(param)); 1934841ab66cSSepherosa Ziehau frm += __offsetof(struct ieee80211_wme_info, wme_info); 1935841ab66cSSepherosa Ziehau *frm++ = wme->wme_bssChanParams.cap_info; /* AC info */ 1936841ab66cSSepherosa Ziehau *frm++ = 0; /* reserved field */ 1937841ab66cSSepherosa Ziehau for (i = 0; i < WME_NUM_AC; i++) { 1938841ab66cSSepherosa Ziehau const struct wmeParams *ac = 1939841ab66cSSepherosa Ziehau &wme->wme_bssChanParams.cap_wmeParams[i]; 1940841ab66cSSepherosa Ziehau *frm++ = SM(i, WME_PARAM_ACI) 1941841ab66cSSepherosa Ziehau | SM(ac->wmep_acm, WME_PARAM_ACM) 1942841ab66cSSepherosa Ziehau | SM(ac->wmep_aifsn, WME_PARAM_AIFSN) 1943841ab66cSSepherosa Ziehau ; 1944841ab66cSSepherosa Ziehau *frm++ = SM(ac->wmep_logcwmax, WME_PARAM_LOGCWMAX) 1945841ab66cSSepherosa Ziehau | SM(ac->wmep_logcwmin, WME_PARAM_LOGCWMIN) 1946841ab66cSSepherosa Ziehau ; 1947841ab66cSSepherosa Ziehau ADDSHORT(frm, ac->wmep_txopLimit); 1948841ab66cSSepherosa Ziehau } 1949841ab66cSSepherosa Ziehau return frm; 1950841ab66cSSepherosa Ziehau #undef SM 1951841ab66cSSepherosa Ziehau #undef ADDSHORT 1952841ab66cSSepherosa Ziehau } 1953841ab66cSSepherosa Ziehau #undef WME_OUI_BYTES 1954841ab66cSSepherosa Ziehau 1955841ab66cSSepherosa Ziehau /* 195632176cfdSRui Paulo * Add an 11h Power Constraint element to a frame. 195732176cfdSRui Paulo */ 195832176cfdSRui Paulo static uint8_t * 195932176cfdSRui Paulo ieee80211_add_powerconstraint(uint8_t *frm, struct ieee80211vap *vap) 196032176cfdSRui Paulo { 196132176cfdSRui Paulo const struct ieee80211_channel *c = vap->iv_bss->ni_chan; 196232176cfdSRui Paulo /* XXX per-vap tx power limit? */ 196332176cfdSRui Paulo int8_t limit = vap->iv_ic->ic_txpowlimit / 2; 196432176cfdSRui Paulo 196532176cfdSRui Paulo frm[0] = IEEE80211_ELEMID_PWRCNSTR; 196632176cfdSRui Paulo frm[1] = 1; 196732176cfdSRui Paulo frm[2] = c->ic_maxregpower > limit ? c->ic_maxregpower - limit : 0; 196832176cfdSRui Paulo return frm + 3; 196932176cfdSRui Paulo } 197032176cfdSRui Paulo 197132176cfdSRui Paulo /* 197232176cfdSRui Paulo * Add an 11h Power Capability element to a frame. 197332176cfdSRui Paulo */ 197432176cfdSRui Paulo static uint8_t * 197532176cfdSRui Paulo ieee80211_add_powercapability(uint8_t *frm, const struct ieee80211_channel *c) 197632176cfdSRui Paulo { 197732176cfdSRui Paulo frm[0] = IEEE80211_ELEMID_PWRCAP; 197832176cfdSRui Paulo frm[1] = 2; 197932176cfdSRui Paulo frm[2] = c->ic_minpower; 198032176cfdSRui Paulo frm[3] = c->ic_maxpower; 198132176cfdSRui Paulo return frm + 4; 198232176cfdSRui Paulo } 198332176cfdSRui Paulo 198432176cfdSRui Paulo /* 198532176cfdSRui Paulo * Add an 11h Supported Channels element to a frame. 198632176cfdSRui Paulo */ 198732176cfdSRui Paulo static uint8_t * 198832176cfdSRui Paulo ieee80211_add_supportedchannels(uint8_t *frm, struct ieee80211com *ic) 198932176cfdSRui Paulo { 199032176cfdSRui Paulo static const int ielen = 26; 199132176cfdSRui Paulo 199232176cfdSRui Paulo frm[0] = IEEE80211_ELEMID_SUPPCHAN; 199332176cfdSRui Paulo frm[1] = ielen; 199432176cfdSRui Paulo /* XXX not correct */ 199532176cfdSRui Paulo memcpy(frm+2, ic->ic_chan_avail, ielen); 199632176cfdSRui Paulo return frm + 2 + ielen; 199732176cfdSRui Paulo } 199832176cfdSRui Paulo 199932176cfdSRui Paulo /* 2000085ff963SMatthew Dillon * Add an 11h Quiet time element to a frame. 2001085ff963SMatthew Dillon */ 2002085ff963SMatthew Dillon static uint8_t * 2003085ff963SMatthew Dillon ieee80211_add_quiet(uint8_t *frm, struct ieee80211vap *vap) 2004085ff963SMatthew Dillon { 2005085ff963SMatthew Dillon struct ieee80211_quiet_ie *quiet = (struct ieee80211_quiet_ie *) frm; 2006085ff963SMatthew Dillon 2007085ff963SMatthew Dillon quiet->quiet_ie = IEEE80211_ELEMID_QUIET; 2008085ff963SMatthew Dillon quiet->len = 6; 2009085ff963SMatthew Dillon if (vap->iv_quiet_count_value == 1) 2010085ff963SMatthew Dillon vap->iv_quiet_count_value = vap->iv_quiet_count; 2011085ff963SMatthew Dillon else if (vap->iv_quiet_count_value > 1) 2012085ff963SMatthew Dillon vap->iv_quiet_count_value--; 2013085ff963SMatthew Dillon 2014085ff963SMatthew Dillon if (vap->iv_quiet_count_value == 0) { 2015085ff963SMatthew Dillon /* value 0 is reserved as per 802.11h standerd */ 2016085ff963SMatthew Dillon vap->iv_quiet_count_value = 1; 2017085ff963SMatthew Dillon } 2018085ff963SMatthew Dillon 2019085ff963SMatthew Dillon quiet->tbttcount = vap->iv_quiet_count_value; 2020085ff963SMatthew Dillon quiet->period = vap->iv_quiet_period; 2021085ff963SMatthew Dillon quiet->duration = htole16(vap->iv_quiet_duration); 2022085ff963SMatthew Dillon quiet->offset = htole16(vap->iv_quiet_offset); 2023085ff963SMatthew Dillon return frm + sizeof(*quiet); 2024085ff963SMatthew Dillon } 2025085ff963SMatthew Dillon 2026085ff963SMatthew Dillon /* 202732176cfdSRui Paulo * Add an 11h Channel Switch Announcement element to a frame. 202832176cfdSRui Paulo * Note that we use the per-vap CSA count to adjust the global 202932176cfdSRui Paulo * counter so we can use this routine to form probe response 203032176cfdSRui Paulo * frames and get the current count. 203132176cfdSRui Paulo */ 203232176cfdSRui Paulo static uint8_t * 203332176cfdSRui Paulo ieee80211_add_csa(uint8_t *frm, struct ieee80211vap *vap) 203432176cfdSRui Paulo { 203532176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 203632176cfdSRui Paulo struct ieee80211_csa_ie *csa = (struct ieee80211_csa_ie *) frm; 203732176cfdSRui Paulo 203832176cfdSRui Paulo csa->csa_ie = IEEE80211_ELEMID_CSA; 203932176cfdSRui Paulo csa->csa_len = 3; 204032176cfdSRui Paulo csa->csa_mode = 1; /* XXX force quiet on channel */ 204132176cfdSRui Paulo csa->csa_newchan = ieee80211_chan2ieee(ic, ic->ic_csa_newchan); 204232176cfdSRui Paulo csa->csa_count = ic->ic_csa_count - vap->iv_csa_count; 204332176cfdSRui Paulo return frm + sizeof(*csa); 204432176cfdSRui Paulo } 204532176cfdSRui Paulo 204632176cfdSRui Paulo /* 204732176cfdSRui Paulo * Add an 11h country information element to a frame. 204832176cfdSRui Paulo */ 204932176cfdSRui Paulo static uint8_t * 205032176cfdSRui Paulo ieee80211_add_countryie(uint8_t *frm, struct ieee80211com *ic) 205132176cfdSRui Paulo { 205232176cfdSRui Paulo 205332176cfdSRui Paulo if (ic->ic_countryie == NULL || 205432176cfdSRui Paulo ic->ic_countryie_chan != ic->ic_bsschan) { 205532176cfdSRui Paulo /* 205632176cfdSRui Paulo * Handle lazy construction of ie. This is done on 205732176cfdSRui Paulo * first use and after a channel change that requires 205832176cfdSRui Paulo * re-calculation. 205932176cfdSRui Paulo */ 206032176cfdSRui Paulo if (ic->ic_countryie != NULL) 206132176cfdSRui Paulo kfree(ic->ic_countryie, M_80211_NODE_IE); 206232176cfdSRui Paulo ic->ic_countryie = ieee80211_alloc_countryie(ic); 206332176cfdSRui Paulo if (ic->ic_countryie == NULL) 206432176cfdSRui Paulo return frm; 206532176cfdSRui Paulo ic->ic_countryie_chan = ic->ic_bsschan; 206632176cfdSRui Paulo } 206732176cfdSRui Paulo return add_appie(frm, ic->ic_countryie); 206832176cfdSRui Paulo } 206932176cfdSRui Paulo 2070085ff963SMatthew Dillon uint8_t * 2071085ff963SMatthew Dillon ieee80211_add_wpa(uint8_t *frm, const struct ieee80211vap *vap) 2072085ff963SMatthew Dillon { 2073085ff963SMatthew Dillon if (vap->iv_flags & IEEE80211_F_WPA1 && vap->iv_wpa_ie != NULL) 2074085ff963SMatthew Dillon return (add_ie(frm, vap->iv_wpa_ie)); 2075085ff963SMatthew Dillon else { 2076085ff963SMatthew Dillon /* XXX else complain? */ 2077085ff963SMatthew Dillon return (frm); 2078085ff963SMatthew Dillon } 2079085ff963SMatthew Dillon } 2080085ff963SMatthew Dillon 2081085ff963SMatthew Dillon uint8_t * 2082085ff963SMatthew Dillon ieee80211_add_rsn(uint8_t *frm, const struct ieee80211vap *vap) 2083085ff963SMatthew Dillon { 2084085ff963SMatthew Dillon if (vap->iv_flags & IEEE80211_F_WPA2 && vap->iv_rsn_ie != NULL) 2085085ff963SMatthew Dillon return (add_ie(frm, vap->iv_rsn_ie)); 2086085ff963SMatthew Dillon else { 2087085ff963SMatthew Dillon /* XXX else complain? */ 2088085ff963SMatthew Dillon return (frm); 2089085ff963SMatthew Dillon } 2090085ff963SMatthew Dillon } 2091085ff963SMatthew Dillon 2092085ff963SMatthew Dillon uint8_t * 2093085ff963SMatthew Dillon ieee80211_add_qos(uint8_t *frm, const struct ieee80211_node *ni) 2094085ff963SMatthew Dillon { 2095085ff963SMatthew Dillon if (ni->ni_flags & IEEE80211_NODE_QOS) { 2096085ff963SMatthew Dillon *frm++ = IEEE80211_ELEMID_QOS; 2097085ff963SMatthew Dillon *frm++ = 1; 2098085ff963SMatthew Dillon *frm++ = 0; 2099085ff963SMatthew Dillon } 2100085ff963SMatthew Dillon 2101085ff963SMatthew Dillon return (frm); 2102085ff963SMatthew Dillon } 2103085ff963SMatthew Dillon 210432176cfdSRui Paulo /* 2105841ab66cSSepherosa Ziehau * Send a probe request frame with the specified ssid 2106841ab66cSSepherosa Ziehau * and any optional information element data. 2107841ab66cSSepherosa Ziehau */ 2108841ab66cSSepherosa Ziehau int 2109841ab66cSSepherosa Ziehau ieee80211_send_probereq(struct ieee80211_node *ni, 2110841ab66cSSepherosa Ziehau const uint8_t sa[IEEE80211_ADDR_LEN], 2111841ab66cSSepherosa Ziehau const uint8_t da[IEEE80211_ADDR_LEN], 2112841ab66cSSepherosa Ziehau const uint8_t bssid[IEEE80211_ADDR_LEN], 211332176cfdSRui Paulo const uint8_t *ssid, size_t ssidlen) 2114841ab66cSSepherosa Ziehau { 211532176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 2116841ab66cSSepherosa Ziehau struct ieee80211com *ic = ni->ni_ic; 211732176cfdSRui Paulo const struct ieee80211_txparam *tp; 211832176cfdSRui Paulo struct ieee80211_bpf_params params; 2119085ff963SMatthew Dillon struct ieee80211_frame *wh; 212032176cfdSRui Paulo const struct ieee80211_rateset *rs; 2121841ab66cSSepherosa Ziehau struct mbuf *m; 2122841ab66cSSepherosa Ziehau uint8_t *frm; 2123085ff963SMatthew Dillon int ret; 2124841ab66cSSepherosa Ziehau 212532176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 212632176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, ni, 212732176cfdSRui Paulo "block %s frame in CAC state", "probe request"); 212832176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 212932176cfdSRui Paulo return EIO; /* XXX */ 213032176cfdSRui Paulo } 213132176cfdSRui Paulo 2132841ab66cSSepherosa Ziehau /* 2133841ab66cSSepherosa Ziehau * Hold a reference on the node so it doesn't go away until after 2134841ab66cSSepherosa Ziehau * the xmit is complete all the way in the driver. On error we 2135841ab66cSSepherosa Ziehau * will remove our reference. 2136841ab66cSSepherosa Ziehau */ 213732176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 21381e290df3SAntonio Huete Jimenez "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2139841ab66cSSepherosa Ziehau __func__, __LINE__, 2140085ff963SMatthew Dillon ni, ether_sprintf(ni->ni_macaddr), 2141841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 2142841ab66cSSepherosa Ziehau ieee80211_ref_node(ni); 2143841ab66cSSepherosa Ziehau 2144841ab66cSSepherosa Ziehau /* 2145841ab66cSSepherosa Ziehau * prreq frame format 2146841ab66cSSepherosa Ziehau * [tlv] ssid 2147841ab66cSSepherosa Ziehau * [tlv] supported rates 214832176cfdSRui Paulo * [tlv] RSN (optional) 2149841ab66cSSepherosa Ziehau * [tlv] extended supported rates 215032176cfdSRui Paulo * [tlv] WPA (optional) 2151841ab66cSSepherosa Ziehau * [tlv] user-specified ie's 2152841ab66cSSepherosa Ziehau */ 2153841ab66cSSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 21544ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 2155841ab66cSSepherosa Ziehau 2 + IEEE80211_NWID_LEN 2156841ab66cSSepherosa Ziehau + 2 + IEEE80211_RATE_SIZE 215732176cfdSRui Paulo + sizeof(struct ieee80211_ie_wpa) 2158841ab66cSSepherosa Ziehau + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 215932176cfdSRui Paulo + sizeof(struct ieee80211_ie_wpa) 216032176cfdSRui Paulo + (vap->iv_appie_probereq != NULL ? 216132176cfdSRui Paulo vap->iv_appie_probereq->ie_len : 0) 2162841ab66cSSepherosa Ziehau ); 2163841ab66cSSepherosa Ziehau if (m == NULL) { 216432176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 2165841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2166841ab66cSSepherosa Ziehau return ENOMEM; 2167841ab66cSSepherosa Ziehau } 2168841ab66cSSepherosa Ziehau 2169841ab66cSSepherosa Ziehau frm = ieee80211_add_ssid(frm, ssid, ssidlen); 217032176cfdSRui Paulo rs = ieee80211_get_suprates(ic, ic->ic_curchan); 217132176cfdSRui Paulo frm = ieee80211_add_rates(frm, rs); 2172085ff963SMatthew Dillon frm = ieee80211_add_rsn(frm, vap); 217332176cfdSRui Paulo frm = ieee80211_add_xrates(frm, rs); 2174085ff963SMatthew Dillon frm = ieee80211_add_wpa(frm, vap); 217532176cfdSRui Paulo if (vap->iv_appie_probereq != NULL) 217632176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_probereq); 2177841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2178841ab66cSSepherosa Ziehau 217932176cfdSRui Paulo KASSERT(M_LEADINGSPACE(m) >= sizeof(struct ieee80211_frame), 218032176cfdSRui Paulo ("leading space %zd", M_LEADINGSPACE(m))); 2181b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 218232176cfdSRui Paulo if (m == NULL) { 218332176cfdSRui Paulo /* NB: cannot happen */ 218432176cfdSRui Paulo ieee80211_free_node(ni); 2185841ab66cSSepherosa Ziehau return ENOMEM; 218632176cfdSRui Paulo } 2187841ab66cSSepherosa Ziehau 2188085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 2189085ff963SMatthew Dillon wh = mtod(m, struct ieee80211_frame *); 219032176cfdSRui Paulo ieee80211_send_setup(ni, m, 2191841ab66cSSepherosa Ziehau IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ, 219232176cfdSRui Paulo IEEE80211_NONQOS_TID, sa, da, bssid); 2193841ab66cSSepherosa Ziehau /* XXX power management? */ 219432176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 219532176cfdSRui Paulo 219632176cfdSRui Paulo M_WME_SETAC(m, WME_AC_BE); 2197841ab66cSSepherosa Ziehau 2198841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_probereq); 2199841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_mgmt); 2200841ab66cSSepherosa Ziehau 220132176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 22021e290df3SAntonio Huete Jimenez "send probe req on channel %u bssid %s ssid \"%.*s\"\n", 2203085ff963SMatthew Dillon ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(bssid), 2204*f92fae3fSSascha Wildner (int)ssidlen, ssid); 2205841ab66cSSepherosa Ziehau 220632176cfdSRui Paulo memset(¶ms, 0, sizeof(params)); 220732176cfdSRui Paulo params.ibp_pri = M_WME_GETAC(m); 220832176cfdSRui Paulo tp = &vap->iv_txparms[ieee80211_chan2mode(ic->ic_curchan)]; 220932176cfdSRui Paulo params.ibp_rate0 = tp->mgmtrate; 221032176cfdSRui Paulo if (IEEE80211_IS_MULTICAST(da)) { 221132176cfdSRui Paulo params.ibp_flags |= IEEE80211_BPF_NOACK; 221232176cfdSRui Paulo params.ibp_try0 = 1; 221332176cfdSRui Paulo } else 221432176cfdSRui Paulo params.ibp_try0 = tp->maxretry; 221532176cfdSRui Paulo params.ibp_power = ni->ni_txpower; 2216085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, ni, m, ¶ms); 2217085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 2218085ff963SMatthew Dillon return (ret); 2219841ab66cSSepherosa Ziehau } 2220841ab66cSSepherosa Ziehau 2221841ab66cSSepherosa Ziehau /* 2222841ab66cSSepherosa Ziehau * Calculate capability information for mgt frames. 2223841ab66cSSepherosa Ziehau */ 222432176cfdSRui Paulo uint16_t 222532176cfdSRui Paulo ieee80211_getcapinfo(struct ieee80211vap *vap, struct ieee80211_channel *chan) 2226841ab66cSSepherosa Ziehau { 222732176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 2228841ab66cSSepherosa Ziehau uint16_t capinfo; 2229841ab66cSSepherosa Ziehau 223032176cfdSRui Paulo KASSERT(vap->iv_opmode != IEEE80211_M_STA, ("station mode")); 2231841ab66cSSepherosa Ziehau 223232176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP) 2233841ab66cSSepherosa Ziehau capinfo = IEEE80211_CAPINFO_ESS; 223432176cfdSRui Paulo else if (vap->iv_opmode == IEEE80211_M_IBSS) 2235841ab66cSSepherosa Ziehau capinfo = IEEE80211_CAPINFO_IBSS; 2236841ab66cSSepherosa Ziehau else 2237841ab66cSSepherosa Ziehau capinfo = 0; 223832176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) 2239841ab66cSSepherosa Ziehau capinfo |= IEEE80211_CAPINFO_PRIVACY; 224032176cfdSRui Paulo if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 224132176cfdSRui Paulo IEEE80211_IS_CHAN_2GHZ(chan)) 2242841ab66cSSepherosa Ziehau capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 2243841ab66cSSepherosa Ziehau if (ic->ic_flags & IEEE80211_F_SHSLOT) 2244841ab66cSSepherosa Ziehau capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 224532176cfdSRui Paulo if (IEEE80211_IS_CHAN_5GHZ(chan) && (vap->iv_flags & IEEE80211_F_DOTH)) 224632176cfdSRui Paulo capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 2247841ab66cSSepherosa Ziehau return capinfo; 2248f186073cSJoerg Sonnenberger } 2249f186073cSJoerg Sonnenberger 2250f186073cSJoerg Sonnenberger /* 2251f186073cSJoerg Sonnenberger * Send a management frame. The node is for the destination (or ic_bss 2252f186073cSJoerg Sonnenberger * when in station mode). Nodes other than ic_bss have their reference 2253f186073cSJoerg Sonnenberger * count bumped to reflect our use for an indeterminant time. 2254f186073cSJoerg Sonnenberger */ 2255f186073cSJoerg Sonnenberger int 225632176cfdSRui Paulo ieee80211_send_mgmt(struct ieee80211_node *ni, int type, int arg) 2257f186073cSJoerg Sonnenberger { 225832176cfdSRui Paulo #define HTFLAGS (IEEE80211_NODE_HT | IEEE80211_NODE_HTCOMPAT) 225932176cfdSRui Paulo #define senderr(_x, _v) do { vap->iv_stats._v++; ret = _x; goto bad; } while (0) 226032176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 226132176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 226232176cfdSRui Paulo struct ieee80211_node *bss = vap->iv_bss; 226332176cfdSRui Paulo struct ieee80211_bpf_params params; 2264f186073cSJoerg Sonnenberger struct mbuf *m; 2265f186073cSJoerg Sonnenberger uint8_t *frm; 2266f186073cSJoerg Sonnenberger uint16_t capinfo; 226732176cfdSRui Paulo int has_challenge, is_shared_key, ret, status; 2268f186073cSJoerg Sonnenberger 2269f186073cSJoerg Sonnenberger KASSERT(ni != NULL, ("null node")); 2270f186073cSJoerg Sonnenberger 2271f186073cSJoerg Sonnenberger /* 2272f186073cSJoerg Sonnenberger * Hold a reference on the node so it doesn't go away until after 2273f186073cSJoerg Sonnenberger * the xmit is complete all the way in the driver. On error we 2274f186073cSJoerg Sonnenberger * will remove our reference. 2275f186073cSJoerg Sonnenberger */ 227632176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 22771e290df3SAntonio Huete Jimenez "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2278841ab66cSSepherosa Ziehau __func__, __LINE__, 2279085ff963SMatthew Dillon ni, ether_sprintf(ni->ni_macaddr), 2280841ab66cSSepherosa Ziehau ieee80211_node_refcnt(ni)+1); 2281f186073cSJoerg Sonnenberger ieee80211_ref_node(ni); 2282841ab66cSSepherosa Ziehau 228332176cfdSRui Paulo memset(¶ms, 0, sizeof(params)); 2284f186073cSJoerg Sonnenberger switch (type) { 2285f186073cSJoerg Sonnenberger 2286f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_AUTH: 2287841ab66cSSepherosa Ziehau status = arg >> 16; 2288841ab66cSSepherosa Ziehau arg &= 0xffff; 2289841ab66cSSepherosa Ziehau has_challenge = ((arg == IEEE80211_AUTH_SHARED_CHALLENGE || 2290841ab66cSSepherosa Ziehau arg == IEEE80211_AUTH_SHARED_RESPONSE) && 2291841ab66cSSepherosa Ziehau ni->ni_challenge != NULL); 2292841ab66cSSepherosa Ziehau 2293841ab66cSSepherosa Ziehau /* 2294841ab66cSSepherosa Ziehau * Deduce whether we're doing open authentication or 2295841ab66cSSepherosa Ziehau * shared key authentication. We do the latter if 2296841ab66cSSepherosa Ziehau * we're in the middle of a shared key authentication 2297841ab66cSSepherosa Ziehau * handshake or if we're initiating an authentication 2298841ab66cSSepherosa Ziehau * request and configured to use shared key. 2299841ab66cSSepherosa Ziehau */ 2300841ab66cSSepherosa Ziehau is_shared_key = has_challenge || 2301841ab66cSSepherosa Ziehau arg >= IEEE80211_AUTH_SHARED_RESPONSE || 2302841ab66cSSepherosa Ziehau (arg == IEEE80211_AUTH_SHARED_REQUEST && 230332176cfdSRui Paulo bss->ni_authmode == IEEE80211_AUTH_SHARED); 2304841ab66cSSepherosa Ziehau 2305841ab66cSSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 23064ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 2307841ab66cSSepherosa Ziehau 3 * sizeof(uint16_t) 2308841ab66cSSepherosa Ziehau + (has_challenge && status == IEEE80211_STATUS_SUCCESS ? 2309841ab66cSSepherosa Ziehau sizeof(uint16_t)+IEEE80211_CHALLENGE_LEN : 0) 2310841ab66cSSepherosa Ziehau ); 2311f186073cSJoerg Sonnenberger if (m == NULL) 2312841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2313841ab66cSSepherosa Ziehau 2314841ab66cSSepherosa Ziehau ((uint16_t *)frm)[0] = 2315841ab66cSSepherosa Ziehau (is_shared_key) ? htole16(IEEE80211_AUTH_ALG_SHARED) 2316841ab66cSSepherosa Ziehau : htole16(IEEE80211_AUTH_ALG_OPEN); 2317f186073cSJoerg Sonnenberger ((uint16_t *)frm)[1] = htole16(arg); /* sequence number */ 2318841ab66cSSepherosa Ziehau ((uint16_t *)frm)[2] = htole16(status);/* status */ 2319841ab66cSSepherosa Ziehau 2320841ab66cSSepherosa Ziehau if (has_challenge && status == IEEE80211_STATUS_SUCCESS) { 2321841ab66cSSepherosa Ziehau ((uint16_t *)frm)[3] = 2322841ab66cSSepherosa Ziehau htole16((IEEE80211_CHALLENGE_LEN << 8) | 2323841ab66cSSepherosa Ziehau IEEE80211_ELEMID_CHALLENGE); 2324841ab66cSSepherosa Ziehau memcpy(&((uint16_t *)frm)[4], ni->ni_challenge, 2325841ab66cSSepherosa Ziehau IEEE80211_CHALLENGE_LEN); 2326841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = 2327841ab66cSSepherosa Ziehau 4 * sizeof(uint16_t) + IEEE80211_CHALLENGE_LEN; 2328841ab66cSSepherosa Ziehau if (arg == IEEE80211_AUTH_SHARED_RESPONSE) { 232932176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 233032176cfdSRui Paulo "request encrypt frame (%s)", __func__); 233132176cfdSRui Paulo /* mark frame for encryption */ 233232176cfdSRui Paulo params.ibp_flags |= IEEE80211_BPF_CRYPTO; 2333841ab66cSSepherosa Ziehau } 2334841ab66cSSepherosa Ziehau } else 2335841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = 3 * sizeof(uint16_t); 2336841ab66cSSepherosa Ziehau 2337841ab66cSSepherosa Ziehau /* XXX not right for shared key */ 2338841ab66cSSepherosa Ziehau if (status == IEEE80211_STATUS_SUCCESS) 2339841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_auth); 2340841ab66cSSepherosa Ziehau else 2341841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_auth_fail); 2342841ab66cSSepherosa Ziehau 234332176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_STA) 234432176cfdSRui Paulo ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 234532176cfdSRui Paulo (void *) vap->iv_state); 2346f186073cSJoerg Sonnenberger break; 2347f186073cSJoerg Sonnenberger 2348f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DEAUTH: 234932176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_AUTH, ni, 235032176cfdSRui Paulo "send station deauthenticate (reason %d)", arg); 23514ac84526SSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 23524ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 23534ac84526SSepherosa Ziehau sizeof(uint16_t)); 2354f186073cSJoerg Sonnenberger if (m == NULL) 2355841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2356841ab66cSSepherosa Ziehau *(uint16_t *)frm = htole16(arg); /* reason */ 2357841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 2358841ab66cSSepherosa Ziehau 2359841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_deauth); 2360841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_SET(ni, tx_deauth_code, arg); 2361841ab66cSSepherosa Ziehau 2362841ab66cSSepherosa Ziehau ieee80211_node_unauthorize(ni); /* port closed */ 2363f186073cSJoerg Sonnenberger break; 2364f186073cSJoerg Sonnenberger 2365f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: 2366208a1285SSepherosa Ziehau case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: 2367f186073cSJoerg Sonnenberger /* 2368f186073cSJoerg Sonnenberger * asreq frame format 2369f186073cSJoerg Sonnenberger * [2] capability information 2370f186073cSJoerg Sonnenberger * [2] listen interval 2371f186073cSJoerg Sonnenberger * [6*] current AP address (reassoc only) 2372f186073cSJoerg Sonnenberger * [tlv] ssid 2373f186073cSJoerg Sonnenberger * [tlv] supported rates 2374f186073cSJoerg Sonnenberger * [tlv] extended supported rates 237532176cfdSRui Paulo * [4] power capability (optional) 237632176cfdSRui Paulo * [28] supported channels (optional) 237732176cfdSRui Paulo * [tlv] HT capabilities 237832176cfdSRui Paulo * [tlv] WME (optional) 237932176cfdSRui Paulo * [tlv] Vendor OUI HT capabilities (optional) 238032176cfdSRui Paulo * [tlv] Atheros capabilities (if negotiated) 238132176cfdSRui Paulo * [tlv] AppIE's (optional) 2382f186073cSJoerg Sonnenberger */ 2383841ab66cSSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 23844ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 2385841ab66cSSepherosa Ziehau sizeof(uint16_t) 2386f186073cSJoerg Sonnenberger + sizeof(uint16_t) 2387f186073cSJoerg Sonnenberger + IEEE80211_ADDR_LEN 2388841ab66cSSepherosa Ziehau + 2 + IEEE80211_NWID_LEN 2389f186073cSJoerg Sonnenberger + 2 + IEEE80211_RATE_SIZE 2390841ab66cSSepherosa Ziehau + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 239132176cfdSRui Paulo + 4 239232176cfdSRui Paulo + 2 + 26 2393841ab66cSSepherosa Ziehau + sizeof(struct ieee80211_wme_info) 239432176cfdSRui Paulo + sizeof(struct ieee80211_ie_htcap) 239532176cfdSRui Paulo + 4 + sizeof(struct ieee80211_ie_htcap) 239632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 239732176cfdSRui Paulo + sizeof(struct ieee80211_ath_ie) 239832176cfdSRui Paulo #endif 239932176cfdSRui Paulo + (vap->iv_appie_wpa != NULL ? 240032176cfdSRui Paulo vap->iv_appie_wpa->ie_len : 0) 240132176cfdSRui Paulo + (vap->iv_appie_assocreq != NULL ? 240232176cfdSRui Paulo vap->iv_appie_assocreq->ie_len : 0) 2403841ab66cSSepherosa Ziehau ); 2404f186073cSJoerg Sonnenberger if (m == NULL) 2405841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2406f186073cSJoerg Sonnenberger 240732176cfdSRui Paulo KASSERT(vap->iv_opmode == IEEE80211_M_STA, 240832176cfdSRui Paulo ("wrong mode %u", vap->iv_opmode)); 2409841ab66cSSepherosa Ziehau capinfo = IEEE80211_CAPINFO_ESS; 241032176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_PRIVACY) 2411f186073cSJoerg Sonnenberger capinfo |= IEEE80211_CAPINFO_PRIVACY; 2412f186073cSJoerg Sonnenberger /* 2413f186073cSJoerg Sonnenberger * NB: Some 11a AP's reject the request when 241432176cfdSRui Paulo * short premable is set. 2415f186073cSJoerg Sonnenberger */ 241632176cfdSRui Paulo if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) && 241732176cfdSRui Paulo IEEE80211_IS_CHAN_2GHZ(ic->ic_curchan)) 2418f186073cSJoerg Sonnenberger capinfo |= IEEE80211_CAPINFO_SHORT_PREAMBLE; 241932176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(ic->ic_curchan) && 2420841ab66cSSepherosa Ziehau (ic->ic_caps & IEEE80211_C_SHSLOT)) 2421f186073cSJoerg Sonnenberger capinfo |= IEEE80211_CAPINFO_SHORT_SLOTTIME; 242232176cfdSRui Paulo if ((ni->ni_capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) && 242332176cfdSRui Paulo (vap->iv_flags & IEEE80211_F_DOTH)) 242432176cfdSRui Paulo capinfo |= IEEE80211_CAPINFO_SPECTRUM_MGMT; 2425f186073cSJoerg Sonnenberger *(uint16_t *)frm = htole16(capinfo); 2426f186073cSJoerg Sonnenberger frm += 2; 2427f186073cSJoerg Sonnenberger 242832176cfdSRui Paulo KASSERT(bss->ni_intval != 0, ("beacon interval is zero!")); 242922b21df8SSepherosa Ziehau *(uint16_t *)frm = htole16(howmany(ic->ic_lintval, 243032176cfdSRui Paulo bss->ni_intval)); 2431f186073cSJoerg Sonnenberger frm += 2; 2432f186073cSJoerg Sonnenberger 2433f186073cSJoerg Sonnenberger if (type == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { 243432176cfdSRui Paulo IEEE80211_ADDR_COPY(frm, bss->ni_bssid); 2435f186073cSJoerg Sonnenberger frm += IEEE80211_ADDR_LEN; 2436f186073cSJoerg Sonnenberger } 2437f186073cSJoerg Sonnenberger 2438f186073cSJoerg Sonnenberger frm = ieee80211_add_ssid(frm, ni->ni_essid, ni->ni_esslen); 243932176cfdSRui Paulo frm = ieee80211_add_rates(frm, &ni->ni_rates); 2440085ff963SMatthew Dillon frm = ieee80211_add_rsn(frm, vap); 244132176cfdSRui Paulo frm = ieee80211_add_xrates(frm, &ni->ni_rates); 244232176cfdSRui Paulo if (capinfo & IEEE80211_CAPINFO_SPECTRUM_MGMT) { 244332176cfdSRui Paulo frm = ieee80211_add_powercapability(frm, 244432176cfdSRui Paulo ic->ic_curchan); 244532176cfdSRui Paulo frm = ieee80211_add_supportedchannels(frm, ic); 244632176cfdSRui Paulo } 244732176cfdSRui Paulo if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 244832176cfdSRui Paulo ni->ni_ies.htcap_ie != NULL && 244932176cfdSRui Paulo ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_HTCAP) 245032176cfdSRui Paulo frm = ieee80211_add_htcap(frm, ni); 2451085ff963SMatthew Dillon frm = ieee80211_add_wpa(frm, vap); 245232176cfdSRui Paulo if ((ic->ic_flags & IEEE80211_F_WME) && 245332176cfdSRui Paulo ni->ni_ies.wme_ie != NULL) 245432176cfdSRui Paulo frm = ieee80211_add_wme_info(frm, &ic->ic_wme); 245532176cfdSRui Paulo if ((vap->iv_flags_ht & IEEE80211_FHT_HT) && 245632176cfdSRui Paulo ni->ni_ies.htcap_ie != NULL && 245732176cfdSRui Paulo ni->ni_ies.htcap_ie[0] == IEEE80211_ELEMID_VENDOR) 245832176cfdSRui Paulo frm = ieee80211_add_htcap_vendor(frm, ni); 245932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 246032176cfdSRui Paulo if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) { 246132176cfdSRui Paulo frm = ieee80211_add_ath(frm, 246232176cfdSRui Paulo IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 246332176cfdSRui Paulo ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 246432176cfdSRui Paulo ni->ni_authmode != IEEE80211_AUTH_8021X) ? 246532176cfdSRui Paulo vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 246632176cfdSRui Paulo } 246732176cfdSRui Paulo #endif /* IEEE80211_SUPPORT_SUPERG */ 246832176cfdSRui Paulo if (vap->iv_appie_assocreq != NULL) 246932176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_assocreq); 2470f186073cSJoerg Sonnenberger m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2471f186073cSJoerg Sonnenberger 247232176cfdSRui Paulo ieee80211_add_callback(m, ieee80211_tx_mgt_cb, 247332176cfdSRui Paulo (void *) vap->iv_state); 2474f186073cSJoerg Sonnenberger break; 2475f186073cSJoerg Sonnenberger 2476f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: 2477f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: 2478f186073cSJoerg Sonnenberger /* 247932176cfdSRui Paulo * asresp frame format 2480f186073cSJoerg Sonnenberger * [2] capability information 2481f186073cSJoerg Sonnenberger * [2] status 2482f186073cSJoerg Sonnenberger * [2] association ID 2483f186073cSJoerg Sonnenberger * [tlv] supported rates 2484f186073cSJoerg Sonnenberger * [tlv] extended supported rates 248532176cfdSRui Paulo * [tlv] HT capabilities (standard, if STA enabled) 248632176cfdSRui Paulo * [tlv] HT information (standard, if STA enabled) 248732176cfdSRui Paulo * [tlv] WME (if configured and STA enabled) 248832176cfdSRui Paulo * [tlv] HT capabilities (vendor OUI, if STA enabled) 248932176cfdSRui Paulo * [tlv] HT information (vendor OUI, if STA enabled) 249032176cfdSRui Paulo * [tlv] Atheros capabilities (if STA enabled) 249132176cfdSRui Paulo * [tlv] AppIE's (optional) 2492f186073cSJoerg Sonnenberger */ 2493841ab66cSSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 24944ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 2495841ab66cSSepherosa Ziehau sizeof(uint16_t) 2496f186073cSJoerg Sonnenberger + sizeof(uint16_t) 2497f186073cSJoerg Sonnenberger + sizeof(uint16_t) 2498f186073cSJoerg Sonnenberger + 2 + IEEE80211_RATE_SIZE 2499841ab66cSSepherosa Ziehau + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 250032176cfdSRui Paulo + sizeof(struct ieee80211_ie_htcap) + 4 250132176cfdSRui Paulo + sizeof(struct ieee80211_ie_htinfo) + 4 2502841ab66cSSepherosa Ziehau + sizeof(struct ieee80211_wme_param) 250332176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 250432176cfdSRui Paulo + sizeof(struct ieee80211_ath_ie) 250532176cfdSRui Paulo #endif 250632176cfdSRui Paulo + (vap->iv_appie_assocresp != NULL ? 250732176cfdSRui Paulo vap->iv_appie_assocresp->ie_len : 0) 2508841ab66cSSepherosa Ziehau ); 2509f186073cSJoerg Sonnenberger if (m == NULL) 2510841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2511f186073cSJoerg Sonnenberger 251232176cfdSRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 2513f186073cSJoerg Sonnenberger *(uint16_t *)frm = htole16(capinfo); 2514f186073cSJoerg Sonnenberger frm += 2; 2515f186073cSJoerg Sonnenberger 2516f186073cSJoerg Sonnenberger *(uint16_t *)frm = htole16(arg); /* status */ 2517f186073cSJoerg Sonnenberger frm += 2; 2518f186073cSJoerg Sonnenberger 2519841ab66cSSepherosa Ziehau if (arg == IEEE80211_STATUS_SUCCESS) { 2520f186073cSJoerg Sonnenberger *(uint16_t *)frm = htole16(ni->ni_associd); 2521841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_assoc); 2522841ab66cSSepherosa Ziehau } else 2523841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_assoc_fail); 2524f186073cSJoerg Sonnenberger frm += 2; 2525f186073cSJoerg Sonnenberger 252632176cfdSRui Paulo frm = ieee80211_add_rates(frm, &ni->ni_rates); 252732176cfdSRui Paulo frm = ieee80211_add_xrates(frm, &ni->ni_rates); 252832176cfdSRui Paulo /* NB: respond according to what we received */ 252932176cfdSRui Paulo if ((ni->ni_flags & HTFLAGS) == IEEE80211_NODE_HT) { 253032176cfdSRui Paulo frm = ieee80211_add_htcap(frm, ni); 253132176cfdSRui Paulo frm = ieee80211_add_htinfo(frm, ni); 253232176cfdSRui Paulo } 253332176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_WME) && 253432176cfdSRui Paulo ni->ni_ies.wme_ie != NULL) 2535841ab66cSSepherosa Ziehau frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 253632176cfdSRui Paulo if ((ni->ni_flags & HTFLAGS) == HTFLAGS) { 253732176cfdSRui Paulo frm = ieee80211_add_htcap_vendor(frm, ni); 253832176cfdSRui Paulo frm = ieee80211_add_htinfo_vendor(frm, ni); 253932176cfdSRui Paulo } 254032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 254132176cfdSRui Paulo if (IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS)) 254232176cfdSRui Paulo frm = ieee80211_add_ath(frm, 254332176cfdSRui Paulo IEEE80211_ATH_CAP(vap, ni, IEEE80211_F_ATHEROS), 254432176cfdSRui Paulo ((vap->iv_flags & IEEE80211_F_WPA) == 0 && 254532176cfdSRui Paulo ni->ni_authmode != IEEE80211_AUTH_8021X) ? 254632176cfdSRui Paulo vap->iv_def_txkey : IEEE80211_KEYIX_NONE); 254732176cfdSRui Paulo #endif /* IEEE80211_SUPPORT_SUPERG */ 254832176cfdSRui Paulo if (vap->iv_appie_assocresp != NULL) 254932176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_assocresp); 2550f186073cSJoerg Sonnenberger m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 2551f186073cSJoerg Sonnenberger break; 2552f186073cSJoerg Sonnenberger 2553f186073cSJoerg Sonnenberger case IEEE80211_FC0_SUBTYPE_DISASSOC: 255432176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_ASSOC, ni, 255532176cfdSRui Paulo "send station disassociate (reason %d)", arg); 25564ac84526SSepherosa Ziehau m = ieee80211_getmgtframe(&frm, 25574ac84526SSepherosa Ziehau ic->ic_headroom + sizeof(struct ieee80211_frame), 25584ac84526SSepherosa Ziehau sizeof(uint16_t)); 2559f186073cSJoerg Sonnenberger if (m == NULL) 2560841ab66cSSepherosa Ziehau senderr(ENOMEM, is_tx_nobuf); 2561841ab66cSSepherosa Ziehau *(uint16_t *)frm = htole16(arg); /* reason */ 2562841ab66cSSepherosa Ziehau m->m_pkthdr.len = m->m_len = sizeof(uint16_t); 2563841ab66cSSepherosa Ziehau 2564841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT(ni, tx_disassoc); 2565841ab66cSSepherosa Ziehau IEEE80211_NODE_STAT_SET(ni, tx_disassoc_code, arg); 2566f186073cSJoerg Sonnenberger break; 2567f186073cSJoerg Sonnenberger 2568f186073cSJoerg Sonnenberger default: 256932176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_ANY, ni, 257032176cfdSRui Paulo "invalid mgmt frame type %u", type); 2571f186073cSJoerg Sonnenberger senderr(EINVAL, is_tx_unknownmgt); 2572f186073cSJoerg Sonnenberger /* NOTREACHED */ 2573f186073cSJoerg Sonnenberger } 257432176cfdSRui Paulo 257532176cfdSRui Paulo /* NB: force non-ProbeResp frames to the highest queue */ 257632176cfdSRui Paulo params.ibp_pri = WME_AC_VO; 257732176cfdSRui Paulo params.ibp_rate0 = bss->ni_txparms->mgmtrate; 257832176cfdSRui Paulo /* NB: we know all frames are unicast */ 257932176cfdSRui Paulo params.ibp_try0 = bss->ni_txparms->maxretry; 258032176cfdSRui Paulo params.ibp_power = bss->ni_txpower; 258132176cfdSRui Paulo return ieee80211_mgmt_output(ni, m, type, ¶ms); 2582f186073cSJoerg Sonnenberger bad: 2583841ab66cSSepherosa Ziehau ieee80211_free_node(ni); 2584f186073cSJoerg Sonnenberger return ret; 2585f186073cSJoerg Sonnenberger #undef senderr 258632176cfdSRui Paulo #undef HTFLAGS 2587f186073cSJoerg Sonnenberger } 2588841ab66cSSepherosa Ziehau 2589841ab66cSSepherosa Ziehau /* 259032176cfdSRui Paulo * Return an mbuf with a probe response frame in it. 259132176cfdSRui Paulo * Space is left to prepend and 802.11 header at the 259232176cfdSRui Paulo * front but it's left to the caller to fill in. 25933da93495SSepherosa Ziehau */ 25943da93495SSepherosa Ziehau struct mbuf * 259532176cfdSRui Paulo ieee80211_alloc_proberesp(struct ieee80211_node *bss, int legacy) 25963da93495SSepherosa Ziehau { 259732176cfdSRui Paulo struct ieee80211vap *vap = bss->ni_vap; 259832176cfdSRui Paulo struct ieee80211com *ic = bss->ni_ic; 259932176cfdSRui Paulo const struct ieee80211_rateset *rs; 26003da93495SSepherosa Ziehau struct mbuf *m; 260132176cfdSRui Paulo uint16_t capinfo; 260232176cfdSRui Paulo uint8_t *frm; 26033da93495SSepherosa Ziehau 260432176cfdSRui Paulo /* 260532176cfdSRui Paulo * probe response frame format 260632176cfdSRui Paulo * [8] time stamp 260732176cfdSRui Paulo * [2] beacon interval 260832176cfdSRui Paulo * [2] cabability information 260932176cfdSRui Paulo * [tlv] ssid 261032176cfdSRui Paulo * [tlv] supported rates 261132176cfdSRui Paulo * [tlv] parameter set (FH/DS) 261232176cfdSRui Paulo * [tlv] parameter set (IBSS) 261332176cfdSRui Paulo * [tlv] country (optional) 261432176cfdSRui Paulo * [3] power control (optional) 261532176cfdSRui Paulo * [5] channel switch announcement (CSA) (optional) 261632176cfdSRui Paulo * [tlv] extended rate phy (ERP) 261732176cfdSRui Paulo * [tlv] extended supported rates 261832176cfdSRui Paulo * [tlv] RSN (optional) 261932176cfdSRui Paulo * [tlv] HT capabilities 262032176cfdSRui Paulo * [tlv] HT information 262132176cfdSRui Paulo * [tlv] WPA (optional) 262232176cfdSRui Paulo * [tlv] WME (optional) 262332176cfdSRui Paulo * [tlv] Vendor OUI HT capabilities (optional) 262432176cfdSRui Paulo * [tlv] Vendor OUI HT information (optional) 262532176cfdSRui Paulo * [tlv] Atheros capabilities 262632176cfdSRui Paulo * [tlv] AppIE's (optional) 262732176cfdSRui Paulo * [tlv] Mesh ID (MBSS) 262832176cfdSRui Paulo * [tlv] Mesh Conf (MBSS) 262932176cfdSRui Paulo */ 263032176cfdSRui Paulo m = ieee80211_getmgtframe(&frm, 263132176cfdSRui Paulo ic->ic_headroom + sizeof(struct ieee80211_frame), 263232176cfdSRui Paulo 8 263332176cfdSRui Paulo + sizeof(uint16_t) 263432176cfdSRui Paulo + sizeof(uint16_t) 263532176cfdSRui Paulo + 2 + IEEE80211_NWID_LEN 263632176cfdSRui Paulo + 2 + IEEE80211_RATE_SIZE 263732176cfdSRui Paulo + 7 /* max(7,3) */ 263832176cfdSRui Paulo + IEEE80211_COUNTRY_MAX_SIZE 263932176cfdSRui Paulo + 3 264032176cfdSRui Paulo + sizeof(struct ieee80211_csa_ie) 2641085ff963SMatthew Dillon + sizeof(struct ieee80211_quiet_ie) 264232176cfdSRui Paulo + 3 264332176cfdSRui Paulo + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 264432176cfdSRui Paulo + sizeof(struct ieee80211_ie_wpa) 264532176cfdSRui Paulo + sizeof(struct ieee80211_ie_htcap) 264632176cfdSRui Paulo + sizeof(struct ieee80211_ie_htinfo) 264732176cfdSRui Paulo + sizeof(struct ieee80211_ie_wpa) 264832176cfdSRui Paulo + sizeof(struct ieee80211_wme_param) 264932176cfdSRui Paulo + 4 + sizeof(struct ieee80211_ie_htcap) 265032176cfdSRui Paulo + 4 + sizeof(struct ieee80211_ie_htinfo) 265132176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 265232176cfdSRui Paulo + sizeof(struct ieee80211_ath_ie) 265332176cfdSRui Paulo #endif 265432176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 265532176cfdSRui Paulo + 2 + IEEE80211_MESHID_LEN 265632176cfdSRui Paulo + sizeof(struct ieee80211_meshconf_ie) 265732176cfdSRui Paulo #endif 265832176cfdSRui Paulo + (vap->iv_appie_proberesp != NULL ? 265932176cfdSRui Paulo vap->iv_appie_proberesp->ie_len : 0) 266032176cfdSRui Paulo ); 266132176cfdSRui Paulo if (m == NULL) { 266232176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 26633da93495SSepherosa Ziehau return NULL; 266432176cfdSRui Paulo } 26653da93495SSepherosa Ziehau 266632176cfdSRui Paulo memset(frm, 0, 8); /* timestamp should be filled later */ 266732176cfdSRui Paulo frm += 8; 266832176cfdSRui Paulo *(uint16_t *)frm = htole16(bss->ni_intval); 266932176cfdSRui Paulo frm += 2; 267032176cfdSRui Paulo capinfo = ieee80211_getcapinfo(vap, bss->ni_chan); 267132176cfdSRui Paulo *(uint16_t *)frm = htole16(capinfo); 267232176cfdSRui Paulo frm += 2; 26733da93495SSepherosa Ziehau 267432176cfdSRui Paulo frm = ieee80211_add_ssid(frm, bss->ni_essid, bss->ni_esslen); 267532176cfdSRui Paulo rs = ieee80211_get_suprates(ic, bss->ni_chan); 267632176cfdSRui Paulo frm = ieee80211_add_rates(frm, rs); 267732176cfdSRui Paulo 267832176cfdSRui Paulo if (IEEE80211_IS_CHAN_FHSS(bss->ni_chan)) { 267932176cfdSRui Paulo *frm++ = IEEE80211_ELEMID_FHPARMS; 268032176cfdSRui Paulo *frm++ = 5; 268132176cfdSRui Paulo *frm++ = bss->ni_fhdwell & 0x00ff; 268232176cfdSRui Paulo *frm++ = (bss->ni_fhdwell >> 8) & 0x00ff; 268332176cfdSRui Paulo *frm++ = IEEE80211_FH_CHANSET( 268432176cfdSRui Paulo ieee80211_chan2ieee(ic, bss->ni_chan)); 268532176cfdSRui Paulo *frm++ = IEEE80211_FH_CHANPAT( 268632176cfdSRui Paulo ieee80211_chan2ieee(ic, bss->ni_chan)); 268732176cfdSRui Paulo *frm++ = bss->ni_fhindex; 268832176cfdSRui Paulo } else { 268932176cfdSRui Paulo *frm++ = IEEE80211_ELEMID_DSPARMS; 269032176cfdSRui Paulo *frm++ = 1; 269132176cfdSRui Paulo *frm++ = ieee80211_chan2ieee(ic, bss->ni_chan); 269232176cfdSRui Paulo } 269332176cfdSRui Paulo 269432176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_IBSS) { 269532176cfdSRui Paulo *frm++ = IEEE80211_ELEMID_IBSSPARMS; 269632176cfdSRui Paulo *frm++ = 2; 269732176cfdSRui Paulo *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 269832176cfdSRui Paulo } 269932176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_DOTH) || 270032176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 270132176cfdSRui Paulo frm = ieee80211_add_countryie(frm, ic); 270232176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_DOTH) { 270332176cfdSRui Paulo if (IEEE80211_IS_CHAN_5GHZ(bss->ni_chan)) 270432176cfdSRui Paulo frm = ieee80211_add_powerconstraint(frm, vap); 270532176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_CSAPENDING) 270632176cfdSRui Paulo frm = ieee80211_add_csa(frm, vap); 270732176cfdSRui Paulo } 2708085ff963SMatthew Dillon if (vap->iv_flags & IEEE80211_F_DOTH) { 2709085ff963SMatthew Dillon if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 2710085ff963SMatthew Dillon (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 2711085ff963SMatthew Dillon if (vap->iv_quiet) 2712085ff963SMatthew Dillon frm = ieee80211_add_quiet(frm, vap); 2713085ff963SMatthew Dillon } 2714085ff963SMatthew Dillon } 271532176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(bss->ni_chan)) 271632176cfdSRui Paulo frm = ieee80211_add_erp(frm, ic); 271732176cfdSRui Paulo frm = ieee80211_add_xrates(frm, rs); 2718085ff963SMatthew Dillon frm = ieee80211_add_rsn(frm, vap); 271932176cfdSRui Paulo /* 272032176cfdSRui Paulo * NB: legacy 11b clients do not get certain ie's. 272132176cfdSRui Paulo * The caller identifies such clients by passing 272232176cfdSRui Paulo * a token in legacy to us. Could expand this to be 272332176cfdSRui Paulo * any legacy client for stuff like HT ie's. 272432176cfdSRui Paulo */ 272532176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 272632176cfdSRui Paulo legacy != IEEE80211_SEND_LEGACY_11B) { 272732176cfdSRui Paulo frm = ieee80211_add_htcap(frm, bss); 272832176cfdSRui Paulo frm = ieee80211_add_htinfo(frm, bss); 272932176cfdSRui Paulo } 2730085ff963SMatthew Dillon frm = ieee80211_add_wpa(frm, vap); 273132176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_WME) 273232176cfdSRui Paulo frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 273332176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(bss->ni_chan) && 273432176cfdSRui Paulo (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT) && 273532176cfdSRui Paulo legacy != IEEE80211_SEND_LEGACY_11B) { 273632176cfdSRui Paulo frm = ieee80211_add_htcap_vendor(frm, bss); 273732176cfdSRui Paulo frm = ieee80211_add_htinfo_vendor(frm, bss); 273832176cfdSRui Paulo } 273932176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 274032176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_ATHEROS) && 274132176cfdSRui Paulo legacy != IEEE80211_SEND_LEGACY_11B) 274232176cfdSRui Paulo frm = ieee80211_add_athcaps(frm, bss); 274332176cfdSRui Paulo #endif 274432176cfdSRui Paulo if (vap->iv_appie_proberesp != NULL) 274532176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_proberesp); 274632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 274732176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 274832176cfdSRui Paulo frm = ieee80211_add_meshid(frm, vap); 274932176cfdSRui Paulo frm = ieee80211_add_meshconf(frm, vap); 275032176cfdSRui Paulo } 275132176cfdSRui Paulo #endif 275232176cfdSRui Paulo m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 27533da93495SSepherosa Ziehau 27543da93495SSepherosa Ziehau return m; 27553da93495SSepherosa Ziehau } 27563da93495SSepherosa Ziehau 27573da93495SSepherosa Ziehau /* 275832176cfdSRui Paulo * Send a probe response frame to the specified mac address. 275932176cfdSRui Paulo * This does not go through the normal mgt frame api so we 276032176cfdSRui Paulo * can specify the destination address and re-use the bss node 276132176cfdSRui Paulo * for the sta reference. 2762841ab66cSSepherosa Ziehau */ 276332176cfdSRui Paulo int 276432176cfdSRui Paulo ieee80211_send_proberesp(struct ieee80211vap *vap, 276532176cfdSRui Paulo const uint8_t da[IEEE80211_ADDR_LEN], int legacy) 2766841ab66cSSepherosa Ziehau { 276732176cfdSRui Paulo struct ieee80211_node *bss = vap->iv_bss; 276832176cfdSRui Paulo struct ieee80211com *ic = vap->iv_ic; 2769085ff963SMatthew Dillon struct ieee80211_frame *wh; 2770841ab66cSSepherosa Ziehau struct mbuf *m; 2771085ff963SMatthew Dillon int ret; 277232176cfdSRui Paulo 277332176cfdSRui Paulo if (vap->iv_state == IEEE80211_S_CAC) { 277432176cfdSRui Paulo IEEE80211_NOTE(vap, IEEE80211_MSG_OUTPUT, bss, 277532176cfdSRui Paulo "block %s frame in CAC state", "probe response"); 277632176cfdSRui Paulo vap->iv_stats.is_tx_badstate++; 277732176cfdSRui Paulo return EIO; /* XXX */ 277832176cfdSRui Paulo } 277932176cfdSRui Paulo 278032176cfdSRui Paulo /* 278132176cfdSRui Paulo * Hold a reference on the node so it doesn't go away until after 278232176cfdSRui Paulo * the xmit is complete all the way in the driver. On error we 278332176cfdSRui Paulo * will remove our reference. 278432176cfdSRui Paulo */ 278532176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_NODE, 27861e290df3SAntonio Huete Jimenez "ieee80211_ref_node (%s:%u) %p<%s> refcnt %d\n", 2787085ff963SMatthew Dillon __func__, __LINE__, bss, ether_sprintf(bss->ni_macaddr), 278832176cfdSRui Paulo ieee80211_node_refcnt(bss)+1); 278932176cfdSRui Paulo ieee80211_ref_node(bss); 279032176cfdSRui Paulo 279132176cfdSRui Paulo m = ieee80211_alloc_proberesp(bss, legacy); 279232176cfdSRui Paulo if (m == NULL) { 279332176cfdSRui Paulo ieee80211_free_node(bss); 279432176cfdSRui Paulo return ENOMEM; 279532176cfdSRui Paulo } 279632176cfdSRui Paulo 2797b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 279832176cfdSRui Paulo KASSERT(m != NULL, ("no room for header")); 279932176cfdSRui Paulo 2800085ff963SMatthew Dillon IEEE80211_TX_LOCK(ic); 2801085ff963SMatthew Dillon wh = mtod(m, struct ieee80211_frame *); 280232176cfdSRui Paulo ieee80211_send_setup(bss, m, 280332176cfdSRui Paulo IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_RESP, 280432176cfdSRui Paulo IEEE80211_NONQOS_TID, vap->iv_myaddr, da, bss->ni_bssid); 280532176cfdSRui Paulo /* XXX power management? */ 280632176cfdSRui Paulo m->m_flags |= M_ENCAP; /* mark encapsulated */ 280732176cfdSRui Paulo 280832176cfdSRui Paulo M_WME_SETAC(m, WME_AC_BE); 280932176cfdSRui Paulo 281032176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_DEBUG | IEEE80211_MSG_DUMPPKTS, 28111e290df3SAntonio Huete Jimenez "send probe resp on channel %u to %s%s\n", 2812085ff963SMatthew Dillon ieee80211_chan2ieee(ic, ic->ic_curchan), ether_sprintf(da), 281332176cfdSRui Paulo legacy ? " <legacy>" : ""); 281432176cfdSRui Paulo IEEE80211_NODE_STAT(bss, tx_mgmt); 281532176cfdSRui Paulo 2816085ff963SMatthew Dillon ret = ieee80211_raw_output(vap, bss, m, NULL); 2817085ff963SMatthew Dillon IEEE80211_TX_UNLOCK(ic); 2818085ff963SMatthew Dillon return (ret); 281932176cfdSRui Paulo } 282032176cfdSRui Paulo 282132176cfdSRui Paulo /* 282232176cfdSRui Paulo * Allocate and build a RTS (Request To Send) control frame. 282332176cfdSRui Paulo */ 282432176cfdSRui Paulo struct mbuf * 282532176cfdSRui Paulo ieee80211_alloc_rts(struct ieee80211com *ic, 282632176cfdSRui Paulo const uint8_t ra[IEEE80211_ADDR_LEN], 282732176cfdSRui Paulo const uint8_t ta[IEEE80211_ADDR_LEN], 282832176cfdSRui Paulo uint16_t dur) 282932176cfdSRui Paulo { 283032176cfdSRui Paulo struct ieee80211_frame_rts *rts; 283132176cfdSRui Paulo struct mbuf *m; 283232176cfdSRui Paulo 283332176cfdSRui Paulo /* XXX honor ic_headroom */ 2834b5523eacSSascha Wildner m = m_gethdr(M_NOWAIT, MT_DATA); 283532176cfdSRui Paulo if (m != NULL) { 283632176cfdSRui Paulo rts = mtod(m, struct ieee80211_frame_rts *); 283732176cfdSRui Paulo rts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 283832176cfdSRui Paulo IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_RTS; 283932176cfdSRui Paulo rts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 284032176cfdSRui Paulo *(u_int16_t *)rts->i_dur = htole16(dur); 284132176cfdSRui Paulo IEEE80211_ADDR_COPY(rts->i_ra, ra); 284232176cfdSRui Paulo IEEE80211_ADDR_COPY(rts->i_ta, ta); 284332176cfdSRui Paulo 284432176cfdSRui Paulo m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_rts); 284532176cfdSRui Paulo } 284632176cfdSRui Paulo return m; 284732176cfdSRui Paulo } 284832176cfdSRui Paulo 284932176cfdSRui Paulo /* 285032176cfdSRui Paulo * Allocate and build a CTS (Clear To Send) control frame. 285132176cfdSRui Paulo */ 285232176cfdSRui Paulo struct mbuf * 285332176cfdSRui Paulo ieee80211_alloc_cts(struct ieee80211com *ic, 285432176cfdSRui Paulo const uint8_t ra[IEEE80211_ADDR_LEN], uint16_t dur) 285532176cfdSRui Paulo { 285632176cfdSRui Paulo struct ieee80211_frame_cts *cts; 285732176cfdSRui Paulo struct mbuf *m; 285832176cfdSRui Paulo 285932176cfdSRui Paulo /* XXX honor ic_headroom */ 2860b5523eacSSascha Wildner m = m_gethdr(M_NOWAIT, MT_DATA); 286132176cfdSRui Paulo if (m != NULL) { 286232176cfdSRui Paulo cts = mtod(m, struct ieee80211_frame_cts *); 286332176cfdSRui Paulo cts->i_fc[0] = IEEE80211_FC0_VERSION_0 | 286432176cfdSRui Paulo IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_CTS; 286532176cfdSRui Paulo cts->i_fc[1] = IEEE80211_FC1_DIR_NODS; 286632176cfdSRui Paulo *(u_int16_t *)cts->i_dur = htole16(dur); 286732176cfdSRui Paulo IEEE80211_ADDR_COPY(cts->i_ra, ra); 286832176cfdSRui Paulo 286932176cfdSRui Paulo m->m_pkthdr.len = m->m_len = sizeof(struct ieee80211_frame_cts); 287032176cfdSRui Paulo } 287132176cfdSRui Paulo return m; 287232176cfdSRui Paulo } 287332176cfdSRui Paulo 287432176cfdSRui Paulo static void 2875085ff963SMatthew Dillon ieee80211_tx_mgt_timeout(void *arg) 287632176cfdSRui Paulo { 2877085ff963SMatthew Dillon struct ieee80211vap *vap = arg; 287832176cfdSRui Paulo 2879085ff963SMatthew Dillon IEEE80211_LOCK(vap->iv_ic); 288032176cfdSRui Paulo if (vap->iv_state != IEEE80211_S_INIT && 288132176cfdSRui Paulo (vap->iv_ic->ic_flags & IEEE80211_F_SCAN) == 0) { 288232176cfdSRui Paulo /* 288332176cfdSRui Paulo * NB: it's safe to specify a timeout as the reason here; 288432176cfdSRui Paulo * it'll only be used in the right state. 288532176cfdSRui Paulo */ 2886085ff963SMatthew Dillon ieee80211_new_state_locked(vap, IEEE80211_S_SCAN, 288732176cfdSRui Paulo IEEE80211_SCAN_FAIL_TIMEOUT); 288832176cfdSRui Paulo } 2889085ff963SMatthew Dillon IEEE80211_UNLOCK(vap->iv_ic); 289032176cfdSRui Paulo } 289132176cfdSRui Paulo 2892085ff963SMatthew Dillon /* 2893085ff963SMatthew Dillon * This is the callback set on net80211-sourced transmitted 2894085ff963SMatthew Dillon * authentication request frames. 2895085ff963SMatthew Dillon * 2896085ff963SMatthew Dillon * This does a couple of things: 2897085ff963SMatthew Dillon * 2898085ff963SMatthew Dillon * + If the frame transmitted was a success, it schedules a future 2899085ff963SMatthew Dillon * event which will transition the interface to scan. 2900085ff963SMatthew Dillon * If a state transition _then_ occurs before that event occurs, 2901085ff963SMatthew Dillon * said state transition will cancel this callout. 2902085ff963SMatthew Dillon * 2903085ff963SMatthew Dillon * + If the frame transmit was a failure, it immediately schedules 2904085ff963SMatthew Dillon * the transition back to scan. 2905085ff963SMatthew Dillon */ 290632176cfdSRui Paulo static void 290732176cfdSRui Paulo ieee80211_tx_mgt_cb(struct ieee80211_node *ni, void *arg, int status) 290832176cfdSRui Paulo { 290932176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 291032176cfdSRui Paulo enum ieee80211_state ostate = (enum ieee80211_state) arg; 291132176cfdSRui Paulo 291232176cfdSRui Paulo /* 291332176cfdSRui Paulo * Frame transmit completed; arrange timer callback. If 291432176cfdSRui Paulo * transmit was successfuly we wait for response. Otherwise 291532176cfdSRui Paulo * we arrange an immediate callback instead of doing the 291632176cfdSRui Paulo * callback directly since we don't know what state the driver 291732176cfdSRui Paulo * is in (e.g. what locks it is holding). This work should 291832176cfdSRui Paulo * not be too time-critical and not happen too often so the 291932176cfdSRui Paulo * added overhead is acceptable. 292032176cfdSRui Paulo * 292132176cfdSRui Paulo * XXX what happens if !acked but response shows up before callback? 292232176cfdSRui Paulo */ 2923085ff963SMatthew Dillon if (vap->iv_state == ostate) { 292432176cfdSRui Paulo callout_reset(&vap->iv_mgtsend, 292532176cfdSRui Paulo status == 0 ? IEEE80211_TRANS_WAIT*hz : 0, 2926085ff963SMatthew Dillon ieee80211_tx_mgt_timeout, vap); 2927085ff963SMatthew Dillon } 292832176cfdSRui Paulo } 292932176cfdSRui Paulo 293032176cfdSRui Paulo static void 293132176cfdSRui Paulo ieee80211_beacon_construct(struct mbuf *m, uint8_t *frm, 293232176cfdSRui Paulo struct ieee80211_beacon_offsets *bo, struct ieee80211_node *ni) 293332176cfdSRui Paulo { 293432176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 293532176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 293632176cfdSRui Paulo struct ieee80211_rateset *rs = &ni->ni_rates; 2937841ab66cSSepherosa Ziehau uint16_t capinfo; 2938841ab66cSSepherosa Ziehau 2939841ab66cSSepherosa Ziehau /* 2940841ab66cSSepherosa Ziehau * beacon frame format 2941841ab66cSSepherosa Ziehau * [8] time stamp 2942841ab66cSSepherosa Ziehau * [2] beacon interval 2943841ab66cSSepherosa Ziehau * [2] cabability information 2944841ab66cSSepherosa Ziehau * [tlv] ssid 2945841ab66cSSepherosa Ziehau * [tlv] supported rates 2946841ab66cSSepherosa Ziehau * [3] parameter set (DS) 294732176cfdSRui Paulo * [8] CF parameter set (optional) 2948841ab66cSSepherosa Ziehau * [tlv] parameter set (IBSS/TIM) 294932176cfdSRui Paulo * [tlv] country (optional) 295032176cfdSRui Paulo * [3] power control (optional) 295132176cfdSRui Paulo * [5] channel switch announcement (CSA) (optional) 2952841ab66cSSepherosa Ziehau * [tlv] extended rate phy (ERP) 2953841ab66cSSepherosa Ziehau * [tlv] extended supported rates 295432176cfdSRui Paulo * [tlv] RSN parameters 295532176cfdSRui Paulo * [tlv] HT capabilities 295632176cfdSRui Paulo * [tlv] HT information 2957841ab66cSSepherosa Ziehau * XXX Vendor-specific OIDs (e.g. Atheros) 295832176cfdSRui Paulo * [tlv] WPA parameters 295932176cfdSRui Paulo * [tlv] WME parameters 296032176cfdSRui Paulo * [tlv] Vendor OUI HT capabilities (optional) 296132176cfdSRui Paulo * [tlv] Vendor OUI HT information (optional) 296232176cfdSRui Paulo * [tlv] Atheros capabilities (optional) 296332176cfdSRui Paulo * [tlv] TDMA parameters (optional) 296432176cfdSRui Paulo * [tlv] Mesh ID (MBSS) 296532176cfdSRui Paulo * [tlv] Mesh Conf (MBSS) 296632176cfdSRui Paulo * [tlv] application data (optional) 2967841ab66cSSepherosa Ziehau */ 296832176cfdSRui Paulo 296932176cfdSRui Paulo memset(bo, 0, sizeof(*bo)); 2970841ab66cSSepherosa Ziehau 2971841ab66cSSepherosa Ziehau memset(frm, 0, 8); /* XXX timestamp is set by hardware/driver */ 2972841ab66cSSepherosa Ziehau frm += 8; 2973841ab66cSSepherosa Ziehau *(uint16_t *)frm = htole16(ni->ni_intval); 2974841ab66cSSepherosa Ziehau frm += 2; 297532176cfdSRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 2976841ab66cSSepherosa Ziehau bo->bo_caps = (uint16_t *)frm; 2977841ab66cSSepherosa Ziehau *(uint16_t *)frm = htole16(capinfo); 2978841ab66cSSepherosa Ziehau frm += 2; 2979841ab66cSSepherosa Ziehau *frm++ = IEEE80211_ELEMID_SSID; 298032176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_HIDESSID) == 0) { 2981841ab66cSSepherosa Ziehau *frm++ = ni->ni_esslen; 2982841ab66cSSepherosa Ziehau memcpy(frm, ni->ni_essid, ni->ni_esslen); 2983841ab66cSSepherosa Ziehau frm += ni->ni_esslen; 2984841ab66cSSepherosa Ziehau } else 2985841ab66cSSepherosa Ziehau *frm++ = 0; 2986841ab66cSSepherosa Ziehau frm = ieee80211_add_rates(frm, rs); 298732176cfdSRui Paulo if (!IEEE80211_IS_CHAN_FHSS(ni->ni_chan)) { 2988841ab66cSSepherosa Ziehau *frm++ = IEEE80211_ELEMID_DSPARMS; 2989841ab66cSSepherosa Ziehau *frm++ = 1; 2990841ab66cSSepherosa Ziehau *frm++ = ieee80211_chan2ieee(ic, ni->ni_chan); 2991841ab66cSSepherosa Ziehau } 299232176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_PCF) { 299332176cfdSRui Paulo bo->bo_cfp = frm; 299432176cfdSRui Paulo frm = ieee80211_add_cfparms(frm, ic); 299532176cfdSRui Paulo } 2996841ab66cSSepherosa Ziehau bo->bo_tim = frm; 299732176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_IBSS) { 2998841ab66cSSepherosa Ziehau *frm++ = IEEE80211_ELEMID_IBSSPARMS; 2999841ab66cSSepherosa Ziehau *frm++ = 2; 3000841ab66cSSepherosa Ziehau *frm++ = 0; *frm++ = 0; /* TODO: ATIM window */ 3001841ab66cSSepherosa Ziehau bo->bo_tim_len = 0; 300232176cfdSRui Paulo } else if (vap->iv_opmode == IEEE80211_M_HOSTAP || 300332176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { 300432176cfdSRui Paulo /* TIM IE is the same for Mesh and Hostap */ 3005841ab66cSSepherosa Ziehau struct ieee80211_tim_ie *tie = (struct ieee80211_tim_ie *) frm; 3006841ab66cSSepherosa Ziehau 3007841ab66cSSepherosa Ziehau tie->tim_ie = IEEE80211_ELEMID_TIM; 3008841ab66cSSepherosa Ziehau tie->tim_len = 4; /* length */ 3009841ab66cSSepherosa Ziehau tie->tim_count = 0; /* DTIM count */ 301032176cfdSRui Paulo tie->tim_period = vap->iv_dtim_period; /* DTIM period */ 3011841ab66cSSepherosa Ziehau tie->tim_bitctl = 0; /* bitmap control */ 3012841ab66cSSepherosa Ziehau tie->tim_bitmap[0] = 0; /* Partial Virtual Bitmap */ 3013841ab66cSSepherosa Ziehau frm += sizeof(struct ieee80211_tim_ie); 3014841ab66cSSepherosa Ziehau bo->bo_tim_len = 1; 3015841ab66cSSepherosa Ziehau } 301632176cfdSRui Paulo bo->bo_tim_trailer = frm; 301732176cfdSRui Paulo if ((vap->iv_flags & IEEE80211_F_DOTH) || 301832176cfdSRui Paulo (vap->iv_flags_ext & IEEE80211_FEXT_DOTD)) 301932176cfdSRui Paulo frm = ieee80211_add_countryie(frm, ic); 302032176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_DOTH) { 302132176cfdSRui Paulo if (IEEE80211_IS_CHAN_5GHZ(ni->ni_chan)) 302232176cfdSRui Paulo frm = ieee80211_add_powerconstraint(frm, vap); 302332176cfdSRui Paulo bo->bo_csa = frm; 302432176cfdSRui Paulo if (ic->ic_flags & IEEE80211_F_CSAPENDING) 302532176cfdSRui Paulo frm = ieee80211_add_csa(frm, vap); 302632176cfdSRui Paulo } else 302732176cfdSRui Paulo bo->bo_csa = frm; 3028085ff963SMatthew Dillon 3029085ff963SMatthew Dillon if (vap->iv_flags & IEEE80211_F_DOTH) { 3030085ff963SMatthew Dillon bo->bo_quiet = frm; 3031085ff963SMatthew Dillon if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 3032085ff963SMatthew Dillon (vap->iv_flags_ext & IEEE80211_FEXT_DFS)) { 3033085ff963SMatthew Dillon if (vap->iv_quiet) 3034085ff963SMatthew Dillon frm = ieee80211_add_quiet(frm,vap); 3035085ff963SMatthew Dillon } 3036085ff963SMatthew Dillon } else 3037085ff963SMatthew Dillon bo->bo_quiet = frm; 3038085ff963SMatthew Dillon 303932176cfdSRui Paulo if (IEEE80211_IS_CHAN_ANYG(ni->ni_chan)) { 3040841ab66cSSepherosa Ziehau bo->bo_erp = frm; 3041841ab66cSSepherosa Ziehau frm = ieee80211_add_erp(frm, ic); 3042841ab66cSSepherosa Ziehau } 304332176cfdSRui Paulo frm = ieee80211_add_xrates(frm, rs); 3044085ff963SMatthew Dillon frm = ieee80211_add_rsn(frm, vap); 304532176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(ni->ni_chan)) { 304632176cfdSRui Paulo frm = ieee80211_add_htcap(frm, ni); 304732176cfdSRui Paulo bo->bo_htinfo = frm; 304832176cfdSRui Paulo frm = ieee80211_add_htinfo(frm, ni); 304932176cfdSRui Paulo } 3050085ff963SMatthew Dillon frm = ieee80211_add_wpa(frm, vap); 305132176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_WME) { 305232176cfdSRui Paulo bo->bo_wme = frm; 305332176cfdSRui Paulo frm = ieee80211_add_wme_param(frm, &ic->ic_wme); 305432176cfdSRui Paulo } 305532176cfdSRui Paulo if (IEEE80211_IS_CHAN_HT(ni->ni_chan) && 305632176cfdSRui Paulo (vap->iv_flags_ht & IEEE80211_FHT_HTCOMPAT)) { 305732176cfdSRui Paulo frm = ieee80211_add_htcap_vendor(frm, ni); 305832176cfdSRui Paulo frm = ieee80211_add_htinfo_vendor(frm, ni); 305932176cfdSRui Paulo } 306032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 306132176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_ATHEROS) { 306232176cfdSRui Paulo bo->bo_ath = frm; 306332176cfdSRui Paulo frm = ieee80211_add_athcaps(frm, ni); 306432176cfdSRui Paulo } 306532176cfdSRui Paulo #endif 306632176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 306732176cfdSRui Paulo if (vap->iv_caps & IEEE80211_C_TDMA) { 306832176cfdSRui Paulo bo->bo_tdma = frm; 306932176cfdSRui Paulo frm = ieee80211_add_tdma(frm, vap); 307032176cfdSRui Paulo } 307132176cfdSRui Paulo #endif 307232176cfdSRui Paulo if (vap->iv_appie_beacon != NULL) { 307332176cfdSRui Paulo bo->bo_appie = frm; 307432176cfdSRui Paulo bo->bo_appie_len = vap->iv_appie_beacon->ie_len; 307532176cfdSRui Paulo frm = add_appie(frm, vap->iv_appie_beacon); 307632176cfdSRui Paulo } 307732176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 307832176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) { 307932176cfdSRui Paulo frm = ieee80211_add_meshid(frm, vap); 308032176cfdSRui Paulo bo->bo_meshconf = frm; 308132176cfdSRui Paulo frm = ieee80211_add_meshconf(frm, vap); 308232176cfdSRui Paulo } 308332176cfdSRui Paulo #endif 308432176cfdSRui Paulo bo->bo_tim_trailer_len = frm - bo->bo_tim_trailer; 308532176cfdSRui Paulo bo->bo_csa_trailer_len = frm - bo->bo_csa; 308632176cfdSRui Paulo m->m_pkthdr.len = m->m_len = frm - mtod(m, uint8_t *); 308732176cfdSRui Paulo } 308832176cfdSRui Paulo 308932176cfdSRui Paulo /* 309032176cfdSRui Paulo * Allocate a beacon frame and fillin the appropriate bits. 309132176cfdSRui Paulo */ 309232176cfdSRui Paulo struct mbuf * 309332176cfdSRui Paulo ieee80211_beacon_alloc(struct ieee80211_node *ni, 309432176cfdSRui Paulo struct ieee80211_beacon_offsets *bo) 309532176cfdSRui Paulo { 309632176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 309732176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 309832176cfdSRui Paulo struct ifnet *ifp = vap->iv_ifp; 309932176cfdSRui Paulo struct ieee80211_frame *wh; 310032176cfdSRui Paulo struct mbuf *m; 310132176cfdSRui Paulo int pktlen; 310232176cfdSRui Paulo uint8_t *frm; 310332176cfdSRui Paulo 310432176cfdSRui Paulo /* 310532176cfdSRui Paulo * beacon frame format 310632176cfdSRui Paulo * [8] time stamp 310732176cfdSRui Paulo * [2] beacon interval 310832176cfdSRui Paulo * [2] cabability information 310932176cfdSRui Paulo * [tlv] ssid 311032176cfdSRui Paulo * [tlv] supported rates 311132176cfdSRui Paulo * [3] parameter set (DS) 311232176cfdSRui Paulo * [8] CF parameter set (optional) 311332176cfdSRui Paulo * [tlv] parameter set (IBSS/TIM) 311432176cfdSRui Paulo * [tlv] country (optional) 311532176cfdSRui Paulo * [3] power control (optional) 311632176cfdSRui Paulo * [5] channel switch announcement (CSA) (optional) 311732176cfdSRui Paulo * [tlv] extended rate phy (ERP) 311832176cfdSRui Paulo * [tlv] extended supported rates 311932176cfdSRui Paulo * [tlv] RSN parameters 312032176cfdSRui Paulo * [tlv] HT capabilities 312132176cfdSRui Paulo * [tlv] HT information 312232176cfdSRui Paulo * [tlv] Vendor OUI HT capabilities (optional) 312332176cfdSRui Paulo * [tlv] Vendor OUI HT information (optional) 312432176cfdSRui Paulo * XXX Vendor-specific OIDs (e.g. Atheros) 312532176cfdSRui Paulo * [tlv] WPA parameters 312632176cfdSRui Paulo * [tlv] WME parameters 312732176cfdSRui Paulo * [tlv] TDMA parameters (optional) 312832176cfdSRui Paulo * [tlv] Mesh ID (MBSS) 312932176cfdSRui Paulo * [tlv] Mesh Conf (MBSS) 313032176cfdSRui Paulo * [tlv] application data (optional) 313132176cfdSRui Paulo * NB: we allocate the max space required for the TIM bitmap. 313232176cfdSRui Paulo * XXX how big is this? 313332176cfdSRui Paulo */ 313432176cfdSRui Paulo pktlen = 8 /* time stamp */ 313532176cfdSRui Paulo + sizeof(uint16_t) /* beacon interval */ 313632176cfdSRui Paulo + sizeof(uint16_t) /* capabilities */ 313732176cfdSRui Paulo + 2 + ni->ni_esslen /* ssid */ 313832176cfdSRui Paulo + 2 + IEEE80211_RATE_SIZE /* supported rates */ 313932176cfdSRui Paulo + 2 + 1 /* DS parameters */ 314032176cfdSRui Paulo + 2 + 6 /* CF parameters */ 314132176cfdSRui Paulo + 2 + 4 + vap->iv_tim_len /* DTIM/IBSSPARMS */ 314232176cfdSRui Paulo + IEEE80211_COUNTRY_MAX_SIZE /* country */ 314332176cfdSRui Paulo + 2 + 1 /* power control */ 314432176cfdSRui Paulo + sizeof(struct ieee80211_csa_ie) /* CSA */ 3145085ff963SMatthew Dillon + sizeof(struct ieee80211_quiet_ie) /* Quiet */ 314632176cfdSRui Paulo + 2 + 1 /* ERP */ 314732176cfdSRui Paulo + 2 + (IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE) 314832176cfdSRui Paulo + (vap->iv_caps & IEEE80211_C_WPA ? /* WPA 1+2 */ 314932176cfdSRui Paulo 2*sizeof(struct ieee80211_ie_wpa) : 0) 315032176cfdSRui Paulo /* XXX conditional? */ 315132176cfdSRui Paulo + 4+2*sizeof(struct ieee80211_ie_htcap)/* HT caps */ 315232176cfdSRui Paulo + 4+2*sizeof(struct ieee80211_ie_htinfo)/* HT info */ 315332176cfdSRui Paulo + (vap->iv_caps & IEEE80211_C_WME ? /* WME */ 315432176cfdSRui Paulo sizeof(struct ieee80211_wme_param) : 0) 315532176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 315632176cfdSRui Paulo + sizeof(struct ieee80211_ath_ie) /* ATH */ 315732176cfdSRui Paulo #endif 315832176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 315932176cfdSRui Paulo + (vap->iv_caps & IEEE80211_C_TDMA ? /* TDMA */ 316032176cfdSRui Paulo sizeof(struct ieee80211_tdma_param) : 0) 316132176cfdSRui Paulo #endif 316232176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 316332176cfdSRui Paulo + 2 + ni->ni_meshidlen 316432176cfdSRui Paulo + sizeof(struct ieee80211_meshconf_ie) 316532176cfdSRui Paulo #endif 316632176cfdSRui Paulo + IEEE80211_MAX_APPIE 316732176cfdSRui Paulo ; 316832176cfdSRui Paulo m = ieee80211_getmgtframe(&frm, 316932176cfdSRui Paulo ic->ic_headroom + sizeof(struct ieee80211_frame), pktlen); 317032176cfdSRui Paulo if (m == NULL) { 317132176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_ANY, 317232176cfdSRui Paulo "%s: cannot get buf; size %u\n", __func__, pktlen); 317332176cfdSRui Paulo vap->iv_stats.is_tx_nobuf++; 317432176cfdSRui Paulo return NULL; 317532176cfdSRui Paulo } 317632176cfdSRui Paulo ieee80211_beacon_construct(m, frm, bo, ni); 3177841ab66cSSepherosa Ziehau 3178b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ieee80211_frame), M_NOWAIT); 3179841ab66cSSepherosa Ziehau KASSERT(m != NULL, ("no space for 802.11 header?")); 3180841ab66cSSepherosa Ziehau wh = mtod(m, struct ieee80211_frame *); 3181841ab66cSSepherosa Ziehau wh->i_fc[0] = IEEE80211_FC0_VERSION_0 | IEEE80211_FC0_TYPE_MGT | 3182841ab66cSSepherosa Ziehau IEEE80211_FC0_SUBTYPE_BEACON; 3183841ab66cSSepherosa Ziehau wh->i_fc[1] = IEEE80211_FC1_DIR_NODS; 3184841ab66cSSepherosa Ziehau *(uint16_t *)wh->i_dur = 0; 3185841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr1, ifp->if_broadcastaddr); 318632176cfdSRui Paulo IEEE80211_ADDR_COPY(wh->i_addr2, vap->iv_myaddr); 3187841ab66cSSepherosa Ziehau IEEE80211_ADDR_COPY(wh->i_addr3, ni->ni_bssid); 3188841ab66cSSepherosa Ziehau *(uint16_t *)wh->i_seq = 0; 3189841ab66cSSepherosa Ziehau 3190841ab66cSSepherosa Ziehau return m; 3191841ab66cSSepherosa Ziehau } 3192841ab66cSSepherosa Ziehau 3193841ab66cSSepherosa Ziehau /* 3194841ab66cSSepherosa Ziehau * Update the dynamic parts of a beacon frame based on the current state. 3195841ab66cSSepherosa Ziehau */ 3196841ab66cSSepherosa Ziehau int 319732176cfdSRui Paulo ieee80211_beacon_update(struct ieee80211_node *ni, 3198841ab66cSSepherosa Ziehau struct ieee80211_beacon_offsets *bo, struct mbuf *m, int mcast) 3199841ab66cSSepherosa Ziehau { 320032176cfdSRui Paulo struct ieee80211vap *vap = ni->ni_vap; 320132176cfdSRui Paulo struct ieee80211com *ic = ni->ni_ic; 3202841ab66cSSepherosa Ziehau int len_changed = 0; 3203841ab66cSSepherosa Ziehau uint16_t capinfo; 3204085ff963SMatthew Dillon struct ieee80211_frame *wh; 3205085ff963SMatthew Dillon ieee80211_seq seqno; 3206841ab66cSSepherosa Ziehau 3207085ff963SMatthew Dillon IEEE80211_LOCK(ic); 320832176cfdSRui Paulo /* 320932176cfdSRui Paulo * Handle 11h channel change when we've reached the count. 321032176cfdSRui Paulo * We must recalculate the beacon frame contents to account 321132176cfdSRui Paulo * for the new channel. Note we do this only for the first 321232176cfdSRui Paulo * vap that reaches this point; subsequent vaps just update 321332176cfdSRui Paulo * their beacon state to reflect the recalculated channel. 321432176cfdSRui Paulo */ 321532176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_CSA) && 321632176cfdSRui Paulo vap->iv_csa_count == ic->ic_csa_count) { 321732176cfdSRui Paulo vap->iv_csa_count = 0; 321832176cfdSRui Paulo /* 321932176cfdSRui Paulo * Effect channel change before reconstructing the beacon 322032176cfdSRui Paulo * frame contents as many places reference ni_chan. 322132176cfdSRui Paulo */ 322232176cfdSRui Paulo if (ic->ic_csa_newchan != NULL) 322332176cfdSRui Paulo ieee80211_csa_completeswitch(ic); 322432176cfdSRui Paulo /* 322532176cfdSRui Paulo * NB: ieee80211_beacon_construct clears all pending 322632176cfdSRui Paulo * updates in bo_flags so we don't need to explicitly 322732176cfdSRui Paulo * clear IEEE80211_BEACON_CSA. 322832176cfdSRui Paulo */ 322932176cfdSRui Paulo ieee80211_beacon_construct(m, 323032176cfdSRui Paulo mtod(m, uint8_t*) + sizeof(struct ieee80211_frame), bo, ni); 323132176cfdSRui Paulo 323232176cfdSRui Paulo /* XXX do WME aggressive mode processing? */ 3233085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 323432176cfdSRui Paulo return 1; /* just assume length changed */ 323532176cfdSRui Paulo } 3236841ab66cSSepherosa Ziehau 3237085ff963SMatthew Dillon wh = mtod(m, struct ieee80211_frame *); 3238085ff963SMatthew Dillon seqno = ni->ni_txseqs[IEEE80211_NONQOS_TID]++; 3239085ff963SMatthew Dillon *(uint16_t *)&wh->i_seq[0] = 3240085ff963SMatthew Dillon htole16(seqno << IEEE80211_SEQ_SEQ_SHIFT); 3241085ff963SMatthew Dillon M_SEQNO_SET(m, seqno); 3242085ff963SMatthew Dillon 3243841ab66cSSepherosa Ziehau /* XXX faster to recalculate entirely or just changes? */ 324432176cfdSRui Paulo capinfo = ieee80211_getcapinfo(vap, ni->ni_chan); 3245841ab66cSSepherosa Ziehau *bo->bo_caps = htole16(capinfo); 3246841ab66cSSepherosa Ziehau 324732176cfdSRui Paulo if (vap->iv_flags & IEEE80211_F_WME) { 3248841ab66cSSepherosa Ziehau struct ieee80211_wme_state *wme = &ic->ic_wme; 3249841ab66cSSepherosa Ziehau 3250841ab66cSSepherosa Ziehau /* 3251841ab66cSSepherosa Ziehau * Check for agressive mode change. When there is 3252841ab66cSSepherosa Ziehau * significant high priority traffic in the BSS 3253841ab66cSSepherosa Ziehau * throttle back BE traffic by using conservative 3254841ab66cSSepherosa Ziehau * parameters. Otherwise BE uses agressive params 3255841ab66cSSepherosa Ziehau * to optimize performance of legacy/non-QoS traffic. 3256841ab66cSSepherosa Ziehau */ 3257841ab66cSSepherosa Ziehau if (wme->wme_flags & WME_F_AGGRMODE) { 3258841ab66cSSepherosa Ziehau if (wme->wme_hipri_traffic > 3259841ab66cSSepherosa Ziehau wme->wme_hipri_switch_thresh) { 326032176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 3261841ab66cSSepherosa Ziehau "%s: traffic %u, disable aggressive mode\n", 3262841ab66cSSepherosa Ziehau __func__, wme->wme_hipri_traffic); 3263841ab66cSSepherosa Ziehau wme->wme_flags &= ~WME_F_AGGRMODE; 326432176cfdSRui Paulo ieee80211_wme_updateparams_locked(vap); 3265841ab66cSSepherosa Ziehau wme->wme_hipri_traffic = 3266841ab66cSSepherosa Ziehau wme->wme_hipri_switch_hysteresis; 3267841ab66cSSepherosa Ziehau } else 3268841ab66cSSepherosa Ziehau wme->wme_hipri_traffic = 0; 3269841ab66cSSepherosa Ziehau } else { 3270841ab66cSSepherosa Ziehau if (wme->wme_hipri_traffic <= 3271841ab66cSSepherosa Ziehau wme->wme_hipri_switch_thresh) { 327232176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_WME, 3273841ab66cSSepherosa Ziehau "%s: traffic %u, enable aggressive mode\n", 3274841ab66cSSepherosa Ziehau __func__, wme->wme_hipri_traffic); 3275841ab66cSSepherosa Ziehau wme->wme_flags |= WME_F_AGGRMODE; 327632176cfdSRui Paulo ieee80211_wme_updateparams_locked(vap); 3277841ab66cSSepherosa Ziehau wme->wme_hipri_traffic = 0; 3278841ab66cSSepherosa Ziehau } else 3279841ab66cSSepherosa Ziehau wme->wme_hipri_traffic = 3280841ab66cSSepherosa Ziehau wme->wme_hipri_switch_hysteresis; 3281841ab66cSSepherosa Ziehau } 328232176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_WME)) { 3283841ab66cSSepherosa Ziehau (void) ieee80211_add_wme_param(bo->bo_wme, wme); 328432176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_WME); 3285841ab66cSSepherosa Ziehau } 3286841ab66cSSepherosa Ziehau } 3287841ab66cSSepherosa Ziehau 328832176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_HTINFO)) { 328932176cfdSRui Paulo ieee80211_ht_update_beacon(vap, bo); 329032176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_HTINFO); 329132176cfdSRui Paulo } 329232176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_TDMA 329332176cfdSRui Paulo if (vap->iv_caps & IEEE80211_C_TDMA) { 329432176cfdSRui Paulo /* 329532176cfdSRui Paulo * NB: the beacon is potentially updated every TBTT. 329632176cfdSRui Paulo */ 329732176cfdSRui Paulo ieee80211_tdma_update_beacon(vap, bo); 329832176cfdSRui Paulo } 329932176cfdSRui Paulo #endif 330032176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_MESH 330132176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_MBSS) 330232176cfdSRui Paulo ieee80211_mesh_update_beacon(vap, bo); 330332176cfdSRui Paulo #endif 330432176cfdSRui Paulo 330532176cfdSRui Paulo if (vap->iv_opmode == IEEE80211_M_HOSTAP || 330632176cfdSRui Paulo vap->iv_opmode == IEEE80211_M_MBSS) { /* NB: no IBSS support*/ 3307841ab66cSSepherosa Ziehau struct ieee80211_tim_ie *tie = 3308841ab66cSSepherosa Ziehau (struct ieee80211_tim_ie *) bo->bo_tim; 330932176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_TIM)) { 3310841ab66cSSepherosa Ziehau u_int timlen, timoff, i; 3311841ab66cSSepherosa Ziehau /* 3312841ab66cSSepherosa Ziehau * ATIM/DTIM needs updating. If it fits in the 3313841ab66cSSepherosa Ziehau * current space allocated then just copy in the 3314841ab66cSSepherosa Ziehau * new bits. Otherwise we need to move any trailing 3315841ab66cSSepherosa Ziehau * data to make room. Note that we know there is 3316841ab66cSSepherosa Ziehau * contiguous space because ieee80211_beacon_allocate 3317841ab66cSSepherosa Ziehau * insures there is space in the mbuf to write a 331832176cfdSRui Paulo * maximal-size virtual bitmap (based on iv_max_aid). 3319841ab66cSSepherosa Ziehau */ 3320841ab66cSSepherosa Ziehau /* 3321841ab66cSSepherosa Ziehau * Calculate the bitmap size and offset, copy any 3322841ab66cSSepherosa Ziehau * trailer out of the way, and then copy in the 3323841ab66cSSepherosa Ziehau * new bitmap and update the information element. 3324841ab66cSSepherosa Ziehau * Note that the tim bitmap must contain at least 3325841ab66cSSepherosa Ziehau * one byte and any offset must be even. 3326841ab66cSSepherosa Ziehau */ 332732176cfdSRui Paulo if (vap->iv_ps_pending != 0) { 3328841ab66cSSepherosa Ziehau timoff = 128; /* impossibly large */ 332932176cfdSRui Paulo for (i = 0; i < vap->iv_tim_len; i++) 333032176cfdSRui Paulo if (vap->iv_tim_bitmap[i]) { 3331841ab66cSSepherosa Ziehau timoff = i &~ 1; 3332841ab66cSSepherosa Ziehau break; 3333841ab66cSSepherosa Ziehau } 3334841ab66cSSepherosa Ziehau KASSERT(timoff != 128, ("tim bitmap empty!")); 333532176cfdSRui Paulo for (i = vap->iv_tim_len-1; i >= timoff; i--) 333632176cfdSRui Paulo if (vap->iv_tim_bitmap[i]) 3337841ab66cSSepherosa Ziehau break; 3338841ab66cSSepherosa Ziehau timlen = 1 + (i - timoff); 3339841ab66cSSepherosa Ziehau } else { 3340841ab66cSSepherosa Ziehau timoff = 0; 3341841ab66cSSepherosa Ziehau timlen = 1; 3342841ab66cSSepherosa Ziehau } 3343841ab66cSSepherosa Ziehau if (timlen != bo->bo_tim_len) { 3344841ab66cSSepherosa Ziehau /* copy up/down trailer */ 3345841ab66cSSepherosa Ziehau int adjust = tie->tim_bitmap+timlen 334632176cfdSRui Paulo - bo->bo_tim_trailer; 334732176cfdSRui Paulo ovbcopy(bo->bo_tim_trailer, 334832176cfdSRui Paulo bo->bo_tim_trailer+adjust, 334932176cfdSRui Paulo bo->bo_tim_trailer_len); 335032176cfdSRui Paulo bo->bo_tim_trailer += adjust; 3351841ab66cSSepherosa Ziehau bo->bo_erp += adjust; 335232176cfdSRui Paulo bo->bo_htinfo += adjust; 3353085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_SUPERG 335432176cfdSRui Paulo bo->bo_ath += adjust; 335532176cfdSRui Paulo #endif 3356085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_TDMA 335732176cfdSRui Paulo bo->bo_tdma += adjust; 335832176cfdSRui Paulo #endif 3359085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 336032176cfdSRui Paulo bo->bo_meshconf += adjust; 336132176cfdSRui Paulo #endif 336232176cfdSRui Paulo bo->bo_appie += adjust; 336332176cfdSRui Paulo bo->bo_wme += adjust; 336432176cfdSRui Paulo bo->bo_csa += adjust; 3365085ff963SMatthew Dillon bo->bo_quiet += adjust; 3366841ab66cSSepherosa Ziehau bo->bo_tim_len = timlen; 3367841ab66cSSepherosa Ziehau 3368841ab66cSSepherosa Ziehau /* update information element */ 3369841ab66cSSepherosa Ziehau tie->tim_len = 3 + timlen; 3370841ab66cSSepherosa Ziehau tie->tim_bitctl = timoff; 3371841ab66cSSepherosa Ziehau len_changed = 1; 3372841ab66cSSepherosa Ziehau } 337332176cfdSRui Paulo memcpy(tie->tim_bitmap, vap->iv_tim_bitmap + timoff, 3374841ab66cSSepherosa Ziehau bo->bo_tim_len); 3375841ab66cSSepherosa Ziehau 337632176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_TIM); 3377841ab66cSSepherosa Ziehau 337832176cfdSRui Paulo IEEE80211_DPRINTF(vap, IEEE80211_MSG_POWER, 3379841ab66cSSepherosa Ziehau "%s: TIM updated, pending %u, off %u, len %u\n", 338032176cfdSRui Paulo __func__, vap->iv_ps_pending, timoff, timlen); 3381841ab66cSSepherosa Ziehau } 3382841ab66cSSepherosa Ziehau /* count down DTIM period */ 3383841ab66cSSepherosa Ziehau if (tie->tim_count == 0) 3384841ab66cSSepherosa Ziehau tie->tim_count = tie->tim_period - 1; 3385841ab66cSSepherosa Ziehau else 3386841ab66cSSepherosa Ziehau tie->tim_count--; 3387841ab66cSSepherosa Ziehau /* update state for buffered multicast frames on DTIM */ 3388841ab66cSSepherosa Ziehau if (mcast && tie->tim_count == 0) 3389841ab66cSSepherosa Ziehau tie->tim_bitctl |= 1; 3390841ab66cSSepherosa Ziehau else 3391841ab66cSSepherosa Ziehau tie->tim_bitctl &= ~1; 339232176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_CSA)) { 339332176cfdSRui Paulo struct ieee80211_csa_ie *csa = 339432176cfdSRui Paulo (struct ieee80211_csa_ie *) bo->bo_csa; 339532176cfdSRui Paulo 339632176cfdSRui Paulo /* 339732176cfdSRui Paulo * Insert or update CSA ie. If we're just starting 339832176cfdSRui Paulo * to count down to the channel switch then we need 339932176cfdSRui Paulo * to insert the CSA ie. Otherwise we just need to 340032176cfdSRui Paulo * drop the count. The actual change happens above 340132176cfdSRui Paulo * when the vap's count reaches the target count. 340232176cfdSRui Paulo */ 340332176cfdSRui Paulo if (vap->iv_csa_count == 0) { 340432176cfdSRui Paulo memmove(&csa[1], csa, bo->bo_csa_trailer_len); 340532176cfdSRui Paulo bo->bo_erp += sizeof(*csa); 340632176cfdSRui Paulo bo->bo_htinfo += sizeof(*csa); 340732176cfdSRui Paulo bo->bo_wme += sizeof(*csa); 3408085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_SUPERG 340932176cfdSRui Paulo bo->bo_ath += sizeof(*csa); 341032176cfdSRui Paulo #endif 3411085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_TDMA 341232176cfdSRui Paulo bo->bo_tdma += sizeof(*csa); 341332176cfdSRui Paulo #endif 3414085ff963SMatthew Dillon #ifdef IEEE80211_SUPPORT_MESH 341532176cfdSRui Paulo bo->bo_meshconf += sizeof(*csa); 341632176cfdSRui Paulo #endif 341732176cfdSRui Paulo bo->bo_appie += sizeof(*csa); 341832176cfdSRui Paulo bo->bo_csa_trailer_len += sizeof(*csa); 3419085ff963SMatthew Dillon bo->bo_quiet += sizeof(*csa); 342032176cfdSRui Paulo bo->bo_tim_trailer_len += sizeof(*csa); 342132176cfdSRui Paulo m->m_len += sizeof(*csa); 342232176cfdSRui Paulo m->m_pkthdr.len += sizeof(*csa); 342332176cfdSRui Paulo 342432176cfdSRui Paulo ieee80211_add_csa(bo->bo_csa, vap); 342532176cfdSRui Paulo } else 342632176cfdSRui Paulo csa->csa_count--; 342732176cfdSRui Paulo vap->iv_csa_count++; 342832176cfdSRui Paulo /* NB: don't clear IEEE80211_BEACON_CSA */ 342932176cfdSRui Paulo } 3430085ff963SMatthew Dillon if (IEEE80211_IS_CHAN_DFS(ic->ic_bsschan) && 3431085ff963SMatthew Dillon (vap->iv_flags_ext & IEEE80211_FEXT_DFS) ){ 3432085ff963SMatthew Dillon if (vap->iv_quiet) 3433085ff963SMatthew Dillon ieee80211_add_quiet(bo->bo_quiet, vap); 3434085ff963SMatthew Dillon } 343532176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_ERP)) { 3436841ab66cSSepherosa Ziehau /* 3437841ab66cSSepherosa Ziehau * ERP element needs updating. 3438841ab66cSSepherosa Ziehau */ 3439841ab66cSSepherosa Ziehau (void) ieee80211_add_erp(bo->bo_erp, ic); 344032176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_ERP); 3441841ab66cSSepherosa Ziehau } 344232176cfdSRui Paulo #ifdef IEEE80211_SUPPORT_SUPERG 344332176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_ATH)) { 344432176cfdSRui Paulo ieee80211_add_athcaps(bo->bo_ath, ni); 344532176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_ATH); 34466dd1c373SSepherosa Ziehau } 3447841ab66cSSepherosa Ziehau #endif 3448841ab66cSSepherosa Ziehau } 344932176cfdSRui Paulo if (isset(bo->bo_flags, IEEE80211_BEACON_APPIE)) { 345032176cfdSRui Paulo const struct ieee80211_appie *aie = vap->iv_appie_beacon; 345132176cfdSRui Paulo int aielen; 345232176cfdSRui Paulo uint8_t *frm; 3453841ab66cSSepherosa Ziehau 345432176cfdSRui Paulo aielen = 0; 345532176cfdSRui Paulo if (aie != NULL) 345632176cfdSRui Paulo aielen += aie->ie_len; 345732176cfdSRui Paulo if (aielen != bo->bo_appie_len) { 345832176cfdSRui Paulo /* copy up/down trailer */ 345932176cfdSRui Paulo int adjust = aielen - bo->bo_appie_len; 346032176cfdSRui Paulo ovbcopy(bo->bo_tim_trailer, bo->bo_tim_trailer+adjust, 346132176cfdSRui Paulo bo->bo_tim_trailer_len); 346232176cfdSRui Paulo bo->bo_tim_trailer += adjust; 346332176cfdSRui Paulo bo->bo_appie += adjust; 346432176cfdSRui Paulo bo->bo_appie_len = aielen; 3465841ab66cSSepherosa Ziehau 346632176cfdSRui Paulo len_changed = 1; 3467841ab66cSSepherosa Ziehau } 346832176cfdSRui Paulo frm = bo->bo_appie; 346932176cfdSRui Paulo if (aie != NULL) 347032176cfdSRui Paulo frm = add_appie(frm, aie); 347132176cfdSRui Paulo clrbit(bo->bo_flags, IEEE80211_BEACON_APPIE); 34722d7dda79SSepherosa Ziehau } 3473085ff963SMatthew Dillon IEEE80211_UNLOCK(ic); 34742d7dda79SSepherosa Ziehau 347532176cfdSRui Paulo return len_changed; 3476322b19a8SSepherosa Ziehau } 3477085ff963SMatthew Dillon 3478085ff963SMatthew Dillon /* 3479085ff963SMatthew Dillon * Do Ethernet-LLC encapsulation for each payload in a fast frame 3480085ff963SMatthew Dillon * tunnel encapsulation. The frame is assumed to have an Ethernet 3481085ff963SMatthew Dillon * header at the front that must be stripped before prepending the 3482085ff963SMatthew Dillon * LLC followed by the Ethernet header passed in (with an Ethernet 3483085ff963SMatthew Dillon * type that specifies the payload size). 3484085ff963SMatthew Dillon */ 3485085ff963SMatthew Dillon struct mbuf * 3486085ff963SMatthew Dillon ieee80211_ff_encap1(struct ieee80211vap *vap, struct mbuf *m, 3487085ff963SMatthew Dillon const struct ether_header *eh) 3488085ff963SMatthew Dillon { 3489085ff963SMatthew Dillon struct llc *llc; 3490085ff963SMatthew Dillon uint16_t payload; 3491085ff963SMatthew Dillon 3492085ff963SMatthew Dillon /* XXX optimize by combining m_adj+M_PREPEND */ 3493085ff963SMatthew Dillon m_adj(m, sizeof(struct ether_header) - sizeof(struct llc)); 3494085ff963SMatthew Dillon llc = mtod(m, struct llc *); 3495085ff963SMatthew Dillon llc->llc_dsap = llc->llc_ssap = LLC_SNAP_LSAP; 3496085ff963SMatthew Dillon llc->llc_control = LLC_UI; 3497085ff963SMatthew Dillon llc->llc_snap.org_code[0] = 0; 3498085ff963SMatthew Dillon llc->llc_snap.org_code[1] = 0; 3499085ff963SMatthew Dillon llc->llc_snap.org_code[2] = 0; 3500085ff963SMatthew Dillon llc->llc_snap.ether_type = eh->ether_type; 3501085ff963SMatthew Dillon payload = m->m_pkthdr.len; /* NB: w/o Ethernet header */ 3502085ff963SMatthew Dillon 3503b5523eacSSascha Wildner M_PREPEND(m, sizeof(struct ether_header), M_NOWAIT); 3504085ff963SMatthew Dillon if (m == NULL) { /* XXX cannot happen */ 3505085ff963SMatthew Dillon IEEE80211_DPRINTF(vap, IEEE80211_MSG_SUPERG, 3506085ff963SMatthew Dillon "%s: no space for ether_header\n", __func__); 3507085ff963SMatthew Dillon vap->iv_stats.is_tx_nobuf++; 3508085ff963SMatthew Dillon return NULL; 3509085ff963SMatthew Dillon } 3510085ff963SMatthew Dillon ETHER_HEADER_COPY(mtod(m, void *), eh); 3511085ff963SMatthew Dillon mtod(m, struct ether_header *)->ether_type = htons(payload); 3512085ff963SMatthew Dillon return m; 3513085ff963SMatthew Dillon } 3514085ff963SMatthew Dillon 3515085ff963SMatthew Dillon /* 3516085ff963SMatthew Dillon * Complete an mbuf transmission. 3517085ff963SMatthew Dillon * 3518085ff963SMatthew Dillon * For now, this simply processes a completed frame after the 3519085ff963SMatthew Dillon * driver has completed it's transmission and/or retransmission. 3520085ff963SMatthew Dillon * It assumes the frame is an 802.11 encapsulated frame. 3521085ff963SMatthew Dillon * 3522085ff963SMatthew Dillon * Later on it will grow to become the exit path for a given frame 3523085ff963SMatthew Dillon * from the driver and, depending upon how it's been encapsulated 3524085ff963SMatthew Dillon * and already transmitted, it may end up doing A-MPDU retransmission, 3525085ff963SMatthew Dillon * power save requeuing, etc. 3526085ff963SMatthew Dillon * 3527085ff963SMatthew Dillon * In order for the above to work, the driver entry point to this 3528085ff963SMatthew Dillon * must not hold any driver locks. Thus, the driver needs to delay 3529085ff963SMatthew Dillon * any actual mbuf completion until it can release said locks. 3530085ff963SMatthew Dillon * 3531085ff963SMatthew Dillon * This frees the mbuf and if the mbuf has a node reference, 3532085ff963SMatthew Dillon * the node reference will be freed. 3533085ff963SMatthew Dillon */ 3534085ff963SMatthew Dillon void 3535085ff963SMatthew Dillon ieee80211_tx_complete(struct ieee80211_node *ni, struct mbuf *m, int status) 3536085ff963SMatthew Dillon { 3537085ff963SMatthew Dillon 3538085ff963SMatthew Dillon if (ni != NULL) { 3539085ff963SMatthew Dillon if (m->m_flags & M_TXCB) 3540085ff963SMatthew Dillon ieee80211_process_callback(ni, m, status); 3541085ff963SMatthew Dillon ieee80211_free_node(ni); 3542085ff963SMatthew Dillon } 3543085ff963SMatthew Dillon m_freem(m); 3544085ff963SMatthew Dillon } 3545