1138568Ssam/*- 2186904Ssam * Copyright (c) 2003-2009 Sam Leffler, Errno Consulting 3138568Ssam * All rights reserved. 4138568Ssam * 5138568Ssam * Redistribution and use in source and binary forms, with or without 6138568Ssam * modification, are permitted provided that the following conditions 7138568Ssam * are met: 8138568Ssam * 1. Redistributions of source code must retain the above copyright 9138568Ssam * notice, this list of conditions and the following disclaimer. 10138568Ssam * 2. Redistributions in binary form must reproduce the above copyright 11138568Ssam * notice, this list of conditions and the following disclaimer in the 12138568Ssam * documentation and/or other materials provided with the distribution. 13138568Ssam * 14138568Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15138568Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16138568Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17138568Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18138568Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19138568Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20138568Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21138568Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22138568Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23138568Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24138568Ssam */ 25138568Ssam 26138568Ssam#include <sys/cdefs.h> 27138568Ssam__FBSDID("$FreeBSD: stable/11/sys/net80211/ieee80211_freebsd.c 343817 2019-02-06 01:47:22Z avos $"); 28138568Ssam 29138568Ssam/* 30138568Ssam * IEEE 802.11 support (FreeBSD-specific code) 31138568Ssam */ 32178354Ssam#include "opt_wlan.h" 33178354Ssam 34138568Ssam#include <sys/param.h> 35138568Ssam#include <sys/systm.h> 36293470Smelifaro#include <sys/eventhandler.h> 37295126Sglebius#include <sys/kernel.h> 38138568Ssam#include <sys/linker.h> 39295126Sglebius#include <sys/malloc.h> 40138568Ssam#include <sys/mbuf.h> 41138568Ssam#include <sys/module.h> 42138568Ssam#include <sys/proc.h> 43138568Ssam#include <sys/sysctl.h> 44138568Ssam 45138568Ssam#include <sys/socket.h> 46138568Ssam 47192468Ssam#include <net/bpf.h> 48138568Ssam#include <net/if.h> 49257176Sglebius#include <net/if_var.h> 50190526Ssam#include <net/if_dl.h> 51178354Ssam#include <net/if_clone.h> 52138568Ssam#include <net/if_media.h> 53178354Ssam#include <net/if_types.h> 54138568Ssam#include <net/ethernet.h> 55138568Ssam#include <net/route.h> 56196019Srwatson#include <net/vnet.h> 57138568Ssam 58138568Ssam#include <net80211/ieee80211_var.h> 59195757Ssam#include <net80211/ieee80211_input.h> 60138568Ssam 61138568SsamSYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters"); 62138568Ssam 63138568Ssam#ifdef IEEE80211_DEBUG 64300232Savosstatic int ieee80211_debug = 0; 65138568SsamSYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug, 66138568Ssam 0, "debugging printfs"); 67138568Ssam#endif 68138568Ssam 69241610Sglebiusstatic const char wlanname[] = "wlan"; 70241610Sglebiusstatic struct if_clone *wlan_cloner; 71241610Sglebius 72138568Ssamstatic int 73178354Ssamwlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) 74173273Ssam{ 75178354Ssam struct ieee80211_clone_params cp; 76178354Ssam struct ieee80211vap *vap; 77178354Ssam struct ieee80211com *ic; 78173273Ssam int error; 79173273Ssam 80178354Ssam error = copyin(params, &cp, sizeof(cp)); 81178354Ssam if (error) 82178354Ssam return error; 83287197Sglebius ic = ieee80211_find_com(cp.icp_parent); 84287197Sglebius if (ic == NULL) 85178354Ssam return ENXIO; 86178957Ssam if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) { 87287197Sglebius ic_printf(ic, "%s: invalid opmode %d\n", __func__, 88287197Sglebius cp.icp_opmode); 89178354Ssam return EINVAL; 90178354Ssam } 91178957Ssam if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) { 92287197Sglebius ic_printf(ic, "%s mode not supported\n", 93178957Ssam ieee80211_opmode_name[cp.icp_opmode]); 94178957Ssam return EOPNOTSUPP; 95178957Ssam } 96186904Ssam if ((cp.icp_flags & IEEE80211_CLONE_TDMA) && 97186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 98186904Ssam (ic->ic_caps & IEEE80211_C_TDMA) == 0 99186904Ssam#else 100186904Ssam (1) 101186904Ssam#endif 102186904Ssam ) { 103287197Sglebius ic_printf(ic, "TDMA not supported\n"); 104186904Ssam return EOPNOTSUPP; 105186904Ssam } 106241610Sglebius vap = ic->ic_vap_create(ic, wlanname, unit, 107178354Ssam cp.icp_opmode, cp.icp_flags, cp.icp_bssid, 108178354Ssam cp.icp_flags & IEEE80211_CLONE_MACADDR ? 109287197Sglebius cp.icp_macaddr : ic->ic_macaddr); 110242154Sadrian 111178354Ssam return (vap == NULL ? EIO : 0); 112178354Ssam} 113178354Ssam 114178354Ssamstatic void 115178354Ssamwlan_clone_destroy(struct ifnet *ifp) 116178354Ssam{ 117178354Ssam struct ieee80211vap *vap = ifp->if_softc; 118178354Ssam struct ieee80211com *ic = vap->iv_ic; 119178354Ssam 120178354Ssam ic->ic_vap_delete(vap); 121178354Ssam} 122178354Ssam 123178354Ssamvoid 124178354Ssamieee80211_vap_destroy(struct ieee80211vap *vap) 125178354Ssam{ 126242149Sadrian CURVNET_SET(vap->iv_ifp->if_vnet); 127241610Sglebius if_clone_destroyif(wlan_cloner, vap->iv_ifp); 128242149Sadrian CURVNET_RESTORE(); 129178354Ssam} 130178354Ssam 131192473Ssamint 132178354Ssamieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS) 133178354Ssam{ 134178354Ssam int msecs = ticks_to_msecs(*(int *)arg1); 135178354Ssam int error, t; 136178354Ssam 137178354Ssam error = sysctl_handle_int(oidp, &msecs, 0, req); 138173273Ssam if (error || !req->newptr) 139173273Ssam return error; 140178354Ssam t = msecs_to_ticks(msecs); 141178354Ssam *(int *)arg1 = (t < 1) ? 1 : t; 142173273Ssam return 0; 143173273Ssam} 144178354Ssam 145173273Ssamstatic int 146138568Ssamieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS) 147138568Ssam{ 148138568Ssam int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT; 149138568Ssam int error; 150138568Ssam 151138568Ssam error = sysctl_handle_int(oidp, &inact, 0, req); 152138568Ssam if (error || !req->newptr) 153138568Ssam return error; 154138568Ssam *(int *)arg1 = inact / IEEE80211_INACT_WAIT; 155138568Ssam return 0; 156138568Ssam} 157138568Ssam 158138568Ssamstatic int 159138568Ssamieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS) 160138568Ssam{ 161138568Ssam struct ieee80211com *ic = arg1; 162138568Ssam 163283529Sglebius return SYSCTL_OUT_STR(req, ic->ic_name); 164138568Ssam} 165138568Ssam 166181194Ssamstatic int 167181194Ssamieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS) 168181194Ssam{ 169181194Ssam struct ieee80211com *ic = arg1; 170181194Ssam int t = 0, error; 171181194Ssam 172181194Ssam error = sysctl_handle_int(oidp, &t, 0, req); 173181194Ssam if (error || !req->newptr) 174181194Ssam return error; 175181194Ssam IEEE80211_LOCK(ic); 176181194Ssam ieee80211_dfs_notify_radar(ic, ic->ic_curchan); 177181194Ssam IEEE80211_UNLOCK(ic); 178181194Ssam return 0; 179181194Ssam} 180181194Ssam 181330466Seadler/* 182330466Seadler * For now, just restart everything. 183330466Seadler * 184330466Seadler * Later on, it'd be nice to have a separate VAP restart to 185330466Seadler * full-device restart. 186330466Seadler */ 187330466Seadlerstatic int 188330466Seadlerieee80211_sysctl_vap_restart(SYSCTL_HANDLER_ARGS) 189330466Seadler{ 190330466Seadler struct ieee80211vap *vap = arg1; 191330466Seadler int t = 0, error; 192330466Seadler 193330466Seadler error = sysctl_handle_int(oidp, &t, 0, req); 194330466Seadler if (error || !req->newptr) 195330466Seadler return error; 196330466Seadler 197330466Seadler ieee80211_restart_all(vap->iv_ic); 198330466Seadler return 0; 199330466Seadler} 200330466Seadler 201138568Ssamvoid 202138568Ssamieee80211_sysctl_attach(struct ieee80211com *ic) 203138568Ssam{ 204178354Ssam} 205178354Ssam 206178354Ssamvoid 207178354Ssamieee80211_sysctl_detach(struct ieee80211com *ic) 208178354Ssam{ 209178354Ssam} 210178354Ssam 211178354Ssamvoid 212178354Ssamieee80211_sysctl_vattach(struct ieee80211vap *vap) 213178354Ssam{ 214178354Ssam struct ifnet *ifp = vap->iv_ifp; 215138568Ssam struct sysctl_ctx_list *ctx; 216138568Ssam struct sysctl_oid *oid; 217138568Ssam char num[14]; /* sufficient for 32 bits */ 218138568Ssam 219283538Sadrian ctx = (struct sysctl_ctx_list *) IEEE80211_MALLOC(sizeof(struct sysctl_ctx_list), 220283538Sadrian M_DEVBUF, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 221138568Ssam if (ctx == NULL) { 222178354Ssam if_printf(ifp, "%s: cannot allocate sysctl context!\n", 223138568Ssam __func__); 224138568Ssam return; 225138568Ssam } 226138568Ssam sysctl_ctx_init(ctx); 227178354Ssam snprintf(num, sizeof(num), "%u", ifp->if_dunit); 228138568Ssam oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan), 229138568Ssam OID_AUTO, num, CTLFLAG_RD, NULL, ""); 230138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 231217554Smdf "%parent", CTLTYPE_STRING | CTLFLAG_RD, vap->iv_ic, 0, 232178354Ssam ieee80211_sysctl_parent, "A", "parent device"); 233217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 234178354Ssam "driver_caps", CTLFLAG_RW, &vap->iv_caps, 0, 235178354Ssam "driver capabilities"); 236138568Ssam#ifdef IEEE80211_DEBUG 237178354Ssam vap->iv_debug = ieee80211_debug; 238217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 239178354Ssam "debug", CTLFLAG_RW, &vap->iv_debug, 0, 240138568Ssam "control debugging printfs"); 241138568Ssam#endif 242178354Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 243178354Ssam "bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0, 244178354Ssam "consecutive beacon misses before scanning"); 245138568Ssam /* XXX inherit from tunables */ 246138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 247178354Ssam "inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0, 248138568Ssam ieee80211_sysctl_inact, "I", 249138568Ssam "station inactivity timeout (sec)"); 250138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 251178354Ssam "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0, 252138568Ssam ieee80211_sysctl_inact, "I", 253138568Ssam "station inactivity probe timeout (sec)"); 254138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 255178354Ssam "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0, 256138568Ssam ieee80211_sysctl_inact, "I", 257138568Ssam "station authentication timeout (sec)"); 258138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 259178354Ssam "inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0, 260138568Ssam ieee80211_sysctl_inact, "I", 261138568Ssam "station initial state timeout (sec)"); 262178354Ssam if (vap->iv_htcaps & IEEE80211_HTC_HT) { 263217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 264178354Ssam "ampdu_mintraffic_bk", CTLFLAG_RW, 265178354Ssam &vap->iv_ampdu_mintraffic[WME_AC_BK], 0, 266178354Ssam "BK traffic tx aggr threshold (pps)"); 267217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 268178354Ssam "ampdu_mintraffic_be", CTLFLAG_RW, 269178354Ssam &vap->iv_ampdu_mintraffic[WME_AC_BE], 0, 270178354Ssam "BE traffic tx aggr threshold (pps)"); 271217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 272178354Ssam "ampdu_mintraffic_vo", CTLFLAG_RW, 273178354Ssam &vap->iv_ampdu_mintraffic[WME_AC_VO], 0, 274178354Ssam "VO traffic tx aggr threshold (pps)"); 275217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 276178354Ssam "ampdu_mintraffic_vi", CTLFLAG_RW, 277178354Ssam &vap->iv_ampdu_mintraffic[WME_AC_VI], 0, 278178354Ssam "VI traffic tx aggr threshold (pps)"); 279178354Ssam } 280330466Seadler 281330466Seadler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 282330466Seadler "force_restart", CTLTYPE_INT | CTLFLAG_RW, vap, 0, 283330466Seadler ieee80211_sysctl_vap_restart, "I", 284330466Seadler "force a VAP restart"); 285330466Seadler 286181194Ssam if (vap->iv_caps & IEEE80211_C_DFS) { 287181194Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 288181194Ssam "radar", CTLTYPE_INT | CTLFLAG_RW, vap->iv_ic, 0, 289193115Ssam ieee80211_sysctl_radar, "I", "simulate radar event"); 290181194Ssam } 291178354Ssam vap->iv_sysctl = ctx; 292178354Ssam vap->iv_oid = oid; 293138568Ssam} 294138568Ssam 295138568Ssamvoid 296178354Ssamieee80211_sysctl_vdetach(struct ieee80211vap *vap) 297138568Ssam{ 298138568Ssam 299178354Ssam if (vap->iv_sysctl != NULL) { 300178354Ssam sysctl_ctx_free(vap->iv_sysctl); 301283538Sadrian IEEE80211_FREE(vap->iv_sysctl, M_DEVBUF); 302178354Ssam vap->iv_sysctl = NULL; 303138568Ssam } 304138568Ssam} 305138568Ssam 306343489Savos#define MS(_v, _f) (((_v) & _f##_M) >> _f##_S) 307138568Ssamint 308343489Savosieee80211_com_vincref(struct ieee80211vap *vap) 309343489Savos{ 310343489Savos uint32_t ostate; 311343489Savos 312343489Savos ostate = atomic_fetchadd_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD); 313343489Savos 314343489Savos if (ostate & IEEE80211_COM_DETACHED) { 315343489Savos atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD); 316343489Savos return (ENETDOWN); 317343489Savos } 318343489Savos 319343489Savos if (MS(ostate, IEEE80211_COM_REF) == IEEE80211_COM_REF_MAX) { 320343489Savos atomic_subtract_32(&vap->iv_com_state, IEEE80211_COM_REF_ADD); 321343489Savos return (EOVERFLOW); 322343489Savos } 323343489Savos 324343489Savos return (0); 325343489Savos} 326343489Savos 327343489Savosvoid 328343489Savosieee80211_com_vdecref(struct ieee80211vap *vap) 329343489Savos{ 330343489Savos uint32_t ostate; 331343489Savos 332343489Savos ostate = atomic_fetchadd_32(&vap->iv_com_state, -IEEE80211_COM_REF_ADD); 333343489Savos 334343489Savos KASSERT(MS(ostate, IEEE80211_COM_REF) != 0, 335343489Savos ("com reference counter underflow")); 336343489Savos 337343489Savos (void) ostate; 338343489Savos} 339343489Savos 340343489Savosvoid 341343489Savosieee80211_com_vdetach(struct ieee80211vap *vap) 342343489Savos{ 343343489Savos int sleep_time; 344343489Savos 345343489Savos sleep_time = msecs_to_ticks(250); 346343489Savos if (sleep_time == 0) 347343489Savos sleep_time = 1; 348343489Savos 349343489Savos atomic_set_32(&vap->iv_com_state, IEEE80211_COM_DETACHED); 350343489Savos while (MS(atomic_load_32(&vap->iv_com_state), IEEE80211_COM_REF) != 0) 351343489Savos pause("comref", sleep_time); 352343489Savos} 353343489Savos#undef MS 354343489Savos 355343489Savosint 356138568Ssamieee80211_node_dectestref(struct ieee80211_node *ni) 357138568Ssam{ 358138568Ssam /* XXX need equivalent of atomic_dec_and_test */ 359138568Ssam atomic_subtract_int(&ni->ni_refcnt, 1); 360138568Ssam return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); 361138568Ssam} 362138568Ssam 363165894Ssamvoid 364165894Ssamieee80211_drain_ifq(struct ifqueue *ifq) 365165894Ssam{ 366165894Ssam struct ieee80211_node *ni; 367165894Ssam struct mbuf *m; 368165894Ssam 369165894Ssam for (;;) { 370165894Ssam IF_DEQUEUE(ifq, m); 371165894Ssam if (m == NULL) 372165894Ssam break; 373165894Ssam 374165894Ssam ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 375165894Ssam KASSERT(ni != NULL, ("frame w/o node")); 376165894Ssam ieee80211_free_node(ni); 377165894Ssam m->m_pkthdr.rcvif = NULL; 378165894Ssam 379165894Ssam m_freem(m); 380165894Ssam } 381165894Ssam} 382165894Ssam 383178354Ssamvoid 384178354Ssamieee80211_flush_ifq(struct ifqueue *ifq, struct ieee80211vap *vap) 385178354Ssam{ 386178354Ssam struct ieee80211_node *ni; 387178354Ssam struct mbuf *m, **mprev; 388178354Ssam 389178354Ssam IF_LOCK(ifq); 390178354Ssam mprev = &ifq->ifq_head; 391178354Ssam while ((m = *mprev) != NULL) { 392178354Ssam ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 393178354Ssam if (ni != NULL && ni->ni_vap == vap) { 394178354Ssam *mprev = m->m_nextpkt; /* remove from list */ 395178354Ssam ifq->ifq_len--; 396178354Ssam 397178354Ssam m_freem(m); 398178354Ssam ieee80211_free_node(ni); /* reclaim ref */ 399178354Ssam } else 400178354Ssam mprev = &m->m_nextpkt; 401178354Ssam } 402178354Ssam /* recalculate tail ptr */ 403178354Ssam m = ifq->ifq_head; 404178354Ssam for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt) 405178354Ssam ; 406178354Ssam ifq->ifq_tail = m; 407178354Ssam IF_UNLOCK(ifq); 408178354Ssam} 409178354Ssam 410138568Ssam/* 411170530Ssam * As above, for mbufs allocated with m_gethdr/MGETHDR 412170530Ssam * or initialized by M_COPY_PKTHDR. 413170530Ssam */ 414170530Ssam#define MC_ALIGN(m, len) \ 415170530Ssamdo { \ 416298433Spfg (m)->m_data += rounddown2(MCLBYTES - (len), sizeof(long)); \ 417170530Ssam} while (/* CONSTCOND */ 0) 418170530Ssam 419170530Ssam/* 420138568Ssam * Allocate and setup a management frame of the specified 421138568Ssam * size. We return the mbuf and a pointer to the start 422138568Ssam * of the contiguous data area that's been reserved based 423138568Ssam * on the packet length. The data area is forced to 32-bit 424138568Ssam * alignment and the buffer length to a multiple of 4 bytes. 425138568Ssam * This is done mainly so beacon frames (that require this) 426138568Ssam * can use this interface too. 427138568Ssam */ 428138568Ssamstruct mbuf * 429170530Ssamieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen) 430138568Ssam{ 431138568Ssam struct mbuf *m; 432138568Ssam u_int len; 433138568Ssam 434138568Ssam /* 435138568Ssam * NB: we know the mbuf routines will align the data area 436138568Ssam * so we don't need to do anything special. 437138568Ssam */ 438170530Ssam len = roundup2(headroom + pktlen, 4); 439138568Ssam KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); 440138568Ssam if (len < MINCLSIZE) { 441151967Sandre m = m_gethdr(M_NOWAIT, MT_DATA); 442138568Ssam /* 443138568Ssam * Align the data in case additional headers are added. 444138568Ssam * This should only happen when a WEP header is added 445138568Ssam * which only happens for shared key authentication mgt 446138568Ssam * frames which all fit in MHLEN. 447138568Ssam */ 448138568Ssam if (m != NULL) 449276692Srwatson M_ALIGN(m, len); 450170530Ssam } else { 451151967Sandre m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 452170530Ssam if (m != NULL) 453170530Ssam MC_ALIGN(m, len); 454170530Ssam } 455138568Ssam if (m != NULL) { 456171984Ssephe m->m_data += headroom; 457138568Ssam *frm = m->m_data; 458138568Ssam } 459138568Ssam return m; 460138568Ssam} 461138568Ssam 462246710Sglebius#ifndef __NO_STRICT_ALIGNMENT 463195757Ssam/* 464195757Ssam * Re-align the payload in the mbuf. This is mainly used (right now) 465195757Ssam * to handle IP header alignment requirements on certain architectures. 466195757Ssam */ 467195757Ssamstruct mbuf * 468195757Ssamieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align) 469195757Ssam{ 470195757Ssam int pktlen, space; 471195757Ssam struct mbuf *n; 472195757Ssam 473195757Ssam pktlen = m->m_pkthdr.len; 474195757Ssam space = pktlen + align; 475195757Ssam if (space < MINCLSIZE) 476243882Sglebius n = m_gethdr(M_NOWAIT, MT_DATA); 477195757Ssam else { 478243882Sglebius n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 479195757Ssam space <= MCLBYTES ? MCLBYTES : 480195757Ssam#if MJUMPAGESIZE != MCLBYTES 481195757Ssam space <= MJUMPAGESIZE ? MJUMPAGESIZE : 482195757Ssam#endif 483195757Ssam space <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); 484195757Ssam } 485195757Ssam if (__predict_true(n != NULL)) { 486195757Ssam m_move_pkthdr(n, m); 487195757Ssam n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align); 488195757Ssam m_copydata(m, 0, pktlen, mtod(n, caddr_t)); 489195757Ssam n->m_len = pktlen; 490195757Ssam } else { 491195757Ssam IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, 492195757Ssam mtod(m, const struct ieee80211_frame *), NULL, 493195757Ssam "%s", "no mbuf to realign"); 494195757Ssam vap->iv_stats.is_rx_badalign++; 495195757Ssam } 496195757Ssam m_freem(m); 497195757Ssam return n; 498195757Ssam} 499246710Sglebius#endif /* !__NO_STRICT_ALIGNMENT */ 500195757Ssam 501170530Ssamint 502170530Ssamieee80211_add_callback(struct mbuf *m, 503170530Ssam void (*func)(struct ieee80211_node *, void *, int), void *arg) 504170530Ssam{ 505170530Ssam struct m_tag *mtag; 506170530Ssam struct ieee80211_cb *cb; 507170530Ssam 508170530Ssam mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, 509170530Ssam sizeof(struct ieee80211_cb), M_NOWAIT); 510170530Ssam if (mtag == NULL) 511170530Ssam return 0; 512170530Ssam 513170530Ssam cb = (struct ieee80211_cb *)(mtag+1); 514170530Ssam cb->func = func; 515170530Ssam cb->arg = arg; 516170530Ssam m_tag_prepend(m, mtag); 517170530Ssam m->m_flags |= M_TXCB; 518170530Ssam return 1; 519170530Ssam} 520170530Ssam 521283980Sadrianint 522283980Sadrianieee80211_add_xmit_params(struct mbuf *m, 523283980Sadrian const struct ieee80211_bpf_params *params) 524283980Sadrian{ 525283980Sadrian struct m_tag *mtag; 526283980Sadrian struct ieee80211_tx_params *tx; 527283980Sadrian 528283980Sadrian mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS, 529283980Sadrian sizeof(struct ieee80211_tx_params), M_NOWAIT); 530283980Sadrian if (mtag == NULL) 531283980Sadrian return (0); 532283980Sadrian 533283980Sadrian tx = (struct ieee80211_tx_params *)(mtag+1); 534283980Sadrian memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params)); 535283980Sadrian m_tag_prepend(m, mtag); 536283980Sadrian return (1); 537283980Sadrian} 538283980Sadrian 539283980Sadrianint 540283980Sadrianieee80211_get_xmit_params(struct mbuf *m, 541283980Sadrian struct ieee80211_bpf_params *params) 542283980Sadrian{ 543283980Sadrian struct m_tag *mtag; 544283980Sadrian struct ieee80211_tx_params *tx; 545283980Sadrian 546283980Sadrian mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS, 547283980Sadrian NULL); 548283980Sadrian if (mtag == NULL) 549283980Sadrian return (-1); 550283980Sadrian tx = (struct ieee80211_tx_params *)(mtag + 1); 551283980Sadrian memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params)); 552283980Sadrian return (0); 553283980Sadrian} 554283980Sadrian 555170530Ssamvoid 556170530Ssamieee80211_process_callback(struct ieee80211_node *ni, 557170530Ssam struct mbuf *m, int status) 558170530Ssam{ 559170530Ssam struct m_tag *mtag; 560170530Ssam 561170530Ssam mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL); 562170530Ssam if (mtag != NULL) { 563170530Ssam struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1); 564170530Ssam cb->func(ni, cb->arg, status); 565170530Ssam } 566170530Ssam} 567170530Ssam 568248069Sadrian/* 569288245Sadrian * Add RX parameters to the given mbuf. 570288245Sadrian * 571288245Sadrian * Returns 1 if OK, 0 on error. 572288245Sadrian */ 573288245Sadrianint 574288245Sadrianieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs) 575288245Sadrian{ 576288245Sadrian struct m_tag *mtag; 577288245Sadrian struct ieee80211_rx_params *rx; 578288245Sadrian 579288245Sadrian mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, 580288245Sadrian sizeof(struct ieee80211_rx_stats), M_NOWAIT); 581288245Sadrian if (mtag == NULL) 582288245Sadrian return (0); 583288245Sadrian 584288245Sadrian rx = (struct ieee80211_rx_params *)(mtag + 1); 585288245Sadrian memcpy(&rx->params, rxs, sizeof(*rxs)); 586288245Sadrian m_tag_prepend(m, mtag); 587288245Sadrian return (1); 588288245Sadrian} 589288245Sadrian 590288245Sadrianint 591288245Sadrianieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs) 592288245Sadrian{ 593288245Sadrian struct m_tag *mtag; 594288245Sadrian struct ieee80211_rx_params *rx; 595288245Sadrian 596288245Sadrian mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, 597288245Sadrian NULL); 598288245Sadrian if (mtag == NULL) 599288245Sadrian return (-1); 600288245Sadrian rx = (struct ieee80211_rx_params *)(mtag + 1); 601288245Sadrian memcpy(rxs, &rx->params, sizeof(*rxs)); 602288245Sadrian return (0); 603288245Sadrian} 604288245Sadrian 605288245Sadrian/* 606248069Sadrian * Transmit a frame to the parent interface. 607248069Sadrian */ 608248069Sadrianint 609287197Sglebiusieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m) 610248069Sadrian{ 611287197Sglebius int error; 612287197Sglebius 613248069Sadrian /* 614248069Sadrian * Assert the IC TX lock is held - this enforces the 615248069Sadrian * processing -> queuing order is maintained 616248069Sadrian */ 617248069Sadrian IEEE80211_TX_LOCK_ASSERT(ic); 618287197Sglebius error = ic->ic_transmit(ic, m); 619289164Sadrian if (error) { 620289164Sadrian struct ieee80211_node *ni; 621289164Sadrian 622289164Sadrian ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 623289164Sadrian 624289164Sadrian /* XXX number of fragments */ 625289164Sadrian if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); 626289164Sadrian ieee80211_free_node(ni); 627289162Sadrian ieee80211_free_mbuf(m); 628289164Sadrian } 629287197Sglebius return (error); 630248069Sadrian} 631248069Sadrian 632248069Sadrian/* 633248069Sadrian * Transmit a frame to the VAP interface. 634248069Sadrian */ 635248069Sadrianint 636254082Sadrianieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m) 637248069Sadrian{ 638248069Sadrian struct ifnet *ifp = vap->iv_ifp; 639248069Sadrian 640248069Sadrian /* 641248069Sadrian * When transmitting via the VAP, we shouldn't hold 642248069Sadrian * any IC TX lock as the VAP TX path will acquire it. 643248069Sadrian */ 644248069Sadrian IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic); 645248069Sadrian 646248069Sadrian return (ifp->if_transmit(ifp, m)); 647248069Sadrian 648248069Sadrian} 649248069Sadrian 650138568Ssam#include <sys/libkern.h> 651138568Ssam 652138568Ssamvoid 653138568Ssamget_random_bytes(void *p, size_t n) 654138568Ssam{ 655170530Ssam uint8_t *dp = p; 656138568Ssam 657138568Ssam while (n > 0) { 658170530Ssam uint32_t v = arc4random(); 659170530Ssam size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n; 660170530Ssam bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n); 661170530Ssam dp += sizeof(uint32_t), n -= nb; 662138568Ssam } 663138568Ssam} 664138568Ssam 665178354Ssam/* 666178354Ssam * Helper function for events that pass just a single mac address. 667178354Ssam */ 668178354Ssamstatic void 669178354Ssamnotify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN]) 670138568Ssam{ 671138568Ssam struct ieee80211_join_event iev; 672138568Ssam 673191816Szec CURVNET_SET(ifp->if_vnet); 674144302Ssam memset(&iev, 0, sizeof(iev)); 675178354Ssam IEEE80211_ADDR_COPY(iev.iev_addr, mac); 676178354Ssam rt_ieee80211msg(ifp, op, &iev, sizeof(iev)); 677191816Szec CURVNET_RESTORE(); 678178354Ssam} 679178354Ssam 680178354Ssamvoid 681178354Ssamieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc) 682178354Ssam{ 683178354Ssam struct ieee80211vap *vap = ni->ni_vap; 684178354Ssam struct ifnet *ifp = vap->iv_ifp; 685178354Ssam 686191816Szec CURVNET_SET_QUIET(ifp->if_vnet); 687178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join", 688178354Ssam (ni == vap->iv_bss) ? "bss " : ""); 689178354Ssam 690178354Ssam if (ni == vap->iv_bss) { 691178354Ssam notify_macaddr(ifp, newassoc ? 692178354Ssam RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid); 693138568Ssam if_link_state_change(ifp, LINK_STATE_UP); 694144302Ssam } else { 695178354Ssam notify_macaddr(ifp, newassoc ? 696178354Ssam RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr); 697138568Ssam } 698191816Szec CURVNET_RESTORE(); 699138568Ssam} 700138568Ssam 701138568Ssamvoid 702178354Ssamieee80211_notify_node_leave(struct ieee80211_node *ni) 703138568Ssam{ 704178354Ssam struct ieee80211vap *vap = ni->ni_vap; 705178354Ssam struct ifnet *ifp = vap->iv_ifp; 706138568Ssam 707191816Szec CURVNET_SET_QUIET(ifp->if_vnet); 708178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave", 709178354Ssam (ni == vap->iv_bss) ? "bss " : ""); 710178354Ssam 711178354Ssam if (ni == vap->iv_bss) { 712138568Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); 713138568Ssam if_link_state_change(ifp, LINK_STATE_DOWN); 714138568Ssam } else { 715138568Ssam /* fire off wireless event station leaving */ 716178354Ssam notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr); 717138568Ssam } 718191816Szec CURVNET_RESTORE(); 719138568Ssam} 720138568Ssam 721138568Ssamvoid 722178354Ssamieee80211_notify_scan_done(struct ieee80211vap *vap) 723138568Ssam{ 724178354Ssam struct ifnet *ifp = vap->iv_ifp; 725138568Ssam 726178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done"); 727138568Ssam 728138568Ssam /* dispatch wireless event indicating scan completed */ 729191816Szec CURVNET_SET(ifp->if_vnet); 730138568Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); 731191816Szec CURVNET_RESTORE(); 732138568Ssam} 733138568Ssam 734138568Ssamvoid 735178354Ssamieee80211_notify_replay_failure(struct ieee80211vap *vap, 736138568Ssam const struct ieee80211_frame *wh, const struct ieee80211_key *k, 737193541Ssam u_int64_t rsc, int tid) 738138568Ssam{ 739178354Ssam struct ifnet *ifp = vap->iv_ifp; 740138568Ssam 741178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 742226885Sadrian "%s replay detected tid %d <rsc %ju, csc %ju, keyix %u rxkeyix %u>", 743233531Sadrian k->wk_cipher->ic_name, tid, (intmax_t) rsc, 744193541Ssam (intmax_t) k->wk_keyrsc[tid], 745148863Ssam k->wk_keyix, k->wk_rxkeyix); 746138568Ssam 747138568Ssam if (ifp != NULL) { /* NB: for cipher test modules */ 748138568Ssam struct ieee80211_replay_event iev; 749138568Ssam 750138568Ssam IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 751138568Ssam IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 752138568Ssam iev.iev_cipher = k->wk_cipher->ic_cipher; 753148863Ssam if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE) 754148863Ssam iev.iev_keyix = k->wk_rxkeyix; 755148863Ssam else 756148863Ssam iev.iev_keyix = k->wk_keyix; 757193541Ssam iev.iev_keyrsc = k->wk_keyrsc[tid]; 758138568Ssam iev.iev_rsc = rsc; 759191816Szec CURVNET_SET(ifp->if_vnet); 760138568Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); 761191816Szec CURVNET_RESTORE(); 762138568Ssam } 763138568Ssam} 764138568Ssam 765138568Ssamvoid 766178354Ssamieee80211_notify_michael_failure(struct ieee80211vap *vap, 767138568Ssam const struct ieee80211_frame *wh, u_int keyix) 768138568Ssam{ 769178354Ssam struct ifnet *ifp = vap->iv_ifp; 770138568Ssam 771178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 772178354Ssam "michael MIC verification failed <keyix %u>", keyix); 773178354Ssam vap->iv_stats.is_rx_tkipmic++; 774138568Ssam 775138568Ssam if (ifp != NULL) { /* NB: for cipher test modules */ 776138568Ssam struct ieee80211_michael_event iev; 777138568Ssam 778138568Ssam IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 779138568Ssam IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 780138568Ssam iev.iev_cipher = IEEE80211_CIPHER_TKIP; 781138568Ssam iev.iev_keyix = keyix; 782191816Szec CURVNET_SET(ifp->if_vnet); 783138568Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); 784191816Szec CURVNET_RESTORE(); 785138568Ssam } 786138568Ssam} 787138568Ssam 788138568Ssamvoid 789178354Ssamieee80211_notify_wds_discover(struct ieee80211_node *ni) 790178354Ssam{ 791178354Ssam struct ieee80211vap *vap = ni->ni_vap; 792178354Ssam struct ifnet *ifp = vap->iv_ifp; 793178354Ssam 794178354Ssam notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr); 795178354Ssam} 796178354Ssam 797178354Ssamvoid 798178354Ssamieee80211_notify_csa(struct ieee80211com *ic, 799178354Ssam const struct ieee80211_channel *c, int mode, int count) 800178354Ssam{ 801178354Ssam struct ieee80211_csa_event iev; 802283539Sglebius struct ieee80211vap *vap; 803283539Sglebius struct ifnet *ifp; 804178354Ssam 805178354Ssam memset(&iev, 0, sizeof(iev)); 806178354Ssam iev.iev_flags = c->ic_flags; 807178354Ssam iev.iev_freq = c->ic_freq; 808178354Ssam iev.iev_ieee = c->ic_ieee; 809178354Ssam iev.iev_mode = mode; 810178354Ssam iev.iev_count = count; 811283539Sglebius TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 812283539Sglebius ifp = vap->iv_ifp; 813283539Sglebius CURVNET_SET(ifp->if_vnet); 814283539Sglebius rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev)); 815283539Sglebius CURVNET_RESTORE(); 816283539Sglebius } 817178354Ssam} 818178354Ssam 819178354Ssamvoid 820178354Ssamieee80211_notify_radar(struct ieee80211com *ic, 821178354Ssam const struct ieee80211_channel *c) 822178354Ssam{ 823178354Ssam struct ieee80211_radar_event iev; 824283539Sglebius struct ieee80211vap *vap; 825283539Sglebius struct ifnet *ifp; 826178354Ssam 827178354Ssam memset(&iev, 0, sizeof(iev)); 828178354Ssam iev.iev_flags = c->ic_flags; 829178354Ssam iev.iev_freq = c->ic_freq; 830178354Ssam iev.iev_ieee = c->ic_ieee; 831283539Sglebius TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 832283539Sglebius ifp = vap->iv_ifp; 833283539Sglebius CURVNET_SET(ifp->if_vnet); 834283539Sglebius rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev)); 835283539Sglebius CURVNET_RESTORE(); 836283539Sglebius } 837178354Ssam} 838178354Ssam 839178354Ssamvoid 840178354Ssamieee80211_notify_cac(struct ieee80211com *ic, 841178354Ssam const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type) 842178354Ssam{ 843178354Ssam struct ieee80211_cac_event iev; 844283539Sglebius struct ieee80211vap *vap; 845283539Sglebius struct ifnet *ifp; 846178354Ssam 847178354Ssam memset(&iev, 0, sizeof(iev)); 848178354Ssam iev.iev_flags = c->ic_flags; 849178354Ssam iev.iev_freq = c->ic_freq; 850178354Ssam iev.iev_ieee = c->ic_ieee; 851178354Ssam iev.iev_type = type; 852283539Sglebius TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 853283539Sglebius ifp = vap->iv_ifp; 854283539Sglebius CURVNET_SET(ifp->if_vnet); 855283539Sglebius rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev)); 856283539Sglebius CURVNET_RESTORE(); 857283539Sglebius } 858178354Ssam} 859178354Ssam 860178354Ssamvoid 861178354Ssamieee80211_notify_node_deauth(struct ieee80211_node *ni) 862178354Ssam{ 863178354Ssam struct ieee80211vap *vap = ni->ni_vap; 864178354Ssam struct ifnet *ifp = vap->iv_ifp; 865178354Ssam 866178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth"); 867178354Ssam 868178354Ssam notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr); 869178354Ssam} 870178354Ssam 871178354Ssamvoid 872178354Ssamieee80211_notify_node_auth(struct ieee80211_node *ni) 873178354Ssam{ 874178354Ssam struct ieee80211vap *vap = ni->ni_vap; 875178354Ssam struct ifnet *ifp = vap->iv_ifp; 876178354Ssam 877178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth"); 878178354Ssam 879178354Ssam notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr); 880178354Ssam} 881178354Ssam 882178354Ssamvoid 883178354Ssamieee80211_notify_country(struct ieee80211vap *vap, 884178354Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2]) 885178354Ssam{ 886178354Ssam struct ifnet *ifp = vap->iv_ifp; 887178354Ssam struct ieee80211_country_event iev; 888178354Ssam 889178354Ssam memset(&iev, 0, sizeof(iev)); 890178354Ssam IEEE80211_ADDR_COPY(iev.iev_addr, bssid); 891178354Ssam iev.iev_cc[0] = cc[0]; 892178354Ssam iev.iev_cc[1] = cc[1]; 893248539Sadrian CURVNET_SET(ifp->if_vnet); 894178354Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev)); 895248539Sadrian CURVNET_RESTORE(); 896178354Ssam} 897178354Ssam 898178354Ssamvoid 899178354Ssamieee80211_notify_radio(struct ieee80211com *ic, int state) 900178354Ssam{ 901178354Ssam struct ieee80211_radio_event iev; 902283539Sglebius struct ieee80211vap *vap; 903283539Sglebius struct ifnet *ifp; 904178354Ssam 905178354Ssam memset(&iev, 0, sizeof(iev)); 906178354Ssam iev.iev_state = state; 907283539Sglebius TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 908283539Sglebius ifp = vap->iv_ifp; 909283539Sglebius CURVNET_SET(ifp->if_vnet); 910283539Sglebius rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev)); 911283539Sglebius CURVNET_RESTORE(); 912283539Sglebius } 913178354Ssam} 914178354Ssam 915178354Ssamvoid 916138568Ssamieee80211_load_module(const char *modname) 917138568Ssam{ 918159590Sjhb 919138777Ssam#ifdef notyet 920159590Sjhb (void)kern_kldload(curthread, modname, NULL); 921138777Ssam#else 922138777Ssam printf("%s: load the %s module by hand for now.\n", __func__, modname); 923138777Ssam#endif 924138568Ssam} 925138568Ssam 926192468Ssamstatic eventhandler_tag wlan_bpfevent; 927299171Savosstatic eventhandler_tag wlan_ifllevent; 928192468Ssam 929192468Ssamstatic void 930192764Ssambpf_track(void *arg, struct ifnet *ifp, int dlt, int attach) 931192468Ssam{ 932256294Sadrian /* NB: identify vap's by if_init */ 933254082Sadrian if (dlt == DLT_IEEE802_11_RADIO && 934256294Sadrian ifp->if_init == ieee80211_init) { 935192468Ssam struct ieee80211vap *vap = ifp->if_softc; 936192468Ssam /* 937192468Ssam * Track bpf radiotap listener state. We mark the vap 938192468Ssam * to indicate if any listener is present and the com 939192468Ssam * to indicate if any listener exists on any associated 940192468Ssam * vap. This flag is used by drivers to prepare radiotap 941192468Ssam * state only when needed. 942192468Ssam */ 943193292Ssam if (attach) { 944192468Ssam ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF); 945193292Ssam if (vap->iv_opmode == IEEE80211_M_MONITOR) 946193292Ssam atomic_add_int(&vap->iv_ic->ic_montaps, 1); 947193312Ssam } else if (!bpf_peers_present(vap->iv_rawbpf)) { 948192468Ssam ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF); 949193292Ssam if (vap->iv_opmode == IEEE80211_M_MONITOR) 950193292Ssam atomic_subtract_int(&vap->iv_ic->ic_montaps, 1); 951193292Ssam } 952192468Ssam } 953192468Ssam} 954192468Ssam 955138568Ssam/* 956299171Savos * Change MAC address on the vap (if was not started). 957299171Savos */ 958299171Savosstatic void 959299171Savoswlan_iflladdr(void *arg __unused, struct ifnet *ifp) 960299171Savos{ 961299171Savos /* NB: identify vap's by if_init */ 962299171Savos if (ifp->if_init == ieee80211_init && 963299171Savos (ifp->if_flags & IFF_UP) == 0) { 964299171Savos struct ieee80211vap *vap = ifp->if_softc; 965299171Savos 966299171Savos IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp)); 967299171Savos } 968299171Savos} 969299171Savos 970299171Savos/* 971138568Ssam * Module glue. 972138568Ssam * 973138568Ssam * NB: the module name is "wlan" for compatibility with NetBSD. 974138568Ssam */ 975138568Ssamstatic int 976138568Ssamwlan_modevent(module_t mod, int type, void *unused) 977138568Ssam{ 978138568Ssam switch (type) { 979138568Ssam case MOD_LOAD: 980138568Ssam if (bootverbose) 981138568Ssam printf("wlan: <802.11 Link Layer>\n"); 982192468Ssam wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track, 983192468Ssam bpf_track, 0, EVENTHANDLER_PRI_ANY); 984299171Savos wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event, 985299171Savos wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY); 986241610Sglebius wlan_cloner = if_clone_simple(wlanname, wlan_clone_create, 987241610Sglebius wlan_clone_destroy, 0); 988138568Ssam return 0; 989138568Ssam case MOD_UNLOAD: 990241610Sglebius if_clone_detach(wlan_cloner); 991192468Ssam EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent); 992299171Savos EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent); 993138568Ssam return 0; 994138568Ssam } 995138568Ssam return EINVAL; 996138568Ssam} 997138568Ssam 998138568Ssamstatic moduledata_t wlan_mod = { 999241610Sglebius wlanname, 1000138568Ssam wlan_modevent, 1001241394Skevlo 0 1002138568Ssam}; 1003138568SsamDECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 1004138568SsamMODULE_VERSION(wlan, 1); 1005138568SsamMODULE_DEPEND(wlan, ether, 1, 1, 1); 1006233050Sadrian#ifdef IEEE80211_ALQ 1007233050SadrianMODULE_DEPEND(wlan, alq, 1, 1, 1); 1008233050Sadrian#endif /* IEEE80211_ALQ */ 1009233050Sadrian 1010