ieee80211_freebsd.c revision 159590
1170530Ssam/*- 2186904Ssam * Copyright (c) 2003-2005 Sam Leffler, Errno Consulting 3170530Ssam * All rights reserved. 4170530Ssam * 5170530Ssam * Redistribution and use in source and binary forms, with or without 6170530Ssam * modification, are permitted provided that the following conditions 7170530Ssam * are met: 8170530Ssam * 1. Redistributions of source code must retain the above copyright 9170530Ssam * notice, this list of conditions and the following disclaimer. 10170530Ssam * 2. Redistributions in binary form must reproduce the above copyright 11170530Ssam * notice, this list of conditions and the following disclaimer in the 12170530Ssam * documentation and/or other materials provided with the distribution. 13170530Ssam * 3. The name of the author may not be used to endorse or promote products 14170530Ssam * derived from this software without specific prior written permission. 15170530Ssam * 16170530Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17170530Ssam * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18170530Ssam * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19170530Ssam * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20170530Ssam * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21170530Ssam * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22170530Ssam * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23170530Ssam * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24170530Ssam * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25170530Ssam * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26170530Ssam */ 27170530Ssam 28170530Ssam#include <sys/cdefs.h> 29170530Ssam__FBSDID("$FreeBSD: head/sys/net80211/ieee80211_freebsd.c 159590 2006-06-13 21:36:23Z jhb $"); 30170530Ssam 31170530Ssam/* 32178354Ssam * IEEE 802.11 support (FreeBSD-specific code) 33178354Ssam */ 34170530Ssam#include <sys/param.h> 35191746Sthompsa#include <sys/kernel.h> 36170530Ssam#include <sys/systm.h> 37298359Savos#include <sys/linker.h> 38295126Sglebius#include <sys/mbuf.h> 39170530Ssam#include <sys/module.h> 40191746Sthompsa#include <sys/proc.h> 41170530Ssam#include <sys/sysctl.h> 42170530Ssam 43170530Ssam#include <sys/socket.h> 44257176Sglebius 45170530Ssam#include <net/if.h> 46170530Ssam#include <net/if_media.h> 47170530Ssam#include <net/ethernet.h> 48170530Ssam#include <net/route.h> 49178354Ssam 50178354Ssam#include <net80211/ieee80211_var.h> 51186904Ssam 52186904SsamSYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters"); 53186904Ssam 54195618Srpaulo#ifdef IEEE80211_DEBUG 55195618Srpauloint ieee80211_debug = 0; 56195618SrpauloSYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug, 57245928Sadrian 0, "debugging printfs"); 58170530Ssam#endif 59170530Ssam 60170530Ssamstatic int 61170530Ssamieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS) 62170530Ssam{ 63170530Ssam int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT; 64170530Ssam int error; 65170530Ssam 66170530Ssam error = sysctl_handle_int(oidp, &inact, 0, req); 67170530Ssam if (error || !req->newptr) 68170530Ssam return error; 69170530Ssam *(int *)arg1 = inact / IEEE80211_INACT_WAIT; 70170530Ssam return 0; 71170530Ssam} 72170530Ssam 73170530Ssamstatic int 74170530Ssamieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS) 75170530Ssam{ 76170530Ssam struct ieee80211com *ic = arg1; 77170530Ssam const char *name = ic->ic_ifp->if_xname; 78170530Ssam 79170530Ssam return SYSCTL_OUT(req, name, strlen(name)); 80170530Ssam} 81170530Ssam 82170530Ssamvoid 83170530Ssamieee80211_sysctl_attach(struct ieee80211com *ic) 84170530Ssam{ 85170530Ssam struct sysctl_ctx_list *ctx; 86184302Ssam struct sysctl_oid *oid; 87170530Ssam char num[14]; /* sufficient for 32 bits */ 88170530Ssam 89170530Ssam MALLOC(ctx, struct sysctl_ctx_list *, sizeof(struct sysctl_ctx_list), 90170530Ssam M_DEVBUF, M_NOWAIT | M_ZERO); 91170530Ssam if (ctx == NULL) { 92178354Ssam if_printf(ic->ic_ifp, "%s: cannot allocate sysctl context!\n", 93170530Ssam __func__); 94170530Ssam return; 95170530Ssam } 96170530Ssam sysctl_ctx_init(ctx); 97170530Ssam snprintf(num, sizeof(num), "%u", ic->ic_vap); 98170530Ssam oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan), 99170530Ssam OID_AUTO, num, CTLFLAG_RD, NULL, ""); 100186107Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 101186107Ssam "%parent", CTLFLAG_RD, ic, 0, ieee80211_sysctl_parent, "A", 102186107Ssam "parent device"); 103170530Ssam#ifdef IEEE80211_DEBUG 104206617Srpaulo ic->ic_debug = ieee80211_debug; 105170530Ssam SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 106170530Ssam "debug", CTLFLAG_RW, &ic->ic_debug, 0, 107283556Sadrian "control debugging printfs"); 108178354Ssam#endif 109178354Ssam /* XXX inherit from tunables */ 110170530Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 111178354Ssam "inact_run", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_run, 0, 112186107Ssam ieee80211_sysctl_inact, "I", 113170530Ssam "station inactivity timeout (sec)"); 114170530Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 115170530Ssam "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_probe, 0, 116171409Ssam ieee80211_sysctl_inact, "I", 117171409Ssam "station inactivity probe timeout (sec)"); 118171409Ssam SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 119330446Seadler "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_auth, 0, 120171409Ssam ieee80211_sysctl_inact, "I", 121171409Ssam "station authentication timeout (sec)"); 122195618Srpaulo SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 123195618Srpaulo "inact_init", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_init, 0, 124195618Srpaulo ieee80211_sysctl_inact, "I", 125195618Srpaulo "station initial state timeout (sec)"); 126195618Srpaulo SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 127195618Srpaulo "driver_caps", CTLFLAG_RW, &ic->ic_caps, 0, 128195618Srpaulo "driver capabilities"); 129195618Srpaulo SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, 130195618Srpaulo "bmiss_max", CTLFLAG_RW, &ic->ic_bmiss_max, 0, 131195618Srpaulo "consecutive beacon misses before scanning"); 132300232Savos ic->ic_sysctl = ctx; 133195618Srpaulo} 134195618Srpaulo 135195618Srpaulovoid 136195618Srpauloieee80211_sysctl_detach(struct ieee80211com *ic) 137195618Srpaulo{ 138300232Savos 139195618Srpaulo if (ic->ic_sysctl != NULL) { 140195618Srpaulo sysctl_ctx_free(ic->ic_sysctl); 141178354Ssam ic->ic_sysctl = NULL; 142170530Ssam } 143178354Ssam} 144170530Ssam 145178354Ssamint 146178354Ssamieee80211_node_dectestref(struct ieee80211_node *ni) 147178354Ssam{ 148178354Ssam /* XXX need equivalent of atomic_dec_and_test */ 149178354Ssam atomic_subtract_int(&ni->ni_refcnt, 1); 150178354Ssam return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); 151170530Ssam} 152170530Ssam 153195618Srpaulo/* 154195618Srpaulo * Allocate and setup a management frame of the specified 155195618Srpaulo * size. We return the mbuf and a pointer to the start 156195618Srpaulo * of the contiguous data area that's been reserved based 157170530Ssam * on the packet length. The data area is forced to 32-bit 158170530Ssam * alignment and the buffer length to a multiple of 4 bytes. 159170530Ssam * This is done mainly so beacon frames (that require this) 160170530Ssam * can use this interface too. 161170530Ssam */ 162170530Ssamstruct mbuf * 163170530Ssamieee80211_getmgtframe(u_int8_t **frm, u_int pktlen) 164170530Ssam{ 165170530Ssam struct mbuf *m; 166283538Sadrian u_int len; 167283538Sadrian 168283538Sadrian /* 169170530Ssam * NB: we know the mbuf routines will align the data area 170170530Ssam * so we don't need to do anything special. 171206617Srpaulo */ 172283556Sadrian /* XXX 4-address frame? */ 173170530Ssam len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4); 174170530Ssam KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); 175170530Ssam if (len < MINCLSIZE) { 176170530Ssam m = m_gethdr(M_NOWAIT, MT_DATA); 177170530Ssam /* 178170530Ssam * Align the data in case additional headers are added. 179170530Ssam * This should only happen when a WEP header is added 180170530Ssam * which only happens for shared key authentication mgt 181170530Ssam * frames which all fit in MHLEN. 182170530Ssam */ 183170530Ssam if (m != NULL) 184170530Ssam MH_ALIGN(m, len); 185170530Ssam } else 186170530Ssam m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 187170530Ssam if (m != NULL) { 188170530Ssam m->m_data += sizeof(struct ieee80211_frame); 189206617Srpaulo *frm = m->m_data; 190283556Sadrian } 191283538Sadrian return m; 192170530Ssam} 193170530Ssam 194170530Ssam#include <sys/libkern.h> 195170530Ssam 196170530Ssamvoid 197170530Ssamget_random_bytes(void *p, size_t n) 198170530Ssam{ 199170530Ssam u_int8_t *dp = p; 200170530Ssam 201170530Ssam while (n > 0) { 202170530Ssam u_int32_t v = arc4random(); 203170530Ssam size_t nb = n > sizeof(u_int32_t) ? sizeof(u_int32_t) : n; 204170530Ssam bcopy(&v, dp, n > sizeof(u_int32_t) ? sizeof(u_int32_t) : n); 205170530Ssam dp += sizeof(u_int32_t), n -= nb; 206206617Srpaulo } 207170530Ssam} 208206617Srpaulo 209170530Ssamvoid 210170530Ssamieee80211_notify_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int newassoc) 211170530Ssam{ 212170530Ssam struct ifnet *ifp = ic->ic_ifp; 213170530Ssam struct ieee80211_join_event iev; 214170530Ssam 215170530Ssam memset(&iev, 0, sizeof(iev)); 216170530Ssam if (ni == ic->ic_bss) { 217170530Ssam IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_bssid); 218170530Ssam rt_ieee80211msg(ifp, newassoc ? 219170530Ssam RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, 220170530Ssam &iev, sizeof(iev)); 221170530Ssam if_link_state_change(ifp, LINK_STATE_UP); 222170530Ssam } else { 223170530Ssam IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); 224178354Ssam rt_ieee80211msg(ifp, newassoc ? 225283538Sadrian RTM_IEEE80211_JOIN : RTM_IEEE80211_REJOIN, 226170530Ssam &iev, sizeof(iev)); 227178354Ssam } 228170530Ssam} 229170530Ssam 230170530Ssamvoid 231170530Ssamieee80211_notify_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) 232170530Ssam{ 233170530Ssam struct ifnet *ifp = ic->ic_ifp; 234170530Ssam struct ieee80211_leave_event iev; 235170530Ssam 236282742Sadrian if (ni == ic->ic_bss) { 237170530Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); 238170530Ssam if_link_state_change(ifp, LINK_STATE_DOWN); 239192468Ssam } else { 240170530Ssam /* fire off wireless event station leaving */ 241170530Ssam memset(&iev, 0, sizeof(iev)); 242170530Ssam IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); 243170530Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_LEAVE, &iev, sizeof(iev)); 244170530Ssam } 245170530Ssam} 246170530Ssam 247178354Ssamvoid 248178354Ssamieee80211_notify_scan_done(struct ieee80211com *ic) 249224717Sbschmidt{ 250170530Ssam struct ifnet *ifp = ic->ic_ifp; 251170530Ssam 252178354Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, 253170530Ssam "%s: notify scan done\n", ic->ic_ifp->if_xname); 254170530Ssam 255170530Ssam /* dispatch wireless event indicating scan completed */ 256206617Srpaulo rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); 257170530Ssam} 258170530Ssam 259170530Ssamvoid 260283538Sadrianieee80211_notify_replay_failure(struct ieee80211com *ic, 261283538Sadrian const struct ieee80211_frame *wh, const struct ieee80211_key *k, 262170530Ssam u_int64_t rsc) 263206617Srpaulo{ 264170530Ssam struct ifnet *ifp = ic->ic_ifp; 265170530Ssam 266178354Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 267178354Ssam "[%s] %s replay detected <rsc %ju, csc %ju, keyix %u rxkeyix %u>\n", 268170530Ssam ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name, 269170530Ssam (intmax_t) rsc, (intmax_t) k->wk_keyrsc, 270170530Ssam k->wk_keyix, k->wk_rxkeyix); 271170530Ssam 272170530Ssam if (ifp != NULL) { /* NB: for cipher test modules */ 273170530Ssam struct ieee80211_replay_event iev; 274170530Ssam 275170530Ssam IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 276170530Ssam IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 277170530Ssam iev.iev_cipher = k->wk_cipher->ic_cipher; 278170530Ssam if (k->wk_rxkeyix != IEEE80211_KEYIX_NONE) 279170530Ssam iev.iev_keyix = k->wk_rxkeyix; 280170530Ssam else 281170530Ssam iev.iev_keyix = k->wk_keyix; 282178354Ssam iev.iev_keyrsc = k->wk_keyrsc; 283170530Ssam iev.iev_rsc = rsc; 284170530Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); 285170530Ssam } 286170530Ssam} 287170530Ssam 288178354Ssamvoid 289173368Ssamieee80211_notify_michael_failure(struct ieee80211com *ic, 290173368Ssam const struct ieee80211_frame *wh, u_int keyix) 291173368Ssam{ 292173368Ssam struct ifnet *ifp = ic->ic_ifp; 293173368Ssam 294173368Ssam IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, 295178354Ssam "[%s] michael MIC verification failed <keyix %u>\n", 296178354Ssam ether_sprintf(wh->i_addr2), keyix); 297173368Ssam ic->ic_stats.is_rx_tkipmic++; 298173368Ssam 299170530Ssam if (ifp != NULL) { /* NB: for cipher test modules */ 300170530Ssam struct ieee80211_michael_event iev; 301170530Ssam 302195618Srpaulo IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); 303195618Srpaulo IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); 304195618Srpaulo iev.iev_cipher = IEEE80211_CIPHER_TKIP; 305195618Srpaulo iev.iev_keyix = keyix; 306173368Ssam rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); 307173368Ssam } 308173368Ssam} 309178354Ssam 310173368Ssamvoid 311178354Ssamieee80211_load_module(const char *modname) 312173368Ssam{ 313173862Ssam 314178354Ssam#ifdef notyet 315178354Ssam (void)kern_kldload(curthread, modname, NULL); 316178354Ssam#else 317173368Ssam printf("%s: load the %s module by hand for now.\n", __func__, modname); 318178354Ssam#endif 319282742Sadrian} 320173956Ssam 321173956Ssam/* 322173956Ssam * Module glue. 323173862Ssam * 324282742Sadrian * NB: the module name is "wlan" for compatibility with NetBSD. 325173862Ssam */ 326173862Ssamstatic int 327282742Sadrianwlan_modevent(module_t mod, int type, void *unused) 328224717Sbschmidt{ 329224717Sbschmidt switch (type) { 330224717Sbschmidt case MOD_LOAD: 331224717Sbschmidt if (bootverbose) 332224717Sbschmidt printf("wlan: <802.11 Link Layer>\n"); 333224717Sbschmidt return 0; 334224717Sbschmidt case MOD_UNLOAD: 335224717Sbschmidt return 0; 336170530Ssam } 337170530Ssam return EINVAL; 338170530Ssam} 339170530Ssam 340170530Ssamstatic moduledata_t wlan_mod = { 341170530Ssam "wlan", 342170530Ssam wlan_modevent, 343170530Ssam 0 344170530Ssam}; 345178354SsamDECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); 346178354SsamMODULE_VERSION(wlan, 1); 347178354SsamMODULE_DEPEND(wlan, ether, 1, 1, 1); 348178354Ssam