From 8a1b9b6ad42cc9836185b817fbbead06a8d03cec Mon Sep 17 00:00:00 2001 From: Sam Leffler Date: Wed, 8 Dec 2004 17:26:47 +0000 Subject: Update 802.11 support; too much new functionality to fully describe here but it includes completed 802.11g, WPA, 802.11i, 802.1x, WME/WMM, AP-side power-save, crypto plugin framework, authenticator plugin framework, and access control plugin frameowrk. --- sys/net80211/ieee80211_freebsd.c | 338 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 338 insertions(+) create mode 100644 sys/net80211/ieee80211_freebsd.c (limited to 'sys/net80211/ieee80211_freebsd.c') diff --git a/sys/net80211/ieee80211_freebsd.c b/sys/net80211/ieee80211_freebsd.c new file mode 100644 index 000000000000..26ce11b348d2 --- /dev/null +++ b/sys/net80211/ieee80211_freebsd.c @@ -0,0 +1,338 @@ +/*- + * Copyright (c) 2003-2004 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +/* + * IEEE 802.11 support (FreeBSD-specific code) + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include + +SYSCTL_NODE(_net, OID_AUTO, wlan, CTLFLAG_RD, 0, "IEEE 80211 parameters"); + +#ifdef IEEE80211_DEBUG +int ieee80211_debug = 0; +SYSCTL_INT(_net_wlan, OID_AUTO, debug, CTLFLAG_RW, &ieee80211_debug, + 0, "debugging printfs"); +#endif + +static int +ieee80211_sysctl_inact(SYSCTL_HANDLER_ARGS) +{ + int inact = (*(int *)arg1) * IEEE80211_INACT_WAIT; + int error; + + error = sysctl_handle_int(oidp, &inact, 0, req); + if (error || !req->newptr) + return error; + *(int *)arg1 = inact / IEEE80211_INACT_WAIT; + return 0; +} + +static int +ieee80211_sysctl_parent(SYSCTL_HANDLER_ARGS) +{ + struct ieee80211com *ic = arg1; + const char *name = ic->ic_ifp->if_xname; + + return SYSCTL_OUT(req, name, strlen(name)); +} + +void +ieee80211_sysctl_attach(struct ieee80211com *ic) +{ + struct sysctl_ctx_list *ctx; + struct sysctl_oid *oid; + char num[14]; /* sufficient for 32 bits */ + + MALLOC(ctx, struct sysctl_ctx_list *, sizeof(struct sysctl_ctx_list), + M_DEVBUF, M_NOWAIT | M_ZERO); + if (ctx == NULL) { + if_printf(ic->ic_ifp, "%s: cannot allocate sysctl context!\n", + __func__); + return; + } + sysctl_ctx_init(ctx); + snprintf(num, sizeof(num), "%u", ic->ic_vap); + oid = SYSCTL_ADD_NODE(ctx, &SYSCTL_NODE_CHILDREN(_net, wlan), + OID_AUTO, num, CTLFLAG_RD, NULL, ""); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "%parent", CTLFLAG_RD, ic, 0, ieee80211_sysctl_parent, "A", + "parent device"); +#ifdef IEEE80211_DEBUG + ic->ic_debug = ieee80211_debug; + SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "debug", CTLFLAG_RW, &ic->ic_debug, 0, + "control debugging printfs"); +#endif + /* XXX inherit from tunables */ + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "inact", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_run, 0, + ieee80211_sysctl_inact, "I", + "station inactivity timeout (sec)"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "inact_probe", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_probe, 0, + ieee80211_sysctl_inact, "I", + "station inactivity probe timeout (sec)"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "inact_auth", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_auth, 0, + ieee80211_sysctl_inact, "I", + "station authentication timeout (sec)"); + SYSCTL_ADD_PROC(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, + "inact_init", CTLTYPE_INT | CTLFLAG_RW, &ic->ic_inact_init, 0, + ieee80211_sysctl_inact, "I", + "station initial state timeout (sec)"); + ic->ic_sysctl = ctx; +} + +void +ieee80211_sysctl_detach(struct ieee80211com *ic) +{ + + if (ic->ic_sysctl != NULL) { + sysctl_ctx_free(ic->ic_sysctl); + ic->ic_sysctl = NULL; + } +} + +int +ieee80211_node_dectestref(struct ieee80211_node *ni) +{ + /* XXX need equivalent of atomic_dec_and_test */ + atomic_subtract_int(&ni->ni_refcnt, 1); + return atomic_cmpset_int(&ni->ni_refcnt, 0, 1); +} + +/* + * Allocate and setup a management frame of the specified + * size. We return the mbuf and a pointer to the start + * of the contiguous data area that's been reserved based + * on the packet length. The data area is forced to 32-bit + * alignment and the buffer length to a multiple of 4 bytes. + * This is done mainly so beacon frames (that require this) + * can use this interface too. + */ +struct mbuf * +ieee80211_getmgtframe(u_int8_t **frm, u_int pktlen) +{ + struct mbuf *m; + u_int len; + + /* + * NB: we know the mbuf routines will align the data area + * so we don't need to do anything special. + */ + /* XXX 4-address frame? */ + len = roundup(sizeof(struct ieee80211_frame) + pktlen, 4); + KASSERT(len <= MCLBYTES, ("802.11 mgt frame too large: %u", len)); + if (len < MINCLSIZE) { + m = m_gethdr(M_NOWAIT, MT_HEADER); + /* + * Align the data in case additional headers are added. + * This should only happen when a WEP header is added + * which only happens for shared key authentication mgt + * frames which all fit in MHLEN. + */ + if (m != NULL) + MH_ALIGN(m, len); + } else + m = m_getcl(M_NOWAIT, MT_HEADER, M_PKTHDR); + if (m != NULL) { + m->m_data += sizeof(struct ieee80211_frame); + *frm = m->m_data; + } + return m; +} + +#include + +void +get_random_bytes(void *p, size_t n) +{ + u_int8_t *dp = p; + + while (n > 0) { + u_int32_t v = arc4random(); + size_t nb = n > sizeof(u_int32_t) ? sizeof(u_int32_t) : n; + bcopy(&v, dp, n > sizeof(u_int32_t) ? sizeof(u_int32_t) : n); + dp += sizeof(u_int32_t), n -= nb; + } +} + +void +ieee80211_notify_node_join(struct ieee80211com *ic, struct ieee80211_node *ni, int newassoc) +{ + struct ifnet *ifp = ic->ic_ifp; + struct ieee80211_join_event iev; + + if (ni == ic->ic_bss) { + memset(&iev, 0, sizeof(iev)); + IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_bssid); + rt_ieee80211msg(ifp, newassoc ? + RTM_IEEE80211_ASSOC : RTM_IEEE80211_REASSOC, + &iev, sizeof(iev)); + if_link_state_change(ifp, LINK_STATE_UP); + } else if (newassoc) { + /* fire off wireless event only for new station */ + memset(&iev, 0, sizeof(iev)); + IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); + rt_ieee80211msg(ifp, RTM_IEEE80211_JOIN, &iev, sizeof(iev)); + } +} + +void +ieee80211_notify_node_leave(struct ieee80211com *ic, struct ieee80211_node *ni) +{ + struct ifnet *ifp = ic->ic_ifp; + struct ieee80211_leave_event iev; + + if (ni == ic->ic_bss) { + rt_ieee80211msg(ifp, RTM_IEEE80211_DISASSOC, NULL, 0); + if_link_state_change(ifp, LINK_STATE_DOWN); + } else { + /* fire off wireless event station leaving */ + memset(&iev, 0, sizeof(iev)); + IEEE80211_ADDR_COPY(iev.iev_addr, ni->ni_macaddr); + rt_ieee80211msg(ifp, RTM_IEEE80211_LEAVE, &iev, sizeof(iev)); + } +} + +void +ieee80211_notify_scan_done(struct ieee80211com *ic) +{ + struct ifnet *ifp = ic->ic_ifp; + + IEEE80211_DPRINTF(ic, IEEE80211_MSG_SCAN, + "%s: notify scan done\n", ic->ic_ifp->if_xname); + + /* dispatch wireless event indicating scan completed */ + rt_ieee80211msg(ifp, RTM_IEEE80211_SCAN, NULL, 0); +} + +void +ieee80211_notify_replay_failure(struct ieee80211com *ic, + const struct ieee80211_frame *wh, const struct ieee80211_key *k, + u_int64_t rsc) +{ + struct ifnet *ifp = ic->ic_ifp; + + IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, + "[%s] %s replay detected \n", + ether_sprintf(wh->i_addr2), k->wk_cipher->ic_name, + rsc, k->wk_keyrsc); + + if (ifp != NULL) { /* NB: for cipher test modules */ + struct ieee80211_replay_event iev; + + IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); + IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); + iev.iev_cipher = k->wk_cipher->ic_cipher; + iev.iev_keyix = k->wk_keyix; + iev.iev_keyrsc = k->wk_keyrsc; + iev.iev_rsc = rsc; + rt_ieee80211msg(ifp, RTM_IEEE80211_REPLAY, &iev, sizeof(iev)); + } +} + +void +ieee80211_notify_michael_failure(struct ieee80211com *ic, + const struct ieee80211_frame *wh, u_int keyix) +{ + struct ifnet *ifp = ic->ic_ifp; + + IEEE80211_DPRINTF(ic, IEEE80211_MSG_CRYPTO, + "[%s] Michael MIC verification failed \n", + ether_sprintf(wh->i_addr2), keyix); + ic->ic_stats.is_rx_tkipmic++; + + if (ifp != NULL) { /* NB: for cipher test modules */ + struct ieee80211_michael_event iev; + + IEEE80211_ADDR_COPY(iev.iev_dst, wh->i_addr1); + IEEE80211_ADDR_COPY(iev.iev_src, wh->i_addr2); + iev.iev_cipher = IEEE80211_CIPHER_TKIP; + iev.iev_keyix = keyix; + rt_ieee80211msg(ifp, RTM_IEEE80211_MICHAEL, &iev, sizeof(iev)); + } +} + +void +ieee80211_load_module(const char *modname) +{ + struct thread *td = curthread; + + if (suser(td) == 0 && securelevel_gt(td->td_ucred, 0) == 0) { + mtx_lock(&Giant); + (void) linker_load_module(modname, NULL, NULL, NULL, NULL); + mtx_unlock(&Giant); + } +} + +/* + * Module glue. + * + * NB: the module name is "wlan" for compatibility with NetBSD. + */ +static int +wlan_modevent(module_t mod, int type, void *unused) +{ + switch (type) { + case MOD_LOAD: + if (bootverbose) + printf("wlan: <802.11 Link Layer>\n"); + return 0; + case MOD_UNLOAD: + return 0; + } + return EINVAL; +} + +static moduledata_t wlan_mod = { + "wlan", + wlan_modevent, + 0 +}; +DECLARE_MODULE(wlan, wlan_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST); +MODULE_VERSION(wlan, 1); +MODULE_DEPEND(wlan, ether, 1, 1, 1); -- cgit v1.2.3