18a1b9b6aSSam Leffler /*- 2ae8b7333SSam Leffler * Copyright (c) 2003-2007 Sam Leffler, Errno Consulting 38a1b9b6aSSam Leffler * All rights reserved. 48a1b9b6aSSam Leffler * 58a1b9b6aSSam Leffler * Redistribution and use in source and binary forms, with or without 68a1b9b6aSSam Leffler * modification, are permitted provided that the following conditions 78a1b9b6aSSam Leffler * are met: 88a1b9b6aSSam Leffler * 1. Redistributions of source code must retain the above copyright 98a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer. 108a1b9b6aSSam Leffler * 2. Redistributions in binary form must reproduce the above copyright 118a1b9b6aSSam Leffler * notice, this list of conditions and the following disclaimer in the 128a1b9b6aSSam Leffler * documentation and/or other materials provided with the distribution. 138a1b9b6aSSam Leffler * 148a1b9b6aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 158a1b9b6aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 168a1b9b6aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 178a1b9b6aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 188a1b9b6aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 198a1b9b6aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 208a1b9b6aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 218a1b9b6aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 228a1b9b6aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 238a1b9b6aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 248a1b9b6aSSam Leffler */ 258a1b9b6aSSam Leffler 268a1b9b6aSSam Leffler #include <sys/cdefs.h> 278a1b9b6aSSam Leffler __FBSDID("$FreeBSD$"); 288a1b9b6aSSam Leffler 298a1b9b6aSSam Leffler /* 308a1b9b6aSSam Leffler * IEEE 802.11 support (FreeBSD-specific code) 318a1b9b6aSSam Leffler */ 328a1b9b6aSSam Leffler #include <sys/param.h> 338a1b9b6aSSam Leffler #include <sys/kernel.h> 348a1b9b6aSSam Leffler #include <sys/systm.h> 358a1b9b6aSSam Leffler #include <sys/linker.h> 368a1b9b6aSSam Leffler #include <sys/mbuf.h> 378a1b9b6aSSam Leffler #include <sys/module.h> 388a1b9b6aSSam Leffler #include <sys/proc.h> 398a1b9b6aSSam Leffler #include <sys/sysctl.h> 408a1b9b6aSSam Leffler 418a1b9b6aSSam Leffler #include <sys/socket.h> 428a1b9b6aSSam Leffler 438a1b9b6aSSam Leffler #include <net/if.h> 448a1b9b6aSSam Leffler #include <net/if_media.h> 458a1b9b6aSSam Leffler #include <net/ethernet.h> 468a1b9b6aSSam Leffler #include <net/route.h> 478a1b9b6aSSam Leffler 488a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h> 498a1b9b6aSSam Leffler 508a1b9b6aSSam Leffler SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters"); 518a1b9b6aSSam Leffler 528a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 538a1b9b6aSSam Leffler int ieee80211_debug = 0; 548a1b9b6aSSam Leffler SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug, 558a1b9b6aSSam Leffler 0, "debugging printfs"); 568a1b9b6aSSam Leffler #endif 571b6167d2SSam Leffler extern int ieee80211_recv_bar_ena; 581b6167d2SSam Leffler SYSCTL_INT(_net_wlan, OID_AUTO, recv_bar, CTLFLAG_RW, &ieee80211_recv_bar_ena, 591b6167d2SSam Leffler 0, "BAR frame processing (ena/dis)"); 601b6167d2SSam Leffler 611b6167d2SSam Leffler #ifdef IEEE80211_AMPDU_AGE 621b6167d2SSam Leffler static int 631b6167d2SSam Leffler ieee80211_sysctl_ampdu_age(SYSCTL_HANDLER_ARGS) 641b6167d2SSam Leffler { 651b6167d2SSam Leffler extern int ieee80211_ampdu_age; 661b6167d2SSam Leffler int ampdu_age = ticks_to_msecs(ieee80211_ampdu_age); 671b6167d2SSam Leffler int error; 681b6167d2SSam Leffler 691b6167d2SSam Leffler error = sysctl_handle_int(oidp, &du_age, 0, req); 701b6167d2SSam Leffler if (error || !req->newptr) 711b6167d2SSam Leffler return error; 721b6167d2SSam Leffler ieee80211_ampdu_age = msecs_to_ticks(ampdu_age); 731b6167d2SSam Leffler return 0; 741b6167d2SSam Leffler } 751b6167d2SSam Leffler SYSCTL_PROC(_net_wlan, OID_AUTO, "ampdu_age", CTLFLAG_RW, NULL, 0, 761b6167d2SSam Leffler ieee80211_sysctl_ampdu_age, "A", "AMPDU max reorder age (ms)"); 771b6167d2SSam Leffler #endif 788a1b9b6aSSam Leffler 798a1b9b6aSSam Leffler static int 808a1b9b6aSSam Leffler ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS) 818a1b9b6aSSam Leffler { 828a1b9b6aSSam Leffler int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT; 838a1b9b6aSSam Leffler int error; 848a1b9b6aSSam Leffler 858a1b9b6aSSam Leffler error = sysctl_handle_int(oidp, &inact, 0, req); 868a1b9b6aSSam Leffler if (error || !req->newptr) 878a1b9b6aSSam Leffler return error; 888a1b9b6aSSam Leffler *(int *)arg1 = inact / IEEE80211_INACT_WAIT; 898a1b9b6aSSam Leffler return 0; 908a1b9b6aSSam Leffler } 918a1b9b6aSSam Leffler 928a1b9b6aSSam Leffler static int 938a1b9b6aSSam Leffler ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS) 948a1b9b6aSSam Leffler { 958a1b9b6aSSam Leffler struct ieee80211com *ic = arg1; 968a1b9b6aSSam Leffler const char *name = ic->ic_ifp->if_xname; 978a1b9b6aSSam Leffler 988a1b9b6aSSam Leffler return SYSCTL_OUT(req, name, strlen(name)); 998a1b9b6aSSam Leffler } 1008a1b9b6aSSam Leffler 1018a1b9b6aSSam Leffler void 1028a1b9b6aSSam Leffler ieee80211_sysctl_attach(struct ieee80211com *ic) 1038a1b9b6aSSam Leffler { 1048a1b9b6aSSam Leffler struct sysctl_ctx_list *ctx; 1058a1b9b6aSSam Leffler struct sysctl_oid *oid; 1068a1b9b6aSSam Leffler char num[14]; /* sufficient for 32 bits */ 1078a1b9b6aSSam Leffler 1088a1b9b6aSSam Leffler MALLOC(ctx, struct sysctl_ctx_list *, sizeof(struct sysctl_ctx_list), 1098a1b9b6aSSam Leffler M_DEVBUF, M_NOWAIT | M_ZERO); 1108a1b9b6aSSam Leffler if (ctx == NULL) { 1118a1b9b6aSSam Leffler if_printf(ic->ic_ifp, "%s: cannot allocate sysctl context!\n", 1128a1b9b6aSSam Leffler __func__); 1138a1b9b6aSSam Leffler return; 1148a1b9b6aSSam Leffler } 1158a1b9b6aSSam Leffler sysctl_ctx_init(ctx); 1168a1b9b6aSSam Leffler snprintf(num, sizeof(num), "%u", ic->ic_vap); 1178a1b9b6aSSam Leffler oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan), 1188a1b9b6aSSam Leffler OID_AUTO, num, CTLFLAG_RD, NULL, ""); 1198a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1208a1b9b6aSSam Leffler "%parent", CTLFLAG_RD, ic, 0, ieee80211_sysctl_parent, "A", 1218a1b9b6aSSam Leffler "parent device"); 1228a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 1238a1b9b6aSSam Leffler ic->ic_debug = ieee80211_debug; 1248a1b9b6aSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1258a1b9b6aSSam Leffler "debug", CTLFLAG_RW, &ic->ic_debug, 0, 1268a1b9b6aSSam Leffler "control debugging printfs"); 1278a1b9b6aSSam Leffler #endif 1288a1b9b6aSSam Leffler /* XXX inherit from tunables */ 1298a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 130e5a96ac7SSam Leffler "inact_run", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_run, 0, 1318a1b9b6aSSam Leffler ieee80211_sysctl_inact, "I", 1328a1b9b6aSSam Leffler "station inactivity timeout (sec)"); 1338a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1348a1b9b6aSSam Leffler "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_probe, 0, 1358a1b9b6aSSam Leffler ieee80211_sysctl_inact, "I", 1368a1b9b6aSSam Leffler "station inactivity probe timeout (sec)"); 1378a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1388a1b9b6aSSam Leffler "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_auth, 0, 1398a1b9b6aSSam Leffler ieee80211_sysctl_inact, "I", 1408a1b9b6aSSam Leffler "station authentication timeout (sec)"); 1418a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1428a1b9b6aSSam Leffler "inact_init", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_init, 0, 1438a1b9b6aSSam Leffler ieee80211_sysctl_inact, "I", 1448a1b9b6aSSam Leffler "station initial state timeout (sec)"); 145da615e95SSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 146da615e95SSam Leffler "driver_caps", CTLFLAG_RW, &ic->ic_caps, 0, 147da615e95SSam Leffler "driver capabilities"); 148e701e041SSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 149e701e041SSam Leffler "bmiss_max", CTLFLAG_RW, &ic->ic_bmiss_max, 0, 150e701e041SSam Leffler "consecutive beacon misses before scanning"); 1518a1b9b6aSSam Leffler ic->ic_sysctl = ctx; 1528a1b9b6aSSam Leffler } 1538a1b9b6aSSam Leffler 1548a1b9b6aSSam Leffler void 1558a1b9b6aSSam Leffler ieee80211_sysctl_detach(struct ieee80211com *ic) 1568a1b9b6aSSam Leffler { 1578a1b9b6aSSam Leffler 1588a1b9b6aSSam Leffler if (ic->ic_sysctl != NULL) { 1598a1b9b6aSSam Leffler sysctl_ctx_free(ic->ic_sysctl); 16098b33550SSepherosa Ziehau FREE(ic->ic_sysctl, M_DEVBUF); 1618a1b9b6aSSam Leffler ic->ic_sysctl = NULL; 1628a1b9b6aSSam Leffler } 1638a1b9b6aSSam Leffler } 1648a1b9b6aSSam Leffler 1658a1b9b6aSSam Leffler int 1668a1b9b6aSSam Leffler ieee80211_node_dectestref(struct ieee80211_node *ni) 1678a1b9b6aSSam Leffler { 1688a1b9b6aSSam Leffler /* XXX need equivalent of atomic_dec_and_test */ 1698a1b9b6aSSam Leffler atomic_subtract_int(&ni->ni_refcnt, 1); 1708a1b9b6aSSam Leffler return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); 1718a1b9b6aSSam Leffler } 1728a1b9b6aSSam Leffler 173915f1482SSam Leffler void 174915f1482SSam Leffler ieee80211_drain_ifq(struct ifqueue *ifq) 175915f1482SSam Leffler { 176915f1482SSam Leffler struct ieee80211_node *ni; 177915f1482SSam Leffler struct mbuf *m; 178915f1482SSam Leffler 179915f1482SSam Leffler for (;;) { 180915f1482SSam Leffler IF_DEQUEUE(ifq, m); 181915f1482SSam Leffler if (m == NULL) 182915f1482SSam Leffler break; 183915f1482SSam Leffler 184915f1482SSam Leffler ni = (struct ieee80211_node *)m->m_pkthdr.rcvif; 185915f1482SSam Leffler KASSERT(ni != NULL, ("frame w/o node")); 186915f1482SSam Leffler ieee80211_free_node(ni); 187915f1482SSam Leffler m->m_pkthdr.rcvif = NULL; 188915f1482SSam Leffler 189915f1482SSam Leffler m_freem(m); 190915f1482SSam Leffler } 191915f1482SSam Leffler } 192915f1482SSam Leffler 1938a1b9b6aSSam Leffler /* 19468e8e04eSSam Leffler * As above, for mbufs allocated with m_gethdr/MGETHDR 19568e8e04eSSam Leffler * or initialized by M_COPY_PKTHDR. 19668e8e04eSSam Leffler */ 19768e8e04eSSam Leffler #define MC_ALIGN(m, len) \ 19868e8e04eSSam Leffler do { \ 19968e8e04eSSam Leffler (m)->m_data += (MCLBYTES - (len)) &~ (sizeof(long) - 1); \ 20068e8e04eSSam Leffler } while (/* CONSTCOND */ 0) 20168e8e04eSSam Leffler 20268e8e04eSSam Leffler /* 2038a1b9b6aSSam Leffler * Allocate and setup a management frame of the specified 2048a1b9b6aSSam Leffler * size. We return the mbuf and a pointer to the start 2058a1b9b6aSSam Leffler * of the contiguous data area that's been reserved based 2068a1b9b6aSSam Leffler * on the packet length. The data area is forced to 32-bit 2078a1b9b6aSSam Leffler * alignment and the buffer length to a multiple of 4 bytes. 2088a1b9b6aSSam Leffler * This is done mainly so beacon frames (that require this) 2098a1b9b6aSSam Leffler * can use this interface too. 2108a1b9b6aSSam Leffler */ 2118a1b9b6aSSam Leffler struct mbuf * 21268e8e04eSSam Leffler ieee80211_getmgtframe(uint8_t **frm, int headroom, int pktlen) 2138a1b9b6aSSam Leffler { 2148a1b9b6aSSam Leffler struct mbuf *m; 2158a1b9b6aSSam Leffler u_int len; 2168a1b9b6aSSam Leffler 2178a1b9b6aSSam Leffler /* 2188a1b9b6aSSam Leffler * NB: we know the mbuf routines will align the data area 2198a1b9b6aSSam Leffler * so we don't need to do anything special. 2208a1b9b6aSSam Leffler */ 22168e8e04eSSam Leffler len = roundup2(headroom + pktlen, 4); 2228a1b9b6aSSam Leffler KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); 2238a1b9b6aSSam Leffler if (len < MINCLSIZE) { 22434333b16SAndre Oppermann m = m_gethdr(M_NOWAIT, MT_DATA); 2258a1b9b6aSSam Leffler /* 2268a1b9b6aSSam Leffler * Align the data in case additional headers are added. 2278a1b9b6aSSam Leffler * This should only happen when a WEP header is added 2288a1b9b6aSSam Leffler * which only happens for shared key authentication mgt 2298a1b9b6aSSam Leffler * frames which all fit in MHLEN. 2308a1b9b6aSSam Leffler */ 2318a1b9b6aSSam Leffler if (m != NULL) 2328a1b9b6aSSam Leffler MH_ALIGN(m, len); 23368e8e04eSSam Leffler } else { 23434333b16SAndre Oppermann m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 23568e8e04eSSam Leffler if (m != NULL) 23668e8e04eSSam Leffler MC_ALIGN(m, len); 23768e8e04eSSam Leffler } 2388a1b9b6aSSam Leffler if (m != NULL) { 23998b33550SSepherosa Ziehau m->m_data += headroom; 2408a1b9b6aSSam Leffler *frm = m->m_data; 2418a1b9b6aSSam Leffler } 2428a1b9b6aSSam Leffler return m; 2438a1b9b6aSSam Leffler } 2448a1b9b6aSSam Leffler 24568e8e04eSSam Leffler int 24668e8e04eSSam Leffler ieee80211_add_callback(struct mbuf *m, 24768e8e04eSSam Leffler void (*func)(struct ieee80211_node *, void *, int), void *arg) 24868e8e04eSSam Leffler { 24968e8e04eSSam Leffler struct m_tag *mtag; 25068e8e04eSSam Leffler struct ieee80211_cb *cb; 25168e8e04eSSam Leffler 25268e8e04eSSam Leffler mtag = m_tag_alloc(MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, 25368e8e04eSSam Leffler sizeof(struct ieee80211_cb), M_NOWAIT); 25468e8e04eSSam Leffler if (mtag == NULL) 25568e8e04eSSam Leffler return 0; 25668e8e04eSSam Leffler 25768e8e04eSSam Leffler cb = (struct ieee80211_cb *)(mtag+1); 25868e8e04eSSam Leffler cb->func = func; 25968e8e04eSSam Leffler cb->arg = arg; 26068e8e04eSSam Leffler m_tag_prepend(m, mtag); 26168e8e04eSSam Leffler m->m_flags |= M_TXCB; 26268e8e04eSSam Leffler return 1; 26368e8e04eSSam Leffler } 26468e8e04eSSam Leffler 26568e8e04eSSam Leffler void 26668e8e04eSSam Leffler ieee80211_process_callback(struct ieee80211_node *ni, 26768e8e04eSSam Leffler struct mbuf *m, int status) 26868e8e04eSSam Leffler { 26968e8e04eSSam Leffler struct m_tag *mtag; 27068e8e04eSSam Leffler 27168e8e04eSSam Leffler mtag = m_tag_locate(m, MTAG_ABI_NET80211, NET80211_TAG_CALLBACK, NULL); 27268e8e04eSSam Leffler if (mtag != NULL) { 27368e8e04eSSam Leffler struct ieee80211_cb *cb = (struct ieee80211_cb *)(mtag+1); 27468e8e04eSSam Leffler cb->func(ni, cb->arg, status); 27568e8e04eSSam Leffler } 27668e8e04eSSam Leffler } 27768e8e04eSSam Leffler 2788a1b9b6aSSam Leffler #include <sys/libkern.h> 2798a1b9b6aSSam Leffler 2808a1b9b6aSSam Leffler void 2818a1b9b6aSSam Leffler get_random_bytes(void *p, size_t n) 2828a1b9b6aSSam Leffler { 28368e8e04eSSam Leffler uint8_t *dp = p; 2848a1b9b6aSSam Leffler 2858a1b9b6aSSam Leffler while (n > 0) { 28668e8e04eSSam Leffler uint32_t v = arc4random(); 28768e8e04eSSam Leffler size_t nb = n > sizeof(uint32_t) ? sizeof(uint32_t) : n; 28868e8e04eSSam Leffler bcopy(&v, dp, n > sizeof(uint32_t) ? sizeof(uint32_t) : n); 28968e8e04eSSam Leffler dp += sizeof(uint32_t), n -= nb; 2908a1b9b6aSSam Leffler } 2918a1b9b6aSSam Leffler } 2928a1b9b6aSSam Leffler 2938a1b9b6aSSam Leffler void 2948a1b9b6aSSam Leffler ieee80211_notify_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int newassoc) 2958a1b9b6aSSam Leffler { 2968a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 2978a1b9b6aSSam Leffler struct ieee80211_join_event iev; 2988a1b9b6aSSam Leffler 2998a1b9b6aSSam Leffler memset(&iev, 0, sizeof(iev)); 3000fc5fe12SSam Leffler if (ni == ic->ic_bss) { 3018a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_bssid); 3028a1b9b6aSSam Leffler rt_ieee80211msg(ifp, newassoc ? 3038a1b9b6aSSam Leffler RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, 3048a1b9b6aSSam Leffler &iev, sizeof(iev)); 3058a1b9b6aSSam Leffler if_link_state_change(ifp, LINK_STATE_UP); 3060fc5fe12SSam Leffler } else { 3078a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); 3080fc5fe12SSam Leffler rt_ieee80211msg(ifp, newassoc ? 3090fc5fe12SSam Leffler RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, 3100fc5fe12SSam Leffler &iev, sizeof(iev)); 3118a1b9b6aSSam Leffler } 3128a1b9b6aSSam Leffler } 3138a1b9b6aSSam Leffler 3148a1b9b6aSSam Leffler void 3158a1b9b6aSSam Leffler ieee80211_notify_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 3168a1b9b6aSSam Leffler { 3178a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 3188a1b9b6aSSam Leffler struct ieee80211_leave_event iev; 3198a1b9b6aSSam Leffler 3208a1b9b6aSSam Leffler if (ni == ic->ic_bss) { 3218a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); 3228a1b9b6aSSam Leffler if_link_state_change(ifp, LINK_STATE_DOWN); 3238a1b9b6aSSam Leffler } else { 3248a1b9b6aSSam Leffler /* fire off wireless event station leaving */ 3258a1b9b6aSSam Leffler memset(&iev, 0, sizeof(iev)); 3268a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); 3278a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_LEAVE, &iev, sizeof(iev)); 3288a1b9b6aSSam Leffler } 3298a1b9b6aSSam Leffler } 3308a1b9b6aSSam Leffler 3318a1b9b6aSSam Leffler void 3328a1b9b6aSSam Leffler ieee80211_notify_scan_done(struct ieee80211com *ic) 3338a1b9b6aSSam Leffler { 3348a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 3358a1b9b6aSSam Leffler 336f1bf5adeSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, "%s\n", "notify scan done"); 3378a1b9b6aSSam Leffler 3388a1b9b6aSSam Leffler /* dispatch wireless event indicating scan completed */ 3398a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); 3408a1b9b6aSSam Leffler } 3418a1b9b6aSSam Leffler 3428a1b9b6aSSam Leffler void 3438a1b9b6aSSam Leffler ieee80211_notify_replay_failure(struct ieee80211com *ic, 3448a1b9b6aSSam Leffler const struct ieee80211_frame *wh, const struct ieee80211_key *k, 3458a1b9b6aSSam Leffler u_int64_t rsc) 3468a1b9b6aSSam Leffler { 3478a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 3488a1b9b6aSSam Leffler 3498a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 350c1225b52SSam Leffler "[%s] %s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>\n", 3518a1b9b6aSSam Leffler ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name, 352c1225b52SSam Leffler (intmax_t) rsc, (intmax_t) k->wk_keyrsc, 353c1225b52SSam Leffler k->wk_keyix, k->wk_rxkeyix); 3548a1b9b6aSSam Leffler 3558a1b9b6aSSam Leffler if (ifp != NULL) { /* NB: for cipher test modules */ 3568a1b9b6aSSam Leffler struct ieee80211_replay_event iev; 3578a1b9b6aSSam Leffler 3588a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 3598a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 3608a1b9b6aSSam Leffler iev.iev_cipher = k->wk_cipher->ic_cipher; 361c1225b52SSam Leffler if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE) 362c1225b52SSam Leffler iev.iev_keyix = k->wk_rxkeyix; 363c1225b52SSam Leffler else 3648a1b9b6aSSam Leffler iev.iev_keyix = k->wk_keyix; 3658a1b9b6aSSam Leffler iev.iev_keyrsc = k->wk_keyrsc; 3668a1b9b6aSSam Leffler iev.iev_rsc = rsc; 3678a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); 3688a1b9b6aSSam Leffler } 3698a1b9b6aSSam Leffler } 3708a1b9b6aSSam Leffler 3718a1b9b6aSSam Leffler void 3728a1b9b6aSSam Leffler ieee80211_notify_michael_failure(struct ieee80211com *ic, 3738a1b9b6aSSam Leffler const struct ieee80211_frame *wh, u_int keyix) 3748a1b9b6aSSam Leffler { 3758a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 3768a1b9b6aSSam Leffler 3778a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 378da615e95SSam Leffler "[%s] michael MIC verification failed <keyix %u>\n", 3798a1b9b6aSSam Leffler ether_sprintf(wh->i_addr2), keyix); 3808a1b9b6aSSam Leffler ic->ic_stats.is_rx_tkipmic++; 3818a1b9b6aSSam Leffler 3828a1b9b6aSSam Leffler if (ifp != NULL) { /* NB: for cipher test modules */ 3838a1b9b6aSSam Leffler struct ieee80211_michael_event iev; 3848a1b9b6aSSam Leffler 3858a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 3868a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 3878a1b9b6aSSam Leffler iev.iev_cipher = IEEE80211_CIPHER_TKIP; 3888a1b9b6aSSam Leffler iev.iev_keyix = keyix; 3898a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); 3908a1b9b6aSSam Leffler } 3918a1b9b6aSSam Leffler } 3928a1b9b6aSSam Leffler 3938a1b9b6aSSam Leffler void 3948a1b9b6aSSam Leffler ieee80211_load_module(const char *modname) 3958a1b9b6aSSam Leffler { 3968a1b9b6aSSam Leffler 397edd32c2dSJohn Baldwin #ifdef notyet 398edd32c2dSJohn Baldwin (void)kern_kldload(curthread, modname, NULL); 399472f08caSSam Leffler #else 400472f08caSSam Leffler printf("%s: load the %s module by hand for now.\n", __func__, modname); 401472f08caSSam Leffler #endif 4028a1b9b6aSSam Leffler } 4038a1b9b6aSSam Leffler 4048a1b9b6aSSam Leffler /* 4058a1b9b6aSSam Leffler * Module glue. 4068a1b9b6aSSam Leffler * 4078a1b9b6aSSam Leffler * NB: the module name is "wlan" for compatibility with NetBSD. 4088a1b9b6aSSam Leffler */ 4098a1b9b6aSSam Leffler static int 4108a1b9b6aSSam Leffler wlan_modevent(module_t mod, int type, void *unused) 4118a1b9b6aSSam Leffler { 4128a1b9b6aSSam Leffler switch (type) { 4138a1b9b6aSSam Leffler case MOD_LOAD: 4148a1b9b6aSSam Leffler if (bootverbose) 4158a1b9b6aSSam Leffler printf("wlan: <802.11 Link Layer>\n"); 4168a1b9b6aSSam Leffler return 0; 4178a1b9b6aSSam Leffler case MOD_UNLOAD: 4188a1b9b6aSSam Leffler return 0; 4198a1b9b6aSSam Leffler } 4208a1b9b6aSSam Leffler return EINVAL; 4218a1b9b6aSSam Leffler } 4228a1b9b6aSSam Leffler 4238a1b9b6aSSam Leffler static moduledata_t wlan_mod = { 4248a1b9b6aSSam Leffler "wlan", 4258a1b9b6aSSam Leffler wlan_modevent, 4268a1b9b6aSSam Leffler 0 4278a1b9b6aSSam Leffler }; 4288a1b9b6aSSam Leffler DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 4298a1b9b6aSSam Leffler MODULE_VERSION(wlan, 1); 4308a1b9b6aSSam Leffler MODULE_DEPEND(wlan, ether, 1, 1, 1); 431