]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Add preliminary RADIUS dynamic authorization server (RFC 5176)
authorJouni Malinen <j@w1.fi>
Sun, 6 May 2012 19:02:42 +0000 (22:02 +0300)
committerJouni Malinen <j@w1.fi>
Sun, 6 May 2012 19:02:42 +0000 (22:02 +0300)
This adds the basic DAS mechanism to enable hostapd to be configured
to request dynamic authorization requests (Disconnect-Request and
CoA-Request). This commit does not add actual processing of the
requests, i.e., this will only receive and authenticate the requests
and NAK them regardless of what operation is requested.

Signed-hostap: Jouni Malinen <j@w1.fi>

hostapd/Makefile
hostapd/config_file.c
hostapd/hostapd.conf
src/ap/ap_config.c
src/ap/ap_config.h
src/ap/hostapd.c
src/ap/hostapd.h
src/radius/radius.c
src/radius/radius.h
src/radius/radius_das.c [new file with mode: 0644]
src/radius/radius_das.h [new file with mode: 0644]

index 05a363b5449855eb80ce30b80fab5302c81a2b85..9e42d037fda0f16b76af730e970eae4f3cbe6764 100644 (file)
@@ -110,6 +110,7 @@ CONFIG_NO_ACCOUNTING=y
 else
 OBJS += ../src/radius/radius.o
 OBJS += ../src/radius/radius_client.o
+OBJS += ../src/radius/radius_das.o
 endif
 
 ifdef CONFIG_NO_ACCOUNTING
index 5c8824c54ccd4fc8d589db171cc5e4d362c66e99..eab8ad46480b7f4077b75fa362ac2897b9889339 100644 (file)
@@ -561,6 +561,34 @@ hostapd_parse_radius_attr(const char *value)
 
        return attr;
 }
+
+
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
+                                   const char *val)
+{
+       char *secret;
+       size_t len;
+
+       secret = os_strchr(val, ' ');
+       if (secret == NULL)
+               return -1;
+
+       secret++;
+       len = os_strlen(secret);
+
+       if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
+               return -1;
+
+       os_free(bss->radius_das_shared_secret);
+       bss->radius_das_shared_secret = os_malloc(len);
+       if (bss->radius_das_shared_secret == NULL)
+               return -1;
+
+       os_memcpy(bss->radius_das_shared_secret, secret, len);
+       bss->radius_das_shared_secret_len = len;
+
+       return 0;
+}
 #endif /* CONFIG_NO_RADIUS */
 
 
@@ -1657,6 +1685,14 @@ static int hostapd_config_fill(struct hostapd_config *conf,
                                        a = a->next;
                                a->next = attr;
                        }
