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