[Madwifi-cvs] madwifi/net80211 ieee80211_acl.c,NONE,1.1.2.1
Status: Beta
Brought to you by:
otaku
From: Sam L. <sam...@us...> - 2004-06-09 19:11:03
|
Update of /cvsroot/madwifi/madwifi/net80211 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv27877 Added Files: Tag: WPA ieee80211_acl.c Log Message: First cut at mac-based acl support based on patch by Kristian Hoffmann. This works as an optional loadable module and uses the existing MLME private ioctl to kick stations rather than adding a new one. Note: untested! May also want to rethink where acls are applied (currently do it on associate but if we do it "sooner" then we can use it to mitigate some potential dos attacks) --- NEW FILE: ieee80211_acl.c --- /*- * Copyright (c) 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. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * 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. */ #ifndef EXPORT_SYMTAB #define EXPORT_SYMTAB #endif /* * IEEE 802.11 MAC ACL support. * * When this module is loaded the sender address of each received * frame is passed to the iac_check method and the module indicates * if the frame should be accepted or rejected. If the policy is * set to ACL_POLICY_OPEN then all frames are accepted w/o checking * the address. Otherwise, the address is looked up in the database * and if found the frame is either accepted (ACL_POLICY_ALLOW) * or rejected (ACL_POLICY_DENT). */ #include <linux/config.h> #include <linux/version.h> #include <linux/module.h> #include <linux/skbuff.h> #include <linux/netdevice.h> #include "if_media.h" #include <net80211/ieee80211_var.h> enum { ACL_POLICY_OPEN = 0, /* open, don't check ACL's */ ACL_POLICY_ALLOW = 1, /* allow traffic from MAC */ ACL_POLICY_DENY = 2, /* deny traffic from MAC */ }; #define ACL_HASHSIZE 32 struct acl { TAILQ_ENTRY(acl) acl_list; LIST_ENTRY(acl) acl_hash; u_int8_t acl_macaddr[IEEE80211_ADDR_LEN]; }; struct aclstate { acl_lock_t as_lock; int as_policy; TAILQ_HEAD(, acl) as_list; /* list of all ACL's */ ATH_LIST_HEAD(, acl) as_hash[ACL_HASHSIZE]; }; /* simple hash is enough for variation of macaddr */ #define ACL_HASH(addr) \ (((u_int8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % ACL_HASHSIZE) MALLOC_DEFINE(M_80211_ACL, "acl", "802.11 station acl"); static int acl_free_all(struct ieee80211com *); static int acl_attach(struct ieee80211com *ic) { struct aclstate *as; _MOD_INC_USE(THIS_MODULE, return 0); MALLOC(as, struct aclstate *, sizeof(struct aclstate), M_DEVBUF, M_NOWAIT | M_ZERO); if (as == NULL) { _MOD_DEC_USE(THIS_MODULE); return 0; } TAILQ_INIT(&as->as_list); as->as_policy = ACL_POLICY_OPEN; ic->ic_as = as; return 1; } static void acl_detach(struct ieee80211com *ic) { struct aclstate *as = ic->ic_as; acl_free_all(ic); ic->ic_as = NULL; FREE(as, M_DEVBUF); _MOD_DEC_USE(THIS_MODULE); } static inline struct acl * _find_acl(struct aclstate *as, const u_int8_t *macaddr) { struct acl *acl; int hash; hash = ACL_HASH(macaddr); LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) { if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr)) return acl; } return NULL; } static void _acl_free(struct aclstate *as, struct acl *acl) { ACL_LOCK_ASSERT(as); TAILQ_REMOVE(&as->as_list, acl, acl_list); LIST_REMOVE(acl, acl_hash); FREE(acl, M_80211_ACL); } static int acl_check(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN]) { struct aclstate *as = ic->ic_as; switch (as->as_policy) { case ACL_POLICY_OPEN: return 1; case ACL_POLICY_ALLOW: return _find_acl(as, mac) != NULL; case ACL_POLICY_DENY: return _find_acl(as, mac) == NULL; } return 0; /* should not happen */ } static int acl_add(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN]) { struct aclstate *as = ic->ic_as; struct acl *acl; int hash; MALLOC(acl, struct acl *, sizeof(struct acl), M_80211_ACL, M_NOWAIT | M_ZERO); if (acl == NULL) return ENOMEM; ACL_LOCK(as); hash = ACL_HASH(mac); LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) { if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) { ACL_UNLOCK(as); FREE(acl, M_80211_ACL); return EEXIST; } } IEEE80211_ADDR_COPY(acl->acl_macaddr, mac); TAILQ_INSERT_TAIL(&as->as_list, acl, acl_list); LIST_INSERT_HEAD(&as->as_hash[hash], acl, acl_hash); ACL_UNLOCK(as); return 0; } static int acl_remove(struct ieee80211com *ic, const u_int8_t mac[IEEE80211_ADDR_LEN]) { struct aclstate *as = ic->ic_as; struct acl *acl; ACL_LOCK(as); acl = _find_acl(as, mac); if (acl != NULL) _acl_free(as, acl); ACL_UNLOCK(as); return (acl == NULL ? ENOENT : 0); } static int acl_free_all(struct ieee80211com *ic) { struct aclstate *as = ic->ic_as; struct acl *acl; ACL_LOCK(as); while ((acl = TAILQ_FIRST(&as->as_list)) != NULL) _acl_free(as, acl); ACL_UNLOCK(as); return 0; } static int acl_setpolicy(struct ieee80211com *ic, int policy) { struct aclstate *as = ic->ic_as; switch (policy) { case IEEE80211_MACCMD_POLICY_OPEN: as->as_policy = ACL_POLICY_OPEN; break; case IEEE80211_MACCMD_POLICY_ALLOW: as->as_policy = ACL_POLICY_ALLOW; break; case IEEE80211_MACCMD_POLICY_DENY: as->as_policy = ACL_POLICY_DENY; break; default: return EINVAL; } return 0; } static int acl_getpolicy(struct ieee80211com *ic) { struct aclstate *as = ic->ic_as; return as->as_policy; } /* * Module glue. */ MODULE_AUTHOR("Errno Consulting, Sam Leffler"); MODULE_DESCRIPTION("802.11 wireless support: MAC-based ACL policy"); #ifdef MODULE_LICENSE MODULE_LICENSE("Dual BSD/GPL"); #endif static const struct ieee80211_aclator mac = { .iac_name = "mac", .iac_attach = acl_attach, .iac_detach = acl_detach, .iac_check = acl_check, .iac_add = acl_add, .iac_remove = acl_remove, .iac_flush = acl_free_all, .iac_setpolicy = acl_setpolicy, .iac_getpolicy = acl_getpolicy, }; static int __init init_ieee80211_acl(void) { ieee80211_aclator_register(&mac); return 0; } module_init(init_ieee80211_acl); static void __exit exit_ieee80211_acl(void) { ieee80211_aclator_unregister(&mac); } module_exit(exit_ieee80211_acl); |