+               } else if (os_strcmp(buf, "radius_das_port") == 0) {
+                       bss->radius_das_port = atoi(pos);
+               } else if (os_strcmp(buf, "radius_das_client") == 0) {
+                       if (hostapd_parse_das_client(bss, pos) < 0) {
+                               wpa_printf(MSG_ERROR, "Line %d: invalid "
+                                          "DAS client", line);
+                               errors++;
+                       }
 #endif /* CONFIG_NO_RADIUS */
                } else if (os_strcmp(buf, "auth_algs") == 0) {
                        bss->auth_algs = atoi(pos);
index 8890cd27c813b0d5bd4fdaf91479a98aa22ed6eb..611ce952e4724883e4425938dcd796b84d219a2b 100644 (file)
@@ -696,6 +696,19 @@ own_ip_addr=127.0.0.1
 # Operator-Name = "Operator"
 #radius_acct_req_attr=126:s:Operator
 
+# Dynamic Authorization Extensions (RFC 5176)
+# This mechanism can be used to allow dynamic changes to user session based on
+# commands from a RADIUS server (or some other disconnect client that has the
+# needed session information). For example, Disconnect message can be used to
+# request an associated station to be disconnected.
+#
+# This is disabled by default. Set radius_das_port to non-zero UDP port
+# number to enable.
+#radius_das_port=3799
+#
+# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+#radius_das_client=192.168.1.123 shared secret here
+
 ##### RADIUS authentication server configuration ##############################
 
 # hostapd can be used as a RADIUS authentication server for other hosts. This
index 392b4fd40074d70b5ae6af0ce6e8133f56fefa74..e916f1207bb9d3103c0fd25dd95585dab72de831 100644 (file)
@@ -432,6 +432,7 @@ static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
        os_free(conf->radius_server_clients);
        os_free(conf->test_socket);
        os_free(conf->radius);
+       os_free(conf->radius_das_shared_secret);
        hostapd_config_free_vlan(conf);
        if (conf->ssid.dyn_vlan_keys) {
                struct hostapd_ssid *ssid = &conf->ssid;
index 5473be156ee7e283cb5c26437c239a33ad272283..78c90689bcc45a6e5de82627381db4c106be9f1d 100644 (file)
@@ -186,6 +186,10 @@ struct hostapd_bss_config {
        int radius_request_cui;
        struct hostapd_radius_attr *radius_auth_req_attr;
        struct hostapd_radius_attr *radius_acct_req_attr;
+       int radius_das_port;
+       struct hostapd_ip_addr radius_das_client_addr;
+       u8 *radius_das_shared_secret;
+       size_t radius_das_shared_secret_len;
 
        struct hostapd_ssid ssid;
 
index 0f94188a039e3275aba5a657217263a9445cd270..9d6fd7b3c8cdae81898c7297cb942da512e2b8ab 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -12,6 +12,7 @@
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "radius/radius_client.h"
+#include "radius/radius_das.h"
 #include "drivers/driver.h"
 #include "hostapd.h"
 #include "authsrv.h"
@@ -241,6 +242,8 @@ static void hostapd_free_hapd_data(struct hostapd_data *hapd)
 #ifndef CONFIG_NO_RADIUS
        radius_client_deinit(hapd->radius);
        hapd->radius = NULL;
+       radius_das_deinit(hapd->radius_das);
+       hapd->radius_das = NULL;
 #endif /* CONFIG_NO_RADIUS */
 
        hostapd_deinit_wps(hapd);
@@ -627,6 +630,22 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
                wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
                return -1;
        }
+
+       if (hapd->conf->radius_das_port) {
+               struct radius_das_conf das_conf;
+               os_memset(&das_conf, 0, sizeof(das_conf));
+               das_conf.port = hapd->conf->radius_das_port;
+               das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+               das_conf.shared_secret_len =
+                       hapd->conf->radius_das_shared_secret_len;
+               das_conf.client_addr = &hapd->conf->radius_das_client_addr;
+               hapd->radius_das = radius_das_init(&das_conf);
+               if (hapd->radius_das == NULL) {
+                       wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
+                                  "failed.");
+                       return -1;
+               }
+       }
 #endif /* CONFIG_NO_RADIUS */
 
        if (hostapd_acl_init(hapd)) {
index 63cf494ec03b252b6d8101ae79f19b1329dc48f9..4e45d59e839a06725649aec6a72cd2f2768ffd2e 100644 (file)
@@ -85,6 +85,7 @@ struct hostapd_data {
 
        struct radius_client_data *radius;
        u32 acct_session_id_hi, acct_session_id_lo;
+       struct radius_das_data *radius_das;
 
        struct iapp_data *iapp;
 
index 0dd6b127e895d7e77b2dc18f71ffd8e9f855e7d7..ed0a9de7d25446d9386184a714e477a9d4d26dd1 100644 (file)
@@ -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 @@ static const char *radius_code_string(u8 code)
        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?";
        }
 }
@@ -225,6 +231,7 @@ static struct radius_attr_type radius_attrs[] =
        { RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-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_srv(struct radius_msg *msg, const u8 *secret,
 }
 
 
+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 @@ void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
 }
 
 
+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)
 {
index 44123bdb56e466e59fdbd2c2bc4d0c64ccc1f54a..8cc611319d4e7e7baeec906203b23f275222425d 100644 (file)
@@ -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 @@ enum { RADIUS_CODE_ACCESS_REQUEST = 1,
        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 @@ enum { RADIUS_ATTR_USER_NAME = 1,
        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 @@ int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
                      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);
diff --git a/src/radius/radius_das.c b/src/radius/radius_das.c
new file mode 100644 (file)
index 0000000..ae3df89
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * 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;
+};
+
+
+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;
+
+       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;
+       }
+
+       hdr = radius_msg_get_hdr(msg);
+
+       switch (hdr->code) {
+       case RADIUS_CODE_DISCONNECT_REQUEST:
+               /* TODO */
+               reply = radius_msg_new(RADIUS_CODE_DISCONNECT_NAK,
+                                      hdr->identifier);
+               if (reply == NULL)
+                       break;
+
+               radius_msg_add_attr_int32(reply, RADIUS_ATTR_ERROR_CAUSE, 405);
+               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) {
+               int res;
+
+               wpa_printf(MSG_DEBUG, "DAS: Reply to %s:%d", abuf, from_port);
+
+               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;
+
+       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 (file)
index 0000000..4e21c6d
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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;
+
+struct radius_das_conf {
+       int port;
+       const u8 *shared_secret;
+       size_t shared_secret_len;
+       const struct hostapd_ip_addr *client_addr;
+};
+
+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 */