diff -u sys/net80211.orig/ieee80211.c sys/net80211/ieee80211.c --- sys/net80211.orig/ieee80211.c Mon Sep 15 00:32:18 2003 +++ sys/net80211/ieee80211.c Sun Feb 22 20:53:28 2004 @@ -87,6 +87,8 @@ "turbo", /* IEEE80211_MODE_TURBO */ }; +MALLOC_DEFINE(M_80211_MACLIST, "maclist", "802.11 maclist"); + void ieee80211_ifattach(struct ifnet *ifp) { @@ -144,6 +146,10 @@ ic->ic_lintval = 100; /* default sleep */ ic->ic_bmisstimeout = 7*ic->ic_lintval; /* default 7 beacons */ + ic->maclist = 0; + ic->maclist_size = 0; + ic->maclist_mode = IEEE80211_MACLIST_MODE_DENY; + ieee80211_node_attach(ifp); ieee80211_proto_attach(ifp); } @@ -159,6 +165,9 @@ ifmedia_removeall(&ic->ic_media); bpfdetach(ifp); ether_ifdetach(ifp); + + if (ic->maclist_size) + free(ic->maclist, M_80211_MACLIST); } /* @@ -843,6 +852,117 @@ return IFM_SUBTYPE(mword) < N(ieeerates) ? ieeerates[IFM_SUBTYPE(mword)] : 0; #undef N +} + +int +ieee80211_is_allowed(struct ieee80211com *ic, u_int8_t *addr) { + int i, is_in_list, result; + u_int8_t *macentry; + + IEEE80211_NODE_LOCK(ic); + is_in_list = 0; + for (i = 0, macentry = ic->maclist; is_in_list == 0 && i < ic->maclist_size; i++) { + if (IEEE80211_ADDR_EQ(addr, macentry)) + is_in_list = 1; + macentry += IEEE80211_ADDR_LEN; + } + result = ic->maclist_mode == IEEE80211_MACLIST_MODE_ALLOW ? is_in_list : !is_in_list; + IEEE80211_NODE_UNLOCK(ic); + return result; +} + +int +ieee80211_maclist_copy_to_user(struct ieee80211com *ic, void *userdata, u_int16_t *len) { + int error; + u_int8_t mode, *data; + + data = userdata; + IEEE80211_NODE_LOCK(ic); + mode = ic->maclist_mode; + *len = 1 + ic->maclist_size * IEEE80211_ADDR_LEN; + error = copyout(&mode, data, 1); + if (error == 0) + error = copyout(ic->maclist, data + 1, ic->maclist_size * IEEE80211_ADDR_LEN); + IEEE80211_NODE_UNLOCK(ic); + return error; +} + +int +ieee80211_maclist_copy_from_user(struct ieee80211com *ic, void *userdata, u_int size) { + int i, error; + u_int8_t *maclist_new, *data; + int8_t mode; + + maclist_new = 0; + data = userdata; + if (size < 1 || (size - 1) % IEEE80211_ADDR_LEN) + return EINVAL; + /* maybe some size sensibility check as well */ + + error = copyin(data, &mode, sizeof(mode)); + if (error) + goto bail; + if (mode != -1 && + mode != IEEE80211_MACLIST_MODE_ALLOW && + mode != IEEE80211_MACLIST_MODE_DENY) + return EINVAL; + + --size; /* the first byte is the allow_mode */ + maclist_new = malloc(size, M_80211_MACLIST, M_NOWAIT | M_ZERO); + if (maclist_new == 0) + return ENOMEM; + + error = copyin(data + 1, maclist_new, size); + if (error) + goto bail; + + /* got everything, grab the mutex and update everything */ + IEEE80211_NODE_LOCK(ic); + if (mode != -1) + ic->maclist_mode = mode; + if (ic->maclist_size) + free(ic->maclist, M_80211_MACLIST); + ic->maclist = maclist_new; + ic->maclist_size = size / IEEE80211_ADDR_LEN; + + if (ic->maclist_mode == IEEE80211_MACLIST_MODE_ALLOW) { + /* + * TODO: go over all associated stations and check their presence on + * the list. if not there, kick. + */ + } else { + /* go over the list and kick off disallowed stations */ + for (i = 0; i < ic->maclist_size; i++) { + struct ieee80211_node *ni; + int hash; + u_int8_t *macaddr; + + /* this is ieee80211_find_node without the lock, + which we already have */ + macaddr = ic->maclist + i * IEEE80211_ADDR_LEN; + hash = IEEE80211_NODE_HASH(macaddr); + LIST_FOREACH(ni, &ic->ic_hash[hash], ni_hash) { + if (IEEE80211_ADDR_EQ(ni->ni_macaddr, macaddr)) { + atomic_add_int(&ni->ni_refcnt, 1); /* mark referenced */ + break; + } + } + if (ni) { + ni->ni_associd = 0; + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_ASSOC_NOT_AUTHED); + ieee80211_unref_node(&ni); + break; + } + } + } + + IEEE80211_NODE_UNLOCK(ic); + return 0; +bail: + free(maclist_new, M_80211_MACLIST); + return error; } /* diff -u sys/net80211.orig/ieee80211_input.c sys/net80211/ieee80211_input.c --- sys/net80211.orig/ieee80211_input.c Sat Oct 18 01:59:11 2003 +++ sys/net80211/ieee80211_input.c Sun Feb 22 19:55:46 2004 @@ -918,6 +918,14 @@ if (ic->ic_opmode != IEEE80211_M_HOSTAP || (ic->ic_state != IEEE80211_S_RUN)) return; + + if (!ieee80211_is_allowed(ic, wh->i_addr2)) { + IEEE80211_DPRINTF(("ignoring association request from banned station %s\n", ether_sprintf(wh->i_addr2))); + IEEE80211_SEND_MGMT(ic, ni, + IEEE80211_FC0_SUBTYPE_DEAUTH, + IEEE80211_REASON_ASSOC_NOT_AUTHED); + return; + } if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) { reassoc = 1; diff -u sys/net80211.orig/ieee80211_ioctl.c sys/net80211/ieee80211_ioctl.c --- sys/net80211.orig/ieee80211_ioctl.c Thu Nov 13 06:23:58 2003 +++ sys/net80211/ieee80211_ioctl.c Sun Feb 22 19:25:04 2004 @@ -858,6 +858,9 @@ case IEEE80211_IOC_RTSTHRESHOLD: ireq->i_val = ic->ic_rtsthreshold; break; + case IEEE80211_IOC_MACLIST: + error = ieee80211_maclist_copy_to_user(ic, ireq->i_data, &ireq->i_len); + break; default: error = EINVAL; } @@ -999,6 +1002,10 @@ ic->ic_rtsthreshold = ireq->i_val; error = ENETRESET; break; + case IEEE80211_IOC_MACLIST: + error = ieee80211_maclist_copy_from_user(ic, ireq->i_data, ireq->i_len); + break; + default: error = EINVAL; break; diff -u sys/net80211.orig/ieee80211_ioctl.h sys/net80211/ieee80211_ioctl.h --- sys/net80211.orig/ieee80211_ioctl.h Sat Oct 18 01:15:30 2003 +++ sys/net80211/ieee80211_ioctl.h Fri Feb 20 22:54:31 2004 @@ -119,6 +119,7 @@ #define IEEE80211_POWERSAVE_ON IEEE80211_POWERSAVE_CAM #define IEEE80211_IOC_POWERSAVESLEEP 11 #define IEEE80211_IOC_RTSTHRESHOLD 12 +#define IEEE80211_IOC_MACLIST 13 #ifndef IEEE80211_CHAN_ANY #define IEEE80211_CHAN_ANY 0xffff /* token for ``any channel'' */ diff -u sys/net80211.orig/ieee80211_proto.h sys/net80211/ieee80211_proto.h --- sys/net80211.orig/ieee80211_proto.h Wed Aug 20 00:17:03 2003 +++ sys/net80211/ieee80211_proto.h Sun Feb 22 19:52:31 2004 @@ -75,4 +75,9 @@ extern void ieee80211_dump_pkt(u_int8_t *, int, int, int); extern const char *ieee80211_state_name[IEEE80211_S_MAX]; + +extern int ieee80211_is_allowed(struct ieee80211com *, u_int8_t *); +extern int ieee80211_maclist_copy_to_user(struct ieee80211com *, void *, u_int16_t *); +extern int ieee80211_maclist_copy_from_user(struct ieee80211com *, void *, u_int); + #endif /* _NET80211_IEEE80211_PROTO_H_ */ diff -u sys/net80211.orig/ieee80211_var.h sys/net80211/ieee80211_var.h --- sys/net80211.orig/ieee80211_var.h Sat Oct 18 01:15:30 2003 +++ sys/net80211/ieee80211_var.h Sun Feb 22 20:50:46 2004 @@ -75,6 +75,11 @@ IEEE80211_M_MONITOR = 8 /* Monitor mode */ }; +enum ieee80211_maclist_mode { + IEEE80211_MACLIST_MODE_DENY, /* do not allow the stations on the list */ + IEEE80211_MACLIST_MODE_ALLOW /* allow just the stations on the list */ +}; + /* * Channels are specified by frequency and attributes. */ @@ -195,6 +200,9 @@ void *ic_wep_ctx; /* wep crypt context */ u_int32_t ic_iv; /* initial vector for wep */ struct ieee80211_stats ic_stats; /* statistics */ + u_int8_t *maclist; /* MAC list for allowing or denying associations */ + u_int maclist_size; + enum ieee80211_maclist_mode maclist_mode; }; #define ic_if ic_ac.ac_if #define ic_softc ic_if.if_softc @@ -257,6 +265,7 @@ int ieee80211_setmode(struct ieee80211com *, enum ieee80211_phymode); enum ieee80211_phymode ieee80211_chan2mode(struct ieee80211com *, struct ieee80211_channel *); +void ieee80211_maclist_set(struct ieee80211com *, u_int8_t *, int); #define IEEE80211_DEBUG #ifdef IEEE80211_DEBUG