ieee802_11_auth.c revision 8d520ff1dc2da35cdca849e982051b86468016d8
18d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/*
28d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd / IEEE 802.11 authentication (ACL)
38d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
48d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
58d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * This program is free software; you can redistribute it and/or modify
68d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * it under the terms of the GNU General Public License version 2 as
78d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * published by the Free Software Foundation.
88d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
98d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Alternatively, this software may be distributed under the terms of BSD
108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * license.
118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * See README and COPYING for more details.
138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt *
148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Access control list for IEEE 802.11 authentication can uses statically
158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * configured ACL from configuration files or an external RADIUS server.
168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Results from external RADIUS queries are cached to allow faster
178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * authentication frame processing.
188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/includes.h"
218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/common.h"
238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "utils/eloop.h"
248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radius/radius.h"
258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "radius/radius_client.h"
268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "hostapd.h"
278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_config.h"
288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ap_drv_ops.h"
298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_11.h"
308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#include "ieee802_11_auth.h"
318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#define RADIUS_ACL_TIMEOUT 30
338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct hostapd_cached_radius_acl {
368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_time_t timestamp;
378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	macaddr addr;
388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int accepted; /* HOSTAPD_ACL_* */
398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_cached_radius_acl *next;
408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 session_timeout;
418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u32 acct_interim_interval;
428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	int vlan_id;
438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstruct hostapd_acl_query_data {
478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_time_t timestamp;
488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 radius_id;
498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	macaddr addr;
508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	size_t auth_msg_len;
528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_acl_query_data *next;
538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt};
548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_cached_radius_acl *prev;
608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (acl_cache) {
628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = acl_cache;
638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		acl_cache = acl_cache->next;
648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_free(prev);
658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 u32 *session_timeout,
718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 u32 *acct_interim_interval, int *vlan_id)
728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_cached_radius_acl *entry;
748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time now;
758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_get_time(&now);
778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry = hapd->acl_cache;
788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (entry) {
808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return -1; /* entry has expired */
838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				if (session_timeout)
858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					*session_timeout =
868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						entry->session_timeout;
878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (acct_interim_interval)
888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				*acct_interim_interval =
898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					entry->acct_interim_interval;
908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (vlan_id)
918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				*vlan_id = entry->vlan_id;
928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return entry->accepted;
938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry = entry->next;
968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
1018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
1048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (query == NULL)
1068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return;
1078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(query->auth_msg);
1088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_free(query);
1098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
1108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
1138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
1148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				    struct hostapd_acl_query_data *query)
1158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
1168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct radius_msg *msg;
1178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	char buf[128];
1188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	query->radius_id = radius_client_get_id(hapd->radius);
1208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
1218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (msg == NULL)
1228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
1238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_msg_make_authenticator(msg, addr, ETH_ALEN);
1258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
1278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
1288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 os_strlen(buf))) {
1298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add User-Name");
1308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!radius_msg_add_attr_user_password(
1348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    msg, (u8 *) buf, os_strlen(buf),
1358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    hapd->conf->radius->auth_server->shared_secret,
1368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    hapd->conf->radius->auth_server->shared_secret_len)) {
1378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add User-Password");
1388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->conf->own_ip_addr.af == AF_INET &&
1428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
1438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
1448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add NAS-IP-Address");
1458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_IPV6
1498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->conf->own_ip_addr.af == AF_INET6 &&
1508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
1518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
1528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add NAS-IPv6-Address");
1538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_IPV6 */
1568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->conf->nas_identifier &&
1588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
1598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 (u8 *) hapd->conf->nas_identifier,
1608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 os_strlen(hapd->conf->nas_identifier))) {
1618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add NAS-Identifier");
1628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
1668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
1678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
1688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 (u8 *) buf, os_strlen(buf))) {
1698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add Called-Station-Id");
1708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
1748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    MAC2STR(addr));
1758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
1768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 (u8 *) buf, os_strlen(buf))) {
1778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
1788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
1828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
1838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add NAS-Port-Type");
1848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
1888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
1898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 (u8 *) buf, os_strlen(buf))) {
1908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
1918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto fail;
1928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
1938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr);
1958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
1968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
1978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt fail:
1988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	radius_msg_free(msg);
1998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return -1;
2008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
2018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
2028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
2058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_allowed_address - Check whether a specified STA can be authenticated
2068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @hapd: hostapd BSS data
2078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @addr: MAC address of the STA
2088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: Authentication message
2098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @len: Length of msg in octets
2108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @session_timeout: Buffer for returning session timeout (from RADIUS)
2118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
2128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @vlan_id: Buffer for returning VLAN ID
2138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
2148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
2158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
2168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    const u8 *msg, size_t len, u32 *session_timeout,
2178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    u32 *acct_interim_interval, int *vlan_id)
2188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
2198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (session_timeout)
2208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*session_timeout = 0;
2218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (acct_interim_interval)
2228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*acct_interim_interval = 0;
2238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (vlan_id)
2248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		*vlan_id = 0;
2258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hostapd_maclist_found(hapd->conf->accept_mac,
2278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  hapd->conf->num_accept_mac, addr, vlan_id))
2288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return HOSTAPD_ACL_ACCEPT;
2298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hostapd_maclist_found(hapd->conf->deny_mac,
2318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				  hapd->conf->num_deny_mac, addr, vlan_id))
2328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return HOSTAPD_ACL_REJECT;
2338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
2358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return HOSTAPD_ACL_ACCEPT;
2368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
2378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return HOSTAPD_ACL_REJECT;
2388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
2408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_NO_RADIUS
2418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return HOSTAPD_ACL_REJECT;
2428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_NO_RADIUS */
2438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		struct hostapd_acl_query_data *query;
2448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Check whether ACL cache has an entry for this station */
2468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
2478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						acct_interim_interval,
2488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt						vlan_id);
2498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (res == HOSTAPD_ACL_ACCEPT ||
2508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
2518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return res;
2528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (res == HOSTAPD_ACL_REJECT)
2538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return HOSTAPD_ACL_REJECT;
2548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		query = hapd->acl_queries;
2568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		while (query) {
2578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
2588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				/* pending query in RADIUS retransmit queue;
2598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				 * do not generate a new one */
2608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				return HOSTAPD_ACL_PENDING;
2618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			}
2628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			query = query->next;
2638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (!hapd->conf->radius->auth_server)
2668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return HOSTAPD_ACL_REJECT;
2678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* No entry in the cache - query external RADIUS server */
2698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		query = os_zalloc(sizeof(*query));
2708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (query == NULL) {
2718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "malloc for query data failed");
2728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return HOSTAPD_ACL_REJECT;
2738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		time(&query->timestamp);
2758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(query->addr, addr, ETH_ALEN);
2768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (hostapd_radius_acl_query(hapd, addr, query)) {
2778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
2788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "for ACL query.");
2798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			hostapd_acl_query_free(query);
2808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return HOSTAPD_ACL_REJECT;
2818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		query->auth_msg = os_malloc(len);
2848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (query->auth_msg == NULL) {
2858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_ERROR, "Failed to allocate memory for "
2868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "auth frame.");
2878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			hostapd_acl_query_free(query);
2888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			return HOSTAPD_ACL_REJECT;
2898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
2908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		os_memcpy(query->auth_msg, msg, len);
2918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		query->auth_msg_len = len;
2928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		query->next = hapd->acl_queries;
2938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd->acl_queries = query;
2948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
2958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		/* Queued data will be processed in hostapd_acl_recv_radius()
2968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		 * when RADIUS server replies to the sent Access-Request. */
2978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return HOSTAPD_ACL_PENDING;
2988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
2998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return HOSTAPD_ACL_REJECT;
3028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
3068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
3078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_cached_radius_acl *prev, *entry, *tmp;
3098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = NULL;
3118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry = hapd->acl_cache;
3128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (entry) {
3148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
3158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
3168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   " has expired.", MAC2STR(entry->addr));
3178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev)
3188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				prev->next = entry->next;
3198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
3208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				hapd->acl_cache = entry->next;
3218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
3228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tmp = entry;
3238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			entry = entry->next;
3248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			os_free(tmp);
3258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
3268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = entry;
3298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry = entry->next;
3308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void hostapd_acl_expire_queries(struct hostapd_data *hapd,
3358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				       os_time_t now)
3368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_acl_query_data *prev, *entry, *tmp;
3388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = NULL;
3408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	entry = hapd->acl_queries;
3418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (entry) {
3438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
3448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
3458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   " has expired.", MAC2STR(entry->addr));
3468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			if (prev)
3478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				prev->next = entry->next;
3488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			else
3498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				hapd->acl_queries = entry->next;
3508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			tmp = entry;
3528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			entry = entry->next;
3538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			hostapd_acl_query_free(tmp);
3548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			continue;
3558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
3568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = entry;
3588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		entry = entry->next;
3598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
3608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_acl_expire - ACL cache expiration callback
3658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @eloop_ctx: struct hostapd_data *
3668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @timeout_ctx: Not used
3678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
3698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd = eloop_ctx;
3718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct os_time now;
3728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_get_time(&now);
3748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_acl_expire_cache(hapd, now.sec);
3758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_acl_expire_queries(hapd, now.sec);
3768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
3788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
3798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
3818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
3828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
3838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @msg: RADIUS response message
3848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @req: RADIUS request message
3858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @shared_secret: RADIUS shared secret
3868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @shared_secret_len: Length of shared_secret in octets
3878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @data: Context data (struct hostapd_data *)
3888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
3898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * was processed here) or RADIUS_RX_UNKNOWN if not.
3908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
3918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtstatic RadiusRxResult
3928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidthostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
3938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			const u8 *shared_secret, size_t shared_secret_len,
3948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			void *data)
3958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
3968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_data *hapd = data;
3978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_acl_query_data *query, *prev;
3988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_cached_radius_acl *cache;
3998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
4008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	query = hapd->acl_queries;
4028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	prev = NULL;
4038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (query) {
4048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (query->radius_id == hdr->identifier)
4058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			break;
4068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = query;
4078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		query = query->next;
4088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (query == NULL)
4108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return RADIUS_RX_UNKNOWN;
4118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
4138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "message (id=%d)", query->radius_id);
4148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
4168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
4178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "correct authenticator - dropped\n");
4188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return RADIUS_RX_INVALID_AUTHENTICATOR;
4198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
4228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	    hdr->code != RADIUS_CODE_ACCESS_REJECT) {
4238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
4248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			   "query", hdr->code);
4258d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return RADIUS_RX_UNKNOWN;
4268d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4278d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4288d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Insert Accept/Reject info into ACL cache */
4298d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cache = os_zalloc(sizeof(*cache));
4308d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (cache == NULL) {
4318d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
4328d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		goto done;
4338d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
4348d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	time(&cache->timestamp);
4358d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
4368d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
4378d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
4388d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					      &cache->session_timeout) == 0)
4398d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
4408d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		else
4418d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cache->accepted = HOSTAPD_ACL_ACCEPT;
4428d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4438d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		if (radius_msg_get_attr_int32(
4448d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
4458d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			    &cache->acct_interim_interval) == 0 &&
4468d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		    cache->acct_interim_interval < 60) {
4478d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			wpa_printf(MSG_DEBUG, "Ignored too small "
4488d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   "Acct-Interim-Interval %d for STA " MACSTR,
4498d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   cache->acct_interim_interval,
4508d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   MAC2STR(query->addr));
4518d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt			cache->acct_interim_interval = 0;
4528d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		}
4538d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4548d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cache->vlan_id = radius_msg_get_vlanid(msg);
4558d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	} else
4568d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		cache->accepted = HOSTAPD_ACL_REJECT;
4578d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	cache->next = hapd->acl_cache;
4588d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hapd->acl_cache = cache;
4598d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4608d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef CONFIG_DRIVER_RADIUS_ACL
4618d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
4628d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt					cache->session_timeout);
4638d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#else /* CONFIG_DRIVER_RADIUS_ACL */
4648d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifdef NEED_AP_MLME
4658d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	/* Re-send original authentication frame for 802.11 processing */
4668d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
4678d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		   "successful RADIUS ACL query");
4688d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
4698d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* NEED_AP_MLME */
4708d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_DRIVER_RADIUS_ACL */
4718d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4728d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt done:
4738d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (prev == NULL)
4748d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hapd->acl_queries = query->next;
4758d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	else
4768d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev->next = query->next;
4778d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4788d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_acl_query_free(query);
4798d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4808d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return RADIUS_RX_PROCESSED;
4818d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
4828d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
4838d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4848d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4858d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
4868d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_acl_init: Initialize IEEE 802.11 ACL
4878d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @hapd: hostapd BSS data
4888d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * Returns: 0 on success, -1 on failure
4898d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
4908d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtint hostapd_acl_init(struct hostapd_data *hapd)
4918d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
4928d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
4938d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	if (radius_client_register(hapd->radius, RADIUS_AUTH,
4948d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt				   hostapd_acl_recv_radius, hapd))
4958d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		return -1;
4968d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
4978d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
4988d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
4998d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5008d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	return 0;
5018d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
5028d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5038d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5048d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt/**
5058d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
5068d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt * @hapd: hostapd BSS data
5078d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt */
5088d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidtvoid hostapd_acl_deinit(struct hostapd_data *hapd)
5098d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt{
5108d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	struct hostapd_acl_query_data *query, *prev;
5118d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5128d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#ifndef CONFIG_NO_RADIUS
5138d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
5148d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5158d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	hostapd_acl_cache_free(hapd->acl_cache);
5168d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt#endif /* CONFIG_NO_RADIUS */
5178d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt
5188d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	query = hapd->acl_queries;
5198d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	while (query) {
5208d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		prev = query;
5218d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		query = query->next;
5228d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt		hostapd_acl_query_free(prev);
5238d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt	}
5248d520ff1dc2da35cdca849e982051b86468016d8Dmitry Shmidt}
525