18a1b9b6aSSam Leffler /*- 21f1d7810SSam Leffler * Copyright (c) 2003-2005 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 * 3. The name of the author may not be used to endorse or promote products 148a1b9b6aSSam Leffler * derived from this software without specific prior written permission. 158a1b9b6aSSam Leffler * 168a1b9b6aSSam Leffler * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 178a1b9b6aSSam Leffler * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 188a1b9b6aSSam Leffler * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 198a1b9b6aSSam Leffler * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 208a1b9b6aSSam Leffler * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 218a1b9b6aSSam Leffler * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 228a1b9b6aSSam Leffler * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 238a1b9b6aSSam Leffler * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 248a1b9b6aSSam Leffler * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 258a1b9b6aSSam Leffler * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 268a1b9b6aSSam Leffler */ 278a1b9b6aSSam Leffler 288a1b9b6aSSam Leffler #include <sys/cdefs.h> 298a1b9b6aSSam Leffler __FBSDID("$FreeBSD$"); 308a1b9b6aSSam Leffler 318a1b9b6aSSam Leffler /* 328a1b9b6aSSam Leffler * IEEE 802.11 support (FreeBSD-specific code) 338a1b9b6aSSam Leffler */ 348a1b9b6aSSam Leffler #include <sys/param.h> 358a1b9b6aSSam Leffler #include <sys/kernel.h> 368a1b9b6aSSam Leffler #include <sys/systm.h> 378a1b9b6aSSam Leffler #include <sys/linker.h> 388a1b9b6aSSam Leffler #include <sys/mbuf.h> 398a1b9b6aSSam Leffler #include <sys/module.h> 408a1b9b6aSSam Leffler #include <sys/proc.h> 418a1b9b6aSSam Leffler #include <sys/sysctl.h> 428a1b9b6aSSam Leffler 438a1b9b6aSSam Leffler #include <sys/socket.h> 448a1b9b6aSSam Leffler 458a1b9b6aSSam Leffler #include <net/if.h> 468a1b9b6aSSam Leffler #include <net/if_media.h> 478a1b9b6aSSam Leffler #include <net/ethernet.h> 488a1b9b6aSSam Leffler #include <net/route.h> 498a1b9b6aSSam Leffler 508a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h> 518a1b9b6aSSam Leffler 528a1b9b6aSSam Leffler SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters"); 538a1b9b6aSSam Leffler 548a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 558a1b9b6aSSam Leffler int ieee80211_debug = 0; 568a1b9b6aSSam Leffler SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug, 578a1b9b6aSSam Leffler 0, "debugging printfs"); 588a1b9b6aSSam Leffler #endif 598a1b9b6aSSam Leffler 608a1b9b6aSSam Leffler static int 618a1b9b6aSSam Leffler ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS) 628a1b9b6aSSam Leffler { 638a1b9b6aSSam Leffler int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT; 648a1b9b6aSSam Leffler int error; 658a1b9b6aSSam Leffler 668a1b9b6aSSam Leffler error = sysctl_handle_int(oidp, &inact, 0, req); 678a1b9b6aSSam Leffler if (error || !req->newptr) 688a1b9b6aSSam Leffler return error; 698a1b9b6aSSam Leffler *(int *)arg1 = inact / IEEE80211_INACT_WAIT; 708a1b9b6aSSam Leffler return 0; 718a1b9b6aSSam Leffler } 728a1b9b6aSSam Leffler 738a1b9b6aSSam Leffler static int 748a1b9b6aSSam Leffler ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS) 758a1b9b6aSSam Leffler { 768a1b9b6aSSam Leffler struct ieee80211com *ic = arg1; 778a1b9b6aSSam Leffler const char *name = ic->ic_ifp->if_xname; 788a1b9b6aSSam Leffler 798a1b9b6aSSam Leffler return SYSCTL_OUT(req, name, strlen(name)); 808a1b9b6aSSam Leffler } 818a1b9b6aSSam Leffler 828a1b9b6aSSam Leffler void 838a1b9b6aSSam Leffler ieee80211_sysctl_attach(struct ieee80211com *ic) 848a1b9b6aSSam Leffler { 858a1b9b6aSSam Leffler struct sysctl_ctx_list *ctx; 868a1b9b6aSSam Leffler struct sysctl_oid *oid; 878a1b9b6aSSam Leffler char num[14]; /* sufficient for 32 bits */ 888a1b9b6aSSam Leffler 898a1b9b6aSSam Leffler MALLOC(ctx, struct sysctl_ctx_list *, sizeof(struct sysctl_ctx_list), 908a1b9b6aSSam Leffler M_DEVBUF, M_NOWAIT | M_ZERO); 918a1b9b6aSSam Leffler if (ctx == NULL) { 928a1b9b6aSSam Leffler if_printf(ic->ic_ifp, "%s: cannot allocate sysctl context!\n", 938a1b9b6aSSam Leffler __func__); 948a1b9b6aSSam Leffler return; 958a1b9b6aSSam Leffler } 968a1b9b6aSSam Leffler sysctl_ctx_init(ctx); 978a1b9b6aSSam Leffler snprintf(num, sizeof(num), "%u", ic->ic_vap); 988a1b9b6aSSam Leffler oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan), 998a1b9b6aSSam Leffler OID_AUTO, num, CTLFLAG_RD, NULL, ""); 1008a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1018a1b9b6aSSam Leffler "%parent", CTLFLAG_RD, ic, 0, ieee80211_sysctl_parent, "A", 1028a1b9b6aSSam Leffler "parent device"); 1038a1b9b6aSSam Leffler #ifdef IEEE80211_DEBUG 1048a1b9b6aSSam Leffler ic->ic_debug = ieee80211_debug; 1058a1b9b6aSSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1068a1b9b6aSSam Leffler "debug", CTLFLAG_RW, &ic->ic_debug, 0, 1078a1b9b6aSSam Leffler "control debugging printfs"); 1088a1b9b6aSSam Leffler #endif 1098a1b9b6aSSam Leffler /* XXX inherit from tunables */ 1108a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 111e5a96ac7SSam Leffler "inact_run", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_run, 0, 1128a1b9b6aSSam Leffler ieee80211_sysctl_inact, "I", 1138a1b9b6aSSam Leffler "station inactivity timeout (sec)"); 1148a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1158a1b9b6aSSam Leffler "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_probe, 0, 1168a1b9b6aSSam Leffler ieee80211_sysctl_inact, "I", 1178a1b9b6aSSam Leffler "station inactivity probe timeout (sec)"); 1188a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1198a1b9b6aSSam Leffler "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_auth, 0, 1208a1b9b6aSSam Leffler ieee80211_sysctl_inact, "I", 1218a1b9b6aSSam Leffler "station authentication timeout (sec)"); 1228a1b9b6aSSam Leffler SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 1238a1b9b6aSSam Leffler "inact_init", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_init, 0, 1248a1b9b6aSSam Leffler ieee80211_sysctl_inact, "I", 1258a1b9b6aSSam Leffler "station initial state timeout (sec)"); 126da615e95SSam Leffler SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 127da615e95SSam Leffler "driver_caps", CTLFLAG_RW, &ic->ic_caps, 0, 128da615e95SSam Leffler "driver capabilities"); 1298a1b9b6aSSam Leffler ic->ic_sysctl = ctx; 1308a1b9b6aSSam Leffler } 1318a1b9b6aSSam Leffler 1328a1b9b6aSSam Leffler void 1338a1b9b6aSSam Leffler ieee80211_sysctl_detach(struct ieee80211com *ic) 1348a1b9b6aSSam Leffler { 1358a1b9b6aSSam Leffler 1368a1b9b6aSSam Leffler if (ic->ic_sysctl != NULL) { 1378a1b9b6aSSam Leffler sysctl_ctx_free(ic->ic_sysctl); 1388a1b9b6aSSam Leffler ic->ic_sysctl = NULL; 1398a1b9b6aSSam Leffler } 1408a1b9b6aSSam Leffler } 1418a1b9b6aSSam Leffler 1428a1b9b6aSSam Leffler int 1438a1b9b6aSSam Leffler ieee80211_node_dectestref(struct ieee80211_node *ni) 1448a1b9b6aSSam Leffler { 1458a1b9b6aSSam Leffler /* XXX need equivalent of atomic_dec_and_test */ 1468a1b9b6aSSam Leffler atomic_subtract_int(&ni->ni_refcnt, 1); 1478a1b9b6aSSam Leffler return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); 1488a1b9b6aSSam Leffler } 1498a1b9b6aSSam Leffler 1508a1b9b6aSSam Leffler /* 1518a1b9b6aSSam Leffler * Allocate and setup a management frame of the specified 1528a1b9b6aSSam Leffler * size. We return the mbuf and a pointer to the start 1538a1b9b6aSSam Leffler * of the contiguous data area that's been reserved based 1548a1b9b6aSSam Leffler * on the packet length. The data area is forced to 32-bit 1558a1b9b6aSSam Leffler * alignment and the buffer length to a multiple of 4 bytes. 1568a1b9b6aSSam Leffler * This is done mainly so beacon frames (that require this) 1578a1b9b6aSSam Leffler * can use this interface too. 1588a1b9b6aSSam Leffler */ 1598a1b9b6aSSam Leffler struct mbuf * 1608a1b9b6aSSam Leffler ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen) 1618a1b9b6aSSam Leffler { 1628a1b9b6aSSam Leffler struct mbuf *m; 1638a1b9b6aSSam Leffler u_int len; 1648a1b9b6aSSam Leffler 1658a1b9b6aSSam Leffler /* 1668a1b9b6aSSam Leffler * NB: we know the mbuf routines will align the data area 1678a1b9b6aSSam Leffler * so we don't need to do anything special. 1688a1b9b6aSSam Leffler */ 1698a1b9b6aSSam Leffler /* XXX 4-address frame? */ 1708a1b9b6aSSam Leffler len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4); 1718a1b9b6aSSam Leffler KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); 1728a1b9b6aSSam Leffler if (len < MINCLSIZE) { 1738a1b9b6aSSam Leffler m = m_gethdr(M_NOWAIT, MT_HEADER); 1748a1b9b6aSSam Leffler /* 1758a1b9b6aSSam Leffler * Align the data in case additional headers are added. 1768a1b9b6aSSam Leffler * This should only happen when a WEP header is added 1778a1b9b6aSSam Leffler * which only happens for shared key authentication mgt 1788a1b9b6aSSam Leffler * frames which all fit in MHLEN. 1798a1b9b6aSSam Leffler */ 1808a1b9b6aSSam Leffler if (m != NULL) 1818a1b9b6aSSam Leffler MH_ALIGN(m, len); 1828a1b9b6aSSam Leffler } else 1838a1b9b6aSSam Leffler m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR); 1848a1b9b6aSSam Leffler if (m != NULL) { 1858a1b9b6aSSam Leffler m->m_data += sizeof(struct ieee80211_frame); 1868a1b9b6aSSam Leffler *frm = m->m_data; 1878a1b9b6aSSam Leffler } 1888a1b9b6aSSam Leffler return m; 1898a1b9b6aSSam Leffler } 1908a1b9b6aSSam Leffler 1918a1b9b6aSSam Leffler #include <sys/libkern.h> 1928a1b9b6aSSam Leffler 1938a1b9b6aSSam Leffler void 1948a1b9b6aSSam Leffler get_random_bytes(void *p, size_t n) 1958a1b9b6aSSam Leffler { 1968a1b9b6aSSam Leffler u_int8_t *dp = p; 1978a1b9b6aSSam Leffler 1988a1b9b6aSSam Leffler while (n > 0) { 1998a1b9b6aSSam Leffler u_int32_t v = arc4random(); 2008a1b9b6aSSam Leffler size_t nb = n > sizeof(u_int32_t) ? sizeof(u_int32_t) : n; 2018a1b9b6aSSam Leffler bcopy(&v, dp, n > sizeof(u_int32_t) ? sizeof(u_int32_t) : n); 2028a1b9b6aSSam Leffler dp += sizeof(u_int32_t), n -= nb; 2038a1b9b6aSSam Leffler } 2048a1b9b6aSSam Leffler } 2058a1b9b6aSSam Leffler 2068a1b9b6aSSam Leffler void 2078a1b9b6aSSam Leffler ieee80211_notify_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int newassoc) 2088a1b9b6aSSam Leffler { 2098a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 2108a1b9b6aSSam Leffler struct ieee80211_join_event iev; 2118a1b9b6aSSam Leffler 2128a1b9b6aSSam Leffler memset(&iev, 0, sizeof(iev)); 2130fc5fe12SSam Leffler if (ni == ic->ic_bss) { 2148a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_bssid); 2158a1b9b6aSSam Leffler rt_ieee80211msg(ifp, newassoc ? 2168a1b9b6aSSam Leffler RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, 2178a1b9b6aSSam Leffler &iev, sizeof(iev)); 2188a1b9b6aSSam Leffler if_link_state_change(ifp, LINK_STATE_UP); 2190fc5fe12SSam Leffler } else { 2208a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); 2210fc5fe12SSam Leffler rt_ieee80211msg(ifp, newassoc ? 2220fc5fe12SSam Leffler RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, 2230fc5fe12SSam Leffler &iev, sizeof(iev)); 2248a1b9b6aSSam Leffler } 2258a1b9b6aSSam Leffler } 2268a1b9b6aSSam Leffler 2278a1b9b6aSSam Leffler void 2288a1b9b6aSSam Leffler ieee80211_notify_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 2298a1b9b6aSSam Leffler { 2308a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 2318a1b9b6aSSam Leffler struct ieee80211_leave_event iev; 2328a1b9b6aSSam Leffler 2338a1b9b6aSSam Leffler if (ni == ic->ic_bss) { 2348a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); 2358a1b9b6aSSam Leffler if_link_state_change(ifp, LINK_STATE_DOWN); 2368a1b9b6aSSam Leffler } else { 2378a1b9b6aSSam Leffler /* fire off wireless event station leaving */ 2388a1b9b6aSSam Leffler memset(&iev, 0, sizeof(iev)); 2398a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); 2408a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_LEAVE, &iev, sizeof(iev)); 2418a1b9b6aSSam Leffler } 2428a1b9b6aSSam Leffler } 2438a1b9b6aSSam Leffler 2448a1b9b6aSSam Leffler void 2458a1b9b6aSSam Leffler ieee80211_notify_scan_done(struct ieee80211com *ic) 2468a1b9b6aSSam Leffler { 2478a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 2488a1b9b6aSSam Leffler 2498a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 2508a1b9b6aSSam Leffler "%s: notify scan done\n", ic->ic_ifp->if_xname); 2518a1b9b6aSSam Leffler 2528a1b9b6aSSam Leffler /* dispatch wireless event indicating scan completed */ 2538a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); 2548a1b9b6aSSam Leffler } 2558a1b9b6aSSam Leffler 2568a1b9b6aSSam Leffler void 2578a1b9b6aSSam Leffler ieee80211_notify_replay_failure(struct ieee80211com *ic, 2588a1b9b6aSSam Leffler const struct ieee80211_frame *wh, const struct ieee80211_key *k, 2598a1b9b6aSSam Leffler u_int64_t rsc) 2608a1b9b6aSSam Leffler { 2618a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 2628a1b9b6aSSam Leffler 2638a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 264da615e95SSam Leffler "[%s] %s replay detected <rsc %ju, csc %ju, keyix %u>\n", 2658a1b9b6aSSam Leffler ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name, 266da615e95SSam Leffler (intmax_t) rsc, (intmax_t) k->wk_keyrsc, k->wk_keyix); 2678a1b9b6aSSam Leffler 2688a1b9b6aSSam Leffler if (ifp != NULL) { /* NB: for cipher test modules */ 2698a1b9b6aSSam Leffler struct ieee80211_replay_event iev; 2708a1b9b6aSSam Leffler 2718a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 2728a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 2738a1b9b6aSSam Leffler iev.iev_cipher = k->wk_cipher->ic_cipher; 2748a1b9b6aSSam Leffler iev.iev_keyix = k->wk_keyix; 2758a1b9b6aSSam Leffler iev.iev_keyrsc = k->wk_keyrsc; 2768a1b9b6aSSam Leffler iev.iev_rsc = rsc; 2778a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); 2788a1b9b6aSSam Leffler } 2798a1b9b6aSSam Leffler } 2808a1b9b6aSSam Leffler 2818a1b9b6aSSam Leffler void 2828a1b9b6aSSam Leffler ieee80211_notify_michael_failure(struct ieee80211com *ic, 2838a1b9b6aSSam Leffler const struct ieee80211_frame *wh, u_int keyix) 2848a1b9b6aSSam Leffler { 2858a1b9b6aSSam Leffler struct ifnet *ifp = ic->ic_ifp; 2868a1b9b6aSSam Leffler 2878a1b9b6aSSam Leffler IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 288da615e95SSam Leffler "[%s] michael MIC verification failed <keyix %u>\n", 2898a1b9b6aSSam Leffler ether_sprintf(wh->i_addr2), keyix); 2908a1b9b6aSSam Leffler ic->ic_stats.is_rx_tkipmic++; 2918a1b9b6aSSam Leffler 2928a1b9b6aSSam Leffler if (ifp != NULL) { /* NB: for cipher test modules */ 2938a1b9b6aSSam Leffler struct ieee80211_michael_event iev; 2948a1b9b6aSSam Leffler 2958a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 2968a1b9b6aSSam Leffler IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 2978a1b9b6aSSam Leffler iev.iev_cipher = IEEE80211_CIPHER_TKIP; 2988a1b9b6aSSam Leffler iev.iev_keyix = keyix; 2998a1b9b6aSSam Leffler rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); 3008a1b9b6aSSam Leffler } 3018a1b9b6aSSam Leffler } 3028a1b9b6aSSam Leffler 3038a1b9b6aSSam Leffler void 3048a1b9b6aSSam Leffler ieee80211_load_module(const char *modname) 3058a1b9b6aSSam Leffler { 306472f08caSSam Leffler #ifdef notyet 3078a1b9b6aSSam Leffler struct thread *td = curthread; 3088a1b9b6aSSam Leffler 3098a1b9b6aSSam Leffler if (suser(td) == 0 && securelevel_gt(td->td_ucred, 0) == 0) { 3108a1b9b6aSSam Leffler mtx_lock(&Giant); 3118a1b9b6aSSam Leffler (void) linker_load_module(modname, NULL, NULL, NULL, NULL); 3128a1b9b6aSSam Leffler mtx_unlock(&Giant); 3138a1b9b6aSSam Leffler } 314472f08caSSam Leffler #else 315472f08caSSam Leffler printf("%s: load the %s module by hand for now.\n", __func__, modname); 316472f08caSSam Leffler #endif 3178a1b9b6aSSam Leffler } 3188a1b9b6aSSam Leffler 3198a1b9b6aSSam Leffler /* 3208a1b9b6aSSam Leffler * Module glue. 3218a1b9b6aSSam Leffler * 3228a1b9b6aSSam Leffler * NB: the module name is "wlan" for compatibility with NetBSD. 3238a1b9b6aSSam Leffler */ 3248a1b9b6aSSam Leffler static int 3258a1b9b6aSSam Leffler wlan_modevent(module_t mod, int type, void *unused) 3268a1b9b6aSSam Leffler { 3278a1b9b6aSSam Leffler switch (type) { 3288a1b9b6aSSam Leffler case MOD_LOAD: 3298a1b9b6aSSam Leffler if (bootverbose) 3308a1b9b6aSSam Leffler printf("wlan: <802.11 Link Layer>\n"); 3318a1b9b6aSSam Leffler return 0; 3328a1b9b6aSSam Leffler case MOD_UNLOAD: 3338a1b9b6aSSam Leffler return 0; 3348a1b9b6aSSam Leffler } 3358a1b9b6aSSam Leffler return EINVAL; 3368a1b9b6aSSam Leffler } 3378a1b9b6aSSam Leffler 3388a1b9b6aSSam Leffler static moduledata_t wlan_mod = { 3398a1b9b6aSSam Leffler "wlan", 3408a1b9b6aSSam Leffler wlan_modevent, 3418a1b9b6aSSam Leffler 0 3428a1b9b6aSSam Leffler }; 3438a1b9b6aSSam Leffler DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 3448a1b9b6aSSam Leffler MODULE_VERSION(wlan, 1); 3458a1b9b6aSSam Leffler MODULE_DEPEND(wlan, ether, 1, 1, 1); 346