ieee80211_freebsd.c revision 192108
1/*- 2 * Copyright (c) 2003-2009 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_freebsd.c 192108 2009-05-14 16:25:57Z sam $"); 28 29/* 30 * IEEE 802.11 support (FreeBSD-specific code) 31 */ 32#include "opt_wlan.h" 33 34#include <sys/param.h> 35#include <sys/kernel.h> 36#include <sys/systm.h> 37#include <sys/linker.h> 38#include <sys/mbuf.h> 39#include <sys/module.h> 40#include <sys/proc.h> 41#include <sys/sysctl.h> 42 43#include <sys/socket.h> 44#include <sys/vimage.h> 45 46#include <net/if.h> 47#include <net/if_dl.h> 48#include <net/if_clone.h> 49#include <net/if_media.h> 50#include <net/if_types.h> 51#include <net/ethernet.h> 52#include <net/route.h> 53 54#include <net80211/ieee80211_var.h> 55 56SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters"); 57 58#ifdef IEEE80211_DEBUG 59int ieee80211_debug = 0; 60SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug, 61 0, "debugging printfs"); 62#endif 63extern int ieee80211_recv_bar_ena; 64SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena, 65 0, "BAR frame processing (ena/dis)"); 66extern int ieee80211_nol_timeout; 67SYSCTL_INT(_net_wlan, OID_AUTO, nol_timeout, CTLFLAG_RW, 68 &ieee80211_nol_timeout, 0, "NOL timeout (secs)"); 69extern int ieee80211_cac_timeout; 70SYSCTL_INT(_net_wlan, OID_AUTO, cac_timeout, CTLFLAG_RW, 71 &ieee80211_cac_timeout, 0, "CAC timeout (secs)"); 72 73MALLOC_DEFINE(M_80211_COM, "80211com", "802.11 com state"); 74 75/* 76 * Allocate/free com structure in conjunction with ifnet; 77 * these routines are registered with if_register_com_alloc 78 * below and are called automatically by the ifnet code 79 * when the ifnet of the parent device is created. 80 */ 81static void * 82wlan_alloc(u_char type, struct ifnet *ifp) 83{ 84 struct ieee80211com *ic; 85 86 ic = malloc(sizeof(struct ieee80211com), M_80211_COM, M_WAITOK|M_ZERO); 87 ic->ic_ifp = ifp; 88 89 return (ic); 90} 91 92static void 93wlan_free(void *ic, u_char type) 94{ 95 free(ic, M_80211_COM); 96} 97 98static int 99wlan_clone_create(struct if_clone *ifc, int unit, caddr_t params) 100{ 101 struct ieee80211_clone_params cp; 102 struct ieee80211vap *vap; 103 struct ieee80211com *ic; 104 struct ifnet *ifp; 105 int error; 106 107 error = copyin(params, &cp, sizeof(cp)); 108 if (error) 109 return error; 110 ifp = ifunit(cp.icp_parent); 111 if (ifp == NULL) 112 return ENXIO; 113 /* XXX move printfs to DIAGNOSTIC before release */ 114 if (ifp->if_type != IFT_IEEE80211) { 115 if_printf(ifp, "%s: reject, not an 802.11 device\n", __func__); 116 return ENXIO; 117 } 118 if (cp.icp_opmode >= IEEE80211_OPMODE_MAX) { 119 if_printf(ifp, "%s: invalid opmode %d\n", 120 __func__, cp.icp_opmode); 121 return EINVAL; 122 } 123 ic = ifp->if_l2com; 124 if ((ic->ic_caps & ieee80211_opcap[cp.icp_opmode]) == 0) { 125 if_printf(ifp, "%s mode not supported\n", 126 ieee80211_opmode_name[cp.icp_opmode]); 127 return EOPNOTSUPP; 128 } 129 if ((cp.icp_flags & IEEE80211_CLONE_TDMA) && 130#ifdef IEEE80211_SUPPORT_TDMA 131 (ic->ic_caps & IEEE80211_C_TDMA) == 0 132#else 133 (1) 134#endif 135 ) { 136 if_printf(ifp, "TDMA not supported\n"); 137 return EOPNOTSUPP; 138 } 139 vap = ic->ic_vap_create(ic, ifc->ifc_name, unit, 140 cp.icp_opmode, cp.icp_flags, cp.icp_bssid, 141 cp.icp_flags & IEEE80211_CLONE_MACADDR ? 142 cp.icp_macaddr : (const uint8_t *)IF_LLADDR(ifp)); 143 return (vap == NULL ? EIO : 0); 144} 145 146static void 147wlan_clone_destroy(struct ifnet *ifp) 148{ 149 struct ieee80211vap *vap = ifp->if_softc; 150 struct ieee80211com *ic = vap->iv_ic; 151 152 ic->ic_vap_delete(vap); 153} 154IFC_SIMPLE_DECLARE(wlan, 0); 155 156void 157ieee80211_vap_destroy(struct ieee80211vap *vap) 158{ 159 if_clone_destroyif(&wlan_cloner, vap->iv_ifp); 160} 161 162static int 163ieee80211_sysctl_msecs_ticks(SYSCTL_HANDLER_ARGS) 164{ 165 int msecs = ticks_to_msecs(*(int *)arg1); 166 int error, t; 167 168 error = sysctl_handle_int(oidp, &msecs, 0, req); 169 if (error || !req->newptr) 170 return error; 171 t = msecs_to_ticks(msecs); 172 *(int *)arg1 = (t < 1) ? 1 : t; 173 return 0; 174} 175 176#ifdef IEEE80211_AMPDU_AGE 177extern int ieee80211_ampdu_age; 178SYSCTL_PROC(_net_wlan, OID_AUTO, ampdu_age, CTLTYPE_INT | CTLFLAG_RW, 179 &ieee80211_ampdu_age, 0, ieee80211_sysctl_msecs_ticks, "I", 180 "AMPDU max reorder age (ms)"); 181#endif 182extern int ieee80211_addba_timeout; 183SYSCTL_PROC(_net_wlan, OID_AUTO, addba_timeout, CTLTYPE_INT | CTLFLAG_RW, 184 &ieee80211_addba_timeout, 0, ieee80211_sysctl_msecs_ticks, "I", 185 "ADDBA request timeout (ms)"); 186extern int ieee80211_addba_backoff; 187SYSCTL_PROC(_net_wlan, OID_AUTO, addba_backoff, CTLTYPE_INT | CTLFLAG_RW, 188 &ieee80211_addba_backoff, 0, ieee80211_sysctl_msecs_ticks, "I", 189 "ADDBA request backoff (ms)"); 190extern int ieee80211_addba_maxtries; 191SYSCTL_INT(_net_wlan, OID_AUTO, addba_maxtries, CTLTYPE_INT | CTLFLAG_RW, 192 &ieee80211_addba_maxtries, 0, "max ADDBA requests sent before backoff"); 193#ifdef IEEE80211_SUPPORT_SUPERG 194extern int ieee80211_ffppsmin; 195SYSCTL_INT(_net_wlan, OID_AUTO, ffppsmin, CTLTYPE_INT | CTLFLAG_RW, 196 &ieee80211_ffppsmin, 0, "min packet rate before fast-frame staging"); 197extern int ieee80211_ffagemax; 198SYSCTL_PROC(_net_wlan, OID_AUTO, ffagemax, CTLTYPE_INT | CTLFLAG_RW, 199 &ieee80211_ffagemax, 0, ieee80211_sysctl_msecs_ticks, "I", 200 "max hold time for fast-frame staging (ms)"); 201#endif /* IEEE80211_SUPPORT_SUPERG */ 202 203static int 204ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS) 205{ 206 int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT; 207 int error; 208 209 error = sysctl_handle_int(oidp, &inact, 0, req); 210 if (error || !req->newptr) 211 return error; 212 *(int *)arg1 = inact / IEEE80211_INACT_WAIT; 213 return 0; 214} 215 216static int 217ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS) 218{ 219 struct ieee80211com *ic = arg1; 220 const char *name = ic->ic_ifp->if_xname; 221 222 return SYSCTL_OUT(req, name, strlen(name)); 223} 224 225static int 226ieee80211_sysctl_radar(SYSCTL_HANDLER_ARGS) 227{ 228 struct ieee80211com *ic = arg1; 229 int t = 0, error; 230 231 error = sysctl_handle_int(oidp, &t, 0, req); 232 if (error || !req->newptr) 233 return error; 234 IEEE80211_LOCK(ic); 235 ieee80211_dfs_notify_radar(ic, ic->ic_curchan); 236 IEEE80211_UNLOCK(ic); 237 return 0; 238} 239 240void 241ieee80211_sysctl_attach(struct ieee80211com *ic) 242{ 243} 244 245void 246ieee80211_sysctl_detach(struct ieee80211com *ic) 247{ 248} 249 250void 251ieee80211_sysctl_vattach(struct ieee80211vap *vap) 252{ 253 struct ifnet *ifp = vap->iv_ifp; 254 struct sysctl_ctx_list *ctx; 255 struct sysctl_oid *oid; 256 char num[14]; /* sufficient for 32 bits */ 257 258 ctx = (struct sysctl_ctx_list *) malloc(sizeof(struct sysctl_ctx_list), 259 M_DEVBUF, M_NOWAIT | M_ZERO); 260 if (ctx == NULL) { 261 if_printf(ifp, "%s: cannot allocate sysctl context!\n", 262 __func__); 263 return; 264 } 265 sysctl_ctx_init(ctx); 266 snprintf(num, sizeof(num), "%u", ifp->if_dunit); 267 oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan), 268 OID_AUTO, num, CTLFLAG_RD, NULL, ""); 269 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 270 "%parent", CTLFLAG_RD, vap->iv_ic, 0, 271 ieee80211_sysctl_parent, "A", "parent device"); 272 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 273 "driver_caps", CTLFLAG_RW, &vap->iv_caps, 0, 274 "driver capabilities"); 275#ifdef IEEE80211_DEBUG 276 vap->iv_debug = ieee80211_debug; 277 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 278 "debug", CTLFLAG_RW, &vap->iv_debug, 0, 279 "control debugging printfs"); 280#endif 281 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 282 "bmiss_max", CTLFLAG_RW, &vap->iv_bmiss_max, 0, 283 "consecutive beacon misses before scanning"); 284 /* XXX inherit from tunables */ 285 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 286 "inact_run", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_run, 0, 287 ieee80211_sysctl_inact, "I", 288 "station inactivity timeout (sec)"); 289 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 290 "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_probe, 0, 291 ieee80211_sysctl_inact, "I", 292 "station inactivity probe timeout (sec)"); 293 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 294 "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_auth, 0, 295 ieee80211_sysctl_inact, "I", 296 "station authentication timeout (sec)"); 297 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 298 "inact_init", CTLTYPE_INT | CTLFLAG_RW, &vap->iv_inact_init, 0, 299 ieee80211_sysctl_inact, "I", 300 "station initial state timeout (sec)"); 301 if (vap->iv_htcaps & IEEE80211_HTC_HT) { 302 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 303 "ampdu_mintraffic_bk", CTLFLAG_RW, 304 &vap->iv_ampdu_mintraffic[WME_AC_BK], 0, 305 "BK traffic tx aggr threshold (pps)"); 306 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 307 "ampdu_mintraffic_be", CTLFLAG_RW, 308 &vap->iv_ampdu_mintraffic[WME_AC_BE], 0, 309 "BE traffic tx aggr threshold (pps)"); 310 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 311 "ampdu_mintraffic_vo", CTLFLAG_RW, 312 &vap->iv_ampdu_mintraffic[WME_AC_VO], 0, 313 "VO traffic tx aggr threshold (pps)"); 314 SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 315 "ampdu_mintraffic_vi", CTLFLAG_RW, 316 &vap->iv_ampdu_mintraffic[WME_AC_VI], 0, 317 "VI traffic tx aggr threshold (pps)"); 318 } 319 if (vap->iv_caps & IEEE80211_C_DFS) { 320 SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 321 "radar", CTLTYPE_INT | CTLFLAG_RW, vap->iv_ic, 0, 322 ieee80211_sysctl_radar, "I", "simulare radar event"); 323 } 324 vap->iv_sysctl = ctx; 325 vap->iv_oid = oid; 326} 327 328void 329ieee80211_sysctl_vdetach(struct ieee80211vap *vap) 330{ 331 332 if (vap->iv_sysctl != NULL) { 333 sysctl_ctx_free(vap->iv_sysctl); 334 free(vap->iv_sysctl, M_DEVBUF); 335 vap->iv_sysctl = NULL; 336 } 337} 338 339int 340ieee80211_node_dectestref(struct ieee80211_node *ni) 341{ 342 /* XXX need equivalent of atomic_dec_and_test */ 343 atomic_subtract_int(&ni->ni_refcnt, 1); 344 return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); 345} 346 347void 348ieee80211_drain_ifq(struct ifqueue *ifq) 349{ 350 struct ieee80211_node *ni; 351 struct mbuf *m; 352 353 for (;;) { 354 IF_DEQUEUE(ifq, m); 355 if (m == NULL) 356 break; 357 358 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 359 KASSERT(ni != NULL, ("frame w/o node")); 360 ieee80211_free_node(ni); 361 m->m_pkthdr.rcvif = NULL; 362 363 m_freem(m); 364 } 365} 366 367void 368ieee80211_flush_ifq(struct ifqueue *ifq, struct ieee80211vap *vap) 369{ 370 struct ieee80211_node *ni; 371 struct mbuf *m, **mprev; 372 373 IF_LOCK(ifq); 374 mprev = &ifq->ifq_head; 375 while ((m = *mprev) != NULL) { 376 ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 377 if (ni != NULL && ni->ni_vap == vap) { 378 *mprev = m->m_nextpkt; /* remove from list */ 379 ifq->ifq_len--; 380 381 m_freem(m); 382 ieee80211_free_node(ni); /* reclaim ref */ 383 } else 384 mprev = &m->m_nextpkt; 385 } 386 /* recalculate tail ptr */ 387 m = ifq->ifq_head; 388 for (; m != NULL && m->m_nextpkt != NULL; m = m->m_nextpkt) 389 ; 390 ifq->ifq_tail = m; 391 IF_UNLOCK(ifq); 392} 393 394/* 395 * As above, for mbufs allocated with m_gethdr/MGETHDR 396 * or initialized by M_COPY_PKTHDR. 397 */ 398#define MC_ALIGN(m, len) \ 399do { \ 400 (m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1); \ 401} while (/* CONSTCOND */ 0) 402 403/* 404 * Allocate and setup a management frame of the specified 405 * size. We return the mbuf and a pointer to the start 406 * of the contiguous data area that's been reserved based 407 * on the packet length. The data area is forced to 32-bit 408 * alignment and the buffer length to a multiple of 4 bytes. 409 * This is done mainly so beacon frames (that require this) 410 * can use this interface too. 411 */ 412struct mbuf * 413ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen) 414{ 415 struct mbuf *m; 416 u_int len; 417 418 /* 419 * NB: we know the mbuf routines will align the data area 420 * so we don't need to do anything special. 421 */ 422 len = roundup2(headroom + pktlen, 4); 423 KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); 424 if (len < MINCLSIZE) { 425 m = m_gethdr(M_NOWAIT, MT_DATA); 426 /* 427 * Align the data in case additional headers are added. 428 * This should only happen when a WEP header is added 429 * which only happens for shared key authentication mgt 430 * frames which all fit in MHLEN. 431 */ 432 if (m != NULL) 433 MH_ALIGN(m, len); 434 } else { 435 m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 436 if (m != NULL) 437 MC_ALIGN(m, len); 438 } 439 if (m != NULL) { 440 m->m_data += headroom; 441 *frm = m->m_data; 442 } 443 return m; 444} 445 446int 447ieee80211_add_callback(struct mbuf *m, 448 void (*func)(struct ieee80211_node *, void *, int), void *arg) 449{ 450 struct m_tag *mtag; 451 struct ieee80211_cb *cb; 452 453 mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, 454 sizeof(struct ieee80211_cb), M_NOWAIT); 455 if (mtag == NULL) 456 return 0; 457 458 cb = (struct ieee80211_cb *)(mtag+1); 459 cb->func = func; 460 cb->arg = arg; 461 m_tag_prepend(m, mtag); 462 m->m_flags |= M_TXCB; 463 return 1; 464} 465 466void 467ieee80211_process_callback(struct ieee80211_node *ni, 468 struct mbuf *m, int status) 469{ 470 struct m_tag *mtag; 471 472 mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL); 473 if (mtag != NULL) { 474 struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1); 475 cb->func(ni, cb->arg, status); 476 } 477} 478 479#include <sys/libkern.h> 480 481void 482get_random_bytes(void *p, size_t n) 483{ 484 uint8_t *dp = p; 485 486 while (n > 0) { 487 uint32_t v = arc4random(); 488 size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n; 489 bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n); 490 dp += sizeof(uint32_t), n -= nb; 491 } 492} 493 494/* 495 * Helper function for events that pass just a single mac address. 496 */ 497static void 498notify_macaddr(struct ifnet *ifp, int op, const uint8_t mac[IEEE80211_ADDR_LEN]) 499{ 500 struct ieee80211_join_event iev; 501 502 CURVNET_SET(ifp->if_vnet); 503 memset(&iev, 0, sizeof(iev)); 504 IEEE80211_ADDR_COPY(iev.iev_addr, mac); 505 rt_ieee80211msg(ifp, op, &iev, sizeof(iev)); 506 CURVNET_RESTORE(); 507} 508 509void 510ieee80211_notify_node_join(struct ieee80211_node *ni, int newassoc) 511{ 512 struct ieee80211vap *vap = ni->ni_vap; 513 struct ifnet *ifp = vap->iv_ifp; 514 515 CURVNET_SET_QUIET(ifp->if_vnet); 516 IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode join", 517 (ni == vap->iv_bss) ? "bss " : ""); 518 519 if (ni == vap->iv_bss) { 520 notify_macaddr(ifp, newassoc ? 521 RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, ni->ni_bssid); 522 if_link_state_change(ifp, LINK_STATE_UP); 523 } else { 524 notify_macaddr(ifp, newassoc ? 525 RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, ni->ni_macaddr); 526 } 527 CURVNET_RESTORE(); 528} 529 530void 531ieee80211_notify_node_leave(struct ieee80211_node *ni) 532{ 533 struct ieee80211vap *vap = ni->ni_vap; 534 struct ifnet *ifp = vap->iv_ifp; 535 536 CURVNET_SET_QUIET(ifp->if_vnet); 537 IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%snode leave", 538 (ni == vap->iv_bss) ? "bss " : ""); 539 540 if (ni == vap->iv_bss) { 541 rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); 542 if_link_state_change(ifp, LINK_STATE_DOWN); 543 } else { 544 /* fire off wireless event station leaving */ 545 notify_macaddr(ifp, RTM_IEEE80211_LEAVE, ni->ni_macaddr); 546 } 547 CURVNET_RESTORE(); 548} 549 550void 551ieee80211_notify_scan_done(struct ieee80211vap *vap) 552{ 553 struct ifnet *ifp = vap->iv_ifp; 554 555 IEEE80211_DPRINTF(vap, IEEE80211_MSG_SCAN, "%s\n", "notify scan done"); 556 557 /* dispatch wireless event indicating scan completed */ 558 CURVNET_SET(ifp->if_vnet); 559 rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); 560 CURVNET_RESTORE(); 561} 562 563void 564ieee80211_notify_replay_failure(struct ieee80211vap *vap, 565 const struct ieee80211_frame *wh, const struct ieee80211_key *k, 566 u_int64_t rsc) 567{ 568 struct ifnet *ifp = vap->iv_ifp; 569 570 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 571 "%s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>", 572 k->wk_cipher->ic_name, (intmax_t) rsc, 573 (intmax_t) k->wk_keyrsc[IEEE80211_NONQOS_TID], 574 k->wk_keyix, k->wk_rxkeyix); 575 576 if (ifp != NULL) { /* NB: for cipher test modules */ 577 struct ieee80211_replay_event iev; 578 579 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 580 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 581 iev.iev_cipher = k->wk_cipher->ic_cipher; 582 if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE) 583 iev.iev_keyix = k->wk_rxkeyix; 584 else 585 iev.iev_keyix = k->wk_keyix; 586 iev.iev_keyrsc = k->wk_keyrsc[0]; /* XXX need tid */ 587 iev.iev_rsc = rsc; 588 CURVNET_SET(ifp->if_vnet); 589 rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); 590 CURVNET_RESTORE(); 591 } 592} 593 594void 595ieee80211_notify_michael_failure(struct ieee80211vap *vap, 596 const struct ieee80211_frame *wh, u_int keyix) 597{ 598 struct ifnet *ifp = vap->iv_ifp; 599 600 IEEE80211_NOTE_MAC(vap, IEEE80211_MSG_CRYPTO, wh->i_addr2, 601 "michael MIC verification failed <keyix %u>", keyix); 602 vap->iv_stats.is_rx_tkipmic++; 603 604 if (ifp != NULL) { /* NB: for cipher test modules */ 605 struct ieee80211_michael_event iev; 606 607 IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 608 IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 609 iev.iev_cipher = IEEE80211_CIPHER_TKIP; 610 iev.iev_keyix = keyix; 611 CURVNET_SET(ifp->if_vnet); 612 rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); 613 CURVNET_RESTORE(); 614 } 615} 616 617void 618ieee80211_notify_wds_discover(struct ieee80211_node *ni) 619{ 620 struct ieee80211vap *vap = ni->ni_vap; 621 struct ifnet *ifp = vap->iv_ifp; 622 623 notify_macaddr(ifp, RTM_IEEE80211_WDS, ni->ni_macaddr); 624} 625 626void 627ieee80211_notify_csa(struct ieee80211com *ic, 628 const struct ieee80211_channel *c, int mode, int count) 629{ 630 struct ifnet *ifp = ic->ic_ifp; 631 struct ieee80211_csa_event iev; 632 633 memset(&iev, 0, sizeof(iev)); 634 iev.iev_flags = c->ic_flags; 635 iev.iev_freq = c->ic_freq; 636 iev.iev_ieee = c->ic_ieee; 637 iev.iev_mode = mode; 638 iev.iev_count = count; 639 rt_ieee80211msg(ifp, RTM_IEEE80211_CSA, &iev, sizeof(iev)); 640} 641 642void 643ieee80211_notify_radar(struct ieee80211com *ic, 644 const struct ieee80211_channel *c) 645{ 646 struct ifnet *ifp = ic->ic_ifp; 647 struct ieee80211_radar_event iev; 648 649 memset(&iev, 0, sizeof(iev)); 650 iev.iev_flags = c->ic_flags; 651 iev.iev_freq = c->ic_freq; 652 iev.iev_ieee = c->ic_ieee; 653 rt_ieee80211msg(ifp, RTM_IEEE80211_RADAR, &iev, sizeof(iev)); 654} 655 656void 657ieee80211_notify_cac(struct ieee80211com *ic, 658 const struct ieee80211_channel *c, enum ieee80211_notify_cac_event type) 659{ 660 struct ifnet *ifp = ic->ic_ifp; 661 struct ieee80211_cac_event iev; 662 663 memset(&iev, 0, sizeof(iev)); 664 iev.iev_flags = c->ic_flags; 665 iev.iev_freq = c->ic_freq; 666 iev.iev_ieee = c->ic_ieee; 667 iev.iev_type = type; 668 rt_ieee80211msg(ifp, RTM_IEEE80211_CAC, &iev, sizeof(iev)); 669} 670 671void 672ieee80211_notify_node_deauth(struct ieee80211_node *ni) 673{ 674 struct ieee80211vap *vap = ni->ni_vap; 675 struct ifnet *ifp = vap->iv_ifp; 676 677 IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node deauth"); 678 679 notify_macaddr(ifp, RTM_IEEE80211_DEAUTH, ni->ni_macaddr); 680} 681 682void 683ieee80211_notify_node_auth(struct ieee80211_node *ni) 684{ 685 struct ieee80211vap *vap = ni->ni_vap; 686 struct ifnet *ifp = vap->iv_ifp; 687 688 IEEE80211_NOTE(vap, IEEE80211_MSG_NODE, ni, "%s", "node auth"); 689 690 notify_macaddr(ifp, RTM_IEEE80211_AUTH, ni->ni_macaddr); 691} 692 693void 694ieee80211_notify_country(struct ieee80211vap *vap, 695 const uint8_t bssid[IEEE80211_ADDR_LEN], const uint8_t cc[2]) 696{ 697 struct ifnet *ifp = vap->iv_ifp; 698 struct ieee80211_country_event iev; 699 700 memset(&iev, 0, sizeof(iev)); 701 IEEE80211_ADDR_COPY(iev.iev_addr, bssid); 702 iev.iev_cc[0] = cc[0]; 703 iev.iev_cc[1] = cc[1]; 704 rt_ieee80211msg(ifp, RTM_IEEE80211_COUNTRY, &iev, sizeof(iev)); 705} 706 707void 708ieee80211_notify_radio(struct ieee80211com *ic, int state) 709{ 710 struct ifnet *ifp = ic->ic_ifp; 711 struct ieee80211_radio_event iev; 712 713 memset(&iev, 0, sizeof(iev)); 714 iev.iev_state = state; 715 rt_ieee80211msg(ifp, RTM_IEEE80211_RADIO, &iev, sizeof(iev)); 716} 717 718void 719ieee80211_load_module(const char *modname) 720{ 721 722#ifdef notyet 723 (void)kern_kldload(curthread, modname, NULL); 724#else 725 printf("%s: load the %s module by hand for now.\n", __func__, modname); 726#endif 727} 728 729/* 730 * Module glue. 731 * 732 * NB: the module name is "wlan" for compatibility with NetBSD. 733 */ 734static int 735wlan_modevent(module_t mod, int type, void *unused) 736{ 737 switch (type) { 738 case MOD_LOAD: 739 if (bootverbose) 740 printf("wlan: <802.11 Link Layer>\n"); 741 if_clone_attach(&wlan_cloner); 742 if_register_com_alloc(IFT_IEEE80211, wlan_alloc, wlan_free); 743 return 0; 744 case MOD_UNLOAD: 745 if_deregister_com_alloc(IFT_IEEE80211); 746 if_clone_detach(&wlan_cloner); 747 return 0; 748 } 749 return EINVAL; 750} 751 752static moduledata_t wlan_mod = { 753 "wlan", 754 wlan_modevent, 755 0 756}; 757DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 758MODULE_VERSION(wlan, 1); 759MODULE_DEPEND(wlan, ether, 1, 1, 1); 760