wpa_supplicant: Update to 07-Jul-2012 TOT
commit a5ed45586c63ffd8f9d2b44e27c251d7bacbeaf4
Author: Jouni Malinen <j@w1.fi>
Date: Sat Jul 7 13:01:45 2012 +0300
WPS SSDP: Fix socket leaks on error paths
Change-Id: I0864aac7fc88fa2a60f5cca7d524b94363410c85
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 0dd6b12..2b9cbca 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2011-2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -147,6 +147,12 @@
case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
case RADIUS_CODE_RESERVED: return "Reserved";
+ case RADIUS_CODE_DISCONNECT_REQUEST: return "Disconnect-Request";
+ case RADIUS_CODE_DISCONNECT_ACK: return "Disconnect-ACK";
+ case RADIUS_CODE_DISCONNECT_NAK: return "Disconnect-NAK";
+ case RADIUS_CODE_COA_REQUEST: return "CoA-Request";
+ case RADIUS_CODE_COA_ACK: return "CoA-ACK";
+ case RADIUS_CODE_COA_NAK: return "CoA-NAK";
default: return "?Unknown?";
}
}
@@ -222,9 +228,10 @@
RADIUS_ATTR_HEXDUMP },
{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
RADIUS_ATTR_INT32 },
- { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",
+ { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
RADIUS_ATTR_TEXT },
{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
+ { RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 }
};
#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
@@ -406,6 +413,45 @@
}
+int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len,
+ const struct radius_hdr *req_hdr)
+{
+ const u8 *addr[2];
+ size_t len[2];
+ u8 auth[MD5_MAC_LEN];
+ struct radius_attr_hdr *attr;
+
+ os_memset(auth, 0, MD5_MAC_LEN);
+ attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+ auth, MD5_MAC_LEN);
+ if (attr == NULL) {
+ wpa_printf(MSG_WARNING, "Could not add Message-Authenticator");
+ return -1;
+ }
+
+ msg->hdr->length = htons(wpabuf_len(msg->buf));
+ os_memcpy(msg->hdr->authenticator, req_hdr->authenticator, 16);
+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), (u8 *) (attr + 1));
+
+ /* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+ addr[0] = wpabuf_head_u8(msg->buf);
+ len[0] = wpabuf_len(msg->buf);
+ addr[1] = secret;
+ len[1] = secret_len;
+ if (md5_vector(2, addr, len, msg->hdr->authenticator) < 0)
+ return -1;
+
+ if (wpabuf_len(msg->buf) > 0xffff) {
+ wpa_printf(MSG_WARNING, "RADIUS: Too long message (%lu)",
+ (unsigned long) wpabuf_len(msg->buf));
+ return -1;
+ }
+ return 0;
+}
+
+
void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len)
{
@@ -427,6 +473,88 @@
}
+int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len)
+{
+ const u8 *addr[4];
+ size_t len[4];
+ u8 zero[MD5_MAC_LEN];
+ u8 hash[MD5_MAC_LEN];
+
+ os_memset(zero, 0, sizeof(zero));
+ addr[0] = (u8 *) msg->hdr;
+ len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
+ addr[1] = zero;
+ len[1] = MD5_MAC_LEN;
+ addr[2] = (u8 *) (msg->hdr + 1);
+ len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
+ addr[3] = secret;
+ len[3] = secret_len;
+ md5_vector(4, addr, len, hash);
+ return os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0;
+}
+
+
+int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len)
+{
+ const u8 *addr[4];
+ size_t len[4];
+ u8 zero[MD5_MAC_LEN];
+ u8 hash[MD5_MAC_LEN];
+ u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
+ u8 orig_authenticator[16];
+
+ struct radius_attr_hdr *attr = NULL, *tmp;
+ size_t i;
+
+ os_memset(zero, 0, sizeof(zero));
+ addr[0] = (u8 *) msg->hdr;
+ len[0] = sizeof(struct radius_hdr) - MD5_MAC_LEN;
+ addr[1] = zero;
+ len[1] = MD5_MAC_LEN;
+ addr[2] = (u8 *) (msg->hdr + 1);
+ len[2] = wpabuf_len(msg->buf) - sizeof(struct radius_hdr);
+ addr[3] = secret;
+ len[3] = secret_len;
+ md5_vector(4, addr, len, hash);
+ if (os_memcmp(msg->hdr->authenticator, hash, MD5_MAC_LEN) != 0)
+ return 1;
+
+ for (i = 0; i < msg->attr_used; i++) {
+ tmp = radius_get_attr_hdr(msg, i);
+ if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
+ if (attr != NULL) {
+ wpa_printf(MSG_WARNING, "Multiple "
+ "Message-Authenticator attributes "
+ "in RADIUS message");
+ return 1;
+ }
+ attr = tmp;
+ }
+ }
+
+ if (attr == NULL) {
+ /* Message-Authenticator is MAY; not required */
+ return 0;
+ }
+
+ os_memcpy(orig, attr + 1, MD5_MAC_LEN);
+ os_memset(attr + 1, 0, MD5_MAC_LEN);
+ os_memcpy(orig_authenticator, msg->hdr->authenticator,
+ sizeof(orig_authenticator));
+ os_memset(msg->hdr->authenticator, 0,
+ sizeof(msg->hdr->authenticator));
+ hmac_md5(secret, secret_len, wpabuf_head(msg->buf),
+ wpabuf_len(msg->buf), auth);
+ os_memcpy(attr + 1, orig, MD5_MAC_LEN);
+ os_memcpy(msg->hdr->authenticator, orig_authenticator,
+ sizeof(orig_authenticator));
+
+ return os_memcmp(orig, auth, MD5_MAC_LEN) != 0;
+}
+
+
static int radius_msg_add_attr_to_array(struct radius_msg *msg,
struct radius_attr_hdr *attr)
{
@@ -1424,3 +1552,24 @@
return 0;
}
+
+
+u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs)
+{
+ size_t i, j;
+ struct radius_attr_hdr *attr;
+
+ for (i = 0; i < msg->attr_used; i++) {
+ attr = radius_get_attr_hdr(msg, i);
+
+ for (j = 0; attrs[j]; j++) {
+ if (attr->type == attrs[j])
+ break;
+ }
+
+ if (attrs[j] == 0)
+ return attr->type; /* unlisted attr */
+ }
+
+ return 0;
+}
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 44123bd..2d059df 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -1,6 +1,6 @@
/*
* RADIUS message processing
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -31,6 +31,12 @@
RADIUS_CODE_ACCESS_CHALLENGE = 11,
RADIUS_CODE_STATUS_SERVER = 12,
RADIUS_CODE_STATUS_CLIENT = 13,
+ RADIUS_CODE_DISCONNECT_REQUEST = 40,
+ RADIUS_CODE_DISCONNECT_ACK = 41,
+ RADIUS_CODE_DISCONNECT_NAK = 42,
+ RADIUS_CODE_COA_REQUEST = 43,
+ RADIUS_CODE_COA_ACK = 44,
+ RADIUS_CODE_COA_NAK = 45,
RADIUS_CODE_RESERVED = 255
};
@@ -83,7 +89,8 @@
RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID = 81,
RADIUS_ATTR_ACCT_INTERIM_INTERVAL = 85,
RADIUS_ATTR_CHARGEABLE_USER_IDENTITY = 89,
- RADIUS_ATTR_NAS_IPV6_ADDRESS = 95
+ RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
+ RADIUS_ATTR_ERROR_CAUSE = 101
};
@@ -192,8 +199,15 @@
size_t secret_len);
int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
size_t secret_len, const u8 *req_authenticator);
+int radius_msg_finish_das_resp(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len,
+ const struct radius_hdr *req_hdr);
void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
size_t secret_len);
+int radius_msg_verify_acct_req(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len);
+int radius_msg_verify_das_req(struct radius_msg *msg, const u8 *secret,
+ size_t secret_len);
struct radius_attr_hdr * radius_msg_add_attr(struct radius_msg *msg, u8 type,
const u8 *data, size_t data_len);
struct radius_msg * radius_msg_parse(const u8 *data, size_t len);
@@ -268,4 +282,6 @@
int radius_copy_class(struct radius_class_data *dst,
const struct radius_class_data *src);
+u8 radius_msg_find_unlisted_attr(struct radius_msg *msg, u8 *attrs);
+
#endif /* RADIUS_H */
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index bcd471b..1ee7131 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -505,7 +505,7 @@
NULL);
hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
- " %ld seconds\n", (long int) (first - now.sec));
+ " %ld seconds", (long int) (first - now.sec));
}
@@ -678,7 +678,7 @@
radius_client_list_add(radius, msg, msg_type, shared_secret,
shared_secret_len, addr);
- return res;
+ return 0;
}
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
new file mode 100644
index 0000000..8ecfffc
--- /dev/null
+++ b/src/radius/radius_das.c
@@ -0,0 +1,356 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS) (RFC 5176)
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <net/if.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/ip_addr.h"
+#include "radius.h"
+#include "radius_das.h"
+
+
+extern int wpa_debug_level;
+
+
+struct radius_das_data {
+ int sock;
+ u8 *shared_secret;
+ size_t shared_secret_len;
+ struct hostapd_ip_addr client_addr;
+ unsigned int time_window;
+ int require_event_timestamp;
+ void *ctx;
+ enum radius_das_res (*disconnect)(void *ctx,
+ struct radius_das_attrs *attr);
+};
+
+
+static struct radius_msg * radius_das_disconnect(struct radius_das_data *das,
+ struct radius_msg *msg,
+ const char *abuf,
+ int from_port)
+{
+ struct radius_hdr *hdr;
+ struct radius_msg *reply;
+ u8 allowed[] = {
+ RADIUS_ATTR_USER_NAME,
+ RADIUS_ATTR_CALLING_STATION_ID,
+ RADIUS_ATTR_ACCT_SESSION_ID,
+ RADIUS_ATTR_EVENT_TIMESTAMP,
+ RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ 0
+ };
+ int error = 405;
+ u8 attr;
+ enum radius_das_res res;
+ struct radius_das_attrs attrs;
+ u8 *buf;
+ size_t len;
+ char tmp[100];
+ u8 sta_addr[ETH_ALEN];
+
+ hdr = radius_msg_get_hdr(msg);
+
+ attr = radius_msg_find_unlisted_attr(msg, allowed);
+ if (attr) {
+ wpa_printf(MSG_INFO, "DAS: Unsupported attribute %u in "
+ "Disconnect-Request from %s:%d", attr,
+ abuf, from_port);
+ error = 401;
+ goto fail;
+ }
+
+ os_memset(&attrs, 0, sizeof(attrs));
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+ &buf, &len, NULL) == 0) {
+ if (len >= sizeof(tmp))
+ len = sizeof(tmp) - 1;
+ os_memcpy(tmp, buf, len);
+ tmp[len] = '\0';
+ if (hwaddr_aton2(tmp, sta_addr) < 0) {
+ wpa_printf(MSG_INFO, "DAS: Invalid Calling-Station-Id "
+ "'%s' from %s:%d", tmp, abuf, from_port);
+ error = 407;
+ goto fail;
+ }
+ attrs.sta_addr = sta_addr;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+ &buf, &len, NULL) == 0) {
+ attrs.user_name = buf;
+ attrs.user_name_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+ &buf, &len, NULL) == 0) {
+ attrs.acct_session_id = buf;
+ attrs.acct_session_id_len = len;
+ }
+
+ if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+ &buf, &len, NULL) == 0) {
+ attrs.cui = buf;
+ attrs.cui_len = len;
+ }
+
+ res = das->disconnect(das->ctx, &attrs);
+ switch (res) {
+ case RADIUS_DAS_NAS_MISMATCH:
+ wpa_printf(MSG_INFO, "DAS: NAS mismatch from %s:%d",
+ abuf, from_port);
+ error = 403;
+ break;
+ case RADIUS_DAS_SESSION_NOT_FOUND:
+ wpa_printf(MSG_INFO, "DAS: Session not found for request from "
+ "%s:%d", abuf, from_port);
+ error = 503;
+ break;
+ case RADIUS_DAS_SUCCESS:
+ error = 0;
+ break;
+ }
+
+fail:
+ reply = radius_msg_new(error ? RADIUS_CODE_DISCONNECT_NAK :
+ RADIUS_CODE_DISCONNECT_ACK, hdr->identifier);
+ if (reply == NULL)
+ return NULL;
+
+ if (error) {
+ radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE,
+ error);
+ }
+
+ return reply;
+}
+
+
+static void radius_das_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct radius_das_data *das = eloop_ctx;
+ u8 buf[1500];
+ union {
+ struct sockaddr_storage ss;
+ struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+ } from;
+ char abuf[50];
+ int from_port = 0;
+ socklen_t fromlen;
+ int len;
+ struct radius_msg *msg, *reply = NULL;
+ struct radius_hdr *hdr;
+ struct wpabuf *rbuf;
+ u32 val;
+ int res;
+ struct os_time now;
+
+ fromlen = sizeof(from);
+ len = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *) &from.ss, &fromlen);
+ if (len < 0) {
+ wpa_printf(MSG_ERROR, "DAS: recvfrom: %s", strerror(errno));
+ return;
+ }
+
+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+ from_port = ntohs(from.sin.sin_port);
+
+ wpa_printf(MSG_DEBUG, "DAS: Received %d bytes from %s:%d",
+ len, abuf, from_port);
+ if (das->client_addr.u.v4.s_addr != from.sin.sin_addr.s_addr) {
+ wpa_printf(MSG_DEBUG, "DAS: Drop message from unknown client");
+ return;
+ }
+
+ msg = radius_msg_parse(buf, len);
+ if (msg == NULL) {
+ wpa_printf(MSG_DEBUG, "DAS: Parsing incoming RADIUS packet "
+ "from %s:%d failed", abuf, from_port);
+ return;
+ }
+
+ if (wpa_debug_level <= MSG_MSGDUMP)
+ radius_msg_dump(msg);
+
+ if (radius_msg_verify_das_req(msg, das->shared_secret,
+ das->shared_secret_len)) {
+ wpa_printf(MSG_DEBUG, "DAS: Invalid authenticator in packet "
+ "from %s:%d - drop", abuf, from_port);
+ goto fail;
+ }
+
+ os_get_time(&now);
+ res = radius_msg_get_attr(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+ (u8 *) &val, 4);
+ if (res == 4) {
+ u32 timestamp = ntohl(val);
+ if (abs(now.sec - timestamp) > das->time_window) {
+ wpa_printf(MSG_DEBUG, "DAS: Unacceptable "
+ "Event-Timestamp (%u; local time %u) in "
+ "packet from %s:%d - drop",
+ timestamp, (unsigned int) now.sec,
+ abuf, from_port);
+ goto fail;
+ }
+ } else if (das->require_event_timestamp) {
+ wpa_printf(MSG_DEBUG, "DAS: Missing Event-Timestamp in packet "
+ "from %s:%d - drop", abuf, from_port);
+ goto fail;
+ }
+
+ hdr = radius_msg_get_hdr(msg);
+
+ switch (hdr->code) {
+ case RADIUS_CODE_DISCONNECT_REQUEST:
+ reply = radius_das_disconnect(das, msg, abuf, from_port);
+ break;
+ case RADIUS_CODE_COA_REQUEST:
+ /* TODO */
+ reply = radius_msg_new(RADIUS_CODE_COA_NAK,
+ hdr->identifier);
+ if (reply == NULL)
+ break;
+
+ /* Unsupported Service */
+ radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "DAS: Unexpected RADIUS code %u in "
+ "packet from %s:%d",
+ hdr->code, abuf, from_port);
+ }
+
+ if (reply) {
+ wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port);
+
+ if (!radius_msg_add_attr_int32(reply,
+ RADIUS_ATTR_EVENT_TIMESTAMP,
+ now.sec)) {
+ wpa_printf(MSG_DEBUG, "DAS: Failed to add "
+ "Event-Timestamp attribute");
+ }
+
+ if (radius_msg_finish_das_resp(reply, das->shared_secret,
+ das->shared_secret_len, hdr) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "DAS: Failed to add "
+ "Message-Authenticator attribute");
+ }
+
+ if (wpa_debug_level <= MSG_MSGDUMP)
+ radius_msg_dump(reply);
+
+ rbuf = radius_msg_get_buf(reply);
+ res = sendto(das->sock, wpabuf_head(rbuf),
+ wpabuf_len(rbuf), 0,
+ (struct sockaddr *) &from.ss, fromlen);
+ if (res < 0) {
+ wpa_printf(MSG_ERROR, "DAS: sendto(to %s:%d): %s",
+ abuf, from_port, strerror(errno));
+ }
+ }
+
+fail:
+ radius_msg_free(msg);
+ radius_msg_free(reply);
+}
+
+
+static int radius_das_open_socket(int port)
+{
+ int s;
+ struct sockaddr_in addr;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ close(s);
+ return -1;
+ }
+
+ return s;
+}
+
+
+struct radius_das_data *
+radius_das_init(struct radius_das_conf *conf)
+{
+ struct radius_das_data *das;
+
+ if (conf->port == 0 || conf->shared_secret == NULL ||
+ conf->client_addr == NULL)
+ return NULL;
+
+ das = os_zalloc(sizeof(*das));
+ if (das == NULL)
+ return NULL;
+
+ das->time_window = conf->time_window;
+ das->require_event_timestamp = conf->require_event_timestamp;
+ das->ctx = conf->ctx;
+ das->disconnect = conf->disconnect;
+
+ os_memcpy(&das->client_addr, conf->client_addr,
+ sizeof(das->client_addr));
+
+ das->shared_secret = os_malloc(conf->shared_secret_len);
+ if (das->shared_secret == NULL) {
+ radius_das_deinit(das);
+ return NULL;
+ }
+ os_memcpy(das->shared_secret, conf->shared_secret,
+ conf->shared_secret_len);
+ das->shared_secret_len = conf->shared_secret_len;
+
+ das->sock = radius_das_open_socket(conf->port);
+ if (das->sock < 0) {
+ wpa_printf(MSG_ERROR, "Failed to open UDP socket for RADIUS "
+ "DAS");
+ radius_das_deinit(das);
+ return NULL;
+ }
+
+ if (eloop_register_read_sock(das->sock, radius_das_receive, das, NULL))
+ {
+ radius_das_deinit(das);
+ return NULL;
+ }
+
+ return das;
+}
+
+
+void radius_das_deinit(struct radius_das_data *das)
+{
+ if (das == NULL)
+ return;
+
+ if (das->sock >= 0) {
+ eloop_unregister_read_sock(das->sock);
+ close(das->sock);
+ }
+
+ os_free(das->shared_secret);
+ os_free(das);
+}
diff --git a/src/radius/radius_das.h b/src/radius/radius_das.h
new file mode 100644
index 0000000..738b18b
--- /dev/null
+++ b/src/radius/radius_das.h
@@ -0,0 +1,47 @@
+/*
+ * RADIUS Dynamic Authorization Server (DAS)
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RADIUS_DAS_H
+#define RADIUS_DAS_H
+
+struct radius_das_data;
+
+enum radius_das_res {
+ RADIUS_DAS_SUCCESS,
+ RADIUS_DAS_NAS_MISMATCH,
+ RADIUS_DAS_SESSION_NOT_FOUND
+};
+
+struct radius_das_attrs {
+ const u8 *sta_addr;
+ const u8 *user_name;
+ size_t user_name_len;
+ const u8 *acct_session_id;
+ size_t acct_session_id_len;
+ const u8 *cui;
+ size_t cui_len;
+};
+
+struct radius_das_conf {
+ int port;
+ const u8 *shared_secret;
+ size_t shared_secret_len;
+ const struct hostapd_ip_addr *client_addr;
+ unsigned int time_window;
+ int require_event_timestamp;
+ void *ctx;
+ enum radius_das_res (*disconnect)(void *ctx,
+ struct radius_das_attrs *attr);
+};
+
+struct radius_das_data *
+radius_das_init(struct radius_das_conf *conf);
+
+void radius_das_deinit(struct radius_das_data *data);
+
+#endif /* RADIUS_DAS_H */