xref: /dflybsd-src/sys/netproto/802_11/wlan_acl/ieee80211_acl.c (revision bff82488b6f45c2f067e4c552e649b1d3e07cd7c)
132176cfdSRui Paulo /*-
232176cfdSRui Paulo  * Copyright (c) 2004-2008 Sam Leffler, Errno Consulting
3841ab66cSSepherosa Ziehau  * All rights reserved.
4841ab66cSSepherosa Ziehau  *
5841ab66cSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
6841ab66cSSepherosa Ziehau  * modification, are permitted provided that the following conditions
7841ab66cSSepherosa Ziehau  * are met:
8841ab66cSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
9841ab66cSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
10841ab66cSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
11841ab66cSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
12841ab66cSSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
13841ab66cSSepherosa Ziehau  *
14841ab66cSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15841ab66cSSepherosa Ziehau  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16841ab66cSSepherosa Ziehau  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17841ab66cSSepherosa Ziehau  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18841ab66cSSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19841ab66cSSepherosa Ziehau  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20841ab66cSSepherosa Ziehau  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21841ab66cSSepherosa Ziehau  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22841ab66cSSepherosa Ziehau  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23841ab66cSSepherosa Ziehau  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24841ab66cSSepherosa Ziehau  */
25841ab66cSSepherosa Ziehau 
26085ff963SMatthew Dillon #include <sys/cdefs.h>
27085ff963SMatthew Dillon __FBSDID("$FreeBSD$");
28085ff963SMatthew Dillon 
29841ab66cSSepherosa Ziehau /*
30841ab66cSSepherosa Ziehau  * IEEE 802.11 MAC ACL support.
31841ab66cSSepherosa Ziehau  *
3232176cfdSRui Paulo  * When this module is loaded the sender address of each auth mgt
33841ab66cSSepherosa Ziehau  * frame is passed to the iac_check method and the module indicates
34841ab66cSSepherosa Ziehau  * if the frame should be accepted or rejected.  If the policy is
35841ab66cSSepherosa Ziehau  * set to ACL_POLICY_OPEN then all frames are accepted w/o checking
36841ab66cSSepherosa Ziehau  * the address.  Otherwise, the address is looked up in the database
37841ab66cSSepherosa Ziehau  * and if found the frame is either accepted (ACL_POLICY_ALLOW)
38841ab66cSSepherosa Ziehau  * or rejected (ACL_POLICY_DENT).
39841ab66cSSepherosa Ziehau  */
4032176cfdSRui Paulo #include "opt_wlan.h"
4132176cfdSRui Paulo 
42841ab66cSSepherosa Ziehau #include <sys/param.h>
43841ab66cSSepherosa Ziehau #include <sys/kernel.h>
44841ab66cSSepherosa Ziehau #include <sys/systm.h>
454f655ef5SMatthew Dillon #include <sys/malloc.h>
46841ab66cSSepherosa Ziehau #include <sys/mbuf.h>
47841ab66cSSepherosa Ziehau #include <sys/module.h>
48841ab66cSSepherosa Ziehau #include <sys/queue.h>
49841ab66cSSepherosa Ziehau 
50841ab66cSSepherosa Ziehau #include <sys/socket.h>
51841ab66cSSepherosa Ziehau 
52841ab66cSSepherosa Ziehau #include <net/if.h>
53*bff82488SAaron LI #include <net/if_var.h>
54841ab66cSSepherosa Ziehau #include <net/if_media.h>
55841ab66cSSepherosa Ziehau #include <net/ethernet.h>
56841ab66cSSepherosa Ziehau #include <net/route.h>
57841ab66cSSepherosa Ziehau 
58841ab66cSSepherosa Ziehau #include <netproto/802_11/ieee80211_var.h>
59841ab66cSSepherosa Ziehau 
60841ab66cSSepherosa Ziehau enum {
61841ab66cSSepherosa Ziehau 	ACL_POLICY_OPEN		= 0,	/* open, don't check ACL's */
62841ab66cSSepherosa Ziehau 	ACL_POLICY_ALLOW	= 1,	/* allow traffic from MAC */
63841ab66cSSepherosa Ziehau 	ACL_POLICY_DENY		= 2,	/* deny traffic from MAC */
6432176cfdSRui Paulo 	/*
6532176cfdSRui Paulo 	 * NB: ACL_POLICY_RADIUS must be the same value as
6632176cfdSRui Paulo 	 *     IEEE80211_MACCMD_POLICY_RADIUS because of the way
6732176cfdSRui Paulo 	 *     acl_getpolicy() works.
6832176cfdSRui Paulo 	 */
6932176cfdSRui Paulo 	ACL_POLICY_RADIUS	= 7,	/* defer to RADIUS ACL server */
70841ab66cSSepherosa Ziehau };
71841ab66cSSepherosa Ziehau 
72841ab66cSSepherosa Ziehau #define	ACL_HASHSIZE	32
73841ab66cSSepherosa Ziehau 
74841ab66cSSepherosa Ziehau struct acl {
75841ab66cSSepherosa Ziehau 	TAILQ_ENTRY(acl)	acl_list;
76841ab66cSSepherosa Ziehau 	LIST_ENTRY(acl)		acl_hash;
77841ab66cSSepherosa Ziehau 	uint8_t			acl_macaddr[IEEE80211_ADDR_LEN];
78841ab66cSSepherosa Ziehau };
79841ab66cSSepherosa Ziehau struct aclstate {
80085ff963SMatthew Dillon 	acl_lock_t		as_lock;
81841ab66cSSepherosa Ziehau 	int			as_policy;
82085ff963SMatthew Dillon 	uint32_t		as_nacls;
83841ab66cSSepherosa Ziehau 	TAILQ_HEAD(, acl)	as_list;	/* list of all ACL's */
84841ab66cSSepherosa Ziehau 	LIST_HEAD(, acl)	as_hash[ACL_HASHSIZE];
8532176cfdSRui Paulo 	struct ieee80211vap	*as_vap;
86841ab66cSSepherosa Ziehau };
87841ab66cSSepherosa Ziehau 
88841ab66cSSepherosa Ziehau /* simple hash is enough for variation of macaddr */
89841ab66cSSepherosa Ziehau #define	ACL_HASH(addr)	\
90841ab66cSSepherosa Ziehau 	(((const uint8_t *)(addr))[IEEE80211_ADDR_LEN - 1] % ACL_HASHSIZE)
91841ab66cSSepherosa Ziehau 
92085ff963SMatthew Dillon static MALLOC_DEFINE(M_80211_ACL, "acl", "802.11 station acl");
93841ab66cSSepherosa Ziehau 
9432176cfdSRui Paulo static	int acl_free_all(struct ieee80211vap *);
9532176cfdSRui Paulo 
9632176cfdSRui Paulo /* number of references from net80211 layer */
9732176cfdSRui Paulo static	int nrefs = 0;
98841ab66cSSepherosa Ziehau 
99841ab66cSSepherosa Ziehau static int
acl_attach(struct ieee80211vap * vap)10032176cfdSRui Paulo acl_attach(struct ieee80211vap *vap)
101841ab66cSSepherosa Ziehau {
102841ab66cSSepherosa Ziehau 	struct aclstate *as;
103841ab66cSSepherosa Ziehau 
1044f655ef5SMatthew Dillon #if defined(__DragonFly__)
10532176cfdSRui Paulo 	as = (struct aclstate *) kmalloc(sizeof(struct aclstate),
106c567b546SJoe Talbott 		M_80211_ACL, M_INTWAIT | M_ZERO);
1074f655ef5SMatthew Dillon #else
1084f655ef5SMatthew Dillon 	as = (struct aclstate *) IEEE80211_MALLOC(sizeof(struct aclstate),
1094f655ef5SMatthew Dillon 		M_80211_ACL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1104f655ef5SMatthew Dillon #endif
111841ab66cSSepherosa Ziehau 	if (as == NULL)
112841ab66cSSepherosa Ziehau 		return 0;
113085ff963SMatthew Dillon 	ACL_LOCK_INIT(as, "acl");
114841ab66cSSepherosa Ziehau 	TAILQ_INIT(&as->as_list);
115841ab66cSSepherosa Ziehau 	as->as_policy = ACL_POLICY_OPEN;
11632176cfdSRui Paulo 	as->as_vap = vap;
11732176cfdSRui Paulo 	vap->iv_as = as;
11832176cfdSRui Paulo 	nrefs++;			/* NB: we assume caller locking */
119841ab66cSSepherosa Ziehau 	return 1;
120841ab66cSSepherosa Ziehau }
121841ab66cSSepherosa Ziehau 
122841ab66cSSepherosa Ziehau static void
acl_detach(struct ieee80211vap * vap)12332176cfdSRui Paulo acl_detach(struct ieee80211vap *vap)
124841ab66cSSepherosa Ziehau {
12532176cfdSRui Paulo 	struct aclstate *as = vap->iv_as;
126841ab66cSSepherosa Ziehau 
12732176cfdSRui Paulo 	KASSERT(nrefs > 0, ("imbalanced attach/detach"));
12832176cfdSRui Paulo 	nrefs--;			/* NB: we assume caller locking */
12932176cfdSRui Paulo 
13032176cfdSRui Paulo 	acl_free_all(vap);
13132176cfdSRui Paulo 	vap->iv_as = NULL;
132085ff963SMatthew Dillon 	ACL_LOCK_DESTROY(as);
1334f655ef5SMatthew Dillon 	IEEE80211_FREE(as, M_80211_ACL);
134841ab66cSSepherosa Ziehau }
135841ab66cSSepherosa Ziehau 
136841ab66cSSepherosa Ziehau static __inline struct acl *
_find_acl(struct aclstate * as,const uint8_t * macaddr)137841ab66cSSepherosa Ziehau _find_acl(struct aclstate *as, const uint8_t *macaddr)
138841ab66cSSepherosa Ziehau {
139841ab66cSSepherosa Ziehau 	struct acl *acl;
140841ab66cSSepherosa Ziehau 	int hash;
141841ab66cSSepherosa Ziehau 
142841ab66cSSepherosa Ziehau 	hash = ACL_HASH(macaddr);
143841ab66cSSepherosa Ziehau 	LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
144841ab66cSSepherosa Ziehau 		if (IEEE80211_ADDR_EQ(acl->acl_macaddr, macaddr))
145841ab66cSSepherosa Ziehau 			return acl;
146841ab66cSSepherosa Ziehau 	}
147841ab66cSSepherosa Ziehau 	return NULL;
148841ab66cSSepherosa Ziehau }
149841ab66cSSepherosa Ziehau 
150841ab66cSSepherosa Ziehau static void
_acl_free(struct aclstate * as,struct acl * acl)151841ab66cSSepherosa Ziehau _acl_free(struct aclstate *as, struct acl *acl)
152841ab66cSSepherosa Ziehau {
153085ff963SMatthew Dillon 	ACL_LOCK_ASSERT(as);
154841ab66cSSepherosa Ziehau 
155841ab66cSSepherosa Ziehau 	TAILQ_REMOVE(&as->as_list, acl, acl_list);
156841ab66cSSepherosa Ziehau 	LIST_REMOVE(acl, acl_hash);
1574f655ef5SMatthew Dillon 	IEEE80211_FREE(acl, M_80211_ACL);
158841ab66cSSepherosa Ziehau 	as->as_nacls--;
159841ab66cSSepherosa Ziehau }
160841ab66cSSepherosa Ziehau 
161841ab66cSSepherosa Ziehau static int
acl_check(struct ieee80211vap * vap,const struct ieee80211_frame * wh)162085ff963SMatthew Dillon acl_check(struct ieee80211vap *vap, const struct ieee80211_frame *wh)
163841ab66cSSepherosa Ziehau {
16432176cfdSRui Paulo 	struct aclstate *as = vap->iv_as;
165841ab66cSSepherosa Ziehau 
166841ab66cSSepherosa Ziehau 	switch (as->as_policy) {
167841ab66cSSepherosa Ziehau 	case ACL_POLICY_OPEN:
16832176cfdSRui Paulo 	case ACL_POLICY_RADIUS:
169841ab66cSSepherosa Ziehau 		return 1;
170841ab66cSSepherosa Ziehau 	case ACL_POLICY_ALLOW:
171085ff963SMatthew Dillon 		return _find_acl(as, wh->i_addr2) != NULL;
172841ab66cSSepherosa Ziehau 	case ACL_POLICY_DENY:
173085ff963SMatthew Dillon 		return _find_acl(as, wh->i_addr2) == NULL;
174841ab66cSSepherosa Ziehau 	}
175841ab66cSSepherosa Ziehau 	return 0;		/* should not happen */
176841ab66cSSepherosa Ziehau }
177841ab66cSSepherosa Ziehau 
178841ab66cSSepherosa Ziehau static int
acl_add(struct ieee80211vap * vap,const uint8_t mac[IEEE80211_ADDR_LEN])17932176cfdSRui Paulo acl_add(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
180841ab66cSSepherosa Ziehau {
18132176cfdSRui Paulo 	struct aclstate *as = vap->iv_as;
182841ab66cSSepherosa Ziehau 	struct acl *acl, *new;
183841ab66cSSepherosa Ziehau 	int hash;
184841ab66cSSepherosa Ziehau 
1854f655ef5SMatthew Dillon #if defined(__DragonFly__)
1864f655ef5SMatthew Dillon 	new = (struct acl *) kmalloc(sizeof(struct acl),
1874f655ef5SMatthew Dillon 		M_80211_ACL, M_INTWAIT | M_ZERO);
1884f655ef5SMatthew Dillon #else
1894f655ef5SMatthew Dillon 	new = (struct acl *) IEEE80211_MALLOC(sizeof(struct acl),
1904f655ef5SMatthew Dillon 		M_80211_ACL, IEEE80211_M_NOWAIT | IEEE80211_M_ZERO);
1914f655ef5SMatthew Dillon #endif
192841ab66cSSepherosa Ziehau 	if (new == NULL) {
19332176cfdSRui Paulo 		IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
194085ff963SMatthew Dillon 			"ACL: add %s failed, no memory\n", ether_sprintf(mac));
195841ab66cSSepherosa Ziehau 		/* XXX statistic */
196841ab66cSSepherosa Ziehau 		return ENOMEM;
197841ab66cSSepherosa Ziehau 	}
198841ab66cSSepherosa Ziehau 
199085ff963SMatthew Dillon 	ACL_LOCK(as);
200841ab66cSSepherosa Ziehau 	hash = ACL_HASH(mac);
201841ab66cSSepherosa Ziehau 	LIST_FOREACH(acl, &as->as_hash[hash], acl_hash) {
202841ab66cSSepherosa Ziehau 		if (IEEE80211_ADDR_EQ(acl->acl_macaddr, mac)) {
203085ff963SMatthew Dillon 			ACL_UNLOCK(as);
2044f655ef5SMatthew Dillon 			IEEE80211_FREE(new, M_80211_ACL);
20532176cfdSRui Paulo 			IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
2061e290df3SAntonio Huete Jimenez 				"ACL: add %s failed, already present\n",
207085ff963SMatthew Dillon 				ether_sprintf(mac));
208841ab66cSSepherosa Ziehau 			return EEXIST;
209841ab66cSSepherosa Ziehau 		}
210841ab66cSSepherosa Ziehau 	}
211841ab66cSSepherosa Ziehau 	IEEE80211_ADDR_COPY(new->acl_macaddr, mac);
212841ab66cSSepherosa Ziehau 	TAILQ_INSERT_TAIL(&as->as_list, new, acl_list);
213841ab66cSSepherosa Ziehau 	LIST_INSERT_HEAD(&as->as_hash[hash], new, acl_hash);
214841ab66cSSepherosa Ziehau 	as->as_nacls++;
215085ff963SMatthew Dillon 	ACL_UNLOCK(as);
216841ab66cSSepherosa Ziehau 
21732176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
218085ff963SMatthew Dillon 		"ACL: add %s\n", ether_sprintf(mac));
219841ab66cSSepherosa Ziehau 	return 0;
220841ab66cSSepherosa Ziehau }
221841ab66cSSepherosa Ziehau 
222841ab66cSSepherosa Ziehau static int
acl_remove(struct ieee80211vap * vap,const uint8_t mac[IEEE80211_ADDR_LEN])22332176cfdSRui Paulo acl_remove(struct ieee80211vap *vap, const uint8_t mac[IEEE80211_ADDR_LEN])
224841ab66cSSepherosa Ziehau {
22532176cfdSRui Paulo 	struct aclstate *as = vap->iv_as;
226841ab66cSSepherosa Ziehau 	struct acl *acl;
227841ab66cSSepherosa Ziehau 
228085ff963SMatthew Dillon 	ACL_LOCK(as);
229841ab66cSSepherosa Ziehau 	acl = _find_acl(as, mac);
230841ab66cSSepherosa Ziehau 	if (acl != NULL)
231841ab66cSSepherosa Ziehau 		_acl_free(as, acl);
232085ff963SMatthew Dillon 	ACL_UNLOCK(as);
233841ab66cSSepherosa Ziehau 
23432176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
235085ff963SMatthew Dillon 		"ACL: remove %s%s\n", ether_sprintf(mac),
236841ab66cSSepherosa Ziehau 		acl == NULL ? ", not present" : "");
237841ab66cSSepherosa Ziehau 
238841ab66cSSepherosa Ziehau 	return (acl == NULL ? ENOENT : 0);
239841ab66cSSepherosa Ziehau }
240841ab66cSSepherosa Ziehau 
241841ab66cSSepherosa Ziehau static int
acl_free_all(struct ieee80211vap * vap)24232176cfdSRui Paulo acl_free_all(struct ieee80211vap *vap)
243841ab66cSSepherosa Ziehau {
24432176cfdSRui Paulo 	struct aclstate *as = vap->iv_as;
245841ab66cSSepherosa Ziehau 	struct acl *acl;
246841ab66cSSepherosa Ziehau 
24732176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL, "ACL: %s\n", "free all");
248841ab66cSSepherosa Ziehau 
249085ff963SMatthew Dillon 	ACL_LOCK(as);
250841ab66cSSepherosa Ziehau 	while ((acl = TAILQ_FIRST(&as->as_list)) != NULL)
251841ab66cSSepherosa Ziehau 		_acl_free(as, acl);
252085ff963SMatthew Dillon 	ACL_UNLOCK(as);
253841ab66cSSepherosa Ziehau 
254841ab66cSSepherosa Ziehau 	return 0;
255841ab66cSSepherosa Ziehau }
256841ab66cSSepherosa Ziehau 
257841ab66cSSepherosa Ziehau static int
acl_setpolicy(struct ieee80211vap * vap,int policy)25832176cfdSRui Paulo acl_setpolicy(struct ieee80211vap *vap, int policy)
259841ab66cSSepherosa Ziehau {
26032176cfdSRui Paulo 	struct aclstate *as = vap->iv_as;
261841ab66cSSepherosa Ziehau 
26232176cfdSRui Paulo 	IEEE80211_DPRINTF(vap, IEEE80211_MSG_ACL,
263841ab66cSSepherosa Ziehau 		"ACL: set policy to %u\n", policy);
264841ab66cSSepherosa Ziehau 
265841ab66cSSepherosa Ziehau 	switch (policy) {
266841ab66cSSepherosa Ziehau 	case IEEE80211_MACCMD_POLICY_OPEN:
267841ab66cSSepherosa Ziehau 		as->as_policy = ACL_POLICY_OPEN;
268841ab66cSSepherosa Ziehau 		break;
269841ab66cSSepherosa Ziehau 	case IEEE80211_MACCMD_POLICY_ALLOW:
270841ab66cSSepherosa Ziehau 		as->as_policy = ACL_POLICY_ALLOW;
271841ab66cSSepherosa Ziehau 		break;
272841ab66cSSepherosa Ziehau 	case IEEE80211_MACCMD_POLICY_DENY:
273841ab66cSSepherosa Ziehau 		as->as_policy = ACL_POLICY_DENY;
274841ab66cSSepherosa Ziehau 		break;
27532176cfdSRui Paulo 	case IEEE80211_MACCMD_POLICY_RADIUS:
27632176cfdSRui Paulo 		as->as_policy = ACL_POLICY_RADIUS;
27732176cfdSRui Paulo 		break;
278841ab66cSSepherosa Ziehau 	default:
279841ab66cSSepherosa Ziehau 		return EINVAL;
280841ab66cSSepherosa Ziehau 	}
281841ab66cSSepherosa Ziehau 	return 0;
282841ab66cSSepherosa Ziehau }
283841ab66cSSepherosa Ziehau 
284841ab66cSSepherosa Ziehau static int
acl_getpolicy(struct ieee80211vap * vap)28532176cfdSRui Paulo acl_getpolicy(struct ieee80211vap *vap)
286841ab66cSSepherosa Ziehau {
28732176cfdSRui Paulo 	struct aclstate *as = vap->iv_as;
28832176cfdSRui Paulo 
28932176cfdSRui Paulo 	return as->as_policy;
290841ab66cSSepherosa Ziehau }
291841ab66cSSepherosa Ziehau 
292841ab66cSSepherosa Ziehau static int
acl_setioctl(struct ieee80211vap * vap,struct ieee80211req * ireq)29332176cfdSRui Paulo acl_setioctl(struct ieee80211vap *vap, struct ieee80211req *ireq)
294841ab66cSSepherosa Ziehau {
29532176cfdSRui Paulo 
296841ab66cSSepherosa Ziehau 	return EINVAL;
297841ab66cSSepherosa Ziehau }
298841ab66cSSepherosa Ziehau 
299841ab66cSSepherosa Ziehau static int
acl_getioctl(struct ieee80211vap * vap,struct ieee80211req * ireq)30032176cfdSRui Paulo acl_getioctl(struct ieee80211vap *vap, struct ieee80211req *ireq)
301841ab66cSSepherosa Ziehau {
30232176cfdSRui Paulo 	struct aclstate *as = vap->iv_as;
303841ab66cSSepherosa Ziehau 	struct acl *acl;
304841ab66cSSepherosa Ziehau 	struct ieee80211req_maclist *ap;
305085ff963SMatthew Dillon 	int error;
306085ff963SMatthew Dillon 	uint32_t i, space;
307841ab66cSSepherosa Ziehau 
308841ab66cSSepherosa Ziehau 	switch (ireq->i_val) {
309841ab66cSSepherosa Ziehau 	case IEEE80211_MACCMD_POLICY:
310841ab66cSSepherosa Ziehau 		ireq->i_val = as->as_policy;
311841ab66cSSepherosa Ziehau 		return 0;
312841ab66cSSepherosa Ziehau 	case IEEE80211_MACCMD_LIST:
313841ab66cSSepherosa Ziehau 		space = as->as_nacls * IEEE80211_ADDR_LEN;
314841ab66cSSepherosa Ziehau 		if (ireq->i_len == 0) {
315841ab66cSSepherosa Ziehau 			ireq->i_len = space;	/* return required space */
316841ab66cSSepherosa Ziehau 			return 0;		/* NB: must not error */
317841ab66cSSepherosa Ziehau 		}
3184f655ef5SMatthew Dillon #if defined(__DragonFly__)
31932176cfdSRui Paulo 		ap = (struct ieee80211req_maclist *) kmalloc(space,
320c567b546SJoe Talbott 		    M_TEMP, M_INTWAIT);
3214f655ef5SMatthew Dillon #else
3224f655ef5SMatthew Dillon 		ap = (struct ieee80211req_maclist *) IEEE80211_MALLOC(space,
3234f655ef5SMatthew Dillon 		    M_TEMP, IEEE80211_M_NOWAIT);
3244f655ef5SMatthew Dillon #endif
325841ab66cSSepherosa Ziehau 		if (ap == NULL)
326841ab66cSSepherosa Ziehau 			return ENOMEM;
327841ab66cSSepherosa Ziehau 		i = 0;
328085ff963SMatthew Dillon 		ACL_LOCK(as);
329841ab66cSSepherosa Ziehau 		TAILQ_FOREACH(acl, &as->as_list, acl_list) {
330841ab66cSSepherosa Ziehau 			IEEE80211_ADDR_COPY(ap[i].ml_macaddr, acl->acl_macaddr);
331841ab66cSSepherosa Ziehau 			i++;
332841ab66cSSepherosa Ziehau 		}
333085ff963SMatthew Dillon 		ACL_UNLOCK(as);
334841ab66cSSepherosa Ziehau 		if (ireq->i_len >= space) {
335841ab66cSSepherosa Ziehau 			error = copyout(ap, ireq->i_data, space);
336841ab66cSSepherosa Ziehau 			ireq->i_len = space;
337841ab66cSSepherosa Ziehau 		} else
338841ab66cSSepherosa Ziehau 			error = copyout(ap, ireq->i_data, ireq->i_len);
3394f655ef5SMatthew Dillon 		IEEE80211_FREE(ap, M_TEMP);
340841ab66cSSepherosa Ziehau 		return error;
341841ab66cSSepherosa Ziehau 	}
342841ab66cSSepherosa Ziehau 	return EINVAL;
343841ab66cSSepherosa Ziehau }
344841ab66cSSepherosa Ziehau 
345841ab66cSSepherosa Ziehau static const struct ieee80211_aclator mac = {
346841ab66cSSepherosa Ziehau 	.iac_name	= "mac",
347841ab66cSSepherosa Ziehau 	.iac_attach	= acl_attach,
348841ab66cSSepherosa Ziehau 	.iac_detach	= acl_detach,
349841ab66cSSepherosa Ziehau 	.iac_check	= acl_check,
350841ab66cSSepherosa Ziehau 	.iac_add	= acl_add,
351841ab66cSSepherosa Ziehau 	.iac_remove	= acl_remove,
352841ab66cSSepherosa Ziehau 	.iac_flush	= acl_free_all,
353841ab66cSSepherosa Ziehau 	.iac_setpolicy	= acl_setpolicy,
354841ab66cSSepherosa Ziehau 	.iac_getpolicy	= acl_getpolicy,
355841ab66cSSepherosa Ziehau 	.iac_setioctl	= acl_setioctl,
356841ab66cSSepherosa Ziehau 	.iac_getioctl	= acl_getioctl,
357841ab66cSSepherosa Ziehau };
35832176cfdSRui Paulo IEEE80211_ACL_MODULE(wlan_acl, mac, 1);
359