xref: /freebsd/sys/net80211/ieee80211_acl.c (revision 685dc743)
18a1b9b6aSSam Leffler /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3fe267a55SPedro F. Giffuni  *
4b032f27cSSam Leffler  * Copyright (c) 2004-2008 Sam Leffler, Errno Consulting
58a1b9b6aSSam Leffler  * All rights reserved.
68a1b9b6aSSam Leffler  *
78a1b9b6aSSam Leffler  * Redistribution and use in source and binary forms, with or without
88a1b9b6aSSam Leffler  * modification, are permitted provided that the following conditions
98a1b9b6aSSam Leffler  * are met:
108a1b9b6aSSam Leffler  * 1. Redistributions of source code must retain the above copyright
118a1b9b6aSSam Leffler  *    notice, this list of conditions and the following disclaimer.
128a1b9b6aSSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
138a1b9b6aSSam Leffler  *    notice, this list of conditions and the following disclaimer in the
148a1b9b6aSSam Leffler  *    documentation and/or other materials provided with the distribution.
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 /*
308a1b9b6aSSam Leffler  * IEEE 802.11 MAC ACL support.
318a1b9b6aSSam Leffler  *
32b032f27cSSam Leffler  * When this module is loaded the sender address of each auth mgt
338a1b9b6aSSam Leffler  * frame is passed to the iac_check method and the module indicates
348a1b9b6aSSam Leffler  * if the frame should be accepted or rejected.  If the policy is
358a1b9b6aSSam Leffler  * set to ACL_POLICY_OPEN then all frames are accepted w/o checking
368a1b9b6aSSam Leffler  * the address.  Otherwise, the address is looked up in the database
378a1b9b6aSSam Leffler  * and if found the frame is either accepted (ACL_POLICY_ALLOW)
388a1b9b6aSSam Leffler  * or rejected (ACL_POLICY_DENT).
398a1b9b6aSSam Leffler  */
40b032f27cSSam Leffler #include "opt_wlan.h"
41b032f27cSSam Leffler 
428a1b9b6aSSam Leffler #include <sys/param.h>
438a1b9b6aSSam Leffler #include <sys/kernel.h>
448a1b9b6aSSam Leffler #include <sys/systm.h>
458ec07310SGleb Smirnoff #include <sys/malloc.h>
468a1b9b6aSSam Leffler #include <sys/mbuf.h>
478a1b9b6aSSam Leffler #include <sys/module.h>
488a1b9b6aSSam Leffler #include <sys/queue.h>
498a1b9b6aSSam Leffler 
508a1b9b6aSSam Leffler #include <sys/socket.h>
518a1b9b6aSSam Leffler 
528a1b9b6aSSam Leffler #include <net/if.h>
538a1b9b6aSSam Leffler #include <net/if_media.h>
548a1b9b6aSSam Leffler #include <net/ethernet.h>
558a1b9b6aSSam Leffler #include <net/route.h>
568a1b9b6aSSam Leffler 
578a1b9b6aSSam Leffler #include <net80211/ieee80211_var.h>
588a1b9b6aSSam Leffler 
598a1b9b6aSSam Leffler enum {
608a1b9b6aSSam Leffler 	ACL_POLICY_OPEN		= 0,	/* open, don't check ACL's */
618a1b9b6aSSam Leffler 	ACL_POLICY_ALLOW	= 1,	/* allow traffic from MAC */
628a1b9b6aSSam Leffler 	ACL_POLICY_DENY		= 2,	/* deny traffic from MAC */
63b032f27cSSam Leffler 	/*
64b032f27cSSam Leffler 	 * NB: ACL_POLICY_RADIUS must be the same value as
65b032f27cSSam Leffler 	 *     IEEE80211_MACCMD_POLICY_RADIUS because of the way
66b032f27cSSam Leffler 	 *     acl_getpolicy() works.
67b032f27cSSam Leffler 	 */
68b032f27cSSam Leffler 	ACL_POLICY_RADIUS	= 7,	/* defer to RADIUS ACL server */
698a1b9b6aSSam Leffler };
708a1b9b6aSSam Leffler 
718a1b9b6aSSam Leffler #define	ACL_HASHSIZE	32
728a1b9b6aSSam Leffler 
738a1b9b6aSSam Leffler struct acl {
748a1b9b6aSSam Leffler 	TAILQ_ENTRY(acl)	acl_list;
758a1b9b6aSSam Leffler 	LIST_ENTRY(acl)		acl_hash;
7668e8e04eSSam Leffler 	uint8_t			acl_macaddr[IEEE80211_ADDR_LEN];
778a1b9b6aSSam Leffler };
788a1b9b6aSSam Leffler struct aclstate {
798a1b9b6aSSam Leffler 	acl_lock_t		as_lock;
808a1b9b6aSSam Leffler 	int			as_policy;
81db9ff08bSKevin Lo 	uint32_t		as_nacls;
828a1b9b6aSSam Leffler 	TAILQ_HEAD(, acl)	as_list;	/* list of all ACL's */
838a1b9b6aSSam Leffler 	LIST_HEAD(, acl)	as_hash[ACL_HASHSIZE];
84b032f27cSSam Leffler 	struct ieee80211vap	*as_vap;
858a1b9b6aSSam Leffler };
868a1b9b6aSSam Leffler 
878a1b9b6aSSam Leffler /* simple hash is enough for variation of macaddr */
888a1b9b6aSSam Leffler #define	ACL_HASH(addr)	\
8968e8e04eSSam Leffler 	(((const uint8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % ACL_HASHSIZE)
908a1b9b6aSSam Leffler 
91d745c852SEd Schouten static MALLOC_DEFINE(M_80211_ACL, "acl", "802.11 station acl");
928a1b9b6aSSam Leffler 
93b032f27cSSam Leffler static	int acl_free_all(struct ieee80211vap *);
94b032f27cSSam Leffler 
95b032f27cSSam Leffler /* number of references from net80211 layer */
96b032f27cSSam Leffler static	int nrefs = 0;
978a1b9b6aSSam Leffler 
988a1b9b6aSSam Leffler static int
acl_attach(struct ieee80211vap * vap)99b032f27cSSam Leffler acl_attach(struct ieee80211vap *vap)
1008a1b9b6aSSam Leffler {
1018a1b9b6aSSam Leffler 	struct aclstate *as;
1028a1b9b6aSSam Leffler 
103b9b53389SAdrian Chadd 	as = (struct aclstate *) IEEE80211_MALLOC(sizeof(struct aclstate),
104b9b53389SAdrian Chadd 		M_80211_ACL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1058a1b9b6aSSam Leffler 	if (as == NULL)
1068a1b9b6aSSam Leffler 		return 0;
1078a1b9b6aSSam Leffler 	ACL_LOCK_INIT(as, "acl");
1088a1b9b6aSSam Leffler 	TAILQ_INIT(&as->as_list);
1098a1b9b6aSSam Leffler 	as->as_policy = ACL_POLICY_OPEN;
110b032f27cSSam Leffler 	as->as_vap = vap;
111b032f27cSSam Leffler 	vap->iv_as = as;
112b032f27cSSam Leffler 	nrefs++;			/* NB: we assume caller locking */
1138a1b9b6aSSam Leffler 	return 1;
1148a1b9b6aSSam Leffler }
1158a1b9b6aSSam Leffler 
1168a1b9b6aSSam Leffler static void
acl_detach(struct ieee80211vap * vap)117b032f27cSSam Leffler acl_detach(struct ieee80211vap *vap)
1188a1b9b6aSSam Leffler {
119b032f27cSSam Leffler 	struct aclstate *as = vap->iv_as;
1208a1b9b6aSSam Leffler 
121b032f27cSSam Leffler 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
122b032f27cSSam Leffler 	nrefs--;			/* NB: we assume caller locking */
123b032f27cSSam Leffler 
124b032f27cSSam Leffler 	acl_free_all(vap);
125b032f27cSSam Leffler 	vap->iv_as = NULL;
1268a1b9b6aSSam Leffler 	ACL_LOCK_DESTROY(as);
127b9b53389SAdrian Chadd 	IEEE80211_FREE(as, M_80211_ACL);
1288a1b9b6aSSam Leffler }
1298a1b9b6aSSam Leffler 
13068f5ddcdSSam Leffler static __inline struct acl *
_find_acl(struct aclstate * as,const uint8_t * macaddr)13168e8e04eSSam Leffler _find_acl(struct aclstate *as, const uint8_t *macaddr)
1328a1b9b6aSSam Leffler {
1338a1b9b6aSSam Leffler 	struct acl *acl;
1348a1b9b6aSSam Leffler 	int hash;
1358a1b9b6aSSam Leffler 
1368a1b9b6aSSam Leffler 	hash = ACL_HASH(macaddr);
1378a1b9b6aSSam Leffler 	LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
1388a1b9b6aSSam Leffler 		if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
1398a1b9b6aSSam Leffler 			return acl;
1408a1b9b6aSSam Leffler 	}
1418a1b9b6aSSam Leffler 	return NULL;
1428a1b9b6aSSam Leffler }
1438a1b9b6aSSam Leffler 
1448a1b9b6aSSam Leffler static void
_acl_free(struct aclstate * as,struct acl * acl)1458a1b9b6aSSam Leffler _acl_free(struct aclstate *as, struct acl *acl)
1468a1b9b6aSSam Leffler {
1478a1b9b6aSSam Leffler 	ACL_LOCK_ASSERT(as);
1488a1b9b6aSSam Leffler 
1498a1b9b6aSSam Leffler 	TAILQ_REMOVE(&as->as_list, acl, acl_list);
1508a1b9b6aSSam Leffler 	LIST_REMOVE(acl, acl_hash);
151b9b53389SAdrian Chadd 	IEEE80211_FREE(acl, M_80211_ACL);
152188757f5SSam Leffler 	as->as_nacls--;
1538a1b9b6aSSam Leffler }
1548a1b9b6aSSam Leffler 
1558a1b9b6aSSam Leffler static int
acl_check(struct ieee80211vap * vap,const struct ieee80211_frame * wh)1565a8801b0SBernhard Schmidt acl_check(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
1578a1b9b6aSSam Leffler {
158b032f27cSSam Leffler 	struct aclstate *as = vap->iv_as;
1598a1b9b6aSSam Leffler 
1608a1b9b6aSSam Leffler 	switch (as->as_policy) {
1618a1b9b6aSSam Leffler 	case ACL_POLICY_OPEN:
162b032f27cSSam Leffler 	case ACL_POLICY_RADIUS:
1638a1b9b6aSSam Leffler 		return 1;
1648a1b9b6aSSam Leffler 	case ACL_POLICY_ALLOW:
1655a8801b0SBernhard Schmidt 		return _find_acl(as, wh->i_addr2) != NULL;
1668a1b9b6aSSam Leffler 	case ACL_POLICY_DENY:
1675a8801b0SBernhard Schmidt 		return _find_acl(as, wh->i_addr2) == NULL;
1688a1b9b6aSSam Leffler 	}
1698a1b9b6aSSam Leffler 	return 0;		/* should not happen */
1708a1b9b6aSSam Leffler }
1718a1b9b6aSSam Leffler 
1728a1b9b6aSSam Leffler static int
acl_add(struct ieee80211vap * vap,const uint8_t mac[IEEE80211_ADDR_LEN])173b032f27cSSam Leffler acl_add(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
1748a1b9b6aSSam Leffler {
175b032f27cSSam Leffler 	struct aclstate *as = vap->iv_as;
1768a1b9b6aSSam Leffler 	struct acl *acl, *new;
1778a1b9b6aSSam Leffler 	int hash;
1788a1b9b6aSSam Leffler 
179b9b53389SAdrian Chadd 	new = (struct acl *) IEEE80211_MALLOC(sizeof(struct acl),
180b9b53389SAdrian Chadd 	    M_80211_ACL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1818a1b9b6aSSam Leffler 	if (new == NULL) {
182b032f27cSSam Leffler 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
1838a1b9b6aSSam Leffler 			"ACL: add %s failed, no memory\n", ether_sprintf(mac));
1848a1b9b6aSSam Leffler 		/* XXX statistic */
1858a1b9b6aSSam Leffler 		return ENOMEM;
1868a1b9b6aSSam Leffler 	}
1878a1b9b6aSSam Leffler 
1888a1b9b6aSSam Leffler 	ACL_LOCK(as);
1898a1b9b6aSSam Leffler 	hash = ACL_HASH(mac);
1908a1b9b6aSSam Leffler 	LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
1918a1b9b6aSSam Leffler 		if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) {
1928a1b9b6aSSam Leffler 			ACL_UNLOCK(as);
193b9b53389SAdrian Chadd 			IEEE80211_FREE(new, M_80211_ACL);
194b032f27cSSam Leffler 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
1958a1b9b6aSSam Leffler 				"ACL: add %s failed, already present\n",
1968a1b9b6aSSam Leffler 				ether_sprintf(mac));
1978a1b9b6aSSam Leffler 			return EEXIST;
1988a1b9b6aSSam Leffler 		}
1998a1b9b6aSSam Leffler 	}
2008a1b9b6aSSam Leffler 	IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
2018a1b9b6aSSam Leffler 	TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
2028a1b9b6aSSam Leffler 	LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
203188757f5SSam Leffler 	as->as_nacls++;
2048a1b9b6aSSam Leffler 	ACL_UNLOCK(as);
2058a1b9b6aSSam Leffler 
206b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
2078a1b9b6aSSam Leffler 		"ACL: add %s\n", ether_sprintf(mac));
2088a1b9b6aSSam Leffler 	return 0;
2098a1b9b6aSSam Leffler }
2108a1b9b6aSSam Leffler 
2118a1b9b6aSSam Leffler static int
acl_remove(struct ieee80211vap * vap,const uint8_t mac[IEEE80211_ADDR_LEN])212b032f27cSSam Leffler acl_remove(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
2138a1b9b6aSSam Leffler {
214b032f27cSSam Leffler 	struct aclstate *as = vap->iv_as;
2158a1b9b6aSSam Leffler 	struct acl *acl;
2168a1b9b6aSSam Leffler 
2178a1b9b6aSSam Leffler 	ACL_LOCK(as);
2188a1b9b6aSSam Leffler 	acl = _find_acl(as, mac);
2198a1b9b6aSSam Leffler 	if (acl != NULL)
2208a1b9b6aSSam Leffler 		_acl_free(as, acl);
2218a1b9b6aSSam Leffler 	ACL_UNLOCK(as);
2228a1b9b6aSSam Leffler 
223b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
2248a1b9b6aSSam Leffler 		"ACL: remove %s%s\n", ether_sprintf(mac),
2258a1b9b6aSSam Leffler 		acl == NULL ? ", not present" : "");
2268a1b9b6aSSam Leffler 
2278a1b9b6aSSam Leffler 	return (acl == NULL ? ENOENT : 0);
2288a1b9b6aSSam Leffler }
2298a1b9b6aSSam Leffler 
2308a1b9b6aSSam Leffler static int
acl_free_all(struct ieee80211vap * vap)231b032f27cSSam Leffler acl_free_all(struct ieee80211vap *vap)
2328a1b9b6aSSam Leffler {
233b032f27cSSam Leffler 	struct aclstate *as = vap->iv_as;
2348a1b9b6aSSam Leffler 	struct acl *acl;
2358a1b9b6aSSam Leffler 
236b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: %s\n", "free all");
2378a1b9b6aSSam Leffler 
2388a1b9b6aSSam Leffler 	ACL_LOCK(as);
2398a1b9b6aSSam Leffler 	while ((acl = TAILQ_FIRST(&as->as_list)) != NULL)
2408a1b9b6aSSam Leffler 		_acl_free(as, acl);
2418a1b9b6aSSam Leffler 	ACL_UNLOCK(as);
2428a1b9b6aSSam Leffler 
2438a1b9b6aSSam Leffler 	return 0;
2448a1b9b6aSSam Leffler }
2458a1b9b6aSSam Leffler 
2468a1b9b6aSSam Leffler static int
acl_setpolicy(struct ieee80211vap * vap,int policy)247b032f27cSSam Leffler acl_setpolicy(struct ieee80211vap *vap, int policy)
2488a1b9b6aSSam Leffler {
249b032f27cSSam Leffler 	struct aclstate *as = vap->iv_as;
2508a1b9b6aSSam Leffler 
251b032f27cSSam Leffler 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
2528a1b9b6aSSam Leffler 		"ACL: set policy to %u\n", policy);
2538a1b9b6aSSam Leffler 
2548a1b9b6aSSam Leffler 	switch (policy) {
2558a1b9b6aSSam Leffler 	case IEEE80211_MACCMD_POLICY_OPEN:
2568a1b9b6aSSam Leffler 		as->as_policy = ACL_POLICY_OPEN;
2578a1b9b6aSSam Leffler 		break;
2588a1b9b6aSSam Leffler 	case IEEE80211_MACCMD_POLICY_ALLOW:
2598a1b9b6aSSam Leffler 		as->as_policy = ACL_POLICY_ALLOW;
2608a1b9b6aSSam Leffler 		break;
2618a1b9b6aSSam Leffler 	case IEEE80211_MACCMD_POLICY_DENY:
2628a1b9b6aSSam Leffler 		as->as_policy = ACL_POLICY_DENY;
2638a1b9b6aSSam Leffler 		break;
264b032f27cSSam Leffler 	case IEEE80211_MACCMD_POLICY_RADIUS:
265b032f27cSSam Leffler 		as->as_policy = ACL_POLICY_RADIUS;
266b032f27cSSam Leffler 		break;
2678a1b9b6aSSam Leffler 	default:
2688a1b9b6aSSam Leffler 		return EINVAL;
2698a1b9b6aSSam Leffler 	}
2708a1b9b6aSSam Leffler 	return 0;
2718a1b9b6aSSam Leffler }
2728a1b9b6aSSam Leffler 
2738a1b9b6aSSam Leffler static int
acl_getpolicy(struct ieee80211vap * vap)274b032f27cSSam Leffler acl_getpolicy(struct ieee80211vap *vap)
2758a1b9b6aSSam Leffler {
276b032f27cSSam Leffler 	struct aclstate *as = vap->iv_as;
2778a1b9b6aSSam Leffler 
2788a1b9b6aSSam Leffler 	return as->as_policy;
2798a1b9b6aSSam Leffler }
2808a1b9b6aSSam Leffler 
281188757f5SSam Leffler static int
acl_setioctl(struct ieee80211vap * vap,struct ieee80211req * ireq)282b032f27cSSam Leffler acl_setioctl(struct ieee80211vap *vap, struct ieee80211req *ireq)
283188757f5SSam Leffler {
284188757f5SSam Leffler 
285188757f5SSam Leffler 	return EINVAL;
286188757f5SSam Leffler }
287188757f5SSam Leffler 
288188757f5SSam Leffler static int
acl_getioctl(struct ieee80211vap * vap,struct ieee80211req * ireq)289b032f27cSSam Leffler acl_getioctl(struct ieee80211vap *vap, struct ieee80211req *ireq)
290188757f5SSam Leffler {
291b032f27cSSam Leffler 	struct aclstate *as = vap->iv_as;
292188757f5SSam Leffler 	struct acl *acl;
293188757f5SSam Leffler 	struct ieee80211req_maclist *ap;
294db9ff08bSKevin Lo 	int error;
295db9ff08bSKevin Lo 	uint32_t i, space;
296188757f5SSam Leffler 
297188757f5SSam Leffler 	switch (ireq->i_val) {
298188757f5SSam Leffler 	case IEEE80211_MACCMD_POLICY:
299188757f5SSam Leffler 		ireq->i_val = as->as_policy;
300188757f5SSam Leffler 		return 0;
301188757f5SSam Leffler 	case IEEE80211_MACCMD_LIST:
302188757f5SSam Leffler 		space = as->as_nacls * IEEE80211_ADDR_LEN;
303188757f5SSam Leffler 		if (ireq->i_len == 0) {
304188757f5SSam Leffler 			ireq->i_len = space;	/* return required space */
305188757f5SSam Leffler 			return 0;		/* NB: must not error */
306188757f5SSam Leffler 		}
307b9b53389SAdrian Chadd 		ap = (struct ieee80211req_maclist *) IEEE80211_MALLOC(space,
308b9b53389SAdrian Chadd 		    M_TEMP, IEEE80211_M_NOWAIT);
309188757f5SSam Leffler 		if (ap == NULL)
310188757f5SSam Leffler 			return ENOMEM;
311188757f5SSam Leffler 		i = 0;
312188757f5SSam Leffler 		ACL_LOCK(as);
313188757f5SSam Leffler 		TAILQ_FOREACH(acl, &as->as_list, acl_list) {
314188757f5SSam Leffler 			IEEE80211_ADDR_COPY(ap[i].ml_macaddr, acl->acl_macaddr);
315188757f5SSam Leffler 			i++;
316188757f5SSam Leffler 		}
317188757f5SSam Leffler 		ACL_UNLOCK(as);
318188757f5SSam Leffler 		if (ireq->i_len >= space) {
319188757f5SSam Leffler 			error = copyout(ap, ireq->i_data, space);
320188757f5SSam Leffler 			ireq->i_len = space;
321188757f5SSam Leffler 		} else
322188757f5SSam Leffler 			error = copyout(ap, ireq->i_data, ireq->i_len);
323b9b53389SAdrian Chadd 		IEEE80211_FREE(ap, M_TEMP);
324188757f5SSam Leffler 		return error;
325188757f5SSam Leffler 	}
326188757f5SSam Leffler 	return EINVAL;
327188757f5SSam Leffler }
328188757f5SSam Leffler 
3298a1b9b6aSSam Leffler static const struct ieee80211_aclator mac = {
3308a1b9b6aSSam Leffler 	.iac_name	= "mac",
3318a1b9b6aSSam Leffler 	.iac_attach	= acl_attach,
3328a1b9b6aSSam Leffler 	.iac_detach	= acl_detach,
3338a1b9b6aSSam Leffler 	.iac_check	= acl_check,
3348a1b9b6aSSam Leffler 	.iac_add	= acl_add,
3358a1b9b6aSSam Leffler 	.iac_remove	= acl_remove,
3368a1b9b6aSSam Leffler 	.iac_flush	= acl_free_all,
3378a1b9b6aSSam Leffler 	.iac_setpolicy	= acl_setpolicy,
3388a1b9b6aSSam Leffler 	.iac_getpolicy	= acl_getpolicy,
339188757f5SSam Leffler 	.iac_setioctl	= acl_setioctl,
340188757f5SSam Leffler 	.iac_getioctl	= acl_getioctl,
3418a1b9b6aSSam Leffler };
342b032f27cSSam Leffler IEEE80211_ACL_MODULE(wlan_acl, mac, 1);
343