ieee80211_freebsd.c revision 330466
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 330466 2018-03-05 08:30:47Z eadler $"); 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 69227293Sedstatic MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state"); 70178354Ssam 71241610Sglebiusstatic const char wlanname[] = "wlan"; 72241610Sglebiusstatic struct if_clone *wlan_cloner; 73241610Sglebius 74138568Ssamstatic int 75178354Ssamwlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) 76173273Ssam{ 77178354Ssam struct ieee80211_clone_params cp; 78178354Ssam struct ieee80211vap *vap; 79178354Ssam struct ieee80211com *ic; 80173273Ssam int error; 81173273Ssam 82178354Ssam error = copyin(params, &cp, sizeof(cp)); 83178354Ssam if (error) 84178354Ssam return error; 85287197Sglebius ic = ieee80211_find_com(cp.icp_parent); 86287197Sglebius if (ic == NULL) 87178354Ssam return ENXIO; 88178957Ssam if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) { 89287197Sglebius ic_printf(ic, "%s: invalid opmode %d\n", __func__, 90287197Sglebius cp.icp_opmode); 91178354Ssam return EINVAL; 92178354Ssam } 93178957Ssam if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) { 94287197Sglebius ic_printf(ic, "%s mode not supported\n", 95178957Ssam ieee80211_opmode_name[cp.icp_opmode]); 96178957Ssam return EOPNOTSUPP; 97178957Ssam } 98186904Ssam if ((cp.icp_flags & IEEE80211_CLONE_TDMA) && 99186904Ssam#ifdef IEEE80211_SUPPORT_TDMA 100186904Ssam (ic->ic_caps & IEEE80211_C_TDMA) == 0 101186904Ssam#else 102186904Ssam (1) 103186904Ssam#endif 104186904Ssam ) { 105287197Sglebius ic_printf(ic, "TDMA not supported\n"); 106186904Ssam return EOPNOTSUPP; 107186904Ssam } 108241610Sglebius vap = ic->ic_vap_create(ic, wlanname, unit, 109178354Ssam cp.icp_opmode, cp.icp_flags, cp.icp_bssid, 110178354Ssam cp.icp_flags & IEEE80211_CLONE_MACADDR ? 111287197Sglebius cp.icp_macaddr : ic->ic_macaddr); 112242154Sadrian 113178354Ssam return (vap == NULL ? EIO : 0); 114178354Ssam} 115178354Ssam 116178354Ssamstatic void 117178354Ssamwlan_clone_destroy(struct ifnet *ifp) 118178354Ssam{ 119178354Ssam struct ieee80211vap *vap = ifp->if_softc; 120178354Ssam struct ieee80211com *ic = vap->iv_ic; 121178354Ssam 122178354Ssam ic->ic_vap_delete(vap); 123178354Ssam} 124178354Ssam 125178354Ssamvoid 126178354Ssamieee80211_vap_destroy(struct ieee80211vap *vap) 127178354Ssam{ 128242149Sadrian CURVNET_SET(vap->iv_ifp->if_vnet); 129241610Sglebius if_clone_destroyif(wlan_cloner, vap->iv_ifp); 130242149Sadrian CURVNET_RESTORE(); 131178354Ssam} 132178354Ssam 133192473Ssamint 134178354Ssamieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS) 135178354Ssam{ 136178354Ssam int msecs = ticks_to_msecs(*(int *)arg1); 137178354Ssam int error, t; 138178354Ssam 139178354Ssam error = sysctl_handle_int(oidp, &msecs, 0, req); 140173273Ssam if (error || !req->newptr) 141173273Ssam return error; 142178354Ssam t = msecs_to_ticks(msecs); 143178354Ssam *(int *)arg1 = (t < 1) ? 1 : t; 144173273Ssam return 0; 145173273Ssam} 146178354Ssam 147173273Ssamstatic int 148138568Ssamieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS) 149138568Ssam{ 150138568Ssam int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT; 151138568Ssam int error; 152138568Ssam 153138568Ssam error = sysctl_handle_int(oidp, &inact, 0, req); 154138568Ssam if (error || !req->newptr) 155138568Ssam return error; 156138568Ssam *(int *)arg1 = inact / IEEE80211_INACT_WAIT; 157138568Ssam return 0; 158138568Ssam} 159138568Ssam 160138568Ssamstatic int 161138568Ssamieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS) 162138568Ssam{ 163138568Ssam struct ieee80211com *ic = arg1; 164138568Ssam 165283529Sglebius return SYSCTL_OUT_STR(req, ic->ic_name); 166138568Ssam} 167138568Ssam 168181194Ssamstatic int 169181194Ssamieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS) 170181194Ssam{ 171181194Ssam struct ieee80211com *ic = arg1; 172181194Ssam int t = 0, error; 173181194Ssam 174181194Ssam error = sysctl_handle_int(oidp, &t, 0, req); 175181194Ssam if (error || !req->newptr) 176181194Ssam return error; 177181194Ssam IEEE80211_LOCK(ic); 178181194Ssam ieee80211_dfs_notify_radar(ic, ic->ic_curchan); 179181194Ssam IEEE80211_UNLOCK(ic); 180181194Ssam return 0; 181181194Ssam} 182181194Ssam 183330466Seadler/* 184330466Seadler * For now, just restart everything. 185330466Seadler * 186330466Seadler * Later on, it'd be nice to have a separate VAP restart to 187330466Seadler * full-device restart. 188330466Seadler */ 189330466Seadlerstatic int 190330466Seadlerieee80211_sysctl_vap_restart(SYSCTL_HANDLER_ARGS) 191330466Seadler{ 192330466Seadler struct ieee80211vap *vap = arg1; 193330466Seadler int t = 0, error; 194330466Seadler 195330466Seadler error = sysctl_handle_int(oidp, &t, 0, req); 196330466Seadler if (error || !req->newptr) 197330466Seadler return error; 198330466Seadler 199330466Seadler ieee80211_restart_all(vap->iv_ic); 200330466Seadler return 0; 201330466Seadler} 202330466Seadler 203138568Ssamvoid 204138568Ssamieee80211_sysctl_attach(struct ieee80211com *ic) 205138568Ssam{ 206178354Ssam} 207178354Ssam 208178354Ssamvoid 209178354Ssamieee80211_sysctl_detach(struct ieee80211com *ic) 210178354Ssam{ 211178354Ssam} 212178354Ssam 213178354Ssamvoid 214178354Ssamieee80211_sysctl_vattach(struct ieee80211vap *vap) 215178354Ssam{ 216178354Ssam struct ifnet *ifp = vap->iv_ifp; 217138568Ssam struct sysctl_ctx_list *ctx; 218138568Ssam struct sysctl_oid *oid; 219138568Ssam char num[14]; /* sufficient for 32 bits */ 220138568Ssam 221283538Sadrian ctx = (struct sysctl_ctx_list *) IEEE80211_MALLOC(sizeof(struct sysctl_ctx_list), 222283538Sadrian M_DEVBUF, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO); 223138568Ssam if (ctx == NULL) { 224178354Ssam if_printf(ifp, "%s: cannot allocate sysctl context!\n", 225138568Ssam __func__); 226138568Ssam return; 227138568Ssam } 228138568Ssam sysctl_ctx_init(ctx); 229178354Ssam snprintf(num, sizeof(num), "%u", ifp->if_dunit); 230138568Ssam oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan), 231138568Ssam OID_AUTO, num, CTLFLAG_RD, NULL, ""); 232138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 233217554Smdf "%parent", CTLTYPE_STRING | CTLFLAG_RD, vap->iv_ic, 0, 234178354Ssam ieee80211_sysctl_parent, "A", "parent device"); 235217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 236178354Ssam "driver_caps", CTLFLAG_RW, &vap->iv_caps, 0, 237178354Ssam "driver capabilities"); 238138568Ssam#ifdef IEEE80211_DEBUG 239178354Ssam vap->iv_debug = ieee80211_debug; 240217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 241178354Ssam "debug", CTLFLAG_RW, &vap->iv_debug, 0, 242138568Ssam "control debugging printfs"); 243138568Ssam#endif 244178354Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 245178354Ssam "bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0, 246178354Ssam "consecutive beacon misses before scanning"); 247138568Ssam /* XXX inherit from tunables */ 248138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 249178354Ssam "inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0, 250138568Ssam ieee80211_sysctl_inact, "I", 251138568Ssam "station inactivity timeout (sec)"); 252138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 253178354Ssam "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0, 254138568Ssam ieee80211_sysctl_inact, "I", 255138568Ssam "station inactivity probe timeout (sec)"); 256138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 257178354Ssam "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0, 258138568Ssam ieee80211_sysctl_inact, "I", 259138568Ssam "station authentication timeout (sec)"); 260138568Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 261178354Ssam "inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0, 262138568Ssam ieee80211_sysctl_inact, "I", 263138568Ssam "station initial state timeout (sec)"); 264178354Ssam if (vap->iv_htcaps & IEEE80211_HTC_HT) { 265217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 266178354Ssam "ampdu_mintraffic_bk", CTLFLAG_RW, 267178354Ssam &vap->iv_ampdu_mintraffic[WME_AC_BK], 0, 268178354Ssam "BK traffic tx aggr threshold (pps)"); 269217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 270178354Ssam "ampdu_mintraffic_be", CTLFLAG_RW, 271178354Ssam &vap->iv_ampdu_mintraffic[WME_AC_BE], 0, 272178354Ssam "BE traffic tx aggr threshold (pps)"); 273217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 274178354Ssam "ampdu_mintraffic_vo", CTLFLAG_RW, 275178354Ssam &vap->iv_ampdu_mintraffic[WME_AC_VO], 0, 276178354Ssam "VO traffic tx aggr threshold (pps)"); 277217322Smdf SYSCTL_ADD_UINT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 278178354Ssam "ampdu_mintraffic_vi", CTLFLAG_RW, 279178354Ssam &vap->iv_ampdu_mintraffic[WME_AC_VI], 0, 280178354Ssam "VI traffic tx aggr threshold (pps)"); 281178354Ssam } 282330466Seadler 283330466Seadler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 284330466Seadler "force_restart", CTLTYPE_INT | CTLFLAG_RW, vap, 0, 285330466Seadler ieee80211_sysctl_vap_restart, "I", 286330466Seadler "force a VAP restart"); 287330466Seadler 288181194Ssam if (vap->iv_caps & IEEE80211_C_DFS) { 289181194Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 290181194Ssam "radar", CTLTYPE_INT | CTLFLAG_RW, vap->iv_ic, 0, 291193115Ssam ieee80211_sysctl_radar, "I", "simulate radar event"); 292181194Ssam } 293178354Ssam vap->iv_sysctl = ctx; 294178354Ssam vap->iv_oid = oid; 295138568Ssam} 296138568Ssam 297138568Ssamvoid 298178354Ssamieee80211_sysctl_vdetach(struct ieee80211vap *vap) 299138568Ssam{ 300138568Ssam 301178354Ssam if (vap->iv_sysctl != NULL) { 302178354Ssam sysctl_ctx_free(vap->iv_sysctl); 303283538Sadrian IEEE80211_FREE(vap->iv_sysctl, M_DEVBUF); 304178354Ssam vap->iv_sysctl = NULL; 305138568Ssam } 306138568Ssam} 307138568Ssam 308138568Ssamint 309138568Ssamieee80211_node_dectestref(struct ieee80211_node *ni) 310138568Ssam{ 311138568Ssam /* XXX need equivalent of atomic_dec_and_test */ 312138568Ssam atomic_subtract_int(&ni->ni_refcnt, 1); 313138568Ssam return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); 314138568Ssam} 315138568Ssam 316165894Ssamvoid 317165894Ssamieee80211_drain_ifq(struct ifqueue *ifq) 318165894Ssam{ 319165894Ssam struct ieee80211_node *ni; 320165894Ssam struct mbuf *m; 321165894Ssam 322165894Ssam for (;;) { 323165894Ssam IF_DEQUEUE(ifq, m); 324165894Ssam if (m == NULL) 325165894Ssam break; 326165894Ssam 327165894Ssam ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 328165894Ssam KASSERT(ni != NULL, ("frame w/o node")); 329165894Ssam ieee80211_free_node(ni); 330165894Ssam m->m_pkthdr.rcvif = NULL; 331165894Ssam 332165894Ssam m_freem(m); 333165894Ssam } 334165894Ssam} 335165894Ssam 336178354Ssamvoid 337178354Ssamieee80211_flush_ifq(struct ifqueue *ifq, struct ieee80211vap *vap) 338178354Ssam{ 339178354Ssam struct ieee80211_node *ni; 340178354Ssam struct mbuf *m, **mprev; 341178354Ssam 342178354Ssam IF_LOCK(ifq); 343178354Ssam mprev = &ifq->ifq_head; 344178354Ssam while ((m = *mprev) != NULL) { 345178354Ssam ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 346178354Ssam if (ni != NULL && ni->ni_vap == vap) { 347178354Ssam *mprev = m->m_nextpkt; /* remove from list */ 348178354Ssam ifq->ifq_len--; 349178354Ssam 350178354Ssam m_freem(m); 351178354Ssam ieee80211_free_node(ni); /* reclaim ref */ 352178354Ssam } else 353178354Ssam mprev = &m->m_nextpkt; 354178354Ssam } 355178354Ssam /* recalculate tail ptr */ 356178354Ssam m = ifq->ifq_head; 357178354Ssam for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt) 358178354Ssam ; 359178354Ssam ifq->ifq_tail = m; 360178354Ssam IF_UNLOCK(ifq); 361178354Ssam} 362178354Ssam 363138568Ssam/* 364170530Ssam * As above, for mbufs allocated with m_gethdr/MGETHDR 365170530Ssam * or initialized by M_COPY_PKTHDR. 366170530Ssam */ 367170530Ssam#define MC_ALIGN(m, len) \ 368170530Ssamdo { \ 369298433Spfg (m)->m_data += rounddown2(MCLBYTES - (len), sizeof(long)); \ 370170530Ssam} while (/* CONSTCOND */ 0) 371170530Ssam 372170530Ssam/* 373138568Ssam * Allocate and setup a management frame of the specified 374138568Ssam * size. We return the mbuf and a pointer to the start 375138568Ssam * of the contiguous data area that's been reserved based 376138568Ssam * on the packet length. The data area is forced to 32-bit 377138568Ssam * alignment and the buffer length to a multiple of 4 bytes. 378138568Ssam * This is done mainly so beacon frames (that require this) 379138568Ssam * can use this interface too. 380138568Ssam */ 381138568Ssamstruct mbuf * 382170530Ssamieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen) 383138568Ssam{ 384138568Ssam struct mbuf *m; 385138568Ssam u_int len; 386138568Ssam 387138568Ssam /* 388138568Ssam * NB: we know the mbuf routines will align the data area 389138568Ssam * so we don't need to do anything special. 390138568Ssam */ 391170530Ssam len = roundup2(headroom + pktlen, 4); 392138568Ssam KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); 393138568Ssam if (len < MINCLSIZE) { 394151967Sandre m = m_gethdr(M_NOWAIT, MT_DATA); 395138568Ssam /* 396138568Ssam * Align the data in case additional headers are added. 397138568Ssam * This should only happen when a WEP header is added 398138568Ssam * which only happens for shared key authentication mgt 399138568Ssam * frames which all fit in MHLEN. 400138568Ssam */ 401138568Ssam if (m != NULL) 402276692Srwatson M_ALIGN(m, len); 403170530Ssam } else { 404151967Sandre m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 405170530Ssam if (m != NULL) 406170530Ssam MC_ALIGN(m, len); 407170530Ssam } 408138568Ssam if (m != NULL) { 409171984Ssephe m->m_data += headroom; 410138568Ssam *frm = m->m_data; 411138568Ssam } 412138568Ssam return m; 413138568Ssam} 414138568Ssam 415246710Sglebius#ifndef __NO_STRICT_ALIGNMENT 416195757Ssam/* 417195757Ssam * Re-align the payload in the mbuf. This is mainly used (right now) 418195757Ssam * to handle IP header alignment requirements on certain architectures. 419195757Ssam */ 420195757Ssamstruct mbuf * 421195757Ssamieee80211_realign(struct ieee80211vap *vap, struct mbuf *m, size_t align) 422195757Ssam{ 423195757Ssam int pktlen, space; 424195757Ssam struct mbuf *n; 425195757Ssam 426195757Ssam pktlen = m->m_pkthdr.len; 427195757Ssam space = pktlen + align; 428195757Ssam if (space < MINCLSIZE) 429243882Sglebius n = m_gethdr(M_NOWAIT, MT_DATA); 430195757Ssam else { 431243882Sglebius n = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 432195757Ssam space <= MCLBYTES ? MCLBYTES : 433195757Ssam#if MJUMPAGESIZE != MCLBYTES 434195757Ssam space <= MJUMPAGESIZE ? MJUMPAGESIZE : 435195757Ssam#endif 436195757Ssam space <= MJUM9BYTES ? MJUM9BYTES : MJUM16BYTES); 437195757Ssam } 438195757Ssam if (__predict_true(n != NULL)) { 439195757Ssam m_move_pkthdr(n, m); 440195757Ssam n->m_data = (caddr_t)(ALIGN(n->m_data + align) - align); 441195757Ssam m_copydata(m, 0, pktlen, mtod(n, caddr_t)); 442195757Ssam n->m_len = pktlen; 443195757Ssam } else { 444195757Ssam IEEE80211_DISCARD(vap, IEEE80211_MSG_ANY, 445195757Ssam mtod(m, const struct ieee80211_frame *), NULL, 446195757Ssam "%s", "no mbuf to realign"); 447195757Ssam vap->iv_stats.is_rx_badalign++; 448195757Ssam } 449195757Ssam m_freem(m); 450195757Ssam return n; 451195757Ssam} 452246710Sglebius#endif /* !__NO_STRICT_ALIGNMENT */ 453195757Ssam 454170530Ssamint 455170530Ssamieee80211_add_callback(struct mbuf *m, 456170530Ssam void (*func)(struct ieee80211_node *, void *, int), void *arg) 457170530Ssam{ 458170530Ssam struct m_tag *mtag; 459170530Ssam struct ieee80211_cb *cb; 460170530Ssam 461170530Ssam mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, 462170530Ssam sizeof(struct ieee80211_cb), M_NOWAIT); 463170530Ssam if (mtag == NULL) 464170530Ssam return 0; 465170530Ssam 466170530Ssam cb = (struct ieee80211_cb *)(mtag+1); 467170530Ssam cb->func = func; 468170530Ssam cb->arg = arg; 469170530Ssam m_tag_prepend(m, mtag); 470170530Ssam m->m_flags |= M_TXCB; 471170530Ssam return 1; 472170530Ssam} 473170530Ssam 474283980Sadrianint 475283980Sadrianieee80211_add_xmit_params(struct mbuf *m, 476283980Sadrian const struct ieee80211_bpf_params *params) 477283980Sadrian{ 478283980Sadrian struct m_tag *mtag; 479283980Sadrian struct ieee80211_tx_params *tx; 480283980Sadrian 481283980Sadrian mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS, 482283980Sadrian sizeof(struct ieee80211_tx_params), M_NOWAIT); 483283980Sadrian if (mtag == NULL) 484283980Sadrian return (0); 485283980Sadrian 486283980Sadrian tx = (struct ieee80211_tx_params *)(mtag+1); 487283980Sadrian memcpy(&tx->params, params, sizeof(struct ieee80211_bpf_params)); 488283980Sadrian m_tag_prepend(m, mtag); 489283980Sadrian return (1); 490283980Sadrian} 491283980Sadrian 492283980Sadrianint 493283980Sadrianieee80211_get_xmit_params(struct mbuf *m, 494283980Sadrian struct ieee80211_bpf_params *params) 495283980Sadrian{ 496283980Sadrian struct m_tag *mtag; 497283980Sadrian struct ieee80211_tx_params *tx; 498283980Sadrian 499283980Sadrian mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_XMIT_PARAMS, 500283980Sadrian NULL); 501283980Sadrian if (mtag == NULL) 502283980Sadrian return (-1); 503283980Sadrian tx = (struct ieee80211_tx_params *)(mtag + 1); 504283980Sadrian memcpy(params, &tx->params, sizeof(struct ieee80211_bpf_params)); 505283980Sadrian return (0); 506283980Sadrian} 507283980Sadrian 508170530Ssamvoid 509170530Ssamieee80211_process_callback(struct ieee80211_node *ni, 510170530Ssam struct mbuf *m, int status) 511170530Ssam{ 512170530Ssam struct m_tag *mtag; 513170530Ssam 514170530Ssam mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL); 515170530Ssam if (mtag != NULL) { 516170530Ssam struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1); 517170530Ssam cb->func(ni, cb->arg, status); 518170530Ssam } 519170530Ssam} 520170530Ssam 521248069Sadrian/* 522288245Sadrian * Add RX parameters to the given mbuf. 523288245Sadrian * 524288245Sadrian * Returns 1 if OK, 0 on error. 525288245Sadrian */ 526288245Sadrianint 527288245Sadrianieee80211_add_rx_params(struct mbuf *m, const struct ieee80211_rx_stats *rxs) 528288245Sadrian{ 529288245Sadrian struct m_tag *mtag; 530288245Sadrian struct ieee80211_rx_params *rx; 531288245Sadrian 532288245Sadrian mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, 533288245Sadrian sizeof(struct ieee80211_rx_stats), M_NOWAIT); 534288245Sadrian if (mtag == NULL) 535288245Sadrian return (0); 536288245Sadrian 537288245Sadrian rx = (struct ieee80211_rx_params *)(mtag + 1); 538288245Sadrian memcpy(&rx->params, rxs, sizeof(*rxs)); 539288245Sadrian m_tag_prepend(m, mtag); 540288245Sadrian return (1); 541288245Sadrian} 542288245Sadrian 543288245Sadrianint 544288245Sadrianieee80211_get_rx_params(struct mbuf *m, struct ieee80211_rx_stats *rxs) 545288245Sadrian{ 546288245Sadrian struct m_tag *mtag; 547288245Sadrian struct ieee80211_rx_params *rx; 548288245Sadrian 549288245Sadrian mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_RECV_PARAMS, 550288245Sadrian NULL); 551288245Sadrian if (mtag == NULL) 552288245Sadrian return (-1); 553288245Sadrian rx = (struct ieee80211_rx_params *)(mtag + 1); 554288245Sadrian memcpy(rxs, &rx->params, sizeof(*rxs)); 555288245Sadrian return (0); 556288245Sadrian} 557288245Sadrian 558288245Sadrian/* 559248069Sadrian * Transmit a frame to the parent interface. 560248069Sadrian */ 561248069Sadrianint 562287197Sglebiusieee80211_parent_xmitpkt(struct ieee80211com *ic, struct mbuf *m) 563248069Sadrian{ 564287197Sglebius int error; 565287197Sglebius 566248069Sadrian /* 567248069Sadrian * Assert the IC TX lock is held - this enforces the 568248069Sadrian * processing -> queuing order is maintained 569248069Sadrian */ 570248069Sadrian IEEE80211_TX_LOCK_ASSERT(ic); 571287197Sglebius error = ic->ic_transmit(ic, m); 572289164Sadrian if (error) { 573289164Sadrian struct ieee80211_node *ni; 574289164Sadrian 575289164Sadrian ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 576289164Sadrian 577289164Sadrian /* XXX number of fragments */ 578289164Sadrian if_inc_counter(ni->ni_vap->iv_ifp, IFCOUNTER_OERRORS, 1); 579289164Sadrian ieee80211_free_node(ni); 580289162Sadrian ieee80211_free_mbuf(m); 581289164Sadrian } 582287197Sglebius return (error); 583248069Sadrian} 584248069Sadrian 585248069Sadrian/* 586248069Sadrian * Transmit a frame to the VAP interface. 587248069Sadrian */ 588248069Sadrianint 589254082Sadrianieee80211_vap_xmitpkt(struct ieee80211vap *vap, struct mbuf *m) 590248069Sadrian{ 591248069Sadrian struct ifnet *ifp = vap->iv_ifp; 592248069Sadrian 593248069Sadrian /* 594248069Sadrian * When transmitting via the VAP, we shouldn't hold 595248069Sadrian * any IC TX lock as the VAP TX path will acquire it. 596248069Sadrian */ 597248069Sadrian IEEE80211_TX_UNLOCK_ASSERT(vap->iv_ic); 598248069Sadrian 599248069Sadrian return (ifp->if_transmit(ifp, m)); 600248069Sadrian 601248069Sadrian} 602248069Sadrian 603138568Ssam#include <sys/libkern.h> 604138568Ssam 605138568Ssamvoid 606138568Ssamget_random_bytes(void *p, size_t n) 607138568Ssam{ 608170530Ssam uint8_t *dp = p; 609138568Ssam 610138568Ssam while (n > 0) { 611170530Ssam uint32_t v = arc4random(); 612170530Ssam size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n; 613170530Ssam bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n); 614170530Ssam dp += sizeof(uint32_t), n -= nb; 615138568Ssam } 616138568Ssam} 617138568Ssam 618178354Ssam/* 619178354Ssam * Helper function for events that pass just a single mac address. 620178354Ssam */ 621178354Ssamstatic void 622178354Ssamnotify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN]) 623138568Ssam{ 624138568Ssam struct ieee80211_join_event iev; 625138568Ssam 626191816Szec CURVNET_SET(ifp->if_vnet); 627144302Ssam memset(&iev, 0, sizeof(iev)); 628178354Ssam IEEE80211_ADDR_COPY(iev.iev_addr, mac); 629178354Ssam rt_ieee80211msg(ifp, op, &iev, sizeof(iev)); 630191816Szec CURVNET_RESTORE(); 631178354Ssam} 632178354Ssam 633178354Ssamvoid 634178354Ssamieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc) 635178354Ssam{ 636178354Ssam struct ieee80211vap *vap = ni->ni_vap; 637178354Ssam struct ifnet *ifp = vap->iv_ifp; 638178354Ssam 639191816Szec CURVNET_SET_QUIET(ifp->if_vnet); 640178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join", 641178354Ssam (ni == vap->iv_bss) ? "bss " : ""); 642178354Ssam 643178354Ssam if (ni == vap->iv_bss) { 644178354Ssam notify_macaddr(ifp, newassoc ? 645178354Ssam RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid); 646138568Ssam if_link_state_change(ifp, LINK_STATE_UP); 647144302Ssam } else { 648178354Ssam notify_macaddr(ifp, newassoc ? 649178354Ssam RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr); 650138568Ssam } 651191816Szec CURVNET_RESTORE(); 652138568Ssam} 653138568Ssam 654138568Ssamvoid 655178354Ssamieee80211_notify_node_leave(struct ieee80211_node *ni) 656138568Ssam{ 657178354Ssam struct ieee80211vap *vap = ni->ni_vap; 658178354Ssam struct ifnet *ifp = vap->iv_ifp; 659138568Ssam 660191816Szec CURVNET_SET_QUIET(ifp->if_vnet); 661178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave", 662178354Ssam (ni == vap->iv_bss) ? "bss " : ""); 663178354Ssam 664178354Ssam if (ni == vap->iv_bss) { 665138568Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); 666138568Ssam if_link_state_change(ifp, LINK_STATE_DOWN); 667138568Ssam } else { 668138568Ssam /* fire off wireless event station leaving */ 669178354Ssam notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr); 670138568Ssam } 671191816Szec CURVNET_RESTORE(); 672138568Ssam} 673138568Ssam 674138568Ssamvoid 675178354Ssamieee80211_notify_scan_done(struct ieee80211vap *vap) 676138568Ssam{ 677178354Ssam struct ifnet *ifp = vap->iv_ifp; 678138568Ssam 679178354Ssam IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done"); 680138568Ssam 681138568Ssam /* dispatch wireless event indicating scan completed */ 682191816Szec CURVNET_SET(ifp->if_vnet); 683138568Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); 684191816Szec CURVNET_RESTORE(); 685138568Ssam} 686138568Ssam 687138568Ssamvoid 688178354Ssamieee80211_notify_replay_failure(struct ieee80211vap *vap, 689138568Ssam const struct ieee80211_frame *wh, const struct ieee80211_key *k, 690193541Ssam u_int64_t rsc, int tid) 691138568Ssam{ 692178354Ssam struct ifnet *ifp = vap->iv_ifp; 693138568Ssam 694178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 695226885Sadrian "%s replay detected tid %d <rsc %ju, csc %ju, keyix %u rxkeyix %u>", 696233531Sadrian k->wk_cipher->ic_name, tid, (intmax_t) rsc, 697193541Ssam (intmax_t) k->wk_keyrsc[tid], 698148863Ssam k->wk_keyix, k->wk_rxkeyix); 699138568Ssam 700138568Ssam if (ifp != NULL) { /* NB: for cipher test modules */ 701138568Ssam struct ieee80211_replay_event iev; 702138568Ssam 703138568Ssam IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 704138568Ssam IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 705138568Ssam iev.iev_cipher = k->wk_cipher->ic_cipher; 706148863Ssam if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE) 707148863Ssam iev.iev_keyix = k->wk_rxkeyix; 708148863Ssam else 709148863Ssam iev.iev_keyix = k->wk_keyix; 710193541Ssam iev.iev_keyrsc = k->wk_keyrsc[tid]; 711138568Ssam iev.iev_rsc = rsc; 712191816Szec CURVNET_SET(ifp->if_vnet); 713138568Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); 714191816Szec CURVNET_RESTORE(); 715138568Ssam } 716138568Ssam} 717138568Ssam 718138568Ssamvoid 719178354Ssamieee80211_notify_michael_failure(struct ieee80211vap *vap, 720138568Ssam const struct ieee80211_frame *wh, u_int keyix) 721138568Ssam{ 722178354Ssam struct ifnet *ifp = vap->iv_ifp; 723138568Ssam 724178354Ssam IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 725178354Ssam "michael MIC verification failed <keyix %u>", keyix); 726178354Ssam vap->iv_stats.is_rx_tkipmic++; 727138568Ssam 728138568Ssam if (ifp != NULL) { /* NB: for cipher test modules */ 729138568Ssam struct ieee80211_michael_event iev; 730138568Ssam 731138568Ssam IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 732138568Ssam IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 733138568Ssam iev.iev_cipher = IEEE80211_CIPHER_TKIP; 734138568Ssam iev.iev_keyix = keyix; 735191816Szec CURVNET_SET(ifp->if_vnet); 736138568Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); 737191816Szec CURVNET_RESTORE(); 738138568Ssam } 739138568Ssam} 740138568Ssam 741138568Ssamvoid 742178354Ssamieee80211_notify_wds_discover(struct ieee80211_node *ni) 743178354Ssam{ 744178354Ssam struct ieee80211vap *vap = ni->ni_vap; 745178354Ssam struct ifnet *ifp = vap->iv_ifp; 746178354Ssam 747178354Ssam notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr); 748178354Ssam} 749178354Ssam 750178354Ssamvoid 751178354Ssamieee80211_notify_csa(struct ieee80211com *ic, 752178354Ssam const struct ieee80211_channel *c, int mode, int count) 753178354Ssam{ 754178354Ssam struct ieee80211_csa_event iev; 755283539Sglebius struct ieee80211vap *vap; 756283539Sglebius struct ifnet *ifp; 757178354Ssam 758178354Ssam memset(&iev, 0, sizeof(iev)); 759178354Ssam iev.iev_flags = c->ic_flags; 760178354Ssam iev.iev_freq = c->ic_freq; 761178354Ssam iev.iev_ieee = c->ic_ieee; 762178354Ssam iev.iev_mode = mode; 763178354Ssam iev.iev_count = count; 764283539Sglebius TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 765283539Sglebius ifp = vap->iv_ifp; 766283539Sglebius CURVNET_SET(ifp->if_vnet); 767283539Sglebius rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev)); 768283539Sglebius CURVNET_RESTORE(); 769283539Sglebius } 770178354Ssam} 771178354Ssam 772178354Ssamvoid 773178354Ssamieee80211_notify_radar(struct ieee80211com *ic, 774178354Ssam const struct ieee80211_channel *c) 775178354Ssam{ 776178354Ssam struct ieee80211_radar_event iev; 777283539Sglebius struct ieee80211vap *vap; 778283539Sglebius struct ifnet *ifp; 779178354Ssam 780178354Ssam memset(&iev, 0, sizeof(iev)); 781178354Ssam iev.iev_flags = c->ic_flags; 782178354Ssam iev.iev_freq = c->ic_freq; 783178354Ssam iev.iev_ieee = c->ic_ieee; 784283539Sglebius TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 785283539Sglebius ifp = vap->iv_ifp; 786283539Sglebius CURVNET_SET(ifp->if_vnet); 787283539Sglebius rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev)); 788283539Sglebius CURVNET_RESTORE(); 789283539Sglebius } 790178354Ssam} 791178354Ssam 792178354Ssamvoid 793178354Ssamieee80211_notify_cac(struct ieee80211com *ic, 794178354Ssam const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type) 795178354Ssam{ 796178354Ssam struct ieee80211_cac_event iev; 797283539Sglebius struct ieee80211vap *vap; 798283539Sglebius struct ifnet *ifp; 799178354Ssam 800178354Ssam memset(&iev, 0, sizeof(iev)); 801178354Ssam iev.iev_flags = c->ic_flags; 802178354Ssam iev.iev_freq = c->ic_freq; 803178354Ssam iev.iev_ieee = c->ic_ieee; 804178354Ssam iev.iev_type = type; 805283539Sglebius TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 806283539Sglebius ifp = vap->iv_ifp; 807283539Sglebius CURVNET_SET(ifp->if_vnet); 808283539Sglebius rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev)); 809283539Sglebius CURVNET_RESTORE(); 810283539Sglebius } 811178354Ssam} 812178354Ssam 813178354Ssamvoid 814178354Ssamieee80211_notify_node_deauth(struct ieee80211_node *ni) 815178354Ssam{ 816178354Ssam struct ieee80211vap *vap = ni->ni_vap; 817178354Ssam struct ifnet *ifp = vap->iv_ifp; 818178354Ssam 819178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth"); 820178354Ssam 821178354Ssam notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr); 822178354Ssam} 823178354Ssam 824178354Ssamvoid 825178354Ssamieee80211_notify_node_auth(struct ieee80211_node *ni) 826178354Ssam{ 827178354Ssam struct ieee80211vap *vap = ni->ni_vap; 828178354Ssam struct ifnet *ifp = vap->iv_ifp; 829178354Ssam 830178354Ssam IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth"); 831178354Ssam 832178354Ssam notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr); 833178354Ssam} 834178354Ssam 835178354Ssamvoid 836178354Ssamieee80211_notify_country(struct ieee80211vap *vap, 837178354Ssam const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2]) 838178354Ssam{ 839178354Ssam struct ifnet *ifp = vap->iv_ifp; 840178354Ssam struct ieee80211_country_event iev; 841178354Ssam 842178354Ssam memset(&iev, 0, sizeof(iev)); 843178354Ssam IEEE80211_ADDR_COPY(iev.iev_addr, bssid); 844178354Ssam iev.iev_cc[0] = cc[0]; 845178354Ssam iev.iev_cc[1] = cc[1]; 846248539Sadrian CURVNET_SET(ifp->if_vnet); 847178354Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev)); 848248539Sadrian CURVNET_RESTORE(); 849178354Ssam} 850178354Ssam 851178354Ssamvoid 852178354Ssamieee80211_notify_radio(struct ieee80211com *ic, int state) 853178354Ssam{ 854178354Ssam struct ieee80211_radio_event iev; 855283539Sglebius struct ieee80211vap *vap; 856283539Sglebius struct ifnet *ifp; 857178354Ssam 858178354Ssam memset(&iev, 0, sizeof(iev)); 859178354Ssam iev.iev_state = state; 860283539Sglebius TAILQ_FOREACH(vap, &ic->ic_vaps, iv_next) { 861283539Sglebius ifp = vap->iv_ifp; 862283539Sglebius CURVNET_SET(ifp->if_vnet); 863283539Sglebius rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev)); 864283539Sglebius CURVNET_RESTORE(); 865283539Sglebius } 866178354Ssam} 867178354Ssam 868178354Ssamvoid 869138568Ssamieee80211_load_module(const char *modname) 870138568Ssam{ 871159590Sjhb 872138777Ssam#ifdef notyet 873159590Sjhb (void)kern_kldload(curthread, modname, NULL); 874138777Ssam#else 875138777Ssam printf("%s: load the %s module by hand for now.\n", __func__, modname); 876138777Ssam#endif 877138568Ssam} 878138568Ssam 879192468Ssamstatic eventhandler_tag wlan_bpfevent; 880299171Savosstatic eventhandler_tag wlan_ifllevent; 881192468Ssam 882192468Ssamstatic void 883192764Ssambpf_track(void *arg, struct ifnet *ifp, int dlt, int attach) 884192468Ssam{ 885256294Sadrian /* NB: identify vap's by if_init */ 886254082Sadrian if (dlt == DLT_IEEE802_11_RADIO && 887256294Sadrian ifp->if_init == ieee80211_init) { 888192468Ssam struct ieee80211vap *vap = ifp->if_softc; 889192468Ssam /* 890192468Ssam * Track bpf radiotap listener state. We mark the vap 891192468Ssam * to indicate if any listener is present and the com 892192468Ssam * to indicate if any listener exists on any associated 893192468Ssam * vap. This flag is used by drivers to prepare radiotap 894192468Ssam * state only when needed. 895192468Ssam */ 896193292Ssam if (attach) { 897192468Ssam ieee80211_syncflag_ext(vap, IEEE80211_FEXT_BPF); 898193292Ssam if (vap->iv_opmode == IEEE80211_M_MONITOR) 899193292Ssam atomic_add_int(&vap->iv_ic->ic_montaps, 1); 900193312Ssam } else if (!bpf_peers_present(vap->iv_rawbpf)) { 901192468Ssam ieee80211_syncflag_ext(vap, -IEEE80211_FEXT_BPF); 902193292Ssam if (vap->iv_opmode == IEEE80211_M_MONITOR) 903193292Ssam atomic_subtract_int(&vap->iv_ic->ic_montaps, 1); 904193292Ssam } 905192468Ssam } 906192468Ssam} 907192468Ssam 908138568Ssam/* 909299171Savos * Change MAC address on the vap (if was not started). 910299171Savos */ 911299171Savosstatic void 912299171Savoswlan_iflladdr(void *arg __unused, struct ifnet *ifp) 913299171Savos{ 914299171Savos /* NB: identify vap's by if_init */ 915299171Savos if (ifp->if_init == ieee80211_init && 916299171Savos (ifp->if_flags & IFF_UP) == 0) { 917299171Savos struct ieee80211vap *vap = ifp->if_softc; 918299171Savos 919299171Savos IEEE80211_ADDR_COPY(vap->iv_myaddr, IF_LLADDR(ifp)); 920299171Savos } 921299171Savos} 922299171Savos 923299171Savos/* 924138568Ssam * Module glue. 925138568Ssam * 926138568Ssam * NB: the module name is "wlan" for compatibility with NetBSD. 927138568Ssam */ 928138568Ssamstatic int 929138568Ssamwlan_modevent(module_t mod, int type, void *unused) 930138568Ssam{ 931138568Ssam switch (type) { 932138568Ssam case MOD_LOAD: 933138568Ssam if (bootverbose) 934138568Ssam printf("wlan: <802.11 Link Layer>\n"); 935192468Ssam wlan_bpfevent = EVENTHANDLER_REGISTER(bpf_track, 936192468Ssam bpf_track, 0, EVENTHANDLER_PRI_ANY); 937299171Savos wlan_ifllevent = EVENTHANDLER_REGISTER(iflladdr_event, 938299171Savos wlan_iflladdr, NULL, EVENTHANDLER_PRI_ANY); 939241610Sglebius wlan_cloner = if_clone_simple(wlanname, wlan_clone_create, 940241610Sglebius wlan_clone_destroy, 0); 941138568Ssam return 0; 942138568Ssam case MOD_UNLOAD: 943241610Sglebius if_clone_detach(wlan_cloner); 944192468Ssam EVENTHANDLER_DEREGISTER(bpf_track, wlan_bpfevent); 945299171Savos EVENTHANDLER_DEREGISTER(iflladdr_event, wlan_ifllevent); 946138568Ssam return 0; 947138568Ssam } 948138568Ssam return EINVAL; 949138568Ssam} 950138568Ssam 951138568Ssamstatic moduledata_t wlan_mod = { 952241610Sglebius wlanname, 953138568Ssam wlan_modevent, 954241394Skevlo 0 955138568Ssam}; 956138568SsamDECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 957138568SsamMODULE_VERSION(wlan, 1); 958138568SsamMODULE_DEPEND(wlan, ether, 1, 1, 1); 959233050Sadrian#ifdef IEEE80211_ALQ 960233050SadrianMODULE_DEPEND(wlan, alq, 1, 1, 1); 961233050Sadrian#endif /* IEEE80211_ALQ */ 962233050Sadrian 963