1e28a4053SRui Paulo /*
2e28a4053SRui Paulo * hostapd / IEEE 802.11 authentication (ACL)
3*a90b9d01SCy Schubert * Copyright (c) 2003-2022, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo *
5f05cddf9SRui Paulo * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo * See README for more details.
7e28a4053SRui Paulo *
8e28a4053SRui Paulo * Access control list for IEEE 802.11 authentication can uses statically
9e28a4053SRui Paulo * configured ACL from configuration files or an external RADIUS server.
10e28a4053SRui Paulo * Results from external RADIUS queries are cached to allow faster
11e28a4053SRui Paulo * authentication frame processing.
12e28a4053SRui Paulo */
13e28a4053SRui Paulo
14e28a4053SRui Paulo #include "utils/includes.h"
15e28a4053SRui Paulo
16e28a4053SRui Paulo #include "utils/common.h"
17e28a4053SRui Paulo #include "utils/eloop.h"
18e28a4053SRui Paulo #include "radius/radius.h"
19e28a4053SRui Paulo #include "radius/radius_client.h"
20e28a4053SRui Paulo #include "hostapd.h"
21e28a4053SRui Paulo #include "ap_config.h"
22f05cddf9SRui Paulo #include "ap_drv_ops.h"
23*a90b9d01SCy Schubert #include "sta_info.h"
24*a90b9d01SCy Schubert #include "wpa_auth.h"
25e28a4053SRui Paulo #include "ieee802_11.h"
26f05cddf9SRui Paulo #include "ieee802_1x.h"
27e28a4053SRui Paulo #include "ieee802_11_auth.h"
28e28a4053SRui Paulo
29e28a4053SRui Paulo #define RADIUS_ACL_TIMEOUT 30
30e28a4053SRui Paulo
31e28a4053SRui Paulo
32e28a4053SRui Paulo struct hostapd_cached_radius_acl {
335b9c547cSRui Paulo struct os_reltime timestamp;
34e28a4053SRui Paulo macaddr addr;
35e28a4053SRui Paulo int accepted; /* HOSTAPD_ACL_* */
36e28a4053SRui Paulo struct hostapd_cached_radius_acl *next;
37c1d255d3SCy Schubert struct radius_sta info;
38e28a4053SRui Paulo };
39e28a4053SRui Paulo
40e28a4053SRui Paulo
41e28a4053SRui Paulo struct hostapd_acl_query_data {
425b9c547cSRui Paulo struct os_reltime timestamp;
43e28a4053SRui Paulo u8 radius_id;
44e28a4053SRui Paulo macaddr addr;
45e28a4053SRui Paulo u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
46e28a4053SRui Paulo size_t auth_msg_len;
47e28a4053SRui Paulo struct hostapd_acl_query_data *next;
48*a90b9d01SCy Schubert bool radius_psk;
49*a90b9d01SCy Schubert int akm;
50*a90b9d01SCy Schubert u8 *anonce;
51*a90b9d01SCy Schubert u8 *eapol;
52*a90b9d01SCy Schubert size_t eapol_len;
53e28a4053SRui Paulo };
54e28a4053SRui Paulo
55e28a4053SRui Paulo
56e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS
hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl * e)57f05cddf9SRui Paulo static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
58f05cddf9SRui Paulo {
59c1d255d3SCy Schubert os_free(e->info.identity);
60c1d255d3SCy Schubert os_free(e->info.radius_cui);
61c1d255d3SCy Schubert hostapd_free_psk_list(e->info.psk);
62f05cddf9SRui Paulo os_free(e);
63f05cddf9SRui Paulo }
64f05cddf9SRui Paulo
65f05cddf9SRui Paulo
hostapd_acl_cache_free(struct hostapd_cached_radius_acl * acl_cache)66e28a4053SRui Paulo static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
67e28a4053SRui Paulo {
68e28a4053SRui Paulo struct hostapd_cached_radius_acl *prev;
69e28a4053SRui Paulo
70e28a4053SRui Paulo while (acl_cache) {
71e28a4053SRui Paulo prev = acl_cache;
72e28a4053SRui Paulo acl_cache = acl_cache->next;
73f05cddf9SRui Paulo hostapd_acl_cache_free_entry(prev);
74e28a4053SRui Paulo }
75e28a4053SRui Paulo }
76e28a4053SRui Paulo
77e28a4053SRui Paulo
hostapd_acl_cache_get(struct hostapd_data * hapd,const u8 * addr,struct radius_sta * out)78e28a4053SRui Paulo static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
79c1d255d3SCy Schubert struct radius_sta *out)
80e28a4053SRui Paulo {
81e28a4053SRui Paulo struct hostapd_cached_radius_acl *entry;
825b9c547cSRui Paulo struct os_reltime now;
83e28a4053SRui Paulo
845b9c547cSRui Paulo os_get_reltime(&now);
85e28a4053SRui Paulo
86f05cddf9SRui Paulo for (entry = hapd->acl_cache; entry; entry = entry->next) {
87*a90b9d01SCy Schubert if (!ether_addr_equal(entry->addr, addr))
88f05cddf9SRui Paulo continue;
89f05cddf9SRui Paulo
905b9c547cSRui Paulo if (os_reltime_expired(&now, &entry->timestamp,
915b9c547cSRui Paulo RADIUS_ACL_TIMEOUT))
92e28a4053SRui Paulo return -1; /* entry has expired */
93c1d255d3SCy Schubert *out = entry->info;
94c1d255d3SCy Schubert
95f05cddf9SRui Paulo return entry->accepted;
96e28a4053SRui Paulo }
97e28a4053SRui Paulo
98e28a4053SRui Paulo return -1;
99e28a4053SRui Paulo }
100e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
101e28a4053SRui Paulo
102e28a4053SRui Paulo
hostapd_acl_query_free(struct hostapd_acl_query_data * query)103e28a4053SRui Paulo static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
104e28a4053SRui Paulo {
105*a90b9d01SCy Schubert if (!query)
106e28a4053SRui Paulo return;
107e28a4053SRui Paulo os_free(query->auth_msg);
108*a90b9d01SCy Schubert os_free(query->anonce);
109*a90b9d01SCy Schubert os_free(query->eapol);
110e28a4053SRui Paulo os_free(query);
111e28a4053SRui Paulo }
112e28a4053SRui Paulo
113e28a4053SRui Paulo
114e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS
hostapd_radius_acl_query(struct hostapd_data * hapd,const u8 * addr,struct hostapd_acl_query_data * query)115e28a4053SRui Paulo static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
116e28a4053SRui Paulo struct hostapd_acl_query_data *query)
117e28a4053SRui Paulo {
118e28a4053SRui Paulo struct radius_msg *msg;
119e28a4053SRui Paulo char buf[128];
120e28a4053SRui Paulo
121e28a4053SRui Paulo query->radius_id = radius_client_get_id(hapd->radius);
122e28a4053SRui Paulo msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
123*a90b9d01SCy Schubert if (!msg)
124e28a4053SRui Paulo return -1;
125e28a4053SRui Paulo
126780fb4a2SCy Schubert if (radius_msg_make_authenticator(msg) < 0) {
127780fb4a2SCy Schubert wpa_printf(MSG_INFO, "Could not make Request Authenticator");
128780fb4a2SCy Schubert goto fail;
129780fb4a2SCy Schubert }
130e28a4053SRui Paulo
131*a90b9d01SCy Schubert if (!radius_msg_add_msg_auth(msg))
132*a90b9d01SCy Schubert goto fail;
133*a90b9d01SCy Schubert
134e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
135e28a4053SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
136e28a4053SRui Paulo os_strlen(buf))) {
137e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Could not add User-Name");
138e28a4053SRui Paulo goto fail;
139e28a4053SRui Paulo }
140e28a4053SRui Paulo
141e28a4053SRui Paulo if (!radius_msg_add_attr_user_password(
142e28a4053SRui Paulo msg, (u8 *) buf, os_strlen(buf),
143e28a4053SRui Paulo hapd->conf->radius->auth_server->shared_secret,
144e28a4053SRui Paulo hapd->conf->radius->auth_server->shared_secret_len)) {
145e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Could not add User-Password");
146e28a4053SRui Paulo goto fail;
147e28a4053SRui Paulo }
148e28a4053SRui Paulo
149f05cddf9SRui Paulo if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr,
150f05cddf9SRui Paulo NULL, msg) < 0)
151e28a4053SRui Paulo goto fail;
152e28a4053SRui Paulo
153e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
154e28a4053SRui Paulo MAC2STR(addr));
155e28a4053SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
156e28a4053SRui Paulo (u8 *) buf, os_strlen(buf))) {
157e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
158e28a4053SRui Paulo goto fail;
159e28a4053SRui Paulo }
160e28a4053SRui Paulo
161e28a4053SRui Paulo os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
162e28a4053SRui Paulo if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
163e28a4053SRui Paulo (u8 *) buf, os_strlen(buf))) {
164e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
165e28a4053SRui Paulo goto fail;
166e28a4053SRui Paulo }
167e28a4053SRui Paulo
168*a90b9d01SCy Schubert if (query->akm &&
169*a90b9d01SCy Schubert !radius_msg_add_attr_int32(msg, RADIUS_ATTR_WLAN_AKM_SUITE,
170*a90b9d01SCy Schubert wpa_akm_to_suite(query->akm))) {
171*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "Could not add WLAN-AKM-Suite");
172*a90b9d01SCy Schubert goto fail;
173*a90b9d01SCy Schubert }
174*a90b9d01SCy Schubert
175*a90b9d01SCy Schubert if (query->anonce &&
176*a90b9d01SCy Schubert !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
177*a90b9d01SCy Schubert RADIUS_VENDOR_ID_FREERADIUS,
178*a90b9d01SCy Schubert RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_ANONCE,
179*a90b9d01SCy Schubert query->anonce, WPA_NONCE_LEN)) {
180*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-Anonce");
181*a90b9d01SCy Schubert goto fail;
182*a90b9d01SCy Schubert }
183*a90b9d01SCy Schubert
184*a90b9d01SCy Schubert if (query->eapol &&
185*a90b9d01SCy Schubert !radius_msg_add_ext_vs(msg, RADIUS_ATTR_EXT_VENDOR_SPECIFIC_5,
186*a90b9d01SCy Schubert RADIUS_VENDOR_ID_FREERADIUS,
187*a90b9d01SCy Schubert RADIUS_VENDOR_ATTR_FREERADIUS_802_1X_EAPOL_KEY_MSG,
188*a90b9d01SCy Schubert query->eapol, query->eapol_len)) {
189*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG, "Could not add FreeRADIUS-802.1X-EAPoL-Key-Msg");
190*a90b9d01SCy Schubert goto fail;
191*a90b9d01SCy Schubert }
192*a90b9d01SCy Schubert
193f05cddf9SRui Paulo if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
194f05cddf9SRui Paulo goto fail;
195e28a4053SRui Paulo return 0;
196e28a4053SRui Paulo
197e28a4053SRui Paulo fail:
198e28a4053SRui Paulo radius_msg_free(msg);
199e28a4053SRui Paulo return -1;
200e28a4053SRui Paulo }
201e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
202e28a4053SRui Paulo
203e28a4053SRui Paulo
204e28a4053SRui Paulo /**
205780fb4a2SCy Schubert * hostapd_check_acl - Check a specified STA against accept/deny ACLs
206780fb4a2SCy Schubert * @hapd: hostapd BSS data
207780fb4a2SCy Schubert * @addr: MAC address of the STA
208780fb4a2SCy Schubert * @vlan_id: Buffer for returning VLAN ID
209780fb4a2SCy Schubert * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
210780fb4a2SCy Schubert */
hostapd_check_acl(struct hostapd_data * hapd,const u8 * addr,struct vlan_description * vlan_id)211780fb4a2SCy Schubert int hostapd_check_acl(struct hostapd_data *hapd, const u8 *addr,
212780fb4a2SCy Schubert struct vlan_description *vlan_id)
213780fb4a2SCy Schubert {
214780fb4a2SCy Schubert if (hostapd_maclist_found(hapd->conf->accept_mac,
215780fb4a2SCy Schubert hapd->conf->num_accept_mac, addr, vlan_id))
216780fb4a2SCy Schubert return HOSTAPD_ACL_ACCEPT;
217780fb4a2SCy Schubert
218780fb4a2SCy Schubert if (hostapd_maclist_found(hapd->conf->deny_mac,
219780fb4a2SCy Schubert hapd->conf->num_deny_mac, addr, vlan_id))
220780fb4a2SCy Schubert return HOSTAPD_ACL_REJECT;
221780fb4a2SCy Schubert
222780fb4a2SCy Schubert if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
223780fb4a2SCy Schubert return HOSTAPD_ACL_ACCEPT;
224780fb4a2SCy Schubert if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
225780fb4a2SCy Schubert return HOSTAPD_ACL_REJECT;
226780fb4a2SCy Schubert
227780fb4a2SCy Schubert return HOSTAPD_ACL_PENDING;
228780fb4a2SCy Schubert }
229780fb4a2SCy Schubert
230780fb4a2SCy Schubert
231780fb4a2SCy Schubert /**
232e28a4053SRui Paulo * hostapd_allowed_address - Check whether a specified STA can be authenticated
233e28a4053SRui Paulo * @hapd: hostapd BSS data
234e28a4053SRui Paulo * @addr: MAC address of the STA
235e28a4053SRui Paulo * @msg: Authentication message
236e28a4053SRui Paulo * @len: Length of msg in octets
237c1d255d3SCy Schubert * @out.session_timeout: Buffer for returning session timeout (from RADIUS)
238c1d255d3SCy Schubert * @out.acct_interim_interval: Buffer for returning account interval (from
239c1d255d3SCy Schubert * RADIUS)
240c1d255d3SCy Schubert * @out.vlan_id: Buffer for returning VLAN ID
241c1d255d3SCy Schubert * @out.psk: Linked list buffer for returning WPA PSK
242c1d255d3SCy Schubert * @out.identity: Buffer for returning identity (from RADIUS)
243c1d255d3SCy Schubert * @out.radius_cui: Buffer for returning CUI (from RADIUS)
24485732ac8SCy Schubert * @is_probe_req: Whether this query for a Probe Request frame
245e28a4053SRui Paulo * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
246f05cddf9SRui Paulo *
247c1d255d3SCy Schubert * The caller is responsible for properly cloning the returned out->identity and
248c1d255d3SCy Schubert * out->radius_cui and out->psk values.
249e28a4053SRui Paulo */
hostapd_allowed_address(struct hostapd_data * hapd,const u8 * addr,const u8 * msg,size_t len,struct radius_sta * out,int is_probe_req)250e28a4053SRui Paulo int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
251c1d255d3SCy Schubert const u8 *msg, size_t len, struct radius_sta *out,
25285732ac8SCy Schubert int is_probe_req)
253e28a4053SRui Paulo {
254780fb4a2SCy Schubert int res;
255780fb4a2SCy Schubert
256c1d255d3SCy Schubert os_memset(out, 0, sizeof(*out));
257e28a4053SRui Paulo
258c1d255d3SCy Schubert res = hostapd_check_acl(hapd, addr, &out->vlan_id);
259780fb4a2SCy Schubert if (res != HOSTAPD_ACL_PENDING)
260780fb4a2SCy Schubert return res;
261e28a4053SRui Paulo
262e28a4053SRui Paulo if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
263e28a4053SRui Paulo #ifdef CONFIG_NO_RADIUS
264e28a4053SRui Paulo return HOSTAPD_ACL_REJECT;
265e28a4053SRui Paulo #else /* CONFIG_NO_RADIUS */
266e28a4053SRui Paulo struct hostapd_acl_query_data *query;
267e28a4053SRui Paulo
26885732ac8SCy Schubert if (is_probe_req) {
26985732ac8SCy Schubert /* Skip RADIUS queries for Probe Request frames to avoid
27085732ac8SCy Schubert * excessive load on the authentication server. */
27185732ac8SCy Schubert return HOSTAPD_ACL_ACCEPT;
27285732ac8SCy Schubert };
27385732ac8SCy Schubert
2744bc52338SCy Schubert if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
275c1d255d3SCy Schubert os_memset(&out->vlan_id, 0, sizeof(out->vlan_id));
2764bc52338SCy Schubert
277e28a4053SRui Paulo /* Check whether ACL cache has an entry for this station */
278c1d255d3SCy Schubert res = hostapd_acl_cache_get(hapd, addr, out);
279e28a4053SRui Paulo if (res == HOSTAPD_ACL_ACCEPT ||
280e28a4053SRui Paulo res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
281e28a4053SRui Paulo return res;
282e28a4053SRui Paulo if (res == HOSTAPD_ACL_REJECT)
283e28a4053SRui Paulo return HOSTAPD_ACL_REJECT;
284e28a4053SRui Paulo
285e28a4053SRui Paulo query = hapd->acl_queries;
286e28a4053SRui Paulo while (query) {
287*a90b9d01SCy Schubert if (ether_addr_equal(query->addr, addr)) {
288e28a4053SRui Paulo /* pending query in RADIUS retransmit queue;
289e28a4053SRui Paulo * do not generate a new one */
290e28a4053SRui Paulo return HOSTAPD_ACL_PENDING;
291e28a4053SRui Paulo }
292e28a4053SRui Paulo query = query->next;
293e28a4053SRui Paulo }
294e28a4053SRui Paulo
295e28a4053SRui Paulo if (!hapd->conf->radius->auth_server)
296e28a4053SRui Paulo return HOSTAPD_ACL_REJECT;
297e28a4053SRui Paulo
298e28a4053SRui Paulo /* No entry in the cache - query external RADIUS server */
299e28a4053SRui Paulo query = os_zalloc(sizeof(*query));
300*a90b9d01SCy Schubert if (!query) {
301e28a4053SRui Paulo wpa_printf(MSG_ERROR, "malloc for query data failed");
302e28a4053SRui Paulo return HOSTAPD_ACL_REJECT;
303e28a4053SRui Paulo }
3045b9c547cSRui Paulo os_get_reltime(&query->timestamp);
305e28a4053SRui Paulo os_memcpy(query->addr, addr, ETH_ALEN);
306e28a4053SRui Paulo if (hostapd_radius_acl_query(hapd, addr, query)) {
307*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
308*a90b9d01SCy Schubert "Failed to send Access-Request for ACL query.");
309e28a4053SRui Paulo hostapd_acl_query_free(query);
310e28a4053SRui Paulo return HOSTAPD_ACL_REJECT;
311e28a4053SRui Paulo }
312e28a4053SRui Paulo
31385732ac8SCy Schubert query->auth_msg = os_memdup(msg, len);
314*a90b9d01SCy Schubert if (!query->auth_msg) {
315*a90b9d01SCy Schubert wpa_printf(MSG_ERROR,
316*a90b9d01SCy Schubert "Failed to allocate memory for auth frame.");
317e28a4053SRui Paulo hostapd_acl_query_free(query);
318e28a4053SRui Paulo return HOSTAPD_ACL_REJECT;
319e28a4053SRui Paulo }
320e28a4053SRui Paulo query->auth_msg_len = len;
321e28a4053SRui Paulo query->next = hapd->acl_queries;
322e28a4053SRui Paulo hapd->acl_queries = query;
323e28a4053SRui Paulo
324e28a4053SRui Paulo /* Queued data will be processed in hostapd_acl_recv_radius()
325e28a4053SRui Paulo * when RADIUS server replies to the sent Access-Request. */
326e28a4053SRui Paulo return HOSTAPD_ACL_PENDING;
327e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
328e28a4053SRui Paulo }
329e28a4053SRui Paulo
330e28a4053SRui Paulo return HOSTAPD_ACL_REJECT;
331e28a4053SRui Paulo }
332e28a4053SRui Paulo
333e28a4053SRui Paulo
334e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS
hostapd_acl_expire_cache(struct hostapd_data * hapd,struct os_reltime * now)3355b9c547cSRui Paulo static void hostapd_acl_expire_cache(struct hostapd_data *hapd,
3365b9c547cSRui Paulo struct os_reltime *now)
337e28a4053SRui Paulo {
338e28a4053SRui Paulo struct hostapd_cached_radius_acl *prev, *entry, *tmp;
339e28a4053SRui Paulo
340e28a4053SRui Paulo prev = NULL;
341e28a4053SRui Paulo entry = hapd->acl_cache;
342e28a4053SRui Paulo
343e28a4053SRui Paulo while (entry) {
3445b9c547cSRui Paulo if (os_reltime_expired(now, &entry->timestamp,
3455b9c547cSRui Paulo RADIUS_ACL_TIMEOUT)) {
346e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
347e28a4053SRui Paulo " has expired.", MAC2STR(entry->addr));
348e28a4053SRui Paulo if (prev)
349e28a4053SRui Paulo prev->next = entry->next;
350e28a4053SRui Paulo else
351e28a4053SRui Paulo hapd->acl_cache = entry->next;
352f05cddf9SRui Paulo hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
353e28a4053SRui Paulo tmp = entry;
354e28a4053SRui Paulo entry = entry->next;
355f05cddf9SRui Paulo hostapd_acl_cache_free_entry(tmp);
356e28a4053SRui Paulo continue;
357e28a4053SRui Paulo }
358e28a4053SRui Paulo
359e28a4053SRui Paulo prev = entry;
360e28a4053SRui Paulo entry = entry->next;
361e28a4053SRui Paulo }
362e28a4053SRui Paulo }
363e28a4053SRui Paulo
364e28a4053SRui Paulo
hostapd_acl_expire_queries(struct hostapd_data * hapd,struct os_reltime * now)365f05cddf9SRui Paulo static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
3665b9c547cSRui Paulo struct os_reltime *now)
367e28a4053SRui Paulo {
368e28a4053SRui Paulo struct hostapd_acl_query_data *prev, *entry, *tmp;
369e28a4053SRui Paulo
370e28a4053SRui Paulo prev = NULL;
371e28a4053SRui Paulo entry = hapd->acl_queries;
372e28a4053SRui Paulo
373e28a4053SRui Paulo while (entry) {
3745b9c547cSRui Paulo if (os_reltime_expired(now, &entry->timestamp,
3755b9c547cSRui Paulo RADIUS_ACL_TIMEOUT)) {
376e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
377e28a4053SRui Paulo " has expired.", MAC2STR(entry->addr));
378e28a4053SRui Paulo if (prev)
379e28a4053SRui Paulo prev->next = entry->next;
380e28a4053SRui Paulo else
381e28a4053SRui Paulo hapd->acl_queries = entry->next;
382e28a4053SRui Paulo
383e28a4053SRui Paulo tmp = entry;
384e28a4053SRui Paulo entry = entry->next;
385e28a4053SRui Paulo hostapd_acl_query_free(tmp);
386e28a4053SRui Paulo continue;
387e28a4053SRui Paulo }
388e28a4053SRui Paulo
389e28a4053SRui Paulo prev = entry;
390e28a4053SRui Paulo entry = entry->next;
391e28a4053SRui Paulo }
392e28a4053SRui Paulo }
393e28a4053SRui Paulo
394e28a4053SRui Paulo
395e28a4053SRui Paulo /**
396e28a4053SRui Paulo * hostapd_acl_expire - ACL cache expiration callback
397325151a3SRui Paulo * @hapd: struct hostapd_data *
398e28a4053SRui Paulo */
hostapd_acl_expire(struct hostapd_data * hapd)399325151a3SRui Paulo void hostapd_acl_expire(struct hostapd_data *hapd)
400e28a4053SRui Paulo {
4015b9c547cSRui Paulo struct os_reltime now;
402e28a4053SRui Paulo
4035b9c547cSRui Paulo os_get_reltime(&now);
4045b9c547cSRui Paulo hostapd_acl_expire_cache(hapd, &now);
4055b9c547cSRui Paulo hostapd_acl_expire_queries(hapd, &now);
406e28a4053SRui Paulo }
407e28a4053SRui Paulo
408e28a4053SRui Paulo
decode_tunnel_passwords(struct hostapd_data * hapd,const u8 * shared_secret,size_t shared_secret_len,struct radius_msg * msg,struct radius_msg * req,struct hostapd_cached_radius_acl * cache)409f05cddf9SRui Paulo static void decode_tunnel_passwords(struct hostapd_data *hapd,
410f05cddf9SRui Paulo const u8 *shared_secret,
411f05cddf9SRui Paulo size_t shared_secret_len,
412f05cddf9SRui Paulo struct radius_msg *msg,
413f05cddf9SRui Paulo struct radius_msg *req,
414f05cddf9SRui Paulo struct hostapd_cached_radius_acl *cache)
415f05cddf9SRui Paulo {
416f05cddf9SRui Paulo int passphraselen;
417780fb4a2SCy Schubert char *passphrase;
418f05cddf9SRui Paulo size_t i;
419f05cddf9SRui Paulo struct hostapd_sta_wpa_psk_short *psk;
420f05cddf9SRui Paulo
421f05cddf9SRui Paulo /*
422f05cddf9SRui Paulo * Decode all tunnel passwords as PSK and save them into a linked list.
423f05cddf9SRui Paulo */
424f05cddf9SRui Paulo for (i = 0; ; i++) {
425f05cddf9SRui Paulo passphrase = radius_msg_get_tunnel_password(
426f05cddf9SRui Paulo msg, &passphraselen, shared_secret, shared_secret_len,
427f05cddf9SRui Paulo req, i);
428f05cddf9SRui Paulo /*
429f05cddf9SRui Paulo * Passphrase is NULL iff there is no i-th Tunnel-Password
430f05cddf9SRui Paulo * attribute in msg.
431f05cddf9SRui Paulo */
432*a90b9d01SCy Schubert if (!passphrase)
433f05cddf9SRui Paulo break;
434780fb4a2SCy Schubert
435780fb4a2SCy Schubert /*
436780fb4a2SCy Schubert * Passphase should be 8..63 chars (to be hashed with SSID)
437780fb4a2SCy Schubert * or 64 chars hex string (no separate hashing with SSID).
438780fb4a2SCy Schubert */
439780fb4a2SCy Schubert
440780fb4a2SCy Schubert if (passphraselen < MIN_PASSPHRASE_LEN ||
441780fb4a2SCy Schubert passphraselen > MAX_PASSPHRASE_LEN + 1)
442780fb4a2SCy Schubert goto free_pass;
443780fb4a2SCy Schubert
444f05cddf9SRui Paulo /*
445f05cddf9SRui Paulo * passphrase does not contain the NULL termination.
446f05cddf9SRui Paulo * Add it here as pbkdf2_sha1() requires it.
447f05cddf9SRui Paulo */
448f05cddf9SRui Paulo psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
449780fb4a2SCy Schubert if (psk) {
450780fb4a2SCy Schubert if ((passphraselen == MAX_PASSPHRASE_LEN + 1) &&
451780fb4a2SCy Schubert (hexstr2bin(passphrase, psk->psk, PMK_LEN) < 0)) {
452780fb4a2SCy Schubert hostapd_logger(hapd, cache->addr,
453780fb4a2SCy Schubert HOSTAPD_MODULE_RADIUS,
454780fb4a2SCy Schubert HOSTAPD_LEVEL_WARNING,
455780fb4a2SCy Schubert "invalid hex string (%d chars) in Tunnel-Password",
456780fb4a2SCy Schubert passphraselen);
457780fb4a2SCy Schubert goto skip;
458780fb4a2SCy Schubert } else if (passphraselen <= MAX_PASSPHRASE_LEN) {
459780fb4a2SCy Schubert os_memcpy(psk->passphrase, passphrase,
460780fb4a2SCy Schubert passphraselen);
461780fb4a2SCy Schubert psk->is_passphrase = 1;
462780fb4a2SCy Schubert }
463c1d255d3SCy Schubert psk->next = cache->info.psk;
464c1d255d3SCy Schubert cache->info.psk = psk;
465f05cddf9SRui Paulo psk = NULL;
466f05cddf9SRui Paulo }
467780fb4a2SCy Schubert skip:
468f05cddf9SRui Paulo os_free(psk);
469780fb4a2SCy Schubert free_pass:
470f05cddf9SRui Paulo os_free(passphrase);
471f05cddf9SRui Paulo }
472f05cddf9SRui Paulo }
473f05cddf9SRui Paulo
474f05cddf9SRui Paulo
475e28a4053SRui Paulo /**
476e28a4053SRui Paulo * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
477e28a4053SRui Paulo * @msg: RADIUS response message
478e28a4053SRui Paulo * @req: RADIUS request message
479e28a4053SRui Paulo * @shared_secret: RADIUS shared secret
480e28a4053SRui Paulo * @shared_secret_len: Length of shared_secret in octets
481e28a4053SRui Paulo * @data: Context data (struct hostapd_data *)
482e28a4053SRui Paulo * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
483e28a4053SRui Paulo * was processed here) or RADIUS_RX_UNKNOWN if not.
484e28a4053SRui Paulo */
485e28a4053SRui Paulo static RadiusRxResult
hostapd_acl_recv_radius(struct radius_msg * msg,struct radius_msg * req,const u8 * shared_secret,size_t shared_secret_len,void * data)486e28a4053SRui Paulo hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
487e28a4053SRui Paulo const u8 *shared_secret, size_t shared_secret_len,
488e28a4053SRui Paulo void *data)
489e28a4053SRui Paulo {
490e28a4053SRui Paulo struct hostapd_data *hapd = data;
491e28a4053SRui Paulo struct hostapd_acl_query_data *query, *prev;
492e28a4053SRui Paulo struct hostapd_cached_radius_acl *cache;
493c1d255d3SCy Schubert struct radius_sta *info;
494e28a4053SRui Paulo struct radius_hdr *hdr = radius_msg_get_hdr(msg);
495e28a4053SRui Paulo
496e28a4053SRui Paulo query = hapd->acl_queries;
497e28a4053SRui Paulo prev = NULL;
498e28a4053SRui Paulo while (query) {
499e28a4053SRui Paulo if (query->radius_id == hdr->identifier)
500e28a4053SRui Paulo break;
501e28a4053SRui Paulo prev = query;
502e28a4053SRui Paulo query = query->next;
503e28a4053SRui Paulo }
504*a90b9d01SCy Schubert if (!query)
505e28a4053SRui Paulo return RADIUS_RX_UNKNOWN;
506e28a4053SRui Paulo
507*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
508*a90b9d01SCy Schubert "Found matching Access-Request for RADIUS message (id=%d)",
509*a90b9d01SCy Schubert query->radius_id);
510e28a4053SRui Paulo
511*a90b9d01SCy Schubert if (radius_msg_verify(
512*a90b9d01SCy Schubert msg, shared_secret, shared_secret_len, req,
513*a90b9d01SCy Schubert hapd->conf->radius_require_message_authenticator)) {
514*a90b9d01SCy Schubert wpa_printf(MSG_INFO,
515*a90b9d01SCy Schubert "Incoming RADIUS packet did not have correct authenticator - dropped");
516e28a4053SRui Paulo return RADIUS_RX_INVALID_AUTHENTICATOR;
517e28a4053SRui Paulo }
518e28a4053SRui Paulo
519e28a4053SRui Paulo if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
520e28a4053SRui Paulo hdr->code != RADIUS_CODE_ACCESS_REJECT) {
521*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
522*a90b9d01SCy Schubert "Unknown RADIUS message code %d to ACL query",
523*a90b9d01SCy Schubert hdr->code);
524e28a4053SRui Paulo return RADIUS_RX_UNKNOWN;
525e28a4053SRui Paulo }
526e28a4053SRui Paulo
527e28a4053SRui Paulo /* Insert Accept/Reject info into ACL cache */
528e28a4053SRui Paulo cache = os_zalloc(sizeof(*cache));
529*a90b9d01SCy Schubert if (!cache) {
530e28a4053SRui Paulo wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
531e28a4053SRui Paulo goto done;
532e28a4053SRui Paulo }
5335b9c547cSRui Paulo os_get_reltime(&cache->timestamp);
534e28a4053SRui Paulo os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
535c1d255d3SCy Schubert info = &cache->info;
536e28a4053SRui Paulo if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
537f05cddf9SRui Paulo u8 *buf;
538f05cddf9SRui Paulo size_t len;
539f05cddf9SRui Paulo
540e28a4053SRui Paulo if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
541c1d255d3SCy Schubert &info->session_timeout) == 0)
542e28a4053SRui Paulo cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
543e28a4053SRui Paulo else
544e28a4053SRui Paulo cache->accepted = HOSTAPD_ACL_ACCEPT;
545e28a4053SRui Paulo
546e28a4053SRui Paulo if (radius_msg_get_attr_int32(
547e28a4053SRui Paulo msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
548c1d255d3SCy Schubert &info->acct_interim_interval) == 0 &&
549c1d255d3SCy Schubert info->acct_interim_interval < 60) {
550*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
551*a90b9d01SCy Schubert "Ignored too small Acct-Interim-Interval %d for STA "
552*a90b9d01SCy Schubert MACSTR,
553c1d255d3SCy Schubert info->acct_interim_interval,
554e28a4053SRui Paulo MAC2STR(query->addr));
555c1d255d3SCy Schubert info->acct_interim_interval = 0;
556e28a4053SRui Paulo }
557e28a4053SRui Paulo
5584bc52338SCy Schubert if (hapd->conf->ssid.dynamic_vlan != DYNAMIC_VLAN_DISABLED)
559c1d255d3SCy Schubert info->vlan_id.notempty = !!radius_msg_get_vlanid(
560c1d255d3SCy Schubert msg, &info->vlan_id.untagged,
561c1d255d3SCy Schubert MAX_NUM_TAGGED_VLAN, info->vlan_id.tagged);
562f05cddf9SRui Paulo
563f05cddf9SRui Paulo decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
564f05cddf9SRui Paulo msg, req, cache);
565f05cddf9SRui Paulo
566f05cddf9SRui Paulo if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
567f05cddf9SRui Paulo &buf, &len, NULL) == 0) {
568c1d255d3SCy Schubert info->identity = os_zalloc(len + 1);
569c1d255d3SCy Schubert if (info->identity)
570c1d255d3SCy Schubert os_memcpy(info->identity, buf, len);
571f05cddf9SRui Paulo }
572f05cddf9SRui Paulo if (radius_msg_get_attr_ptr(
573f05cddf9SRui Paulo msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
574f05cddf9SRui Paulo &buf, &len, NULL) == 0) {
575c1d255d3SCy Schubert info->radius_cui = os_zalloc(len + 1);
576c1d255d3SCy Schubert if (info->radius_cui)
577c1d255d3SCy Schubert os_memcpy(info->radius_cui, buf, len);
578f05cddf9SRui Paulo }
579f05cddf9SRui Paulo
580f05cddf9SRui Paulo if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
581c1d255d3SCy Schubert !info->psk)
582f05cddf9SRui Paulo cache->accepted = HOSTAPD_ACL_REJECT;
583325151a3SRui Paulo
584c1d255d3SCy Schubert if (info->vlan_id.notempty &&
585c1d255d3SCy Schubert !hostapd_vlan_valid(hapd->conf->vlan, &info->vlan_id)) {
586325151a3SRui Paulo hostapd_logger(hapd, query->addr,
587325151a3SRui Paulo HOSTAPD_MODULE_RADIUS,
588325151a3SRui Paulo HOSTAPD_LEVEL_INFO,
589780fb4a2SCy Schubert "Invalid VLAN %d%s received from RADIUS server",
590c1d255d3SCy Schubert info->vlan_id.untagged,
591c1d255d3SCy Schubert info->vlan_id.tagged[0] ? "+" : "");
592c1d255d3SCy Schubert os_memset(&info->vlan_id, 0, sizeof(info->vlan_id));
593325151a3SRui Paulo }
594325151a3SRui Paulo if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_REQUIRED &&
595c1d255d3SCy Schubert !info->vlan_id.notempty)
596325151a3SRui Paulo cache->accepted = HOSTAPD_ACL_REJECT;
597e28a4053SRui Paulo } else
598e28a4053SRui Paulo cache->accepted = HOSTAPD_ACL_REJECT;
599e28a4053SRui Paulo cache->next = hapd->acl_cache;
600e28a4053SRui Paulo hapd->acl_cache = cache;
601e28a4053SRui Paulo
602*a90b9d01SCy Schubert if (query->radius_psk) {
603*a90b9d01SCy Schubert struct sta_info *sta;
604*a90b9d01SCy Schubert bool success = cache->accepted == HOSTAPD_ACL_ACCEPT ||
605*a90b9d01SCy Schubert cache->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT;
606*a90b9d01SCy Schubert
607*a90b9d01SCy Schubert sta = ap_get_sta(hapd, query->addr);
608*a90b9d01SCy Schubert if (!sta || !sta->wpa_sm) {
609*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
610*a90b9d01SCy Schubert "No STA/SM entry found for the RADIUS PSK response");
611*a90b9d01SCy Schubert goto done;
612*a90b9d01SCy Schubert }
613*a90b9d01SCy Schubert #ifdef NEED_AP_MLME
614*a90b9d01SCy Schubert if (success &&
615*a90b9d01SCy Schubert (ieee802_11_set_radius_info(hapd, sta, cache->accepted,
616*a90b9d01SCy Schubert info) < 0 ||
617*a90b9d01SCy Schubert ap_sta_bind_vlan(hapd, sta) < 0))
618*a90b9d01SCy Schubert success = false;
619*a90b9d01SCy Schubert #endif /* NEED_AP_MLME */
620*a90b9d01SCy Schubert wpa_auth_sta_radius_psk_resp(sta->wpa_sm, success);
621*a90b9d01SCy Schubert } else {
622e28a4053SRui Paulo #ifdef CONFIG_DRIVER_RADIUS_ACL
623*a90b9d01SCy Schubert hostapd_drv_set_radius_acl_auth(hapd, query->addr,
624*a90b9d01SCy Schubert cache->accepted,
625c1d255d3SCy Schubert info->session_timeout);
626e28a4053SRui Paulo #else /* CONFIG_DRIVER_RADIUS_ACL */
627e28a4053SRui Paulo #ifdef NEED_AP_MLME
628*a90b9d01SCy Schubert /* Re-send original authentication frame for 802.11 processing
629*a90b9d01SCy Schubert */
630*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
631*a90b9d01SCy Schubert "Re-sending authentication frame after successful RADIUS ACL query");
632*a90b9d01SCy Schubert ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len,
633*a90b9d01SCy Schubert NULL);
634e28a4053SRui Paulo #endif /* NEED_AP_MLME */
635e28a4053SRui Paulo #endif /* CONFIG_DRIVER_RADIUS_ACL */
636*a90b9d01SCy Schubert }
637e28a4053SRui Paulo
638e28a4053SRui Paulo done:
639*a90b9d01SCy Schubert if (!prev)
640e28a4053SRui Paulo hapd->acl_queries = query->next;
641e28a4053SRui Paulo else
642e28a4053SRui Paulo prev->next = query->next;
643e28a4053SRui Paulo
644e28a4053SRui Paulo hostapd_acl_query_free(query);
645e28a4053SRui Paulo
646e28a4053SRui Paulo return RADIUS_RX_PROCESSED;
647e28a4053SRui Paulo }
648e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
649e28a4053SRui Paulo
650e28a4053SRui Paulo
651e28a4053SRui Paulo /**
652e28a4053SRui Paulo * hostapd_acl_init: Initialize IEEE 802.11 ACL
653e28a4053SRui Paulo * @hapd: hostapd BSS data
654e28a4053SRui Paulo * Returns: 0 on success, -1 on failure
655e28a4053SRui Paulo */
hostapd_acl_init(struct hostapd_data * hapd)656e28a4053SRui Paulo int hostapd_acl_init(struct hostapd_data *hapd)
657e28a4053SRui Paulo {
658e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS
659e28a4053SRui Paulo if (radius_client_register(hapd->radius, RADIUS_AUTH,
660e28a4053SRui Paulo hostapd_acl_recv_radius, hapd))
661e28a4053SRui Paulo return -1;
662e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
663e28a4053SRui Paulo
664e28a4053SRui Paulo return 0;
665e28a4053SRui Paulo }
666e28a4053SRui Paulo
667e28a4053SRui Paulo
668e28a4053SRui Paulo /**
669e28a4053SRui Paulo * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
670e28a4053SRui Paulo * @hapd: hostapd BSS data
671e28a4053SRui Paulo */
hostapd_acl_deinit(struct hostapd_data * hapd)672e28a4053SRui Paulo void hostapd_acl_deinit(struct hostapd_data *hapd)
673e28a4053SRui Paulo {
674e28a4053SRui Paulo struct hostapd_acl_query_data *query, *prev;
675e28a4053SRui Paulo
676e28a4053SRui Paulo #ifndef CONFIG_NO_RADIUS
677e28a4053SRui Paulo hostapd_acl_cache_free(hapd->acl_cache);
67885732ac8SCy Schubert hapd->acl_cache = NULL;
679e28a4053SRui Paulo #endif /* CONFIG_NO_RADIUS */
680e28a4053SRui Paulo
681e28a4053SRui Paulo query = hapd->acl_queries;
68285732ac8SCy Schubert hapd->acl_queries = NULL;
683e28a4053SRui Paulo while (query) {
684e28a4053SRui Paulo prev = query;
685e28a4053SRui Paulo query = query->next;
686e28a4053SRui Paulo hostapd_acl_query_free(prev);
687e28a4053SRui Paulo }
688e28a4053SRui Paulo }
689f05cddf9SRui Paulo
690f05cddf9SRui Paulo
hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short ** psk,struct hostapd_sta_wpa_psk_short * src)691c1d255d3SCy Schubert void hostapd_copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
692c1d255d3SCy Schubert struct hostapd_sta_wpa_psk_short *src)
693c1d255d3SCy Schubert {
694c1d255d3SCy Schubert if (!psk)
695c1d255d3SCy Schubert return;
696c1d255d3SCy Schubert
697c1d255d3SCy Schubert if (src)
698c1d255d3SCy Schubert src->ref++;
699c1d255d3SCy Schubert
700c1d255d3SCy Schubert *psk = src;
701c1d255d3SCy Schubert }
702c1d255d3SCy Schubert
703c1d255d3SCy Schubert
hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short * psk)704f05cddf9SRui Paulo void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
705f05cddf9SRui Paulo {
706780fb4a2SCy Schubert if (psk && psk->ref) {
707780fb4a2SCy Schubert /* This will be freed when the last reference is dropped. */
708780fb4a2SCy Schubert psk->ref--;
709780fb4a2SCy Schubert return;
710780fb4a2SCy Schubert }
711780fb4a2SCy Schubert
712f05cddf9SRui Paulo while (psk) {
713f05cddf9SRui Paulo struct hostapd_sta_wpa_psk_short *prev = psk;
714f05cddf9SRui Paulo psk = psk->next;
715*a90b9d01SCy Schubert bin_clear_free(prev, sizeof(*prev));
716f05cddf9SRui Paulo }
717f05cddf9SRui Paulo }
718*a90b9d01SCy Schubert
719*a90b9d01SCy Schubert
720*a90b9d01SCy Schubert #ifndef CONFIG_NO_RADIUS
hostapd_acl_req_radius_psk(struct hostapd_data * hapd,const u8 * addr,int key_mgmt,const u8 * anonce,const u8 * eapol,size_t eapol_len)721*a90b9d01SCy Schubert void hostapd_acl_req_radius_psk(struct hostapd_data *hapd, const u8 *addr,
722*a90b9d01SCy Schubert int key_mgmt, const u8 *anonce,
723*a90b9d01SCy Schubert const u8 *eapol, size_t eapol_len)
724*a90b9d01SCy Schubert {
725*a90b9d01SCy Schubert struct hostapd_acl_query_data *query;
726*a90b9d01SCy Schubert
727*a90b9d01SCy Schubert query = os_zalloc(sizeof(*query));
728*a90b9d01SCy Schubert if (!query)
729*a90b9d01SCy Schubert return;
730*a90b9d01SCy Schubert
731*a90b9d01SCy Schubert query->radius_psk = true;
732*a90b9d01SCy Schubert query->akm = key_mgmt;
733*a90b9d01SCy Schubert os_get_reltime(&query->timestamp);
734*a90b9d01SCy Schubert os_memcpy(query->addr, addr, ETH_ALEN);
735*a90b9d01SCy Schubert if (anonce)
736*a90b9d01SCy Schubert query->anonce = os_memdup(anonce, WPA_NONCE_LEN);
737*a90b9d01SCy Schubert if (eapol) {
738*a90b9d01SCy Schubert query->eapol = os_memdup(eapol, eapol_len);
739*a90b9d01SCy Schubert query->eapol_len = eapol_len;
740*a90b9d01SCy Schubert }
741*a90b9d01SCy Schubert if (hostapd_radius_acl_query(hapd, addr, query)) {
742*a90b9d01SCy Schubert wpa_printf(MSG_DEBUG,
743*a90b9d01SCy Schubert "Failed to send Access-Request for RADIUS PSK/ACL query");
744*a90b9d01SCy Schubert hostapd_acl_query_free(query);
745*a90b9d01SCy Schubert return;
746*a90b9d01SCy Schubert }
747*a90b9d01SCy Schubert
748*a90b9d01SCy Schubert query->next = hapd->acl_queries;
749*a90b9d01SCy Schubert hapd->acl_queries = query;
750*a90b9d01SCy Schubert }
751*a90b9d01SCy Schubert #endif /* CONFIG_NO_RADIUS */
752