changeset 365:0146c60af026

Moved to the hostap implementation of RADIUS processing (copied radius.* and md5.* files)
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 22 May 2009 18:11:49 +0900
parents 48de36f08bec
children 4507804fc120
files extensions/radius_gw/CMakeLists.txt extensions/radius_gw/design.txt extensions/radius_gw/hostap_compat.h extensions/radius_gw/md5.c extensions/radius_gw/md5.h extensions/radius_gw/md5.h.in extensions/radius_gw/radius.c extensions/radius_gw/radius.h extensions/radius_gw/radius_gw.c extensions/radius_gw/radius_gw.h extensions/radius_gw/radius_gw.l extensions/radius_gw/radius_gw.y extensions/radius_gw/radius_gw_internal.h extensions/radius_gw/rg_api.h extensions/radius_gw/rg_common.h extensions/radius_gw/rg_host.h.in extensions/radius_gw/rg_utils.c extensions/radius_gw/rg_utils_attrtype.inc extensions/radius_gw/rg_utils_codes.inc extensions/radius_gw/rgw_clients.c extensions/radius_gw/rgw_extensions.c extensions/radius_gw/rgw_msg.c extensions/radius_gw/rgw_msg_attrtype.c extensions/radius_gw/rgw_msg_attrtypes.c extensions/radius_gw/rgw_msg_codes.c extensions/radius_gw/rgw_servers.c extensions/radius_gw/rgw_work.c extensions/radius_gw/rsc/rebuild_inc.sh extensions/radius_gw/sub_sample.c
diffstat 29 files changed, 3224 insertions(+), 1426 deletions(-) [+]
line wrap: on
line diff
--- a/extensions/radius_gw/CMakeLists.txt	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/CMakeLists.txt	Fri May 22 18:11:49 2009 +0900
@@ -4,19 +4,29 @@
 
 ########### Utility library #############
 # utilities libray for both the main extension and the sub extensions
+# See rg_common.h for detail
+
+INCLUDE (TestBigEndian)
+TEST_BIG_ENDIAN(WORDS_BIGENDIAN)
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/rg_host.h.in ${CMAKE_CURRENT_BINARY_DIR}/rg_host.h)
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+
 SET(RG_COMMON_SRC
 	rg_utils.c
+	radius.c
+	md5.c
 )
-ADD_DEFINITIONS(-DRG_COMMON_VERBO=FULL)
-ADD_LIBRARY(rg_common STATIC ${RG_COMMON_SRC})
-# Note : we could remove the STATIC here to avoid duplicating the code; but it is not tested yet.
+SET( RG_COMMON_HEADER
+	rg_common.h
+	rg_host.h
+	rg_api.h
+	radius.h
+	md5.h
+)	
+ADD_DEFINITIONS(-DRG_COMMON_VERBO=2)
+ADD_LIBRARY(rg_common ${RG_COMMON_SRC})
 
 ########### Main radius_gw extension #############
-# md5
-INCLUDE (TestBigEndian)
-TEST_BIG_ENDIAN(HOST_BIG_ENDIAN)
-CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/md5.h.in ${CMAKE_CURRENT_BINARY_DIR}/md5.h)
-INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
 
 # Parser files
 BISON_FILE(radius_gw.y)
@@ -31,18 +41,14 @@
 	radius_gw.tab.h
 	rgw_clients.c
 	rgw_extensions.c
+	rgw_msg.c
 	rgw_servers.c
-	rgw_msg.c
 	rgw_work.c
-	md5.c
 )
 
-SET( RGW_DEFAULT_HEADER
-	radius_gw.h
-)	
 
 # Compile these files as a module
-ADD_LIBRARY(radius_gw MODULE ${RGW_DEFAULT_SRC} ${RGW_DEFAULT_HEADER})
+ADD_LIBRARY(radius_gw MODULE ${RGW_DEFAULT_SRC} ${RG_COMMON_HEADER})
 TARGET_LINK_LIBRARIES(radius_gw rg_common)
 
 
@@ -63,6 +69,6 @@
 
 OPTION(BUILD_RADIUS_GW_SAMPLE "Build sample sub-extension? (for debug only)" ON)
  	IF (BUILD_RADIUS_GW_SAMPLE)
- 	   ADD_LIBRARY(sub_sample MODULE ${RGW_DEFAULT_HEADER} sub_sample.c)
+ 	   ADD_LIBRARY(sub_sample MODULE ${RG_COMMON_HEADER} sub_sample.c)
 	   TARGET_LINK_LIBRARIES(sub_sample rg_common)
  	ENDIF (BUILD_RADIUS_GW_SAMPLE)
--- a/extensions/radius_gw/design.txt	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/design.txt	Fri May 22 18:11:49 2009 +0900
@@ -18,24 +18,22 @@
    - duplicate
    - ... (?)
    - creates a rad_t structure (radius_gw.h) containing the RADIUS message information:
-     - message data
-     - and metadata:
-       - attribute description
-       - already handled by an extension? (always initialized to 0)
+     - message data and metadata
+     - attribute list
  - Pass the RADIUS parsed message, and locations for a diameter message and session to all registered extensions, 
      in the order specified in configuration.
-   - each extension may modify all its input (it must in particular set the "handled" flag to RADIUS attributes it
-      converted to Diameter)
-   - The extensions return error codes. The error may mean:
-     - stop processing and return an immediate error to the RADIUS client (critical error).
+   - each extension may modify all its input (it must delete the RADIUS attributes it processed)
+   - The extensions return error codes (see radius_gw.h for detail). The meaning is:
+     - no error, continue
+     - stop processing and return an immediate error (critical error).
      - (eventually for later) continue processing if a fallback extension is registered (not supported in initial version)
      - (eventually for later) An immediate RADIUS answer must be sent, without going to Diameter network. This can be used for example for 
        fragmented RADIUS requests (not supported in initial version, may require change in the design...).
  - When all extensions have been called, the Diameter message is checked for consistency. If it is a valid message,
    it is sent on the Diameter Network, and the RADIUS message is saved in the session.
    
-When the Diameter answer is received, the radius_gw retrieves the corresponding RADIUS request from
-    the session, then a similar process happens (extensions are the same as for the request). 
+When the Diameter answer is received, the radius_gw retrieves the corresponding RADIUS request, 
+then a similar process happens (extensions are the same as for the request). 
  - It calls all registered extensions with:
    - session pointer
    - RADIUS request
@@ -44,6 +42,7 @@
  - When all extensions have been called, the RADIUS answer is generated, with appropriate authenticator and all, and 
    sent to the RADIUS client.
 
+
 *** About sessions ***
 
 The session is created the first time an Access-Request is received.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/hostap_compat.h	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,117 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2008, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* This file contains compatibility bindings for hostap files.
+ Most of the definitions here come from different files from the hostap project.
+ 
+ We don't care for OS-specific definitions since we are only compatible with POSIX systems.
+ 
+ */
+
+#ifndef _HOSTAP_COMPAT_H
+#define _HOSTAP_COMPAT_H
+
+#include <sys/time.h>
+
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t s8;
+
+/* Waaad uses the POSIX API, so we don't provide alternatives. This may be changed later as needed */
+#define os_malloc(s) malloc((s))
+#define os_realloc(p, s) realloc((p), (s))
+#define os_free(p) free((p))
+
+#define os_memcpy(d, s, n) memcpy((d), (s), (n))
+#define os_memmove(d, s, n) memmove((d), (s), (n))
+#define os_memset(s, c, n) memset(s, c, n)
+#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
+
+#define os_strdup(s) strdup(s)
+#define os_strlen(s) strlen(s)
+#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
+#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
+#define os_strchr(s, c) strchr((s), (c))
+#define os_strcmp(s1, s2) strcmp((s1), (s2))
+#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
+#define os_strncpy(d, s, n) strncpy((d), (s), (n))
+#define os_strrchr(s, c) strrchr((s), (c))
+#define os_strstr(h, n) strstr((h), (n))
+#define os_snprintf snprintf
+
+#define os_random() random()
+
+static __inline__ void * os_zalloc(size_t size)
+{
+	void *n = os_malloc(size);
+	if (n)
+		os_memset(n, 0, size);
+	return n;
+}
+
+typedef long os_time_t;
+struct os_time {
+	os_time_t sec;
+	os_time_t usec;
+};
+
+static __inline__ int os_get_time(struct os_time *t)
+{
+	int res;
+	struct timeval tv;
+	res = gettimeofday(&tv, NULL);
+	t->sec = tv.tv_sec;
+	t->usec = tv.tv_usec;
+	return res;
+}
+
+
+#ifdef __GNUC__
+#define STRUCT_PACKED __attribute__ ((packed))
+#else
+#define STRUCT_PACKED
+#endif
+
+
+#define INTERNAL_MD5
+#define CONFIG_CRYPTO_INTERNAL
+
+
+#endif /* _HOSTAP_COMPAT_H */
--- a/extensions/radius_gw/md5.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/md5.c	Fri May 22 18:11:49 2009 +0900
@@ -1,25 +1,29 @@
-/* Copyright:
- * The content from this file comes for the most part from the hostapd project.
- * That project is licensed under GNU GPL v2 or BSD.
- * We reproduce these bits here under the terms of the BSD license.
- * A part of this file is also public domain.
+/*********************************************************************************/
+/* Waaad author note:
+ *  The content from this file comes directly from the hostap project.
+ * It is redistributed under the terms of the BSD license, as allowed
+ * by the original copyright reproduced bellow.
+ *  In addition to this notide, only the #include directives have been modified.
  */
- 
-#include "md5.h"
-
-#include <string.h>
+#include "rg_common.h"
+/* Forward declaration: */
+void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
+/*********************************************************************************/
 
-
-/* forward declarations */
-void md5_vector(size_t num_elem, const uint8_t *addr[], const size_t *len, uint8_t *mac);
-
-/* the following might come from openssl also */
-struct MD5Context;
-void MD5Init(struct MD5Context *context);
-void MD5Update(struct MD5Context *context, unsigned char const *buf, unsigned len);
-void MD5Final(unsigned char digest[16], struct MD5Context *context);
-
-static void MD5Transform(uint32_t buf[4], uint32_t const in[16]);
+ 
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
 
 
 /**
@@ -31,11 +35,12 @@
  * @len: Lengths of the data blocks
  * @mac: Buffer for the hash (16 bytes)
  */
-void hmac_md5_vector(const uint8_t *key, size_t key_len, size_t num_elem, const uint8_t *addr[], const size_t *len, uint8_t *mac)
+void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
 {
-	uint8_t k_pad[64]; /* padding - key XORd with ipad/opad */
-	uint8_t tk[16];
-	const uint8_t *_addr[6];
+	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
+	u8 tk[16];
+	const u8 *_addr[6];
 	size_t i, _len[6];
 
 	if (num_elem > 5) {
@@ -63,8 +68,8 @@
 	 * and text is the data being protected */
 
 	/* start out by storing key in ipad */
-	memset(k_pad, 0, sizeof(k_pad));
-	memcpy(k_pad, key, key_len);
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
 
 	/* XOR key with ipad values */
 	for (i = 0; i < 64; i++)
@@ -79,8 +84,8 @@
 	}
 	md5_vector(1 + num_elem, _addr, _len, mac);
 
-	memset(k_pad, 0, sizeof(k_pad));
-	memcpy(k_pad, key, key_len);
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
 	/* XOR key with opad values */
 	for (i = 0; i < 64; i++)
 		k_pad[i] ^= 0x5c;
@@ -102,18 +107,28 @@
  * @data_len: Length of the data area
  * @mac: Buffer for the hash (16 bytes)
  */
-void hmac_md5(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t *mac)
+void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	      u8 *mac)
 {
 	hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
 }
 
 
+#ifdef INTERNAL_MD5
+
 struct MD5Context {
-	uint32_t buf[4];
-	uint32_t bits[2];
-	uint8_t in[64];
+	u32 buf[4];
+	u32 bits[2];
+	u8 in[64];
 };
 
+#ifndef CONFIG_CRYPTO_INTERNAL
+static void MD5Init(struct MD5Context *context);
+static void MD5Update(struct MD5Context *context, unsigned char const *buf,
+			  unsigned len);
+static void MD5Final(unsigned char digest[16], struct MD5Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
+static void MD5Transform(u32 buf[4], u32 const in[16]);
 
 
 typedef struct MD5Context MD5_CTX;
@@ -126,7 +141,7 @@
  * @len: Lengths of the data blocks
  * @mac: Buffer for the hash
  */
-void md5_vector(size_t num_elem, const uint8_t *addr[], const size_t *len, uint8_t *mac)
+void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
 {
 	MD5_CTX ctx;
 	size_t i;
@@ -138,11 +153,6 @@
 }
 
 
-
-
-
-
-
 /* ===== start - public domain MD5 implementation ===== */
 /*
  * This code implements the MD5 message-digest algorithm.
@@ -161,7 +171,7 @@
  * will fill a supplied 16-byte array with the digest.
  */
 
-#ifndef HOST_BIG_ENDIAN
+#ifndef WORDS_BIGENDIAN
 #define byteReverse(buf, len)	/* Nothing */
 #else
 /*
@@ -169,11 +179,11 @@
  */
 static void byteReverse(unsigned char *buf, unsigned longs)
 {
-    uint32_t t;
+    u32 t;
     do {
-	t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+	t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
 	    ((unsigned) buf[1] << 8 | buf[0]);
-	*(uint32_t *) buf = t;
+	*(u32 *) buf = t;
 	buf += 4;
     } while (--longs);
 }
@@ -200,12 +210,12 @@
  */
 void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
 {
-    uint32_t t;
+    u32 t;
 
     /* Update bitcount */
 
     t = ctx->bits[0];
-    if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
+    if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
 	ctx->bits[1]++;		/* Carry from low to high */
     ctx->bits[1] += len >> 29;
 
@@ -218,28 +228,28 @@
 
 	t = 64 - t;
 	if (len < t) {
-	    memcpy(p, buf, len);
+	    os_memcpy(p, buf, len);
 	    return;
 	}
-	memcpy(p, buf, t);
+	os_memcpy(p, buf, t);
 	byteReverse(ctx->in, 16);
-	MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
 	buf += t;
 	len -= t;
     }
     /* Process data in 64-byte chunks */
 
     while (len >= 64) {
-	memcpy(ctx->in, buf, 64);
+	os_memcpy(ctx->in, buf, 64);
 	byteReverse(ctx->in, 16);
-	MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
 	buf += 64;
 	len -= 64;
     }
 
     /* Handle any remaining bytes of data. */
 
-    memcpy(ctx->in, buf, len);
+    os_memcpy(ctx->in, buf, len);
 }
 
 /*
@@ -265,26 +275,26 @@
     /* Pad out to 56 mod 64 */
     if (count < 8) {
 	/* Two lots of padding:  Pad the first block to 64 bytes */
-	memset(p, 0, count);
+	os_memset(p, 0, count);
 	byteReverse(ctx->in, 16);
-	MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
 
 	/* Now fill the next block with 56 bytes */
-	memset(ctx->in, 0, 56);
+	os_memset(ctx->in, 0, 56);
     } else {
 	/* Pad block to 56 bytes */
-	memset(p, 0, count - 8);
+	os_memset(p, 0, count - 8);
     }
     byteReverse(ctx->in, 14);
 
     /* Append length in bits and transform */
-    ((uint32_t *) ctx->in)[14] = ctx->bits[0];
-    ((uint32_t *) ctx->in)[15] = ctx->bits[1];
+    ((u32 *) ctx->in)[14] = ctx->bits[0];
+    ((u32 *) ctx->in)[15] = ctx->bits[1];
 
-    MD5Transform(ctx->buf, (uint32_t *) ctx->in);
+    MD5Transform(ctx->buf, (u32 *) ctx->in);
     byteReverse((unsigned char *) ctx->buf, 4);
-    memcpy(digest, ctx->buf, 16);
-    memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+    os_memcpy(digest, ctx->buf, 16);
+    os_memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
 }
 
 /* The four core functions - F1 is optimized somewhat */
@@ -304,9 +314,9 @@
  * reflect the addition of 16 longwords of new data.  MD5Update blocks
  * the data and converts bytes into longwords for this routine.
  */
-static void MD5Transform(uint32_t buf[4], uint32_t const in[16])
+static void MD5Transform(u32 buf[4], u32 const in[16])
 {
-    register uint32_t a, b, c, d;
+    register u32 a, b, c, d;
 
     a = buf[0];
     b = buf[1];
@@ -387,3 +397,5 @@
     buf[3] += d;
 }
 /* ===== end - public domain MD5 implementation ===== */
+
+#endif /* INTERNAL_MD5 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/md5.h	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,43 @@
+/*********************************************************************************/
+/* Waaad author note:
+ *  The content from this file comes directly from the hostap project.
+ * It is redistributed under the terms of the BSD license, as allowed
+ * by the original copyright reproduced bellow.
+ *  The file has not been modified, except for this notice.
+ */
+/*********************************************************************************/
+
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#define MD5_MAC_LEN 16
+
+void hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac);
+void hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	      u8 *mac);
+
+#ifdef CONFIG_CRYPTO_INTERNAL
+struct MD5Context;
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+	       unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+#endif /* CONFIG_CRYPTO_INTERNAL */
+
+#endif /* MD5_H */
--- a/extensions/radius_gw/md5.h.in	Thu May 21 15:20:38 2009 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-/* See Copyright note in md5.c */
-
-#ifndef _MD5_H
-#define _MD5_H
-
-#include <sys/types.h>
-#include <stdint.h>
-
-#cmakedefine HOST_BIG_ENDIAN @HOST_BIG_ENDIAN@
-
-/* MD5 stuff for authenticators */
-#define MD5_MAC_LEN 16
-void hmac_md5_vector(const uint8_t *key, size_t key_len, size_t num_elem, const uint8_t *addr[], const size_t *len, uint8_t *mac);
-void hmac_md5(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len, uint8_t *mac);
-
-#endif /* _MD5_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/radius.c	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,1281 @@
+/*********************************************************************************/
+/* Waaad author note:
+ *  The content from this file comes directly from the hostap project.
+ * It is redistributed under the terms of the BSD license, as allowed
+ * by the original copyright reproduced bellow.
+ *  In addition to this notide, only the #include directives have been modified.
+ */
+#include "rg_common.h"
+/* Overwrite the printf definitions with our custom function */
+#define printf(args...) log_debug(args)
+
+/*********************************************************************************/
+
+
+/*
+ * hostapd / RADIUS message processing
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+static struct radius_attr_hdr *
+radius_get_attr_hdr(struct radius_msg *msg, int idx)
+{
+	return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]);
+}
+
+
+struct radius_msg *radius_msg_new(u8 code, u8 identifier)
+{
+	struct radius_msg *msg;
+
+	msg = os_malloc(sizeof(*msg));
+	if (msg == NULL)
+		return NULL;
+
+	if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {
+		os_free(msg);
+		return NULL;
+	}
+
+	radius_msg_set_hdr(msg, code, identifier);
+
+	return msg;
+}
+
+
+int radius_msg_initialize(struct radius_msg *msg, size_t init_len)
+{
+	if (msg == NULL || init_len < sizeof(struct radius_hdr))
+		return -1;
+
+	os_memset(msg, 0, sizeof(*msg));
+	msg->buf = os_zalloc(init_len);
+	if (msg->buf == NULL)
+		return -1;
+
+	msg->buf_size = init_len;
+	msg->hdr = (struct radius_hdr *) msg->buf;
+	msg->buf_used = sizeof(*msg->hdr);
+
+	msg->attr_pos =
+		os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));
+	if (msg->attr_pos == NULL) {
+		os_free(msg->buf);
+		msg->buf = NULL;
+		msg->hdr = NULL;
+		return -1;
+	}
+
+	msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
+	msg->attr_used = 0;
+
+	return 0;
+}
+
+
+void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
+{
+	msg->hdr->code = code;
+	msg->hdr->identifier = identifier;
+}
+
+
+void radius_msg_free(struct radius_msg *msg)
+{
+	os_free(msg->buf);
+	msg->buf = NULL;
+	msg->hdr = NULL;
+	msg->buf_size = msg->buf_used = 0;
+
+	os_free(msg->attr_pos);
+	msg->attr_pos = NULL;
+	msg->attr_size = msg->attr_used = 0;
+}
+
+
+static const char *radius_code_string(u8 code)
+{
+	switch (code) {
+	case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";
+	case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";
+	case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";
+	case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";
+	case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";
+	case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";
+	case RADIUS_CODE_STATUS_SERVER: return "Status-Server";
+	case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";
+	case RADIUS_CODE_RESERVED: return "Reserved";
+	default: return "?Unknown?";
+	}
+}
+
+
+struct radius_attr_type {
+	u8 type;
+	char *name;
+	enum {
+		RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
+		RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6
+	} data_type;
+};
+
+static struct radius_attr_type radius_attrs[] =
+{
+	{ RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },
+	{ RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",
+	  RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",
+	  RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",
+	  RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
+	  RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
+	  RADIUS_ATTR_UNDIST },
+	{ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",
+	  RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",
+	  RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargeable-User-Identity",
+	  RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
+};
+#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))
+
+
+static struct radius_attr_type *radius_get_attr_type(u8 type)
+{
+	size_t i;
+
+	for (i = 0; i < RADIUS_ATTRS; i++) {
+		if (type == radius_attrs[i].type)
+			return &radius_attrs[i];
+	}
+
+	return NULL;
+}
+
+
+static void print_char(char c)
+{
+	if (c >= 32 && c < 127)
+		printf("%c", c);
+	else
+		printf("<%02x>", c);
+}
+
+
+static void radius_msg_dump_attr(struct radius_attr_hdr *hdr)
+{
+	struct radius_attr_type *attr;
+	int i, len;
+	unsigned char *pos;
+
+	attr = radius_get_attr_type(hdr->type);
+
+	printf("   Attribute %d (%s) length=%d\n",
+	       hdr->type, attr ? attr->name : "?Unknown?", hdr->length);
+
+	if (attr == NULL)
+		return;
+
+	len = hdr->length - sizeof(struct radius_attr_hdr);
+	pos = (unsigned char *) (hdr + 1);
+
+	switch (attr->data_type) {
+	case RADIUS_ATTR_TEXT:
+		printf("      Value: '");
+		for (i = 0; i < len; i++)
+			print_char(pos[i]);
+		printf("'\n");
+		break;
+
+	case RADIUS_ATTR_IP:
+		if (len == 4) {
+			struct in_addr addr;
+			os_memcpy(&addr, pos, 4);
+			printf("      Value: %s\n", inet_ntoa(addr));
+		} else
+			printf("      Invalid IP address length %d\n", len);
+		break;
+
+#ifdef CONFIG_IPV6
+	case RADIUS_ATTR_IPV6:
+		if (len == 16) {
+			char buf[128];
+			const char *atxt;
+			struct in6_addr *addr = (struct in6_addr *) pos;
+			atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));
+			printf("      Value: %s\n", atxt ? atxt : "?");
+		} else
+			printf("      Invalid IPv6 address length %d\n", len);
+		break;
+#endif /* CONFIG_IPV6 */
+
+	case RADIUS_ATTR_HEXDUMP:
+	case RADIUS_ATTR_UNDIST:
+		printf("      Value:");
+		for (i = 0; i < len; i++)
+			printf(" %02x", pos[i]);
+		printf("\n");
+		break;
+
+	case RADIUS_ATTR_INT32:
+		if (len == 4)
+			printf("      Value: %u\n", WPA_GET_BE32(pos));
+		else
+			printf("      Invalid INT32 length %d\n", len);
+		break;
+
+	default:
+		break;
+	}
+}
+
+
+void radius_msg_dump(struct radius_msg *msg)
+{
+	size_t i;
+
+	printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",
+	       msg->hdr->code, radius_code_string(msg->hdr->code),
+	       msg->hdr->identifier, ntohs(msg->hdr->length));
+
+	for (i = 0; i < msg->attr_used; i++) {
+		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
+		radius_msg_dump_attr(attr);
+	}
+}
+
+
+int radius_msg_finish(struct radius_msg *msg, const u8 *secret,
+		      size_t secret_len)
+{
+	if (secret) {
+		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) {
+			printf("WARNING: Could not add "
+			       "Message-Authenticator\n");
+			return -1;
+		}
+		msg->hdr->length = htons(msg->buf_used);
+		hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
+			 (u8 *) (attr + 1));
+	} else
+		msg->hdr->length = htons(msg->buf_used);
+
+	if (msg->buf_used > 0xffff) {
+		printf("WARNING: too long RADIUS message (%lu)\n",
+		       (unsigned long) msg->buf_used);
+		return -1;
+	}
+	return 0;
+}
+
+
+int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,
+			  size_t secret_len, const u8 *req_authenticator)
+{
+	u8 auth[MD5_MAC_LEN];
+	struct radius_attr_hdr *attr;
+	const u8 *addr[4];
+	size_t len[4];
+
+	os_memset(auth, 0, MD5_MAC_LEN);
+	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,
+				   auth, MD5_MAC_LEN);
+	if (attr == NULL) {
+		printf("WARNING: Could not add Message-Authenticator\n");
+		return -1;
+	}
+	msg->hdr->length = htons(msg->buf_used);
+	os_memcpy(msg->hdr->authenticator, req_authenticator,
+		  sizeof(msg->hdr->authenticator));
+	hmac_md5(secret, secret_len, msg->buf, msg->buf_used,
+		 (u8 *) (attr + 1));
+
+	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+	addr[0] = (u8 *) msg->hdr;
+	len[0] = 1 + 1 + 2;
+	addr[1] = req_authenticator;
+	len[1] = MD5_MAC_LEN;
+	addr[2] = (u8 *) (msg->hdr + 1);
+	len[2] = msg->buf_used - sizeof(*msg->hdr);
+	addr[3] = secret;
+	len[3] = secret_len;
+	md5_vector(4, addr, len, msg->hdr->authenticator);
+
+	if (msg->buf_used > 0xffff) {
+		printf("WARNING: too long RADIUS message (%lu)\n",
+		       (unsigned long) msg->buf_used);
+		return -1;
+	}
+	return 0;
+}
+
+
+void radius_msg_finish_acct(struct radius_msg *msg, const u8 *secret,
+			    size_t secret_len)
+{
+	const u8 *addr[2];
+	size_t len[2];
+
+	msg->hdr->length = htons(msg->buf_used);
+	os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);
+	addr[0] = msg->buf;
+	len[0] = msg->buf_used;
+	addr[1] = secret;
+	len[1] = secret_len;
+	md5_vector(2, addr, len, msg->hdr->authenticator);
+
+	if (msg->buf_used > 0xffff) {
+		printf("WARNING: too long RADIUS messages (%lu)\n",
+		       (unsigned long) msg->buf_used);
+	}
+}
+
+
+static int radius_msg_add_attr_to_array(struct radius_msg *msg,
+					struct radius_attr_hdr *attr)
+{
+	if (msg->attr_used >= msg->attr_size) {
+		size_t *nattr_pos;
+		int nlen = msg->attr_size * 2;
+
+		nattr_pos = os_realloc(msg->attr_pos,
+				       nlen * sizeof(*msg->attr_pos));
+		if (nattr_pos == NULL)
+			return -1;
+
+		msg->attr_pos = nattr_pos;
+		msg->attr_size = nlen;
+	}
+
+	msg->attr_pos[msg->attr_used++] = (unsigned char *) attr - msg->buf;
+
+	return 0;
+}
+
+
+struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,
+					    const u8 *data, size_t data_len)
+{
+	size_t buf_needed;
+	struct radius_attr_hdr *attr;
+
+	if (data_len > RADIUS_MAX_ATTR_LEN) {
+		printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",
+		       (unsigned long) data_len);
+		return NULL;
+	}
+
+	buf_needed = msg->buf_used + sizeof(*attr) + data_len;
+
+	if (msg->buf_size < buf_needed) {
+		/* allocate more space for message buffer */
+		unsigned char *nbuf;
+		size_t nlen = msg->buf_size;
+
+		while (nlen < buf_needed)
+			nlen *= 2;
+		nbuf = os_realloc(msg->buf, nlen);
+		if (nbuf == NULL)
+			return NULL;
+		msg->buf = nbuf;
+		msg->hdr = (struct radius_hdr *) msg->buf;
+		os_memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
+		msg->buf_size = nlen;
+	}
+
+	attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
+	attr->type = type;
+	attr->length = sizeof(*attr) + data_len;
+	if (data_len > 0)
+		os_memcpy(attr + 1, data, data_len);
+
+	msg->buf_used += sizeof(*attr) + data_len;
+
+	if (radius_msg_add_attr_to_array(msg, attr))
+		return NULL;
+
+	return attr;
+}
+
+
+struct radius_msg *radius_msg_parse(const u8 *data, size_t len)
+{
+	struct radius_msg *msg;
+	struct radius_hdr *hdr;
+	struct radius_attr_hdr *attr;
+	size_t msg_len;
+	unsigned char *pos, *end;
+
+	if (data == NULL || len < sizeof(*hdr))
+		return NULL;
+
+	hdr = (struct radius_hdr *) data;
+
+	msg_len = ntohs(hdr->length);
+	if (msg_len < sizeof(*hdr) || msg_len > len) {
+		printf("Invalid RADIUS message length\n");
+		return NULL;
+	}
+
+	if (msg_len < len) {
+		printf("Ignored %lu extra bytes after RADIUS message\n",
+		       (unsigned long) len - msg_len);
+	}
+
+	msg = os_malloc(sizeof(*msg));
+	if (msg == NULL)
+		return NULL;
+
+	if (radius_msg_initialize(msg, msg_len)) {
+		os_free(msg);
+		return NULL;
+	}
+
+	os_memcpy(msg->buf, data, msg_len);
+	msg->buf_size = msg->buf_used = msg_len;
+
+	/* parse attributes */
+	pos = (unsigned char *) (msg->hdr + 1);
+	end = msg->buf + msg->buf_used;
+	while (pos < end) {
+		if ((size_t) (end - pos) < sizeof(*attr))
+			goto fail;
+
+		attr = (struct radius_attr_hdr *) pos;
+
+		if (pos + attr->length > end || attr->length < sizeof(*attr))
+			goto fail;
+
+		/* TODO: check that attr->length is suitable for attr->type */
+
+		if (radius_msg_add_attr_to_array(msg, attr))
+			goto fail;
+
+		pos += attr->length;
+	}
+
+	return msg;
+
+ fail:
+	radius_msg_free(msg);
+	os_free(msg);
+	return NULL;
+}
+
+
+int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len)
+{
+	const u8 *pos = data;
+	size_t left = data_len;
+
+	while (left > 0) {
+		int len;
+		if (left > RADIUS_MAX_ATTR_LEN)
+			len = RADIUS_MAX_ATTR_LEN;
+		else
+			len = left;
+
+		if (!radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE,
+					 pos, len))
+			return 0;
+
+		pos += len;
+		left -= len;
+	}
+
+	return 1;
+}
+
+
+u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
+{
+	u8 *eap, *pos;
+	size_t len, i;
+	struct radius_attr_hdr *attr;
+
+	if (msg == NULL)
+		return NULL;
+
+	len = 0;
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		if (attr->type == RADIUS_ATTR_EAP_MESSAGE)
+			len += attr->length - sizeof(struct radius_attr_hdr);
+	}
+
+	if (len == 0)
+		return NULL;
+
+	eap = os_malloc(len);
+	if (eap == NULL)
+		return NULL;
+
+	pos = eap;
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		if (attr->type == RADIUS_ATTR_EAP_MESSAGE) {
+			int flen = attr->length - sizeof(*attr);
+			os_memcpy(pos, attr + 1, flen);
+			pos += flen;
+		}
+	}
+
+	if (eap_len)
+		*eap_len = len;
+
+	return eap;
+}
+
+
+int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
+			       size_t secret_len, const u8 *req_auth)
+{
+	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
+	u8 orig_authenticator[16];
+	struct radius_attr_hdr *attr = NULL, *tmp;
+	size_t i;
+
+	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) {
+				printf("Multiple Message-Authenticator "
+				       "attributes in RADIUS message\n");
+				return 1;
+			}
+			attr = tmp;
+		}
+	}
+
+	if (attr == NULL) {
+		printf("No Message-Authenticator attribute found\n");
+		return 1;
+	}
+
+	os_memcpy(orig, attr + 1, MD5_MAC_LEN);
+	os_memset(attr + 1, 0, MD5_MAC_LEN);
+	if (req_auth) {
+		os_memcpy(orig_authenticator, msg->hdr->authenticator,
+			  sizeof(orig_authenticator));
+		os_memcpy(msg->hdr->authenticator, req_auth,
+			  sizeof(msg->hdr->authenticator));
+	}
+	hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
+	os_memcpy(attr + 1, orig, MD5_MAC_LEN);
+	if (req_auth) {
+		os_memcpy(msg->hdr->authenticator, orig_authenticator,
+			  sizeof(orig_authenticator));
+	}
+
+	if (os_memcmp(orig, auth, MD5_MAC_LEN) != 0) {
+		printf("Invalid Message-Authenticator!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+
+int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
+		      size_t secret_len, struct radius_msg *sent_msg, int auth)
+{
+	const u8 *addr[4];
+	size_t len[4];
+	u8 hash[MD5_MAC_LEN];
+
+	if (sent_msg == NULL) {
+		printf("No matching Access-Request message found\n");
+		return 1;
+	}
+
+	if (auth &&
+	    radius_msg_verify_msg_auth(msg, secret, secret_len,
+				       sent_msg->hdr->authenticator)) {
+		return 1;
+	}
+
+	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+	addr[0] = (u8 *) msg->hdr;
+	len[0] = 1 + 1 + 2;
+	addr[1] = sent_msg->hdr->authenticator;
+	len[1] = MD5_MAC_LEN;
+	addr[2] = (u8 *) (msg->hdr + 1);
+	len[2] = msg->buf_used - sizeof(*msg->hdr);
+	addr[3] = secret;
+	len[3] = secret_len;
+	md5_vector(4, addr, len, hash);
+	if (os_memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0) {
+		printf("Response Authenticator invalid!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+
+int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
+			 u8 type)
+{
+	struct radius_attr_hdr *attr;
+	size_t i;
+	int count = 0;
+
+	for (i = 0; i < src->attr_used; i++) {
+		attr = radius_get_attr_hdr(src, i);
+		if (attr->type == type) {
+			if (!radius_msg_add_attr(dst, type, (u8 *) (attr + 1),
+						 attr->length - sizeof(*attr)))
+				return -1;
+			count++;
+		}
+	}
+
+	return count;
+}
+
+
+/* Create Request Authenticator. The value should be unique over the lifetime
+ * of the shared secret between authenticator and authentication server.
+ * Use one-way MD5 hash calculated from current timestamp and some data given
+ * by the caller. */
+void radius_msg_make_authenticator(struct radius_msg *msg,
+				   const u8 *data, size_t len)
+{
+	struct os_time tv;
+	long int l;
+	const u8 *addr[3];
+	size_t elen[3];
+
+	os_get_time(&tv);
+	l = os_random();
+	addr[0] = (u8 *) &tv;
+	elen[0] = sizeof(tv);
+	addr[1] = data;
+	elen[1] = len;
+	addr[2] = (u8 *) &l;
+	elen[2] = sizeof(l);
+	md5_vector(3, addr, elen, msg->hdr->authenticator);
+}
+
+
+/* Get Vendor-specific RADIUS Attribute from a parsed RADIUS message.
+ * Returns the Attribute payload and sets alen to indicate the length of the
+ * payload if a vendor attribute with subtype is found, otherwise returns NULL.
+ * The returned payload is allocated with os_malloc() and caller must free it
+ * by calling os_free().
+ */
+static u8 *radius_msg_get_vendor_attr(struct radius_msg *msg, u32 vendor,
+				      u8 subtype, size_t *alen)
+{
+	u8 *data, *pos;
+	size_t i, len;
+
+	if (msg == NULL)
+		return NULL;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
+		size_t left;
+		u32 vendor_id;
+		struct radius_attr_vendor *vhdr;
+
+		if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
+			continue;
+
+		left = attr->length - sizeof(*attr);
+		if (left < 4)
+			continue;
+
+		pos = (u8 *) (attr + 1);
+
+		os_memcpy(&vendor_id, pos, 4);
+		pos += 4;
+		left -= 4;
+
+		if (ntohl(vendor_id) != vendor)
+			continue;
+
+		while (left >= sizeof(*vhdr)) {
+			vhdr = (struct radius_attr_vendor *) pos;
+			if (vhdr->vendor_length > left ||
+			    vhdr->vendor_length < sizeof(*vhdr)) {
+				left = 0;
+				break;
+			}
+			if (vhdr->vendor_type != subtype) {
+				pos += vhdr->vendor_length;
+				left -= vhdr->vendor_length;
+				continue;
+			}
+
+			len = vhdr->vendor_length - sizeof(*vhdr);
+			data = os_malloc(len);
+			if (data == NULL)
+				return NULL;
+			os_memcpy(data, pos + sizeof(*vhdr), len);
+			if (alen)
+				*alen = len;
+			return data;
+		}
+	}
+
+	return NULL;
+}
+
+
+static u8 * decrypt_ms_key(const u8 *key, size_t len,
+			   const u8 *req_authenticator,
+			   const u8 *secret, size_t secret_len, size_t *reslen)
+{
+	u8 *plain, *ppos, *res;
+	const u8 *pos;
+	size_t left, plen;
+	u8 hash[MD5_MAC_LEN];
+	int i, first = 1;
+	const u8 *addr[3];
+	size_t elen[3];
+
+	/* key: 16-bit salt followed by encrypted key info */
+
+	if (len < 2 + 16)
+		return NULL;
+
+	pos = key + 2;
+	left = len - 2;
+	if (left % 16) {
+		printf("Invalid ms key len %lu\n", (unsigned long) left);
+		return NULL;
+	}
+
+	plen = left;
+	ppos = plain = os_malloc(plen);
+	if (plain == NULL)
+		return NULL;
+	plain[0] = 0;
+
+	while (left > 0) {
+		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
+		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
+
+		addr[0] = secret;
+		elen[0] = secret_len;
+		if (first) {
+			addr[1] = req_authenticator;
+			elen[1] = MD5_MAC_LEN;
+			addr[2] = key;
+			elen[2] = 2; /* Salt */
+		} else {
+			addr[1] = pos - MD5_MAC_LEN;
+			elen[1] = MD5_MAC_LEN;
+		}
+		md5_vector(first ? 3 : 2, addr, elen, hash);
+		first = 0;
+
+		for (i = 0; i < MD5_MAC_LEN; i++)
+			*ppos++ = *pos++ ^ hash[i];
+		left -= MD5_MAC_LEN;
+	}
+
+	if (plain[0] == 0 || plain[0] > plen - 1) {
+		printf("Failed to decrypt MPPE key\n");
+		os_free(plain);
+		return NULL;
+	}
+
+	res = os_malloc(plain[0]);
+	if (res == NULL) {
+		os_free(plain);
+		return NULL;
+	}
+	os_memcpy(res, plain + 1, plain[0]);
+	if (reslen)
+		*reslen = plain[0];
+	os_free(plain);
+	return res;
+}
+
+
+static void encrypt_ms_key(const u8 *key, size_t key_len, u16 salt,
+			   const u8 *req_authenticator,
+			   const u8 *secret, size_t secret_len,
+			   u8 *ebuf, size_t *elen)
+{
+	int i, len, first = 1;
+	u8 hash[MD5_MAC_LEN], saltbuf[2], *pos;
+	const u8 *addr[3];
+	size_t _len[3];
+
+	WPA_PUT_BE16(saltbuf, salt);
+
+	len = 1 + key_len;
+	if (len & 0x0f) {
+		len = (len & 0xf0) + 16;
+	}
+	os_memset(ebuf, 0, len);
+	ebuf[0] = key_len;
+	os_memcpy(ebuf + 1, key, key_len);
+
+	*elen = len;
+
+	pos = ebuf;
+	while (len > 0) {
+		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
+		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
+		addr[0] = secret;
+		_len[0] = secret_len;
+		if (first) {
+			addr[1] = req_authenticator;
+			_len[1] = MD5_MAC_LEN;
+			addr[2] = saltbuf;
+			_len[2] = sizeof(saltbuf);
+		} else {
+			addr[1] = pos - MD5_MAC_LEN;
+			_len[1] = MD5_MAC_LEN;
+		}
+		md5_vector(first ? 3 : 2, addr, _len, hash);
+		first = 0;
+
+		for (i = 0; i < MD5_MAC_LEN; i++)
+			*pos++ ^= hash[i];
+
+		len -= MD5_MAC_LEN;
+	}
+}
+
+
+struct radius_ms_mppe_keys *
+radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+		       const u8 *secret, size_t secret_len)
+{
+	u8 *key;
+	size_t keylen;
+	struct radius_ms_mppe_keys *keys;
+
+	if (msg == NULL || sent_msg == NULL)
+		return NULL;
+
+	keys = os_zalloc(sizeof(*keys));
+	if (keys == NULL)
+		return NULL;
+
+	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
+					 RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY,
+					 &keylen);
+	if (key) {
+		keys->send = decrypt_ms_key(key, keylen,
+					    sent_msg->hdr->authenticator,
+					    secret, secret_len,
+					    &keys->send_len);
+		os_free(key);
+	}
+
+	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_MICROSOFT,
+					 RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY,
+					 &keylen);
+	if (key) {
+		keys->recv = decrypt_ms_key(key, keylen,
+					    sent_msg->hdr->authenticator,
+					    secret, secret_len,
+					    &keys->recv_len);
+		os_free(key);
+	}
+
+	return keys;
+}
+
+
+struct radius_ms_mppe_keys *
+radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+			  const u8 *secret, size_t secret_len)
+{
+	u8 *key;
+	size_t keylen;
+	struct radius_ms_mppe_keys *keys;
+
+	if (msg == NULL || sent_msg == NULL)
+		return NULL;
+
+	keys = os_zalloc(sizeof(*keys));
+	if (keys == NULL)
+		return NULL;
+
+	key = radius_msg_get_vendor_attr(msg, RADIUS_VENDOR_ID_CISCO,
+					 RADIUS_CISCO_AV_PAIR, &keylen);
+	if (key && keylen == 51 &&
+	    os_memcmp(key, "leap:session-key=", 17) == 0) {
+		keys->recv = decrypt_ms_key(key + 17, keylen - 17,
+					    sent_msg->hdr->authenticator,
+					    secret, secret_len,
+					    &keys->recv_len);
+	}
+	os_free(key);
+
+	return keys;
+}
+
+
+int radius_msg_add_mppe_keys(struct radius_msg *msg,
+			     const u8 *req_authenticator,
+			     const u8 *secret, size_t secret_len,
+			     const u8 *send_key, size_t send_key_len,
+			     const u8 *recv_key, size_t recv_key_len)
+{
+	struct radius_attr_hdr *attr;
+	u32 vendor_id = htonl(RADIUS_VENDOR_ID_MICROSOFT);
+	u8 *buf;
+	struct radius_attr_vendor *vhdr;
+	u8 *pos;
+	size_t elen;
+	int hlen;
+	u16 salt;
+
+	hlen = sizeof(vendor_id) + sizeof(*vhdr) + 2;
+
+	/* MS-MPPE-Send-Key */
+	buf = os_malloc(hlen + send_key_len + 16);
+	if (buf == NULL) {
+		return 0;
+	}
+	pos = buf;
+	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
+	pos += sizeof(vendor_id);
+	vhdr = (struct radius_attr_vendor *) pos;
+	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY;
+	pos = (u8 *) (vhdr + 1);
+	salt = os_random() | 0x8000;
+	WPA_PUT_BE16(pos, salt);
+	pos += 2;
+	encrypt_ms_key(send_key, send_key_len, salt, req_authenticator, secret,
+		       secret_len, pos, &elen);
+	vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
+
+	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+				   buf, hlen + elen);
+	os_free(buf);
+	if (attr == NULL) {
+		return 0;
+	}
+
+	/* MS-MPPE-Recv-Key */
+	buf = os_malloc(hlen + send_key_len + 16);
+	if (buf == NULL) {
+		return 0;
+	}
+	pos = buf;
+	os_memcpy(pos, &vendor_id, sizeof(vendor_id));
+	pos += sizeof(vendor_id);
+	vhdr = (struct radius_attr_vendor *) pos;
+	vhdr->vendor_type = RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY;
+	pos = (u8 *) (vhdr + 1);
+	salt ^= 1;
+	WPA_PUT_BE16(pos, salt);
+	pos += 2;
+	encrypt_ms_key(recv_key, recv_key_len, salt, req_authenticator, secret,
+		       secret_len, pos, &elen);
+	vhdr->vendor_length = hlen + elen - sizeof(vendor_id);
+
+	attr = radius_msg_add_attr(msg, RADIUS_ATTR_VENDOR_SPECIFIC,
+				   buf, hlen + elen);
+	os_free(buf);
+	if (attr == NULL) {
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/* Add User-Password attribute to a RADIUS message and encrypt it as specified
+ * in RFC 2865, Chap. 5.2 */
+struct radius_attr_hdr *
+radius_msg_add_attr_user_password(struct radius_msg *msg,
+				  const u8 *data, size_t data_len,
+				  const u8 *secret, size_t secret_len)
+{
+	u8 buf[128];
+	int padlen, i;
+	size_t buf_len, pos;
+	const u8 *addr[2];
+	size_t len[2];
+	u8 hash[16];
+
+	if (data_len > 128)
+		return NULL;
+
+	os_memcpy(buf, data, data_len);
+	buf_len = data_len;
+
+	padlen = data_len % 16;
+	if (padlen) {
+		padlen = 16 - padlen;
+		os_memset(buf + data_len, 0, padlen);
+		buf_len += padlen;
+	}
+
+	addr[0] = secret;
+	len[0] = secret_len;
+	addr[1] = msg->hdr->authenticator;
+	len[1] = 16;
+	md5_vector(2, addr, len, hash);
+
+	for (i = 0; i < 16; i++)
+		buf[i] ^= hash[i];
+	pos = 16;
+
+	while (pos < buf_len) {
+		addr[0] = secret;
+		len[0] = secret_len;
+		addr[1] = &buf[pos - 16];
+		len[1] = 16;
+		md5_vector(2, addr, len, hash);
+
+		for (i = 0; i < 16; i++)
+			buf[pos + i] ^= hash[i];
+
+		pos += 16;
+	}
+
+	return radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD,
+				   buf, buf_len);
+}
+
+
+int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
+{
+	struct radius_attr_hdr *attr = NULL, *tmp;
+	size_t i, dlen;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		tmp = radius_get_attr_hdr(msg, i);
+		if (tmp->type == type) {
+			attr = tmp;
+			break;
+		}
+	}
+
+	if (!attr)
+		return -1;
+
+	dlen = attr->length - sizeof(*attr);
+	if (buf)
+		os_memcpy(buf, (attr + 1), dlen > len ? len : dlen);
+	return dlen;
+}
+
+
+int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
+			    size_t *len, const u8 *start)
+{
+	size_t i;
+	struct radius_attr_hdr *attr = NULL, *tmp;
+
+	for (i = 0; i < msg->attr_used; i++) {
+		tmp = radius_get_attr_hdr(msg, i);
+		if (tmp->type == type &&
+		    (start == NULL || (u8 *) tmp > start)) {
+			attr = tmp;
+			break;
+		}
+	}
+
+	if (!attr)
+		return -1;
+
+	*buf = (u8 *) (attr + 1);
+	*len = attr->length - sizeof(*attr);
+	return 0;
+}
+
+
+int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len)
+{
+	size_t i;
+	int count;
+
+	for (count = 0, i = 0; i < msg->attr_used; i++) {
+		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);
+		if (attr->type == type &&
+		    attr->length >= sizeof(struct radius_attr_hdr) + min_len)
+			count++;
+	}
+
+	return count;
+}
+
+
+struct radius_tunnel_attrs {
+	int tag_used;
+	int type; /* Tunnel-Type */
+	int medium_type; /* Tunnel-Medium-Type */
+	int vlanid;
+};
+
+
+/**
+ * radius_msg_get_vlanid - Parse RADIUS attributes for VLAN tunnel information
+ * @msg: RADIUS message
+ * Returns: VLAN ID for the first tunnel configuration of -1 if none is found
+ */
+int radius_msg_get_vlanid(struct radius_msg *msg)
+{
+	struct radius_tunnel_attrs tunnel[RADIUS_TUNNEL_TAGS], *tun;
+	size_t i;
+	struct radius_attr_hdr *attr = NULL;
+	const u8 *data;
+	char buf[10];
+	size_t dlen;
+
+	os_memset(&tunnel, 0, sizeof(tunnel));
+
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		data = (const u8 *) (attr + 1);
+		dlen = attr->length - sizeof(*attr);
+		if (attr->length < 3)
+			continue;
+		if (data[0] >= RADIUS_TUNNEL_TAGS)
+			tun = &tunnel[0];
+		else
+			tun = &tunnel[data[0]];
+
+		switch (attr->type) {
+		case RADIUS_ATTR_TUNNEL_TYPE:
+			if (attr->length != 6)
+				break;
+			tun->tag_used++;
+			tun->type = WPA_GET_BE24(data + 1);
+			break;
+		case RADIUS_ATTR_TUNNEL_MEDIUM_TYPE:
+			if (attr->length != 6)
+				break;
+			tun->tag_used++;
+			tun->medium_type = WPA_GET_BE24(data + 1);
+			break;
+		case RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID:
+			if (data[0] < RADIUS_TUNNEL_TAGS) {
+				data++;
+				dlen--;
+			}
+			if (dlen >= sizeof(buf))
+				break;
+			os_memcpy(buf, data, dlen);
+			buf[dlen] = '\0';
+			tun->tag_used++;
+			tun->vlanid = atoi(buf);
+			break;
+		}
+	}
+
+	for (i = 0; i < RADIUS_TUNNEL_TAGS; i++) {
+		tun = &tunnel[i];
+		if (tun->tag_used &&
+		    tun->type == RADIUS_TUNNEL_TYPE_VLAN &&
+		    tun->medium_type == RADIUS_TUNNEL_MEDIUM_TYPE_802 &&
+		    tun->vlanid > 0)
+			return tun->vlanid;
+	}
+
+	return -1;
+}
+
+
+void radius_free_class(struct radius_class_data *c)
+{
+	size_t i;
+	if (c == NULL)
+		return;
+	for (i = 0; i < c->count; i++)
+		os_free(c->attr[i].data);
+	os_free(c->attr);
+	c->attr = NULL;
+	c->count = 0;
+}
+
+
+int radius_copy_class(struct radius_class_data *dst,
+		      const struct radius_class_data *src)
+{
+	size_t i;
+
+	if (src->attr == NULL)
+		return 0;
+
+	dst->attr = os_zalloc(src->count * sizeof(struct radius_attr_data));
+	if (dst->attr == NULL)
+		return -1;
+
+	dst->count = 0;
+
+	for (i = 0; i < src->count; i++) {
+		dst->attr[i].data = os_malloc(src->attr[i].len);
+		if (dst->attr[i].data == NULL)
+			break;
+		dst->count++;
+		os_memcpy(dst->attr[i].data, src->attr[i].data,
+			  src->attr[i].len);
+		dst->attr[i].len = src->attr[i].len;
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/radius.h	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,296 @@
+/*********************************************************************************/
+/* Waaad author note:
+ *  The content from this file comes directly from the hostap project.
+ * It is redistributed under the terms of the BSD license, as allowed
+ * by the original copyright reproduced bellow.
+ *  The file has not been modified, except for this notice.
+ */
+/*********************************************************************************/
+
+/*
+ * hostapd / RADIUS message processing
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef RADIUS_H
+#define RADIUS_H
+
+/* RFC 2865 - RADIUS */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct radius_hdr {
+	u8 code;
+	u8 identifier;
+	u16 length; /* including this header */
+	u8 authenticator[16];
+	/* followed by length-20 octets of attributes */
+} STRUCT_PACKED;
+
+enum { RADIUS_CODE_ACCESS_REQUEST = 1,
+       RADIUS_CODE_ACCESS_ACCEPT = 2,
+       RADIUS_CODE_ACCESS_REJECT = 3,
+       RADIUS_CODE_ACCOUNTING_REQUEST = 4,
+       RADIUS_CODE_ACCOUNTING_RESPONSE = 5,
+       RADIUS_CODE_ACCESS_CHALLENGE = 11,
+       RADIUS_CODE_STATUS_SERVER = 12,
+       RADIUS_CODE_STATUS_CLIENT = 13,
+       RADIUS_CODE_RESERVED = 255
+};
+
+struct radius_attr_hdr {
+	u8 type;
+	u8 length; /* including this header */
+	/* followed by length-2 octets of attribute value */
+} STRUCT_PACKED;
+
+#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
+
+enum { RADIUS_ATTR_USER_NAME = 1,
+       RADIUS_ATTR_USER_PASSWORD = 2,
+       RADIUS_ATTR_NAS_IP_ADDRESS = 4,
+       RADIUS_ATTR_NAS_PORT = 5,
+       RADIUS_ATTR_FRAMED_MTU = 12,
+       RADIUS_ATTR_REPLY_MESSAGE = 18,
+       RADIUS_ATTR_STATE = 24,
+       RADIUS_ATTR_CLASS = 25,
+       RADIUS_ATTR_VENDOR_SPECIFIC = 26,
+       RADIUS_ATTR_SESSION_TIMEOUT = 27,
+       RADIUS_ATTR_IDLE_TIMEOUT = 28,
+       RADIUS_ATTR_TERMINATION_ACTION = 29,
+       RADIUS_ATTR_CALLED_STATION_ID = 30,
+       RADIUS_ATTR_CALLING_STATION_ID = 31,
+       RADIUS_ATTR_NAS_IDENTIFIER = 32,
+       RADIUS_ATTR_PROXY_STATE = 33,
+       RADIUS_ATTR_ACCT_STATUS_TYPE = 40,
+       RADIUS_ATTR_ACCT_DELAY_TIME = 41,
+       RADIUS_ATTR_ACCT_INPUT_OCTETS = 42,
+       RADIUS_ATTR_ACCT_OUTPUT_OCTETS = 43,
+       RADIUS_ATTR_ACCT_SESSION_ID = 44,
+       RADIUS_ATTR_ACCT_AUTHENTIC = 45,
+       RADIUS_ATTR_ACCT_SESSION_TIME = 46,
+       RADIUS_ATTR_ACCT_INPUT_PACKETS = 47,
+       RADIUS_ATTR_ACCT_OUTPUT_PACKETS = 48,
+       RADIUS_ATTR_ACCT_TERMINATE_CAUSE = 49,
+       RADIUS_ATTR_ACCT_MULTI_SESSION_ID = 50,
+       RADIUS_ATTR_ACCT_LINK_COUNT = 51,
+       RADIUS_ATTR_ACCT_INPUT_GIGAWORDS = 52,
+       RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS = 53,
+       RADIUS_ATTR_EVENT_TIMESTAMP = 55,
+       RADIUS_ATTR_NAS_PORT_TYPE = 61,
+       RADIUS_ATTR_TUNNEL_TYPE = 64,
+       RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
+       RADIUS_ATTR_CONNECT_INFO = 77,
+       RADIUS_ATTR_EAP_MESSAGE = 79,
+       RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
+       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
+};
+
+
+/* Termination-Action */
+#define RADIUS_TERMINATION_ACTION_DEFAULT 0
+#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1
+
+/* NAS-Port-Type */
+#define RADIUS_NAS_PORT_TYPE_IEEE_802_11 19
+
+/* Acct-Status-Type */
+#define RADIUS_ACCT_STATUS_TYPE_START 1
+#define RADIUS_ACCT_STATUS_TYPE_STOP 2
+#define RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE 3
+#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON 7
+#define RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF 8
+
+/* Acct-Authentic */
+#define RADIUS_ACCT_AUTHENTIC_RADIUS 1
+#define RADIUS_ACCT_AUTHENTIC_LOCAL 2
+#define RADIUS_ACCT_AUTHENTIC_REMOTE 3
+
+/* Acct-Terminate-Cause */
+#define RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST 1
+#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_CARRIER 2
+#define RADIUS_ACCT_TERMINATE_CAUSE_LOST_SERVICE 3
+#define RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT 4
+#define RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT 5
+#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET 6
+#define RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT 7
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_ERROR 8
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_ERROR 9
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REQUEST 10
+#define RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT 11
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_UNNEEDED 12
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_PREEMPTED 13
+#define RADIUS_ACCT_TERMINATE_CAUSE_PORT_SUSPENDED 14
+#define RADIUS_ACCT_TERMINATE_CAUSE_SERVICE_UNAVAILABLE 15
+#define RADIUS_ACCT_TERMINATE_CAUSE_CALLBACK 16
+#define RADIUS_ACCT_TERMINATE_CAUSE_USER_ERROR 17
+#define RADIUS_ACCT_TERMINATE_CAUSE_HOST_REQUEST 18
+
+#define RADIUS_TUNNEL_TAGS 32
+
+/* Tunnel-Type */
+#define RADIUS_TUNNEL_TYPE_PPTP 1
+#define RADIUS_TUNNEL_TYPE_L2TP 3
+#define RADIUS_TUNNEL_TYPE_IPIP 7
+#define RADIUS_TUNNEL_TYPE_GRE 10
+#define RADIUS_TUNNEL_TYPE_VLAN 13
+
+/* Tunnel-Medium-Type */
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV4 1
+#define RADIUS_TUNNEL_MEDIUM_TYPE_IPV6 2
+#define RADIUS_TUNNEL_MEDIUM_TYPE_802 6
+
+
+struct radius_attr_vendor {
+	u8 vendor_type;
+	u8 vendor_length;
+} STRUCT_PACKED;
+
+#define RADIUS_VENDOR_ID_CISCO 9
+#define RADIUS_CISCO_AV_PAIR 1
+
+/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */
+#define RADIUS_VENDOR_ID_MICROSOFT 311
+
+enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16,
+       RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
+};
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+struct radius_ms_mppe_keys {
+	u8 *send;
+	size_t send_len;
+	u8 *recv;
+	size_t recv_len;
+};
+
+
+/* RADIUS message structure for new and parsed messages */
+struct radius_msg {
+	unsigned char *buf;
+	size_t buf_size; /* total size allocated for buf */
+	size_t buf_used; /* bytes used in buf */
+
+	struct radius_hdr *hdr;
+
+	size_t *attr_pos; /* array of indexes to attributes (number of bytes
+			   * from buf to the beginning of
+			   * struct radius_attr_hdr). */
+	size_t attr_size; /* total size of the attribute pointer array */
+	size_t attr_used; /* total number of attributes in the array */
+};
+
+
+/* Default size to be allocated for new RADIUS messages */
+#define RADIUS_DEFAULT_MSG_SIZE 1024
+
+/* Default size to be allocated for attribute array */
+#define RADIUS_DEFAULT_ATTR_COUNT 16
+
+
+/* MAC address ASCII format for IEEE 802.1X use
+ * (draft-congdon-radius-8021x-20.txt) */
+#define RADIUS_802_1X_ADDR_FORMAT "%02X-%02X-%02X-%02X-%02X-%02X"
+/* MAC address ASCII format for non-802.1X use */
+#define RADIUS_ADDR_FORMAT "%02x%02x%02x%02x%02x%02x"
+
+struct radius_msg *radius_msg_new(u8 code, u8 identifier);
+int radius_msg_initialize(struct radius_msg *msg, size_t init_len);
+void radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier);
+void radius_msg_free(struct radius_msg *msg);
+void radius_msg_dump(struct radius_msg *msg);
+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);
+void radius_msg_finish_acct(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);
+int radius_msg_add_eap(struct radius_msg *msg, const u8 *data,
+		       size_t data_len);
+u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *len);
+int radius_msg_verify(struct radius_msg *msg, const u8 *secret,
+		      size_t secret_len, struct radius_msg *sent_msg,
+		      int auth);
+int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,
+			       size_t secret_len, const u8 *req_auth);
+int radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src,
+			 u8 type);
+void radius_msg_make_authenticator(struct radius_msg *msg,
+				   const u8 *data, size_t len);
+struct radius_ms_mppe_keys *
+radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+		       const u8 *secret, size_t secret_len);
+struct radius_ms_mppe_keys *
+radius_msg_get_cisco_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+			  const u8 *secret, size_t secret_len);
+int radius_msg_add_mppe_keys(struct radius_msg *msg,
+			     const u8 *req_authenticator,
+			     const u8 *secret, size_t secret_len,
+			     const u8 *send_key, size_t send_key_len,
+			     const u8 *recv_key, size_t recv_key_len);
+struct radius_attr_hdr *
+radius_msg_add_attr_user_password(struct radius_msg *msg,
+				  const u8 *data, size_t data_len,
+				  const u8 *secret, size_t secret_len);
+int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
+int radius_msg_get_vlanid(struct radius_msg *msg);
+
+static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
+					    u32 value)
+{
+	u32 val = htonl(value);
+	return radius_msg_add_attr(msg, type, (u8 *) &val, 4) != NULL;
+}
+
+static inline int radius_msg_get_attr_int32(struct radius_msg *msg, u8 type,
+					    u32 *value)
+{
+	u32 val;
+	int res;
+	res = radius_msg_get_attr(msg, type, (u8 *) &val, 4);
+	if (res != 4)
+		return -1;
+
+	*value = ntohl(val);
+	return 0;
+}
+int radius_msg_get_attr_ptr(struct radius_msg *msg, u8 type, u8 **buf,
+			    size_t *len, const u8 *start);
+int radius_msg_count_attr(struct radius_msg *msg, u8 type, int min_len);
+
+
+struct radius_attr_data {
+	u8 *data;
+	size_t len;
+};
+
+struct radius_class_data {
+	struct radius_attr_data *attr;
+	size_t count;
+};
+
+void radius_free_class(struct radius_class_data *c);
+int radius_copy_class(struct radius_class_data *dst,
+		      const struct radius_class_data *src);
+
+#endif /* RADIUS_H */
--- a/extensions/radius_gw/radius_gw.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/radius_gw.c	Fri May 22 18:11:49 2009 +0900
@@ -37,7 +37,7 @@
  */
 
 #define DECLARE_API_POINTERS
-#include "radius_gw_internal.h"
+#include "radius_gw.h"
 
 int radius_gw_verbosity = 0;
 waaad_api_t * waaad_api = NULL;
--- a/extensions/radius_gw/radius_gw.h	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/radius_gw.h	Fri May 22 18:11:49 2009 +0900
@@ -32,270 +32,103 @@
 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
 *********************************************************************************************************/
-/* This file contains the description of the API between the base radius_gw extension and
-  its extensions that add support for specific RADIUS attributes and/or commands.
-  The "notes.txt" file contains the basic mechanism for use of this API. */
 
-/* Note that waaad/waaad.h must be included before this file! */
-#ifndef _WAAAD_API_H
-# error "Do not include this file before waaad/waaad.h"
-#endif
-
+/* This file contains the definitions needed by the radius_gw extension alone, not exported to sub-extensions. */
+  
 #ifndef _RADIUS_GW_H
 #define _RADIUS_GW_H
 
-#include <stdint.h>
-#include <pthread.h>
-
-#include "md5.h"
-
-/* This type is used for all lists in this extension */
-struct rg_list {
-	struct rg_list *next;
-	struct rg_list *prev;
-	struct rg_list *head;
-};
-
-/**************************************************************/
-/*                  RADIUS messages                           */
-/**************************************************************/
-
-#define RADIUS_MAX_MSG_LEN 3000
-
-#define RADIUS_ATTR_MESSAGE_AUTHENTICATOR	80
-
-
-/* Note on design: the parsing of RADIUS message is not very efficient since we have to duplicate the memory of all
- attributes, instead of pointing back to them in the original message. Anyway, it makes adding / removing attributes simpler. */
+/* This file extends definitions from the standard waaad API */
+#define IN_EXTENSION
+#define DEFINE_DEBUG_MACRO	radius_gw
+#include <waaad/waaad.h>
 
-/* This type describes a RADIUS attribute */
-struct rad_attr {
-	/* Meta data */
-	struct rg_list	chain;	/* link this attribute in a message */
-	struct {
-		unsigned	handled : 1; /* Has this attribute already been converted to Diameter? */
-	} flags;
-	
-	/* Data */
-	uint8_t		type;
-	uint8_t		length;
-	union 	{
-		uint8_t	buf[253];
-		struct {
-			uint32_t	vendor_id;
-			union {
-				uint8_t	string[249];			/* generic format */
-				struct {
-					uint8_t	vendor_type;
-					uint8_t	vendor_length;
-					uint8_t vendor_value[247];
-				} 	tlv;				/* TLV format defined in rfc2865#section-5.26 */
-				struct {
-					unsigned	m 	:1;
-					unsigned	tag	:7;
-					uint8_t		data[248];
-				} radext;				/* Extended attributes defined in draft-ietf-radext-extended-attributes-08 */
-			};
-		} 	vsa; /* vendor-specific attributes */
-	}		data; /* Always fits in 253 bytes */
-};
-	
+/* include the common definitions */
+#include "rg_common.h"
+
+/* API definition of waaad */
+extern waaad_api_t * waaad_api;
+    
 
-/* The following type represents a complete RADIUS message (internal representation) with parsing information */
-typedef struct _rad_t {
-	/* Metadata */
-	struct rg_list	attributes;	/* The list of attributes */
-	struct {
-		unsigned serv_type 	: 2; /* The server (auth or acct) it was received on */
-		unsigned auth_ok 	: 1; /* The message has a valid message-authenticator ? */
-	} flags;
-	uint16_t	port;		/* Port the message was received on, network byte order */
-	struct _rad_t *	req;		/* Pointer to the request header (no attr), if msg is a reply */
-		
-	/* Data */
-	uint8_t		code;
-	uint8_t		identifier;
-	uint8_t		authenticator[16];
-} rad_t;
-
-
-/**************************************************************/
-/*                  Extensions registration                   */
-/**************************************************************/
-
-#define RADIUS_GW_API_VER	1 /* increment when making changes to radius_gw_api definition bellow */
-struct radius_gw_api {
-	void *  (*rga_conf_parse_cb) ( char * conf_file );	/* configuration parser. Returns NULL on error only. Called even if no configuration file is passed (with NULL parameter then) */
-	void	(*rga_conf_free_cb) (void * conf); 		/* Free an object returned by previous cb */
+/* The RADIUS server(s) configuration */
+struct rgw_serv {
+	unsigned	disabled	:1;
+	unsigned	ip_disabled	:1;
+	unsigned	ip6_disabled	:1;
+	unsigned	:13; /* padding */
+	
+	uint16_t	port;	/* stored in network byte order */
 	
-	/* handle an incoming RADIUS message */
-	int	(*rga_rad_req_cb) ( void * conf, sess_id_t ** session, rad_t ** rad_req, msg_t ** diam_fw );
-	/* ret 0: continue; 
-	   ret 1: stop processing this message and destroy the session (or fallback if supported)
-	   ret 2: stop processing this message and keep the session (or fallback if supported)
-	   ret 3: reply the content of rad_req to the RADIUS client immediatly and destroy the session
-	   ret 4: reply the content of rad_req to the RADIUS client immediatly and keep the session
-	   ret <0: critical error (-ret), log and exit.
-			   
-	   for cases 3 and 4, the answer must be created with rg_msg_create_ans.
-	 */
-	
-	/* handle the corresponding Diameter answer */
-	int	(*rga_diam_ans_cb) ( void * conf, sess_id_t ** session, msg_t ** diam_ans, rad_t ** rad_fw );
-	/* ret 0: continue; ret 1: ... (tbd) */
+	struct in_addr	ip_endpoint;
+	struct in6_addr	ip6_endpoint;
 };
-
-/* All extensions must provide the following entry point that is called when the extension is loaded.
-Beware, the same extension may be loaded several times, and receive different configuration files. 
-No global data should be initialized during this function; instead it should be done during the rga_conf_parse_cb call,
-and store in the memory pointed by "conf" that is passed in turn to all callbacks. */
-extern int rga_register(int version, waaad_api_t * waaad_api, struct radius_gw_api * api);
-
-
-/**************************************************************/
-/*      Functions exported by the common library extension    */
-/**************************************************************/
-
-/* List management */
-
-void rg_list_init(struct rg_list * plist);
-int  rg_list_is_empty(struct rg_list * plist);
-void rg_list_insert_after(struct rg_list * ref, struct rg_list * item);
-void rg_list_insert_before(struct rg_list * ref, struct rg_list * item);
-void rg_list_unlink(struct rg_list * plist);
+extern struct rgw_servs {
+	struct rgw_serv	auth_serv;
+	struct rgw_serv	acct_serv;
+} rgw_servers;
+int rgw_servers_init(void);
+int rgw_servers_start(void);
+void rgw_servers_dump(void);
+void rgw_servers_fini(void);
 
 
-/* Radius message */
-rad_t * rg_msg_create_ans(rad_t * req);
-void rg_msg_free(rad_t * msg);
-char * rg_msg_code_str(uint8_t c);
-char * rg_msg_attrtype_str(uint8_t c);
-void rg_msg_dump(int level, rad_t * msg);
-
-
-/* Others */
-int rg_thread_term(pthread_t * th);
+/* RADIUS messages + metadata */
+struct rgw_radius_msg_meta {
 
-/****************************************/
-/*      Debug and related stuff         */
-/****************************************/
-
-#include <assert.h>
-#ifndef ASSERT
-#define ASSERT(x) assert(x)
-#endif /* ASSERT */
-
-
-/* CHECK_* macro from the daemon */
-/* Helper for tracing the CHECK_* macros bellow */
-#define TRACE_DEBUG_ALL( str ) 	\
-	TRACE_DEBUG(CALL, str );
+	/* The RADIUS message */
+	struct radius_msg 	radius;
+	
+	/* Metadata */
+	struct {
+		/* The port it was sent from, in network byte order */
+		unsigned	port :16;
+		
+		/* received on ACCT or AUTH port? */
+		unsigned	serv_type :2;
+		
+		/* The message has a valid Message-Authenticator attribute */
+		unsigned	valid_mac :1;
+	};
+	
+};
+void rgw_msg_free(struct rgw_radius_msg_meta ** msg);
+int rgw_msg_parse(unsigned char * buf, size_t len, struct rgw_radius_msg_meta ** msg);
 
 
-/* Macros to check a return value and branch out in case of error.
- * These macro are to be used only when errors are highly improbable, not for expected errors.
- */
-
-/* Check the return value of a system function and execute fallback in case of error */
-#define CHECK_SYS_DO( __call__, __fallback__  ) { 					\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ < 0) {								\
-		int __err__ = errno;	/* We may handle EINTR here */			\
-		log_error("An unexpected error occured (%s), turn on debug for detail\n",\
-			strerror(__err__));						\
-		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
-		__fallback__;								\
-	}										\
-}
-/* Check the return value of a system function, return error code on error */
-#define CHECK_SYS( __call__  ) { 							\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ < 0) {								\
-		int __err__ = errno;	/* We may handle EINTR here */			\
-		log_error("An unexpected error occured (%s), turn on debug for detail\n",\
-			strerror(__err__));						\
-		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
-		return __err__;								\
-	}										\
-}
-
-/* Check the return value of a POSIX function and execute fallback in case of error or special value */
-#define CHECK_POSIX_DO2( __call__, __val__, __fallback1__, __fallback2__ ) {			\
-	int __ret__;										\
-	TRACE_DEBUG_ALL( "Check POSIX: " #__call__ );						\
-	__ret__ = (__call__);									\
-	if (__ret__ != 0) {									\
-		if (__ret__ == (__val__)) {							\
-			__fallback1__;								\
-		} else {									\
-			log_error("An unexpected error, see log for detail\n");			\
-			TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__ret__));	\
-			__fallback2__;								\
-		}										\
-	}											\
-}
-
-/* Check the return value of a POSIX function and execute fallback in case of error */
-#define CHECK_POSIX_DO( __call__, __fallback__ ) 					\
-	CHECK_POSIX_DO2( (__call__), 0, , __fallback__ );
-
-/* Check the return value of a POSIX function and return it if error */
-#define CHECK_POSIX( __call__ ) { 							\
-	int __v__;									\
-	CHECK_POSIX_DO( __v__ = (__call__), return __v__ );				\
-}
-
-/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
-#define CHECK_MALLOC_DO( __call__, __fallback__ ) { 					\
-	void *  __ret__;								\
-	TRACE_DEBUG_ALL( "Check MALLOC: " #__call__ );					\
-	__ret__ = (void *)( __call__ );							\
-	if (__ret__ == NULL) {								\
-		int __err__ = errno;							\
-		log_error("Memory allocation failed: %s\n", strerror(__err__));		\
-		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
-		__fallback__;								\
-	}										\
-}
-
-/* Check that a memory allocator did not return NULL, otherwise return ENOMEM */
-#define CHECK_MALLOC( __call__ )							\
-	CHECK_MALLOC_DO( __call__, return ENOMEM );
+/* The clients allowed to connect to these servers */
+struct rgw_client;
+int rgw_clients_init(void);
+int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen );
+int rgw_clients_getkey(struct rgw_client * cli, unsigned char **key, size_t *key_len);
+int rgw_clients_search(struct sockaddr * ip_port, struct rgw_client ** ref);
+int rgw_clients_check_dup(struct rgw_radius_msg_meta **msg, struct rgw_client *cli);
+void rgw_clients_dispose(struct rgw_client ** ref);
+void rgw_clients_dump(void);
+void rgw_clients_fini(void);
 
 
-/* The next functions can be used also for expected errors */
+/* Management of sub-extensions */
+int rgw_extensions_init(void);
+int rgw_extensions_add( char * extfile, char * conffile, int port, unsigned char ** codes_array, size_t codes_sz );
+void rgw_extensions_dump(void);
+void rgw_extensions_start_cache(void);
+int rgw_extensions_loop_req(struct rgw_radius_msg_meta **rad, sess_id_t **session, msg_t **diam_msg, struct rgw_client * cli);
+void rgw_extensions_fini(void);
 
-/* Check parameters at function entry, execute fallback on error */
-#define CHECK_PARAMS_DO( __bool__, __fallback__ )					\
-	TRACE_DEBUG_ALL( "Check PARAMS: " #__bool__ );					\
-	if ( ! (__bool__) ) {								\
-		TRACE_DEBUG(INFO, "Invalid parameter received in " #__bool__ );		\
-		__fallback__;								\
-	}
-/* Check parameters at function entry, return EINVAL if the boolean is false (similar to assert) */
-#define CHECK_PARAMS( __bool__ )							\
-	CHECK_PARAMS_DO( __bool__, return EINVAL );
 
-/* Check the return value of an internal function, log and propagate */
-#define CHECK_FCT_DO( __call__, __fallback__ ) {					\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check FCT: " #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ != 0) {								\
-		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__ret__));	\
-		__fallback__;								\
-	}										\
-}
-/* Check the return value of a function call, return any error code */
-#define CHECK_FCT( __call__ ) {								\
-	int __v__;									\
-	CHECK_FCT_DO( __v__ = (__call__), return __v__ );				\
-}
-		
+/* The function to parse the configuration file */
+int rgw_conf_handle(char * conffile);
+
+
+/* Worker module, that processes incoming RADIUS messages (in separated threads) */
+int rgw_work_start(void);
+int rgw_work_add(struct rgw_radius_msg_meta * msg, struct rgw_client * client);
+void rgw_work_fini(void);
+
+
+/* Verbosity level for debug */
+extern int radius_gw_verbosity;
+
 
 #endif /* _RADIUS_GW_H */
   
--- a/extensions/radius_gw/radius_gw.l	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/radius_gw.l	Fri May 22 18:11:49 2009 +0900
@@ -37,25 +37,14 @@
  */
 
 %{
-#include "radius_gw_internal.h"
+#include "radius_gw.h"
 #include "radius_gw.tab.h"
 
 /* Update the column information */
-#ifdef DEBUG_LEX
-#define YY_USER_ACTION { 						\
-	yylloc->first_column = yylloc->last_column + 1; 		\
-	yylloc->last_column = yylloc->first_column + yyleng - 1;	\
-	log_debug("(%d:%d-%d:%d) matched rule %d, length=%d, txt='%s'\n",\
-		yylloc->first_line, yylloc->first_column, 		\
-		yylloc->last_line, yylloc->last_column, 		\
-		yy_act, yyleng, yytext); 				\
-}
-#else /* DEBUG_LEX */
 #define YY_USER_ACTION { 						\
 	yylloc->first_column = yylloc->last_column + 1; 		\
 	yylloc->last_column = yylloc->first_column + yyleng - 1;	\
 }
-#endif
 
 /* %option noinput ? */
 #define YY_NO_INPUT
--- a/extensions/radius_gw/radius_gw.y	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/radius_gw.y	Fri May 22 18:11:49 2009 +0900
@@ -49,7 +49,7 @@
 %pure-parser
 
 %{
-#include "radius_gw_internal.h"
+#include "radius_gw.h"
 #include "radius_gw.tab.h"	/* bison is not smart enough to define the YYLTYPE before including this code, so... */
 
 #include <sys/stat.h>
@@ -218,7 +218,7 @@
 extension:		{
 				/* Reset the parameters */
 				buf_reinit();
-				port = RGW_EXT_PORT_AUTH | RGW_EXT_PORT_ACCT ;
+				port = RGW_EXT_TYPE_AUTH | RGW_EXT_TYPE_ACCT ;
 				free(extconffile); extconffile = NULL;
 			}
 			EXT_PREFIX '=' FILENAME ext_attributes ';'
@@ -244,11 +244,11 @@
 			}
 			| ext_attributes ':' AUTH
 			{
-				port = RGW_EXT_PORT_AUTH;
+				port = RGW_EXT_TYPE_AUTH;
 			}
 			| ext_attributes ':' ACCT
 			{
-				port = RGW_EXT_PORT_ACCT;
+				port = RGW_EXT_TYPE_ACCT;
 			}
 			| ext_attributes ':' extcodes_list
 			;
--- a/extensions/radius_gw/radius_gw_internal.h	Thu May 21 15:20:38 2009 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*********************************************************************************************************
-* Software License Agreement (BSD License)                                                               *
-* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
-*													 *
-* Copyright (c) 2008, WIDE Project and NICT								 *
-* All rights reserved.											 *
-* 													 *
-* Redistribution and use of this software in source and binary forms, with or without modification, are  *
-* permitted provided that the following conditions are met:						 *
-* 													 *
-* * Redistributions of source code must retain the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer.										 *
-*    													 *
-* * Redistributions in binary form must reproduce the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer in the documentation and/or other						 *
-*   materials provided with the distribution.								 *
-* 													 *
-* * Neither the name of the WIDE Project or NICT nor the 						 *
-*   names of its contributors may be used to endorse or 						 *
-*   promote products derived from this software without 						 *
-*   specific prior written permission of WIDE Project and 						 *
-*   NICT.												 *
-* 													 *
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
-* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
-* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
-* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
-* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
-* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
-*********************************************************************************************************/
-
-/* This file contains the definitions needed by the radius_gw extension alone, not exported to sub-extensions. */
-  
-#ifndef _RADIUS_GW_INTERNAL_H
-#define _RADIUS_GW_INTERNAL_H
-
-/* This file extends definitions from the standard waaad API */
-#define IN_EXTENSION
-#define DEFINE_DEBUG_MACRO	radius_gw
-#include <waaad/waaad.h>
-
-/* include the general stuff */
-#include "radius_gw.h"
-
-/* Some headers that are useful in many files */
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-/* API definition of waaad */
-extern waaad_api_t * waaad_api;
-    
-/* The RADIUS server(s) interface */
-struct rgw_serv {
-	unsigned	disabled	:1;
-	unsigned	ip_disabled	:1;
-	unsigned	ip6_disabled	:1;
-	unsigned	:13; /* padding */
-	
-	uint16_t	port;	/* stored in network byte order */
-	
-	struct in_addr	ip_endpoint;
-	struct in6_addr	ip6_endpoint;
-};
-
-extern struct rgw_servs {
-	struct rgw_serv	auth_serv;
-	struct rgw_serv	acct_serv;
-} rgw_servers;
-
-int rgw_servers_init(void);
-int rgw_servers_start(void);
-void rgw_servers_dump(void);
-void rgw_servers_fini(void);
-
-
-/* The clients allowed to connect to these servers */
-int rgw_clients_init(void);
-int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen );
-int rgw_clients_getkey(void * cli, unsigned char **key, size_t *key_len);
-int rgw_clients_search(struct sockaddr * ip_port, void ** ref);
-int rgw_clients_checkdup(rad_t **msg, void *cli);
-void rgw_clients_dispose(void ** ref);
-void rgw_clients_dump(void);
-void rgw_clients_fini(void);
-
-
-/* Functions related to RADIUS messages buffers on the network */
-int rgw_msg_parse(unsigned char *buf, size_t len, rad_t **msg);
-int rgw_msg_gen(rad_t *msg, unsigned char **buf, size_t *len);
-int rgw_msg_send(rad_t * msg, void * cli);
-
-
-/* The sub-extensions that provide functions to support RADIUS messages and attributes (see also radius_gw.h) */
-#define RGW_EXT_PORT_AUTH	1
-#define RGW_EXT_PORT_ACCT	2
-int rgw_extensions_init(void);
-int rgw_extensions_add( char * extfile, char * conffile, int port, unsigned char ** codes_array, size_t codes_sz );
-void rgw_extensions_dump(void);
-void rgw_extensions_start_cache(void);
-int rgw_extensions_loop_req(rad_t **rad, sess_id_t **session, msg_t **diam_msg, void * cli);
-void rgw_extensions_fini(void);
-
-/* The function to parse the configuration file */
-int rgw_conf_handle(char * conffile);
-
-
-/* Worker module that handle incoming RADIUS messages */
-int rgw_work_start(void);
-int rgw_work_add(rad_t * msg, void * client);
-void rgw_work_fini(void);
-
-
-/* Verbosity level for debug */
-extern int radius_gw_verbosity;
-
-
-#endif /* _RADIUS_GW_INTERNAL_H */
-  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/rg_api.h	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,74 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2008, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+/* This file contains the description of the API between the base radius_gw extension and
+  its extensions that add support for specific RADIUS attributes and/or commands.
+  The "notes.txt" file contains the basic mechanism for use of this API. */
+
+#ifndef _RG_API_H
+#define _RG_API_H
+
+#define RADIUS_GW_API_VER	1 /* increment when making changes to radius_gw_api definition bellow */
+
+struct rga_conf_state;		/* A structure (definition is subextension-dependant) to hold the subext configuration and state */
+
+struct radius_gw_api {
+	struct rga_conf_state *  
+		(*rga_conf_parse_cb) ( char * conf_file );		/* configuration parser. Returns NULL on error only. Called even if no configuration file is passed (with NULL parameter then) */
+	void	(*rga_conf_free_cb) (struct rga_conf_state * cs); 	/* Free an object returned by rga_conf_parse_cb */
+	
+	/* handle an incoming RADIUS message */
+	int	(*rga_rad_req_cb) ( struct rga_conf_state * cs, sess_id_t ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, msg_t ** diam_fw );
+	/* ret 0: continue; 
+	   ret 1: stop processing this message and destroy the session (or fallback if supported)
+	   ret 2: stop processing this message and keep the session (or fallback if supported)
+	   ret 3: reply the content of rad_ans to the RADIUS client immediatly and destroy the session
+	   ret 4: reply the content of rad_ans to the RADIUS client immediatly and keep the session
+	   ret <0: critical error (-ret), log and exit.
+			   
+	   for cases 3 and 4, the answer must be created with rg_msg_create_ans.
+	 */
+	
+	/* handle the corresponding Diameter answer */
+	int	(*rga_diam_ans_cb) ( struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw );
+	/* ret 0: continue; ret 1: ... (tbd) */
+};
+
+/* All extensions must provide the following entry point that is called when the extension is loaded.
+Beware, the same extension may be loaded several times, and receive different configuration files. 
+No global data should be initialized during this function; instead it should be done during the rga_conf_parse_cb call,
+and store in the memory pointed by "conf" that is passed in turn to all callbacks. */
+extern int rga_register(int version, waaad_api_t * waaad_api, struct radius_gw_api * api);
+
+#endif /* _RG_API_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/rg_common.h	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,221 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2008, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* This file contains definitions for both radius_gw extension and subextensions. */
+
+#ifndef _RG_COMMON_H
+#define _RG_COMMON_H
+
+/* Some headers that are useful in many files */
+#include <pthread.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <stdint.h>
+
+/* This should be overwritten before including this file */
+#ifndef DEFINE_DEBUG_MACRO
+# define DEFINE_DEBUG_MACRO	rg_common
+# ifndef RG_COMMON_VERBO
+#  define RG_COMMON_VERBO	0
+# endif /* RG_COMMON_VERBO */
+static int rg_common_verbosity = RG_COMMON_VERBO;
+#endif /* DEFINE_DEBUG_MACRO */
+
+/* Include the waaad API definition */
+#define IN_EXTENSION
+#include <waaad/waaad.h>
+
+/* Include host-specific defines */
+#include "rg_host.h"
+
+/* Include hostap files for RADIUS processings */
+#include "hostap_compat.h"
+#include "md5.h"
+#include "radius.h"
+
+/* Include the radius_gw API definition */
+#include "rg_api.h"
+
+/* Type of message / server */
+#define RGW_EXT_TYPE_AUTH	1
+#define RGW_EXT_TYPE_ACCT	2
+
+
+
+/**************************************************************/
+/*      Functions exported by the common library extension    */
+/**************************************************************/
+
+/* List management */
+struct rg_list {
+	struct rg_list *next;
+	struct rg_list *prev;
+	struct rg_list *head;
+};
+void rg_list_init(struct rg_list * plist);
+int  rg_list_is_empty(struct rg_list * plist);
+void rg_list_insert_after(struct rg_list * ref, struct rg_list * item);
+void rg_list_insert_before(struct rg_list * ref, struct rg_list * item);
+void rg_list_unlink(struct rg_list * plist);
+
+/* Others */
+int rg_thread_term(pthread_t * th);
+void rg_cleanup_mutex(void * mtx);
+
+
+/****************************************/
+/*      Debug and related stuff         */
+/****************************************/
+
+#include <assert.h>
+#ifndef ASSERT
+#define ASSERT(x) assert(x)
+#endif /* ASSERT */
+
+
+/* CHECK_* macro from the daemon */
+/* Helper for tracing the CHECK_* macros bellow */
+#define TRACE_DEBUG_ALL( str ) 	\
+	TRACE_DEBUG(CALL, str );
+
+
+/* Macros to check a return value and branch out in case of error.
+ * These macro are to be used only when errors are highly improbable, not for expected errors.
+ */
+
+/* Check the return value of a system function and execute fallback in case of error */
+#define CHECK_SYS_DO( __call__, __fallback__  ) { 					\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ < 0) {								\
+		int __err__ = errno;	/* We may handle EINTR here */			\
+		log_error("An unexpected error occured (%s), turn on debug for detail\n",\
+			strerror(__err__));						\
+		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
+		__fallback__;								\
+	}										\
+}
+/* Check the return value of a system function, return error code on error */
+#define CHECK_SYS( __call__  ) { 							\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check SYS: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ < 0) {								\
+		int __err__ = errno;	/* We may handle EINTR here */			\
+		log_error("An unexpected error occured (%s), turn on debug for detail\n",\
+			strerror(__err__));						\
+		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
+		return __err__;								\
+	}										\
+}
+
+/* Check the return value of a POSIX function and execute fallback in case of error or special value */
+#define CHECK_POSIX_DO2( __call__, __val__, __fallback1__, __fallback2__ ) {			\
+	int __ret__;										\
+	TRACE_DEBUG_ALL( "Check POSIX: " #__call__ );						\
+	__ret__ = (__call__);									\
+	if (__ret__ != 0) {									\
+		if (__ret__ == (__val__)) {							\
+			__fallback1__;								\
+		} else {									\
+			log_error("An unexpected error, see log for detail\n");			\
+			TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__ret__));	\
+			__fallback2__;								\
+		}										\
+	}											\
+}
+
+/* Check the return value of a POSIX function and execute fallback in case of error */
+#define CHECK_POSIX_DO( __call__, __fallback__ ) 					\
+	CHECK_POSIX_DO2( (__call__), 0, , __fallback__ );
+
+/* Check the return value of a POSIX function and return it if error */
+#define CHECK_POSIX( __call__ ) { 							\
+	int __v__;									\
+	CHECK_POSIX_DO( __v__ = (__call__), return __v__ );				\
+}
+
+/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
+#define CHECK_MALLOC_DO( __call__, __fallback__ ) { 					\
+	void *  __ret__;								\
+	TRACE_DEBUG_ALL( "Check MALLOC: " #__call__ );					\
+	__ret__ = (void *)( __call__ );							\
+	if (__ret__ == NULL) {								\
+		int __err__ = errno;							\
+		log_error("Memory allocation failed: %s\n", strerror(__err__));		\
+		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__err__));	\
+		__fallback__;								\
+	}										\
+}
+
+/* Check that a memory allocator did not return NULL, otherwise return ENOMEM */
+#define CHECK_MALLOC( __call__ )							\
+	CHECK_MALLOC_DO( __call__, return ENOMEM );
+
+
+/* The next functions can be used also for expected errors */
+
+/* Check parameters at function entry, execute fallback on error */
+#define CHECK_PARAMS_DO( __bool__, __fallback__ )					\
+	TRACE_DEBUG_ALL( "Check PARAMS: " #__bool__ );					\
+	if ( ! (__bool__) ) {								\
+		TRACE_DEBUG(INFO, "Invalid parameter received in " #__bool__ );		\
+		__fallback__;								\
+	}
+/* Check parameters at function entry, return EINVAL if the boolean is false (similar to assert) */
+#define CHECK_PARAMS( __bool__ )							\
+	CHECK_PARAMS_DO( __bool__, return EINVAL );
+
+/* Check the return value of an internal function, log and propagate */
+#define CHECK_FCT_DO( __call__, __fallback__ ) {					\
+	int __ret__;									\
+	TRACE_DEBUG_ALL( "Check FCT: " #__call__ );					\
+	__ret__ = (__call__);								\
+	if (__ret__ != 0) {								\
+		TRACE_DEBUG(INFO, "Error in '" #__call__ "': %s", strerror(__ret__));	\
+		__fallback__;								\
+	}										\
+}
+/* Check the return value of a function call, return any error code */
+#define CHECK_FCT( __call__ ) {								\
+	int __v__;									\
+	CHECK_FCT_DO( __v__ = (__call__), return __v__ );				\
+}
+		
+
+#endif /* _RG_COMMON_H */
+  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/rg_host.h.in	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,8 @@
+#ifndef _RG_HOST_H
+#define _RG_HOST_H
+
+/* Endianness */
+#cmakedefine WORDS_BIGENDIAN @WORDS_BIGENDIAN@
+
+
+#endif /* _RG_HOST_H */
--- a/extensions/radius_gw/rg_utils.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/rg_utils.c	Fri May 22 18:11:49 2009 +0900
@@ -33,23 +33,10 @@
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
 *********************************************************************************************************/
 
-/* Some useful functions for both radius_gw and its sub extensions 
- * These functions are compiled as a static library rg_common.
- */
-
-#define IN_EXTENSION
-#define DEFINE_DEBUG_MACRO	rg_common
-#include <waaad/waaad.h>
+#include "rg_common.h"
 
-#include "radius_gw.h"
 
-#include <stdlib.h>
-#include <string.h>
-
-#ifndef RG_COMMON_VERBO
-#define RG_COMMON_VERBO	1
-#endif /* RG_COMMON_VERBO */
-static int rg_common_verbosity = RG_COMMON_VERBO;
+/************ Lists ***********/
 
 void rg_list_init(struct rg_list * plist)
 {
@@ -102,74 +89,7 @@
 }
 
 
-rad_t * rg_msg_create_ans(rad_t * req)
-{
-	rad_t * ans = NULL;
-	rad_t * reqcpy = NULL;
-	
-	CHECK_MALLOC_DO( reqcpy = malloc(sizeof(rad_t)), return NULL );
-	CHECK_MALLOC_DO( ans = malloc(sizeof(rad_t)), { free(reqcpy); return NULL; } );
-	
-	memcpy(reqcpy, req, sizeof(rad_t));
-	rg_list_init(&reqcpy->attributes);
-	
-	memset(ans, 0, sizeof(rad_t));
-	rg_list_init(&ans->attributes);
-	
-	ans->req = reqcpy;
-	
-	return ans;
-}
-	
-
-void rg_msg_free(rad_t * msg)
-{
-	while ( ! rg_list_is_empty( &msg->attributes ) ) {
-		struct rg_list * item = msg->attributes.next;
-		rg_list_unlink(item);
-		free(item);
-	}
-	free(msg->req);
-	free(msg);
-}
-
-char * rg_msg_code_str(uint8_t c)
-{
-	/* Include generated source file, see rebuild_inc.sh script */
-#include "rg_utils_codes.inc"
-	
-	/* fallback */
-	return "[unknown]";
-}
-
-char * rg_msg_attrtype_str(uint8_t c)
-{
-	/* Include generated source file, see rebuild_inc.sh script */
-#include "rg_utils_attrtype.inc"
-	
-	/* fallback */
-	return "[unknown]";
-}
-
-void rg_msg_dump(int level, rad_t * msg)
-{
-	struct rg_list * attr;
-	
-	log_debug("------ RADIUS msg dump -------\n");
-	log_debug("   id: %02hhx, code: %hhd (%s)\n", msg->identifier, msg->code, rg_msg_code_str(msg->code));
-	log_debug(" auth: %02hhx %02hhx %02hhx %02hhx  %02hhx %02hhx %02hhx %02hhx\n",
-			msg->authenticator[0], msg->authenticator[1], msg->authenticator[2], msg->authenticator[3], 
-			msg->authenticator[4], msg->authenticator[5], msg->authenticator[6], msg->authenticator[7]);
-	log_debug("       %02hhx %02hhx %02hhx %02hhx  %02hhx %02hhx %02hhx %02hhx\n",
-			msg->authenticator[8], msg->authenticator[9], msg->authenticator[10], msg->authenticator[11], 
-			msg->authenticator[12], msg->authenticator[13], msg->authenticator[14], msg->authenticator[15]);
-	for (attr = msg->attributes.next; attr != &msg->attributes; attr = attr->next) {
-		struct rad_attr * loc = (struct rad_attr *)attr;
-		log_debug("    attr: len:%3hhd, type:%02hhx (%s)\n", loc->length, loc->type, rg_msg_attrtype_str(loc->type));
-	}
-	log_debug("-----------------------------\n");
-}
-
+/************ Other helpers ***********/
 
 /* Terminate a thread */
 int rg_thread_term(pthread_t * th)
@@ -199,5 +119,11 @@
 	return ret;
 }
 
+/* Cancellation cleanups */
+void rg_cleanup_mutex(void * mtx)
+{
+	CHECK_POSIX_DO( pthread_mutex_unlock((pthread_mutex_t *)mtx), );
+}
 
 
+
--- a/extensions/radius_gw/rg_utils_attrtype.inc	Thu May 21 15:20:38 2009 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,258 +0,0 @@
-		/* 1         User-Name                                 */
-	if ( c == 1) return "User-Name   ";
-		/* 2         User-Password                             */
-	if ( c == 2) return "User-Password   ";
-		/* 3         CHAP-Password                             */
-	if ( c == 3) return "CHAP-Password   ";
-		/* 4         NAS-IP-Address                            */
-	if ( c == 4) return "NAS-IP-Address   ";
-		/* 5         NAS-Port                                  */
-	if ( c == 5) return "NAS-Port   ";
-		/* 6         Service-Type                              */
-	if ( c == 6) return "Service-Type   ";
-		/* 7         Framed-Protocol                           */
-	if ( c == 7) return "Framed-Protocol   ";
-		/* 8         Framed-IP-Address                         */
-	if ( c == 8) return "Framed-IP-Address   ";
-		/* 9         Framed-IP-Netmask                         */
-	if ( c == 9) return "Framed-IP-Netmask   ";
-		/* 10        Framed-Routing                            */
-	if ( c == 10) return "Framed-Routing   ";
-		/* 11        Filter-Id                                 */
-	if ( c == 11) return "Filter-Id   ";
-		/* 12        Framed-MTU                                */
-	if ( c == 12) return "Framed-MTU   ";
-		/* 13        Framed-Compression                        */
-	if ( c == 13) return "Framed-Compression   ";
-		/* 14        Login-IP-Host                             */
-	if ( c == 14) return "Login-IP-Host   ";
-		/* 15        Login-Service                             */
-	if ( c == 15) return "Login-Service   ";
-		/* 16        Login-TCP-Port                            */
-	if ( c == 16) return "Login-TCP-Port   ";
-		/* 17        Unassigned */
-	if ( c == 17) return "Unassigned   ";
-		/* 18        Reply-Message                             */
-	if ( c == 18) return "Reply-Message   ";
-		/* 19        Callback-Number                           */
-	if ( c == 19) return "Callback-Number   ";
-		/* 20        Callback-Id                               */
-	if ( c == 20) return "Callback-Id   ";
-		/* 21        Unassigned */
-	if ( c == 21) return "Unassigned   ";
-		/* 22        Framed-Route                              */
-	if ( c == 22) return "Framed-Route   ";
-		/* 23        Framed-IPX-Network                        */
-	if ( c == 23) return "Framed-IPX-Network   ";
-		/* 24        State                                     */
-	if ( c == 24) return "State   ";
-		/* 25        Class                                     */
-	if ( c == 25) return "Class   ";
-		/* 26        Vendor-Specific                           */
-	if ( c == 26) return "Vendor-Specific   ";
-		/* 27        Session-Timeout                           */
-	if ( c == 27) return "Session-Timeout   ";
-		/* 28        Idle-Timeout                              */
-	if ( c == 28) return "Idle-Timeout   ";
-		/* 29        Termination-Action                        */
-	if ( c == 29) return "Termination-Action   ";
-		/* 30        Called-Station-Id                         */
-	if ( c == 30) return "Called-Station-Id   ";
-		/* 31        Calling-Station-Id                        */
-	if ( c == 31) return "Calling-Station-Id   ";
-		/* 32        NAS-Identifier                            */
-	if ( c == 32) return "NAS-Identifier   ";
-		/* 33        Proxy-State                               */
-	if ( c == 33) return "Proxy-State   ";
-		/* 34        Login-LAT-Service                         */
-	if ( c == 34) return "Login-LAT-Service   ";
-		/* 35        Login-LAT-Node                            */
-	if ( c == 35) return "Login-LAT-Node   ";
-		/* 36        Login-LAT-Group                           */
-	if ( c == 36) return "Login-LAT-Group   ";
-		/* 37        Framed-AppleTalk-Link                     */
-	if ( c == 37) return "Framed-AppleTalk-Link   ";
-		/* 38        Framed-AppleTalk-Network                  */
-	if ( c == 38) return "Framed-AppleTalk-Network   ";
-		/* 39        Framed-AppleTalk-Zone                     */
-	if ( c == 39) return "Framed-AppleTalk-Zone   ";
-		/* 40        Acct-Status-Type                         [RFC2866] */
-	if ( c == 40) return "Acct-Status-Type [RFC2866]  ";
-		/* 41        Acct-Delay-Time                          [RFC2866] */
-	if ( c == 41) return "Acct-Delay-Time [RFC2866]  ";
-		/* 42        Acct-Input-Octets                        [RFC2866] */
-	if ( c == 42) return "Acct-Input-Octets [RFC2866]  ";
-		/* 43        Acct-Output-Octets                       [RFC2866] */
-	if ( c == 43) return "Acct-Output-Octets [RFC2866]  ";
-		/* 44        Acct-Session-Id                          [RFC2866] */
-	if ( c == 44) return "Acct-Session-Id [RFC2866]  ";
-		/* 45        Acct-Authentic                           [RFC2866] */
-	if ( c == 45) return "Acct-Authentic [RFC2866]  ";
-		/* 46        Acct-Session-Time                        [RFC2866] */
-	if ( c == 46) return "Acct-Session-Time [RFC2866]  ";
-		/* 47        Acct-Input-Packets                       [RFC2866] */
-	if ( c == 47) return "Acct-Input-Packets [RFC2866]  ";
-		/* 48        Acct-Output-Packets                      [RFC2866] */
-	if ( c == 48) return "Acct-Output-Packets [RFC2866]  ";
-		/* 49        Acct-Terminate-Cause                     [RFC2866] */
-	if ( c == 49) return "Acct-Terminate-Cause [RFC2866]  ";
-		/* 50        Acct-Multi-Session-Id                    [RFC2866] */
-	if ( c == 50) return "Acct-Multi-Session-Id [RFC2866]  ";
-		/* 51        Acct-Link-Count                          [RFC2866] */
-	if ( c == 51) return "Acct-Link-Count [RFC2866]  ";
-		/* 52        Acct-Input-Gigawords                     [RFC2869] */
-	if ( c == 52) return "Acct-Input-Gigawords [RFC2869]  ";
-		/* 53        Acct-Output-Gigawords                    [RFC2869] */
-	if ( c == 53) return "Acct-Output-Gigawords [RFC2869]  ";
-		/* 54        Unassigned */
-	if ( c == 54) return "Unassigned   ";
-		/* 55        Event-Timestamp                          [RFC2869] */
-	if ( c == 55) return "Event-Timestamp [RFC2869]  ";
-		/* 56        Egress-VLANID                            [RFC4675] */
-	if ( c == 56) return "Egress-VLANID [RFC4675]  ";
-		/* 57        Ingress-Filters                          [RFC4675] */
-	if ( c == 57) return "Ingress-Filters [RFC4675]  ";
-		/* 58        Egress-VLAN-Name                         [RFC4675] */
-	if ( c == 58) return "Egress-VLAN-Name [RFC4675]  ";
-		/* 59        User-Priority-Table                      [RFC4675] */
-	if ( c == 59) return "User-Priority-Table [RFC4675]  ";
-		/* 60        CHAP-Challenge */
-	if ( c == 60) return "CHAP-Challenge   ";
-		/* 61        NAS-Port-Type */
-	if ( c == 61) return "NAS-Port-Type   ";
-		/* 62        Port-Limit */
-	if ( c == 62) return "Port-Limit   ";
-		/* 63        Login-LAT-Port */
-	if ( c == 63) return "Login-LAT-Port   ";
-		/* 64        Tunnel-Type                              [RFC2868] */
-	if ( c == 64) return "Tunnel-Type [RFC2868]  ";
-		/* 65        Tunnel-Medium-Type                       [RFC2868] */
-	if ( c == 65) return "Tunnel-Medium-Type [RFC2868]  ";
-		/* 66        Tunnel-Client-Endpoint                   [RFC2868] */
-	if ( c == 66) return "Tunnel-Client-Endpoint [RFC2868]  ";
-		/* 67        Tunnel-Server-Endpoint                   [RFC2868] */
-	if ( c == 67) return "Tunnel-Server-Endpoint [RFC2868]  ";
-		/* 68        Acct-Tunnel-Connection                   [RFC2867] */
-	if ( c == 68) return "Acct-Tunnel-Connection [RFC2867]  ";
-		/* 69        Tunnel-Password                          [RFC2868] */
-	if ( c == 69) return "Tunnel-Password [RFC2868]  ";
-		/* 70        ARAP-Password                            [RFC2869] */
-	if ( c == 70) return "ARAP-Password [RFC2869]  ";
-		/* 71        ARAP-Features                            [RFC2869] */
-	if ( c == 71) return "ARAP-Features [RFC2869]  ";
-		/* 72        ARAP-Zone-Access                         [RFC2869] */
-	if ( c == 72) return "ARAP-Zone-Access [RFC2869]  ";
-		/* 73        ARAP-Security                            [RFC2869] */
-	if ( c == 73) return "ARAP-Security [RFC2869]  ";
-		/* 74        ARAP-Security-Data                       [RFC2869] */
-	if ( c == 74) return "ARAP-Security-Data [RFC2869]  ";
-		/* 75        Password-Retry                           [RFC2869] */
-	if ( c == 75) return "Password-Retry [RFC2869]  ";
-		/* 76        Prompt                                   [RFC2869] */
-	if ( c == 76) return "Prompt [RFC2869]  ";
-		/* 77        Connect-Info                             [RFC2869] */
-	if ( c == 77) return "Connect-Info [RFC2869]  ";
-		/* 78        Configuration-Token                      [RFC2869] */
-	if ( c == 78) return "Configuration-Token [RFC2869]  ";
-		/* 79        EAP-Message                              [RFC2869] */
-	if ( c == 79) return "EAP-Message [RFC2869]  ";
-		/* 80        Message-Authenticator                    [RFC2869] */
-	if ( c == 80) return "Message-Authenticator [RFC2869]  ";
-		/* 81        Tunnel-Private-Group-ID                  [RFC2868] */
-	if ( c == 81) return "Tunnel-Private-Group-ID [RFC2868]  ";
-		/* 82        Tunnel-Assignment-ID                     [RFC2868] */
-	if ( c == 82) return "Tunnel-Assignment-ID [RFC2868]  ";
-		/* 83        Tunnel-Preference                        [RFC2868] */
-	if ( c == 83) return "Tunnel-Preference [RFC2868]  ";
-		/* 84        ARAP-Challenge-Response                  [RFC2869] */
-	if ( c == 84) return "ARAP-Challenge-Response [RFC2869]  ";
-		/* 85        Acct-Interim-Interval                    [RFC2869] */
-	if ( c == 85) return "Acct-Interim-Interval [RFC2869]  ";
-		/* 86        Acct-Tunnel-Packets-Lost                 [RFC2867] */
-	if ( c == 86) return "Acct-Tunnel-Packets-Lost [RFC2867]  ";
-		/* 87        NAS-Port-Id                              [RFC2869] */
-	if ( c == 87) return "NAS-Port-Id [RFC2869]  ";
-		/* 88        Framed-Pool                              [RFC2869] */
-	if ( c == 88) return "Framed-Pool [RFC2869]  ";
-		/* 89        CUI                                      [RFC4372] */
-	if ( c == 89) return "CUI [RFC4372]  ";
-		/* 90        Tunnel-Client-Auth-ID                    [RFC2868] */
-	if ( c == 90) return "Tunnel-Client-Auth-ID [RFC2868]  ";
-		/* 91        Tunnel-Server-Auth-ID                    [RFC2868] */
-	if ( c == 91) return "Tunnel-Server-Auth-ID [RFC2868]  ";
-		/* 92        NAS-Filter-Rule                          [RFC4849] */
-	if ( c == 92) return "NAS-Filter-Rule [RFC4849]  ";
-		/* 93        Unassigned */
-	if ( c == 93) return "Unassigned   ";
-		/* 94        Originating-Line-Info                    [RFC4005] */
-	if ( c == 94) return "Originating-Line-Info [RFC4005]  ";
-		/* 95        NAS-IPv6-Address                         [RFC3162] */
-	if ( c == 95) return "NAS-IPv6-Address [RFC3162]  ";
-		/* 96        Framed-Interface-Id                      [RFC3162] */
-	if ( c == 96) return "Framed-Interface-Id [RFC3162]  ";
-		/* 97        Framed-IPv6-Prefix                       [RFC3162] */
-	if ( c == 97) return "Framed-IPv6-Prefix [RFC3162]  ";
-		/* 98        Login-IPv6-Host                          [RFC3162] */
-	if ( c == 98) return "Login-IPv6-Host [RFC3162]  ";
-		/* 99        Framed-IPv6-Route                        [RFC3162] */
-	if ( c == 99) return "Framed-IPv6-Route [RFC3162]  ";
-		/* 100       Framed-IPv6-Pool                         [RFC3162] */
-	if ( c == 100) return "Framed-IPv6-Pool [RFC3162]  ";
-		/* 101       Error-Cause Attribute                    [RFC3576] */
-	if ( c == 101) return "Error-Cause Attribute [RFC3576] ";
-		/* 102       EAP-Key-Name                             [RFC4072] */
-	if ( c == 102) return "EAP-Key-Name [RFC4072]  ";
-		/* 103       Digest-Response                          [RFC5090] */
-	if ( c == 103) return "Digest-Response [RFC5090]  ";
-		/* 104       Digest-Realm                             [RFC5090] */
-	if ( c == 104) return "Digest-Realm [RFC5090]  ";
-		/* 105       Digest-Nonce                             [RFC5090]   */
-	if ( c == 105) return "Digest-Nonce [RFC5090]  ";
-		/* 106       Digest-Response-Auth                     [RFC5090] */
-	if ( c == 106) return "Digest-Response-Auth [RFC5090]  ";
-		/* 107       Digest-Nextnonce                         [RFC5090] */
-	if ( c == 107) return "Digest-Nextnonce [RFC5090]  ";
-		/* 108       Digest-Method                            [RFC5090] */
-	if ( c == 108) return "Digest-Method [RFC5090]  ";
-		/* 109       Digest-URI                               [RFC5090]  */
-	if ( c == 109) return "Digest-URI [RFC5090]  ";
-		/* 110       Digest-Qop                               [RFC5090]  */
-	if ( c == 110) return "Digest-Qop [RFC5090]  ";
-		/* 111       Digest-Algorithm                         [RFC5090]  */
-	if ( c == 111) return "Digest-Algorithm [RFC5090]  ";
-		/* 112       Digest-Entity-Body-Hash                  [RFC5090]  */
-	if ( c == 112) return "Digest-Entity-Body-Hash [RFC5090]  ";
-		/* 113       Digest-CNonce                            [RFC5090]  */
-	if ( c == 113) return "Digest-CNonce [RFC5090]  ";
-		/* 114       Digest-Nonce-Count                       [RFC5090]  */
-	if ( c == 114) return "Digest-Nonce-Count [RFC5090]  ";
-		/* 115       Digest-Username                          [RFC5090]  */
-	if ( c == 115) return "Digest-Username [RFC5090]  ";
-		/* 116       Digest-Opaque                            [RFC5090]  */
-	if ( c == 116) return "Digest-Opaque [RFC5090]  ";
-		/* 117       Digest-Auth-Param                        [RFC5090]  */
-	if ( c == 117) return "Digest-Auth-Param [RFC5090]  ";
-		/* 118       Digest-AKA-Auts                          [RFC5090]  */
-	if ( c == 118) return "Digest-AKA-Auts [RFC5090]  ";
-		/* 119       Digest-Domain                            [RFC5090]  */
-	if ( c == 119) return "Digest-Domain [RFC5090]  ";
-		/* 120       Digest-Stale                             [RFC5090]  */
-	if ( c == 120) return "Digest-Stale [RFC5090]  ";
-		/* 121       Digest-HA1                               [RFC5090]  */
-	if ( c == 121) return "Digest-HA1 [RFC5090]  ";
-		/* 122       SIP-AOR                                  [RFC5090]  */
-	if ( c == 122) return "SIP-AOR [RFC5090]  ";
-		/* 123       Delegated-IPv6-Prefix                    [RFC4818] */
-	if ( c == 123) return "Delegated-IPv6-Prefix [RFC4818]  ";
-		/* 124       MIP6-Feature-Vector                      [RFC5447] */
-	if ( c == 124) return "MIP6-Feature-Vector [RFC5447]  ";
-		/* 125       MIP6-Home-Link-Prefix                    [RFC5447] */
-	if ( c == 125) return "MIP6-Home-Link-Prefix [RFC5447]  ";
-		/* 126-191   Unassigned */
-	if ((c >= 126) && (c <= 191)) return "Unassigned   ";
-		/* 192-223   Experimental Use                         [RFC3575] */
-	if ((c >= 192) && (c <= 223)) return "Experimental Use [RFC3575] ";
-		/* 224-240   Implementation Specific                  [RFC3575] */
-	if ((c >= 224) && (c <= 240)) return "Implementation Specific [RFC3575] ";
-		/* 241-255   Reserved                                 [RFC3575]    */
-	if ((c >= 241) && (c <= 255)) return "Reserved [RFC3575]  ";
--- a/extensions/radius_gw/rg_utils_codes.inc	Thu May 21 15:20:38 2009 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,78 +0,0 @@
-		/* 1        Access-Request                           [RFC2865] */
-	if ( c == 1) return "Access-Request [RFC2865]  ";
-		/* 2        Access-Accept                            [RFC2865] */
-	if ( c == 2) return "Access-Accept [RFC2865]  ";
-		/* 3        Access-Reject                            [RFC2865] */
-	if ( c == 3) return "Access-Reject [RFC2865]  ";
-		/* 4        Accounting-Request                       [RFC2865] */
-	if ( c == 4) return "Accounting-Request [RFC2865]  ";
-		/* 5        Accounting-Response                      [RFC2865] */
-	if ( c == 5) return "Accounting-Response [RFC2865]  ";
-		/* 6        Accounting-Status                        [RFC3575] */
-	if ( c == 6) return "Accounting-Status [RFC3575]  ";
-		/* 7        Password-Request                         [RFC3575] */
-	if ( c == 7) return "Password-Request [RFC3575]  ";
-		/* 8        Password-Ack                             [RFC3575] */
-	if ( c == 8) return "Password-Ack [RFC3575]  ";
-		/* 9        Password-Reject                          [RFC3575] */
-	if ( c == 9) return "Password-Reject [RFC3575]  ";
-		/* 10       Accounting-Message                       [RFC3575] */
-	if ( c == 10) return "Accounting-Message [RFC3575]  ";
-		/* 11       Access-Challenge                         [RFC2865] */
-	if ( c == 11) return "Access-Challenge [RFC2865]  ";
-		/* 12       Status-Server (experimental)             [RFC2865] */
-	if ( c == 12) return "Status-Server (experimental) [RFC2865] ";
-		/* 13       Status-Client (experimental)             [RFC2865] */
-	if ( c == 13) return "Status-Client (experimental) [RFC2865] ";
-		/* 21       Resource-Free-Request                    [RFC3575] */
-	if ( c == 21) return "Resource-Free-Request [RFC3575]  ";
-		/* 22       Resource-Free-Response                   [RFC3575] */
-	if ( c == 22) return "Resource-Free-Response [RFC3575]  ";
-		/* 23       Resource-Query-Request                   [RFC3575] */
-	if ( c == 23) return "Resource-Query-Request [RFC3575]  ";
-		/* 24       Resource-Query-Response                  [RFC3575] */
-	if ( c == 24) return "Resource-Query-Response [RFC3575]  ";
-		/* 25       Alternate-Resource-Reclaim-Request       [RFC3575] */
-	if ( c == 25) return "Alternate-Resource-Reclaim-Request [RFC3575]  ";
-		/* 26       NAS-Reboot-Request                       [RFC3575] */
-	if ( c == 26) return "NAS-Reboot-Request [RFC3575]  ";
-		/* 27       NAS-Reboot-Response                      [RFC3575] */
-	if ( c == 27) return "NAS-Reboot-Response [RFC3575]  ";
-		/* 28       Reserved */
-	if ( c == 28) return "Reserved   ";
-		/* 29       Next-Passcode                            [RFC3575] */
-	if ( c == 29) return "Next-Passcode [RFC3575]  ";
-		/* 30       New-Pin                                  [RFC3575] */
-	if ( c == 30) return "New-Pin [RFC3575]  ";
-		/* 31       Terminate-Session                        [RFC3575] */
-	if ( c == 31) return "Terminate-Session [RFC3575]  ";
-		/* 32       Password-Expired                         [RFC3575] */
-	if ( c == 32) return "Password-Expired [RFC3575]  ";
-		/* 33       Event-Request                            [RFC3575] */
-	if ( c == 33) return "Event-Request [RFC3575]  ";
-		/* 34       Event-Response                           [RFC3575] */
-	if ( c == 34) return "Event-Response [RFC3575]  ";
-		/* 40       Disconnect-Request                       [RFC3575][RFC5176] */
-	if ( c == 40) return "Disconnect-Request [RFC3575][RFC5176]  ";
-		/* 41       Disconnect-ACK                           [RFC3575][RFC5176] */
-	if ( c == 41) return "Disconnect-ACK [RFC3575][RFC5176]  ";
-		/* 42       Disconnect-NAK                           [RFC3575][RFC5176] */
-	if ( c == 42) return "Disconnect-NAK [RFC3575][RFC5176]  ";
-		/* 43       CoA-Request                              [RFC3575][RFC5176] */
-	if ( c == 43) return "CoA-Request [RFC3575][RFC5176]  ";
-		/* 44       CoA-ACK                                  [RFC3575][RFC5176] */
-	if ( c == 44) return "CoA-ACK [RFC3575][RFC5176]  ";
-		/* 45       CoA-NAK                                  [RFC3575][RFC5176] */
-	if ( c == 45) return "CoA-NAK [RFC3575][RFC5176]  ";
-		/* 50       IP-Address-Allocate                      [RFC3575] */
-	if ( c == 50) return "IP-Address-Allocate [RFC3575]  ";
-		/* 51       IP-Address-Release                       [RFC3575] */
-	if ( c == 51) return "IP-Address-Release [RFC3575]  ";
-		/* 52-249   Unassigned */
-	if ((c >= 52) && (c <= 249)) return "Unassigned   ";
-		/* 250-253  Experimental Use                         [RFC3575] */
-	if ((c >= 250) && (c <= 253)) return "Experimental Use [RFC3575] ";
-		/* 254      Reserved                                 [RFC3575] */
-	if ( c == 254) return "Reserved [RFC3575]  ";
-		/* 255      Reserved                                 [RFC3575] */
-	if ( c == 255) return "Reserved [RFC3575]  ";
--- a/extensions/radius_gw/rgw_clients.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/rgw_clients.c	Fri May 22 18:11:49 2009 +0900
@@ -35,7 +35,10 @@
 
 /* Manage the list of RADIUS clients, along with their shared secrets. */
 
-#include "radius_gw_internal.h"
+#include "radius_gw.h"
+
+/* How many bytes of secret keys to dump? */
+#define KEY_DUMP_BYTES	16
 
 /* Ordered lists of clients. The order relationship is a memcmp on the address zone. 
    For same addresses, the port is compared.
@@ -47,38 +50,46 @@
 static pthread_mutex_t cli_mtx = PTHREAD_MUTEX_INITIALIZER;
 
 /* Structure describing one client */
-struct cli_info {
+struct rgw_client {
+	/* Link information in global list */
 	struct rg_list		chain;
+	
+	/* Reference count */
+	int			refcount;
+	
+	/* The address and optional port. The head list determines which one to use */
 	union {
 		struct sockaddr_in	*sin;
 		struct sockaddr_in6	*sin6;
 	};
+	
+	/* The secret key data. */
 	struct {
 		unsigned char * data;
 		size_t		len;
 	} 			key;
-	int			refcount;
 	
-	/* Previous msg received, for duplicate checks. [0] for auth, [1] for acct. */
+	/* information of previous msg received, for duplicate checks. [0] for auth, [1] for acct. */
 	struct {
 		uint16_t	port;
 		uint8_t		id;
 	} last[2];
 };
 
-/* Function to alloc a new cli_info */
-static int cli_info_create(struct cli_info ** res, struct sockaddr ** ip_port, unsigned char ** key, size_t keylen )
+
+/* create a new rgw_client. the arguments are moved into the structure. */
+static int client_create(struct rgw_client ** res, struct sockaddr ** ip_port, unsigned char ** key, size_t keylen )
 {
-	struct cli_info *tmp = NULL;
+	struct rgw_client *tmp = NULL;
 	
 	/* Create the new object */
-	CHECK_MALLOC( tmp = malloc(sizeof (struct cli_info)) );
-	memset(tmp, 0, sizeof(struct cli_info));
+	CHECK_MALLOC( tmp = malloc(sizeof (struct rgw_client)) );
+	memset(tmp, 0, sizeof(struct rgw_client));
 	
 	/* Initialize the chain */
 	rg_list_init(&tmp->chain);
 	
-	/* move the sa info reference */
+	/* move the sa info reference (the two if alternatives should be equivalent, but just in case... ) */
 	if ((*ip_port)->sa_family == AF_INET)
 		tmp->sin = (struct sockaddr_in *) (*ip_port);
 	else
@@ -97,7 +108,7 @@
 
 
 /* Decrease refcount on a client; the lock must be held when this function is called. */
-static void cli_info_unlink(struct cli_info * client)
+static void client_unlink(struct rgw_client * client)
 {
 	client->refcount -= 1;
 	
@@ -113,12 +124,40 @@
 }
 
 
-/* Function to look for an existing cli_info, or the previous element. 
+/* Function to look for an existing rgw_client, or the previous element. 
    The cli_mtx must be held when calling this func. 
    Returns ENOENT if the matching client does not exist, and res points to the previous element in the list. 
    Returns EEXIST if the matching client is found, and res points to this element. 
    Returns other error code on other error. */
-static int cli_info_search(struct cli_info ** res, struct sockaddr * ip_port )
+#define client_search_family( _family_ )												\
+		case AF_INET##_family_: {												\
+			struct sockaddr_in##_family_ * sin##_family_ = (struct sockaddr_in##_family_ *)ip_port;				\
+			for (ref = cli_ip##_family_.next; ref != &cli_ip##_family_; ref = ref->next) {					\
+				cmp = memcmp(&sin##_family_->sin##_family_##_addr, 							\
+					     &((struct rgw_client *)ref)->sin##_family_->sin##_family_##_addr, 				\
+					     sizeof(struct in##_family_##_addr));							\
+				if (cmp > 0) continue; /* search further in the list */							\
+				if (cmp < 0) break; /* this IP is not in the list */							\
+				/* Now compare the ports as follow: */									\
+				     /* If the ip_port we are searching does not contain a port, just return the first match result */	\
+				if ( (sin##_family_->sin##_family_##_port == 0) 							\
+				     /* If the entry in the list does not contain a port, return it as a match */			\
+				  || (((struct rgw_client *)ref)->sin##_family_->sin##_family_##_port == 0) 				\
+				     /* If both ports are equal, it is a match */							\
+				  || (sin##_family_->sin##_family_##_port == 								\
+				  		((struct rgw_client *)ref)->sin##_family_->sin##_family_##_port)) {			\
+					*res = (struct rgw_client *)ref;								\
+					return EEXIST;											\
+				}													\
+				/* Otherwise, the list is ordered by port value (byte order does not matter */				\
+				if (sin##_family_->sin##_family_##_port 								\
+					> ((struct rgw_client *)ref)->sin##_family_->sin##_family_##_port) continue;			\
+				else break;												\
+			}														\
+			*res = (struct rgw_client *)(ref->prev);									\
+			return ENOENT;													\
+		}
+static int client_search(struct rgw_client ** res, struct sockaddr * ip_port )
 {
 	int ret = 0;
 	int cmp;
@@ -127,66 +166,11 @@
 	CHECK_PARAMS(res && ip_port);
 	
 	switch (ip_port->sa_family) {
-		case AF_INET: {
-			struct sockaddr_in * sin = (struct sockaddr_in *)ip_port;
-			
-			for (ref = cli_ip.next; ref != &cli_ip; ref = ref->next) {
-				cmp = memcmp(&sin->sin_addr, &((struct cli_info *)ref)->sin->sin_addr, sizeof(struct in_addr));
-				
-				if (cmp > 0 )
-					continue; /* we must search further in the list */
-				
-				if (cmp < 0 ) /* This IP is not in the list, we return the previous element */
-					break;
-				
-				/* Now we found an entry with the same IP; let's check the port number if both are present */
-				
-				/* If the ip_port we are searching does not contain a port, just return the first match result */
-				/* If the entry in the list does not contain a port, return it as a match */
-				/* If both ports are equal, it is a match */
-				if ((sin->sin_port == 0) 
-						|| (((struct cli_info *)ref)->sin->sin_port == 0) 
-						|| (sin->sin_port == ((struct cli_info *)ref)->sin->sin_port)) {
-					*res = (struct cli_info *)ref;
-					return EEXIST;
-				}
-				
-				/* now we order on the port value (we don't care aboit the network or host byte order there */
-				if (sin->sin_port > ((struct cli_info *)ref)->sin->sin_port)
-					continue;
-				else
-					break;
-			}
-			
-			*res = (struct cli_info *)(ref->prev);
-			return ENOENT;
-		}
-		break;
+		client_search_family()
+				break;
 		
-		case AF_INET6: {
-			struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *)ip_port;
-			
-			/* Exact same logic as for IP */
-			for (ref = cli_ip6.next; ref != &cli_ip6; ref = ref->next) {
-				cmp = memcmp(&sin6->sin6_addr, &((struct cli_info *)ref)->sin6->sin6_addr, sizeof(struct in6_addr));
-				if (cmp > 0 )
-					continue;
-				if (cmp < 0 )
-					break;
-				if ((sin6->sin6_port == 0) 
-						|| (((struct cli_info *)ref)->sin6->sin6_port == 0) 
-						|| (sin6->sin6_port == ((struct cli_info *)ref)->sin6->sin6_port)) {
-					*res = (struct cli_info *)ref;
-					return EEXIST;
-				}
-				if (sin6->sin6_port > ((struct cli_info *)ref)->sin6->sin6_port)
-					continue;
-				else
-					break;
-			}
-			*res = (struct cli_info *)(ref->prev);
-			return ENOENT;
-		}
+		client_search_family( 6 )
+				break;
 	}
 	
 	/* We're never supposed to reach this point */
@@ -194,15 +178,17 @@
 	return EINVAL;
 }
 
-static void cli_key_dump(char * keydump /* 60 bytes */, char * key, size_t keylen)
+#define KEY_DUMP_BUF_SIZE (KEY_DUMP_BYTES * 3 + KEY_DUMP_BYTES / 4 + 3)
+
+/* Display the first KEY_DUMP_BYTES bytes of a secret key */
+static void client_key_dump(char * keydump /* size: KEY_DUMP_BUF_SIZE */, char * key, size_t keylen)
 {
 	int i, j, idx;
-	char * ptr;
 
-	memset(keydump, 0, 60);
+	memset(keydump, 0, KEY_DUMP_BUF_SIZE);
 	idx = 0;
 
-	for (i = 0; i < 2; i++) {
+	for (i = 0; i < KEY_DUMP_BYTES / 8; i++) {
 		for (j = 0; j < 8; j++) {
 			if (idx >= keylen)
 				break;
@@ -215,7 +201,8 @@
 			keydump += 3;
 			idx ++;
 		}
-		
+		if (idx >= keylen)
+			break;		
 		*keydump = '\t'; keydump++;
 	}
 	if (keylen > idx) {
@@ -223,33 +210,31 @@
 	}
 }
 
-int rgw_clients_getkey(void * cli, unsigned char **key, size_t *key_len)
+
+int rgw_clients_getkey(struct rgw_client * cli, unsigned char **key, size_t *key_len)
 {
-	struct cli_info * cliinfo = (struct cli_info *) cli;
-	
 	CHECK_PARAMS( cli && key && key_len );
-	*key = cliinfo->key.data;
-	*key_len = cliinfo->key.len;
+	*key = cli->key.data;
+	*key_len = cli->key.len;
 	return 0;
 }
 
-int rgw_clients_search(struct sockaddr * ip_port, void ** ref)
+int rgw_clients_search(struct sockaddr * ip_port, struct rgw_client ** ref)
 {
 	int ret = 0;
-	struct cli_info * cli;
 	
 	TRACE_ENTRY("%p %p", ip_port, ref);
 	
 	CHECK_PARAMS(ip_port && ref);
-	*ref = NULL;
 	
 	CHECK_POSIX( pthread_mutex_lock(&cli_mtx) );
-	ret = cli_info_search(&cli, ip_port);
-	
+
+	ret = client_search(ref, ip_port);
 	if (ret == EEXIST) {
-		cli->refcount ++;
+		(*ref)->refcount ++;
 		ret = 0;
-		*ref = cli;
+	} else {
+		*ref = NULL;
 	}
 	
 	CHECK_POSIX( pthread_mutex_unlock(&cli_mtx) );
@@ -257,41 +242,39 @@
 	return ret;
 }
 
-int rgw_clients_checkdup(rad_t **msg, void *cli)
+int rgw_clients_check_dup(struct rgw_radius_msg_meta **msg, struct rgw_client *cli)
 {
-	struct cli_info * cli_info = (struct cli_info *) cli;
 	int idx;
 	
 	TRACE_ENTRY("%p %p", msg, cli);
 	
 	CHECK_PARAMS( msg && cli );
 	
-	if ((*msg)->flags.serv_type == RGW_EXT_PORT_AUTH)
+	if ((*msg)->serv_type == RGW_EXT_TYPE_AUTH)
 		idx = 0;
 	else
 		idx = 1;
 	
-	if ((cli_info->last[idx].id == (*msg)->identifier) && (cli_info->last[idx].port == (*msg)->port)) {
+	if ((cli->last[idx].id == (*msg)->radius.hdr->identifier) && (cli->last[idx].port == (*msg)->port)) {
 		/* Duplicate! */
-		TRACE_DEBUG(INFO, "Received duplicated RADIUS message (id: %02hhx, port: %hu), discarding.", (*msg)->identifier, (*msg)->port);
-		rg_msg_free(*msg);
-		*msg = NULL;
+		TRACE_DEBUG(INFO, "Received duplicated RADIUS message (id: %02hhx, port: %hu), discarding.", (*msg)->radius.hdr->identifier, ntohs((*msg)->port));
+		rgw_msg_free(msg);
 	} else {
-		/* Save new information */
-		cli_info->last[idx].id = (*msg)->identifier;
-		cli_info->last[idx].port = (*msg)->port;
+		/* Update information for future message */
+		cli->last[idx].id = (*msg)->radius.hdr->identifier;
+		cli->last[idx].port = (*msg)->port;
 	}
 	
 	return 0;
 }
 
-void rgw_clients_dispose(void ** ref)
+void rgw_clients_dispose(struct rgw_client ** ref)
 {
 	TRACE_ENTRY("%p", ref);
 	CHECK_PARAMS_DO(ref, return);
 	
 	CHECK_POSIX_DO( pthread_mutex_lock(&cli_mtx),  );
-	cli_info_unlink(*(struct cli_info **)ref);
+	client_unlink(*ref);
 	*ref = NULL;
 	CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), );
 }
@@ -305,7 +288,7 @@
 
 int rgw_clients_add( struct sockaddr * ip_port, unsigned char ** key, size_t keylen )
 {
-	struct cli_info * prev = NULL, *new = NULL;
+	struct rgw_client * prev = NULL, *new = NULL;
 	int ret;
 	
 	TRACE_ENTRY("%p %p %lu", ip_port, key, keylen);
@@ -316,7 +299,7 @@
 	/* Dump the entry in debug mode */
 	if (TRACE_BOOL(FULL + 1 )) {
 		char ipstr[INET6_ADDRSTRLEN];
-		char keydump[60];
+		char keydump[KEY_DUMP_BUF_SIZE];
 		uint16_t port;
 		
 		if (ip_port->sa_family == AF_INET) {
@@ -327,7 +310,7 @@
 			port = ntohs(((struct sockaddr_in6 *)ip_port)->sin6_port);
 		}
 		
-		cli_key_dump(&keydump[0], *key, keylen);
+		client_key_dump(&keydump[0], *key, keylen);
 		
 		TRACE_DEBUG(FULL, "Adding client [%s]:%hu with %d bytes key: %s", ipstr, port, keylen, keydump);
 	}
@@ -336,14 +319,12 @@
 	CHECK_POSIX( pthread_mutex_lock(&cli_mtx) );
 	
 	/* Check if the same entry does not already exist */
-	ret = cli_info_search(&prev, ip_port );
+	ret = client_search(&prev, ip_port );
 	if (ret == ENOENT) {
-		CHECK_FCT_DO( ret = cli_info_create( &new, &ip_port, key, keylen ), goto end );
-		
+		/* No duplicate found, Ok to add */
+		CHECK_FCT_DO( ret = client_create( &new, &ip_port, key, keylen ), goto end );
 		rg_list_insert_after(&prev->chain, &new->chain);
-		
 		new->refcount++;
-		
 		ret = 0;
 		goto end;
 	}
@@ -356,10 +337,10 @@
 		}
 		
 		TRACE_DEBUG(INFO, "Error: conflicting entries");	
-		log_error("Error adding a RADIUS client: conflict with a previous entry.\n");
+		log_error("Error adding a RADIUS client in conflict with a previous entry.\n");
 		{
 			char ipstr[INET6_ADDRSTRLEN];
-			char keydump[60];
+			char keydump[KEY_DUMP_BUF_SIZE];
 			uint16_t port;
 
 			if (prev->sin->sin_family == AF_INET) {
@@ -369,9 +350,7 @@
 				inet_ntop(AF_INET6, &prev->sin6->sin6_addr,ipstr,sizeof(ipstr));
 				port = ntohs(prev->sin6->sin6_port);
 			}
-
-			cli_key_dump(&keydump[0], prev->key.data, prev->key.len);
-
+			client_key_dump(&keydump[0], prev->key.data, prev->key.len);
 			log_error( "Previous entry: [%s]:%hu, key (%db): %s\n", ipstr, port, prev->key.len, keydump);
 			
 			if (ip_port->sa_family == AF_INET) {
@@ -381,13 +360,12 @@
 				inet_ntop(AF_INET6, &((struct sockaddr_in6 *)ip_port)->sin6_addr,ipstr,sizeof(ipstr));
 				port = ntohs(((struct sockaddr_in6 *)ip_port)->sin6_port);
 			}
-
-			cli_key_dump(&keydump[0], *key, keylen);
+			client_key_dump(&keydump[0], *key, keylen);
 			log_error( "New entry:      [%s]:%hu, key (%db): %s\n", ipstr, port, keylen, keydump);			
 		}
 	}
 end:
-	/* Lock the lists */
+	/* release the lists */
 	CHECK_POSIX( pthread_mutex_unlock(&cli_mtx) );
 	
 	return ret;
@@ -395,10 +373,10 @@
 
 void rgw_clients_dump(void)
 {
-	struct cli_info * client = NULL;
+	struct rgw_client * client = NULL;
 	struct rg_list *ref = NULL;
 	char ipstr[INET6_ADDRSTRLEN];
-	char keydump[60];
+	char keydump[KEY_DUMP_BUF_SIZE];
 	uint16_t port;
 	
 	if ( ! TRACE_BOOL(FULL) )
@@ -406,29 +384,23 @@
 	
 	CHECK_POSIX_DO( pthread_mutex_lock(&cli_mtx), /* ignore error */ );
 	
-	log_debug(" RADIUS IP clients list:\n");
+	if (!rg_list_is_empty(&cli_ip))
+		log_debug(" RADIUS IP clients list:\n");
 	for (ref = cli_ip.next; ref != &cli_ip; ref = ref->next) {
-		
-		client = (struct cli_info *)ref;
-		
+		client = (struct rgw_client *)ref;
 		inet_ntop(AF_INET, &client->sin->sin_addr,ipstr,sizeof(ipstr));
 		port = ntohs(client->sin->sin_port);
-		
-		cli_key_dump(&keydump[0], client->key.data, client->key.len);
-		
+		client_key_dump(&keydump[0], client->key.data, client->key.len);
 		log_debug("   [%s]:%hu, %d bytes: %s\n", ipstr, port, client->key.len, keydump);
 	}
 		
-	log_debug(" RADIUS IPv6 clients list:\n");
+	if (!rg_list_is_empty(&cli_ip6))
+		log_debug(" RADIUS IPv6 clients list:\n");
 	for (ref = cli_ip6.next; ref != &cli_ip6; ref = ref->next) {
-		
-		client = (struct cli_info *)ref;
-		
+		client = (struct rgw_client *)ref;
 		inet_ntop(AF_INET6, &client->sin6->sin6_addr,ipstr,sizeof(ipstr));
 		port = ntohs(client->sin6->sin6_port);
-		
-		cli_key_dump(&keydump[0], client->key.data, client->key.len);
-		
+		client_key_dump(&keydump[0], client->key.data, client->key.len);
 		log_debug("   [%s]:%hu, %d bytes: %s\n", ipstr, port, client->key.len, keydump);
 	}
 		
@@ -447,12 +419,12 @@
 	while ( ! rg_list_is_empty(&cli_ip) ) {
 		client = cli_ip.next;
 		rg_list_unlink(client);
-		cli_info_unlink((struct cli_info *)client);
+		client_unlink((struct rgw_client *)client);
 	}
 	while (! rg_list_is_empty(&cli_ip6)) {
 		client = cli_ip6.next;
 		rg_list_unlink(client);
-		cli_info_unlink((struct cli_info *)client);
+		client_unlink((struct rgw_client *)client);
 	}
 	
 	CHECK_POSIX_DO( pthread_mutex_unlock(&cli_mtx), /* ignore error */ );
--- a/extensions/radius_gw/rgw_extensions.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/rgw_extensions.c	Fri May 22 18:11:49 2009 +0900
@@ -35,22 +35,22 @@
 
 /* Manage the list of sub-extensions that provide handlers for RADIUS messages / attributes */
 
-#include "radius_gw_internal.h"
+#include "radius_gw.h"
 #include <dlfcn.h>
 #include <libgen.h>
 
-/* List of extensions, in the order they are written in the configuration file. */
+/* List of the extensions, in the order they are written in the configuration file. */
 static struct rg_list ext_list;
 
 /* Description of an extension entry */
 struct ext_descr {
 	struct rg_list		chain; 	/* chaining in the ext_list list */
 	
-	void * 			dlo;	/* object returned by dlopen of the extension, to use with dlclose later */
+	void * 			dlo;	/* object returned by dlopen for the extension, to use with dlclose later */
 	struct radius_gw_api	api;	/* the callbacks registered by rga_register */
-	void *			conf;	/* the parsed configuration returned by rga_conf_parse_cb */
+	struct rga_conf_state *	cs;	/* the configuration and state returned by rga_conf_parse_cb */
 	
-	int			port;	/* this extension is called for messages received on this(these) port(s) only */
+	int			type;	/* this extension is called for messages received on this(these) server(s) only */
 	unsigned char *		cc;	/* array of command codes, or NULL for any cc */
 	size_t			cc_len; /* size of the previous array */
 	
@@ -61,7 +61,7 @@
 /* Accelerators for each command code (one for each port). These accelerators are built on-demand, as a cache, after start_cache function has been called.  */
 static struct rg_list ext_accel_auth, ext_accel_acct;
 
-/* accelerator list, one per command code */
+/* accelerator list, one per command code value (only the ones actually used) */
 struct ext_accel {
 	struct rg_list		chain;	/* link in the ext_accel_* list */
 	unsigned char		ccode;	/* the command code of this accelerator. The previous list is ordered according to this value. We don't handle extended CC yet */
@@ -78,21 +78,21 @@
 static pthread_mutex_t ext_mtx = PTHREAD_MUTEX_INITIALIZER;
 
 /* Has start_cache been called? */
-static int cache_started;
+static int cache_started = 0;
 
 
 /* The lock must be held before calling this function */
-static int get_accelerator(struct rg_list ** list, unsigned char ccode, int port)
+static int get_accelerator(struct rg_list ** list, unsigned char ccode, int type)
 {
 	struct rg_list *refer, *search;
 	struct ext_accel * accel = NULL;
 	struct ext_accel_item * item = NULL;
 	
-	TRACE_ENTRY("%p %hhu %i", list, ccode, port);
+	TRACE_ENTRY("%p %hhu %i", list, ccode, type);
 	
-	CHECK_PARAMS( cache_started && list && ((port == RGW_EXT_PORT_AUTH) || (port == RGW_EXT_PORT_ACCT)) );
+	CHECK_PARAMS( cache_started && list && ((type == RGW_EXT_TYPE_AUTH) || (type == RGW_EXT_TYPE_ACCT)) );
 	
-	if (port == RGW_EXT_PORT_AUTH)
+	if (type == RGW_EXT_TYPE_AUTH)
 		refer = &ext_accel_auth;
 	else
 		refer = &ext_accel_acct;
@@ -112,7 +112,7 @@
 		return 0;
 	}
 	
-	/* We must create the accelerator list, then save it just before search */
+	/* We must create the accelerator list, then save it just before "search" */
 	
 	CHECK_MALLOC( accel = malloc(sizeof(struct ext_accel)) );
 	memset(accel, 0, sizeof(struct ext_accel) );
@@ -120,12 +120,12 @@
 	rg_list_init(&accel->extensions);
 	accel->ccode = ccode;
 	
-	/* Check if each extension from the global list is enabled for this port and ccode */
+	/* Check each extension from the global list for this port and ccode */
 	for (refer = ext_list.next; refer != &ext_list; refer = refer->next) {
 		struct ext_descr * loc = (struct ext_descr *)refer;
 		
 		/* Skip if this extension is not registered for this port */
-		if (! (loc->port & port) )
+		if (! (loc->type & type) )
 			continue;
 		
 		/* Check if the ccode is there */
@@ -143,7 +143,7 @@
 				continue;
 		}
 		
-		/* Ok, this extension is called for this port / ccode, add to the accelerator */
+		/* Ok, this extension must be called for this port / ccode, add to the accelerator */
 		CHECK_MALLOC( item = malloc(sizeof(struct ext_accel_item)) );
 		memset(item, 0, sizeof(struct ext_accel_item));
 		rg_list_init(&item->chain);
@@ -164,7 +164,6 @@
 {
 	TRACE_ENTRY();
 	
-	cache_started = 0;
 	rg_list_init(&ext_list);
 	rg_list_init(&ext_accel_auth);
 	rg_list_init(&ext_accel_acct);
@@ -172,16 +171,16 @@
 	return 0;
 }
 
-int rgw_extensions_add( char * extfile, char * conffile, int port, unsigned char ** codes_array, size_t codes_sz )
+int rgw_extensions_add( char * extfile, char * conffile, int type, unsigned char ** codes_array, size_t codes_sz )
 {
 	struct ext_descr * new;
 	int (* ext_rga_register)(int version, waaad_api_t * waaad, struct radius_gw_api * api);
 	int ret = 0;
-	char * myextfile = NULL;
+	char * myextfile;
 	
 	TRACE_ENTRY();
 	
-	CHECK_PARAMS( extfile && port && codes_array && (cache_started == 0) );
+	CHECK_PARAMS( extfile && type && codes_array && (cache_started == 0) );
 	
 	CHECK_MALLOC( myextfile = strdup(extfile) );
 	
@@ -190,17 +189,17 @@
 	
 	rg_list_init(&new->chain);
 	
-	/* Copy some names to be freed when object is destroyed */
+	/* Copy names, for debug */
 	CHECK_MALLOC( new->extname = strdup(basename(myextfile)) );
 	free(myextfile);
 	CHECK_MALLOC( new->conffile = conffile ? conffile : strdup("(null)") );
 	
 	/* Try and load the extension */
-	TRACE_DEBUG(INFO, "Loading subextension: %s", extfile);
+	TRACE_DEBUG(FULL, "Loading subextension: %s", extfile);
 	new->dlo = dlopen(extfile, RTLD_LAZY | RTLD_LOCAL);
 	if (new->dlo == NULL) {
 		/* An error occured */
-		log_error("Loading of subextension %s failed:\n %s\n", extfile, dlerror());
+		log_error("Loading of subextension '%s' failed:\n %s\n", extfile, dlerror());
 		goto error;
 	}
 	
@@ -208,7 +207,7 @@
 	ext_rga_register = dlsym( new->dlo, "rga_register" );
 	if (ext_rga_register == NULL) {
 		/* An error occured */
-		log_error("Unable to resolve 'rga_register' in subextension %s:\n %s\n", extfile, dlerror());
+		log_error("Unable to resolve 'rga_register' in subextension '%s':\n %s\n", extfile, dlerror());
 		goto error;
 	}
 	
@@ -218,13 +217,13 @@
 	
 	/* Now parse the configuration file, this will initialize all extension states and store it in the returned pointer (the subextensions must be re-entrant) */
 	TRACE_DEBUG(FULL, "Parsing subext conf file: %s", new->conffile );
-	new->conf = (*(new->api.rga_conf_parse_cb))(conffile);
-	if (new->conf == NULL) {
+	new->cs = (*(new->api.rga_conf_parse_cb))(conffile);
+	if (new->cs == NULL) {
 		log_error("An error occurred while parsing configuration parameter for extension '%s' (%s), aborting...\n", new->extname, new->conffile);
 		goto error;
 	}
 	
-	/* Now order the array of command codes and save */
+	/* Now sort the array (very naive algorithm, but this list is usually small) of command codes and save */
 	if (*codes_array && codes_sz) {
 		int i;
 		
@@ -252,7 +251,7 @@
 		new->cc_len = codes_sz;
 	}
 		
-	new->port = port;
+	new->type = type;
 	
 	/* And save this new extension in the list */
 	CHECK_POSIX( pthread_mutex_lock(&ext_mtx) );
@@ -279,9 +278,9 @@
 		return;
 	
 	CHECK_POSIX_DO( pthread_mutex_lock(&ext_mtx), );
+	
 	if ( ! rg_list_is_empty( &ext_list ) )
-		log_debug(" RADIUS gateway registered sub-extensions:\n");
-	
+		log_debug(" RADIUS gateway list of registered sub-extensions:\n");
 	for (ptr = ext_list.next; ptr != &ext_list; ptr = ptr->next) {
 		char * codes = NULL;
 		
@@ -300,9 +299,9 @@
 		
 		log_debug("  %-15s (%-20s) - p: %s %s, %d cc: %s\n", 
 				ext->extname, 
-				ext->conffile, 
-				ext->port & RGW_EXT_PORT_AUTH ? "Au" : "  ",
-				ext->port & RGW_EXT_PORT_ACCT ? "Ac" : "  ",
+				basename(ext->conffile),
+				ext->type & RGW_EXT_TYPE_AUTH ? "Au" : "  ",
+				ext->type & RGW_EXT_TYPE_ACCT ? "Ac" : "  ",
 				ext->cc_len,
 				ext->cc ? codes : "*");
 		
@@ -326,7 +325,7 @@
 
 		for (ptr = accel->extensions.next; ptr != &accel->extensions; ptr = ptr->next) {
 			struct ext_accel_item * item = (struct ext_accel_item *)ptr;
-			log_debug("     %-15s (%s)\n", item->ext->extname, item->ext->conffile);
+			log_debug("     %-15s (%s)\n", item->ext->extname, basename(item->ext->conffile));
 		}
 	}
 	for (ptraccel = ext_accel_acct.next; ptraccel != &ext_accel_acct; ptraccel = ptraccel->next) {
@@ -335,7 +334,7 @@
 
 		for (ptr = accel->extensions.next; ptr != &accel->extensions; ptr = ptr->next) {
 			struct ext_accel_item * item = (struct ext_accel_item *)ptr;
-			log_debug("     %-15s (%s)\n", item->ext->extname, item->ext->conffile);
+			log_debug("     %-15s (%s)\n", item->ext->extname, basename(item->ext->conffile));
 		}
 	}
 	
@@ -349,29 +348,30 @@
 	cache_started++;
 }
 
-int rgw_extensions_loop_req(rad_t **rad, sess_id_t **session, msg_t **diam_msg, void * cli)
+int rgw_extensions_loop_req(struct rgw_radius_msg_meta **rad, sess_id_t **session, msg_t **diam_msg, struct rgw_client * cli)
 {
 	int ret = 0;
 	struct rg_list * head = NULL, *li;
+	struct radius_msg * rad_ans = NULL;
 	
-	TRACE_ENTRY("%p %p %p", rad, session, diam_msg);
-	CHECK_PARAMS( rad && session && diam_msg );
+	TRACE_ENTRY("%p %p %p %p", rad, session, diam_msg, cli);
+	CHECK_PARAMS( rad && *rad && session && diam_msg && cli );
 	
 	/* First, get the list of extensions for this message */
-	CHECK_FCT( get_accelerator(&head, (*rad)->code, (*rad)->flags.serv_type) );
+	CHECK_FCT( get_accelerator(&head, (*rad)->radius.hdr->code, (*rad)->serv_type) );
 	
 	for (li = head->next; li != head; li = li->next) {
 		struct ext_descr * ext = ((struct ext_accel_item *) li)->ext;
 		
 		TRACE_DEBUG(ANNOYING, "Calling next extension: %s", ext->extname);
-		ret = (*ext->api.rga_rad_req_cb)(ext->conf, session, rad, diam_msg);
+		ret = (*ext->api.rga_rad_req_cb)(ext->cs, session, &(*rad)->radius, &rad_ans, diam_msg);
 		if (ret)
 			break;
 	}
 	
-	/* If not error encountered, we're done here */
+	/* If no error encountered, we're done here */
 	if (ret == 0)
-		return ret;
+		return 0;
 	
 	/* Destroy the Diameter temp message, if any */
 	if (*diam_msg) {
@@ -386,8 +386,14 @@
 	}
 	
 	/* Send the radius message back if required */
-	if ((ret == 3) || (ret == 4)) {
-		CHECK_FCT( rgw_msg_send(*rad, cli) );
+	if (((ret == 3) || (ret == 4)) && rad_ans) {
+		/* destination port: (*rad)->port */
+		/* destination ip: derived from cli */
+		/* post-processing: depends on (*rad)->serv_type */
+		/* message content: rad_ans */
+		
+		/* not implemented */
+		ASSERT(0);
 	}
 	
 	if (ret < 0) {
@@ -397,8 +403,7 @@
 	}
 	
 	/* Now, discard the message and return */
-	rg_msg_free(*rad);
-	*rad = NULL;
+	rgw_msg_free(rad);
 	return 0;
 	
 }
@@ -446,8 +451,8 @@
 		free(ext->conffile);
 		free(ext->extname);
 		free(ext->cc);
-		if (ext->conf)
-			(*ext->api.rga_conf_free_cb)(ext->conf);
+		if (ext->cs)
+			(*ext->api.rga_conf_free_cb)(ext->cs);
 		dlclose(ext->dlo);
 		free(ext);
 	}
--- a/extensions/radius_gw/rgw_msg.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/rgw_msg.c	Fri May 22 18:11:49 2009 +0900
@@ -37,163 +37,112 @@
 modules do not need to "know" the actual representation of RADIUS messages on the network. They only 
 receive the logical view as exposed in the radius_gw.h file. */
 
-#include "radius_gw_internal.h"
+#include "radius_gw.h"
 
-/* To ensure packed structures with some common compilers */
-#ifdef __GNUC__
-#define STRUCT_PACKED __attribute__ ((packed))
-#else
-#define STRUCT_PACKED
-#endif
-#ifdef _MSC_VER
-#pragma pack(push, 1)
-#endif /* _MSC_VER */
+/* Two functions for dumping */
+#include "rgw_msg_codes.c"
+#include "rgw_msg_attrtype.c"
 
-struct radius_hdr {
-	uint8_t code;
-	uint8_t identifier;
-	uint16_t length; /* including this header */
-	uint8_t authenticator[16];
-	/* followed by length-20 octets of attributes */
-} STRUCT_PACKED;
+/* Destroy a message */
+void rgw_msg_free(struct rgw_radius_msg_meta ** msg)
+{
+	if (!msg || !*msg)
+		return;
+	
+	radius_msg_free(&(*msg)->radius);
+	free(*msg);
+	*msg = NULL;
+}
 
-struct radius_attr_hdr {
-	uint8_t type;
-	uint8_t length; /* including this header */
-	/* followed by length-2 octets of attribute value */
-} STRUCT_PACKED;
-
-#ifdef _MSC_VER
-#pragma pack(pop)
-#endif /* _MSC_VER */
-
-int rgw_msg_parse(unsigned char *buf, size_t len, rad_t **msg)
+/* This function is derived from radius_msg_parse, but creates a rgw_radius_msg_meta structure instead */
+int rgw_msg_parse(unsigned char * buf, size_t len, struct rgw_radius_msg_meta ** msg)
 {
-	struct radius_hdr * hdr = (struct radius_hdr *)buf;
-	rad_t * new = NULL;
-	size_t remaining = 0;
-	struct radius_attr_hdr *next;
+	struct radius_hdr *hdr;
+	struct radius_attr_hdr *attr;
+	size_t msg_len;
+	unsigned char *pos, *end;
 	
 	TRACE_ENTRY("%p %g %p", buf, len, msg);
 	
-	CHECK_PARAMS(buf && msg);
+	CHECK_PARAMS( buf && len && msg );
 	
-	if (len < sizeof(struct radius_hdr) ) {
-		TRACE_DEBUG(FULL, "Message too short received (%g bytes), discard.\n", len);
-		return EINVAL;
-	}
+	*msg = NULL;
 	
-	remaining = ntohs(hdr->length);
-	if (len < remaining) {
-		TRACE_DEBUG(FULL, "Truncated message received (%g / %g bytes), discard.\n", len, remaining);
+	if (len < sizeof(struct radius_hdr)) {
+		TRACE_DEBUG(INFO, "Buffer too short to contain a RADIUS message: %g", len);
 		return EINVAL;
 	}
 	
-	if (len > remaining) {
-		TRACE_DEBUG(FULL, "Ignore extra bytes at the end of RADIUS message (%g / %g bytes).\n", len, remaining);
+	hdr = (struct radius_hdr *) buf;
+
+	msg_len = ntohs(hdr->length);
+	if (msg_len < sizeof(*hdr) || msg_len > len) {
+		TRACE_DEBUG(INFO, "Invalid RADIUS message length: %g (buf: %g)", msg_len, len);
+		return EINVAL;
 	}
-	
-	/* Ok, we can try and parse the buffer */
-	CHECK_MALLOC( new = malloc(sizeof(rad_t)) );
-	memset(new, 0, sizeof(rad_t));
-	rg_list_init(&new->attributes);
-	
-	/* Copy header data */
-	new->code = hdr->code;
-	new->identifier = hdr->identifier;
-	memcpy(&new->authenticator[0], &hdr->authenticator[0], 16);
-	
-	/* Parse the attributes */
-	next = (struct radius_attr_hdr *)(hdr + 1);
-	remaining -= sizeof(struct radius_hdr);
+
+	if (msg_len < len) {
+		TRACE_DEBUG(INFO, "Received data after RADIUS message, ignoring %g bytes.", len - msg_len);
+	}
+
+	/* Create the structure to store the parsing information */
+	CHECK_MALLOC( *msg = malloc(sizeof(struct rgw_radius_msg_meta)) );
+	memset(*msg, 0, sizeof(struct rgw_radius_msg_meta));
 	
-	while (remaining > sizeof(struct radius_attr_hdr)) {
-		struct rad_attr * newattr = NULL;
-		struct radius_attr_hdr *cur = next;
-		
-		if ((cur->length > remaining) || (cur->length < sizeof(struct radius_attr_hdr)))
-			break;
+	if (radius_msg_initialize(&(*msg)->radius, msg_len)) {
+		TRACE_DEBUG(INFO, "Error in radius_msg_initialize");
+		free(*msg);
+		return ENOMEM; /* the most likely error... */
+	}
+
+	memcpy((*msg)->radius.buf, buf, msg_len);
+	(*msg)->radius.buf_size = (*msg)->radius.buf_used = msg_len;
 
-		next = (struct radius_attr_hdr *)(((unsigned char *)cur) + cur->length);
-		remaining -= cur->length;
-		
-		CHECK_MALLOC( newattr = malloc(sizeof(struct rad_attr)) );
-		memset(newattr, 0, sizeof(struct rad_attr));
-		rg_list_init(&newattr->chain);
-		
-		newattr->type = cur->type;
-		newattr->length = cur->length;
-		
-		if ( cur->length > sizeof(struct radius_attr_hdr) )
-			memcpy(&newattr->data.buf[0], cur+1, cur->length - sizeof(struct radius_attr_hdr));
-		
-		rg_list_insert_before(&new->attributes, &newattr->chain);
+	/* parse attributes */
+	pos = (unsigned char *) ((*msg)->radius.hdr + 1);
+	end = (*msg)->radius.buf + (*msg)->radius.buf_used;
+	while (pos < end) {
+		if ((size_t) (end - pos) < sizeof(*attr)) {
+			TRACE_DEBUG(INFO, "Invalid RADIUS message size (rem: %d)", (end - pos));
+			rgw_msg_free(msg);
+			return EINVAL;
+		}
+
+		attr = (struct radius_attr_hdr *) pos;
+
+		if (pos + attr->length > end || attr->length < sizeof(*attr)) {
+			TRACE_DEBUG(INFO, "Invalid RADIUS message or attribute size (attr: %hhd, rem: %d)", attr->length, (end - pos));
+			rgw_msg_free(msg);
+			return EINVAL;
+		}
+
+		if (radius_msg_add_attr_to_array(&(*msg)->radius, attr)) {
+			TRACE_DEBUG(INFO, "Error in radius_msg_add_attr_to_array");
+			rgw_msg_free(msg);
+			return ENOMEM;
+		}
+
+		pos += attr->length;
 	}
-	
-	/* Done! */
-	*msg = new;
+
 	return 0;
 }
 
-/* Alloc new buffer if *len == 0 on entry */
-int rgw_msg_gen(rad_t *msg, unsigned char **buf, size_t *len)
+/* Check if the message has a valid authenticator, and update the meta-data accordingly */
+int rgw_msg_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth)
 {
-	size_t mylen;
-	struct rg_list * li;
-	struct radius_hdr * hdr;
-	struct radius_attr_hdr *attr;
-	
-	TRACE_ENTRY("%p %p %p", msg, buf, len);
-	
-	CHECK_PARAMS(msg && buf && len);
-	
-	/* Compute the size of the final message */
-	mylen = sizeof(struct radius_hdr);
-	
-	for (li = msg->attributes.next; li != &msg->attributes; li = li->next)
-		mylen += ((struct rad_attr *)li)->length;
-	
-	CHECK_PARAMS( mylen < (1<<16) );
+	unsigned char * key;
+	size_t keylen;
 	
-	if (*len && (*len < mylen)) {
-		TRACE_DEBUG(INFO, "Buffer too short");
-		return ENOSPC;
-	}
-	if (*len == 0) {
-		CHECK_MALLOC( *buf = malloc(mylen) );
-	}
-	memset(*buf, 0, mylen);
+	TRACE_ENTRY("%p %p %p", msg, cli, req_auth);
 	
-	/* Now write the header */
-	hdr = (struct radius_hdr *)*buf;
-	hdr->code = msg->code;
-	hdr->identifier = msg->identifier;
-	hdr->length = htons( (unsigned short)mylen );
-	memcpy(&hdr->authenticator[0], &msg->authenticator[0], 16);
+	CHECK_PARAMS(msg && cli);
 	
-	attr = (struct radius_attr_hdr *)(hdr+1);
-	for (li = msg->attributes.next; li != &msg->attributes; li = li->next) {
-		struct rad_attr * attrmem = (struct rad_attr *)li;
-		
-		attr->type = attrmem->type;
-		attr->length = attrmem->length;
-		
-		if (attr->length > sizeof(struct radius_attr_hdr)) {
-			memcpy(attr+1, &attrmem->data.buf[0], attr->length - sizeof(struct radius_attr_hdr));
-		}
-		
-		attr = (struct radius_attr_hdr *)(((unsigned char *)attr) + attrmem->length);
-	}
+	CHECK_FCT(rgw_clients_getkey(cli, &key, &keylen));
 	
-	/* Done */
-	*len = mylen;
+	msg->valid_mac = ! radius_msg_verify_msg_auth( &msg->radius, key, keylen, req_auth );
 	
 	return 0;
 }
 
-int rgw_msg_send(rad_t * msg, void * cli)
-{
-	TRACE_ENTRY("%p %p", msg, cli);
-	
-	return ENOTSUP;
-}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/rgw_msg_attrtype.c	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,262 @@
+/*  Name of RADIUS attribute from its code */
+const char * rgw_msg_attrtype_str(unsigned char c) {
+		/* 1         User-Name                                 */
+	if ( c == 1) return "User-Name   ";
+		/* 2         User-Password                             */
+	if ( c == 2) return "User-Password   ";
+		/* 3         CHAP-Password                             */
+	if ( c == 3) return "CHAP-Password   ";
+		/* 4         NAS-IP-Address                            */
+	if ( c == 4) return "NAS-IP-Address   ";
+		/* 5         NAS-Port                                  */
+	if ( c == 5) return "NAS-Port   ";
+		/* 6         Service-Type                              */
+	if ( c == 6) return "Service-Type   ";
+		/* 7         Framed-Protocol                           */
+	if ( c == 7) return "Framed-Protocol   ";
+		/* 8         Framed-IP-Address                         */
+	if ( c == 8) return "Framed-IP-Address   ";
+		/* 9         Framed-IP-Netmask                         */
+	if ( c == 9) return "Framed-IP-Netmask   ";
+		/* 10        Framed-Routing                            */
+	if ( c == 10) return "Framed-Routing   ";
+		/* 11        Filter-Id                                 */
+	if ( c == 11) return "Filter-Id   ";
+		/* 12        Framed-MTU                                */
+	if ( c == 12) return "Framed-MTU   ";
+		/* 13        Framed-Compression                        */
+	if ( c == 13) return "Framed-Compression   ";
+		/* 14        Login-IP-Host                             */
+	if ( c == 14) return "Login-IP-Host   ";
+		/* 15        Login-Service                             */
+	if ( c == 15) return "Login-Service   ";
+		/* 16        Login-TCP-Port                            */
+	if ( c == 16) return "Login-TCP-Port   ";
+		/* 17        Unassigned */
+	if ( c == 17) return "Unassigned   ";
+		/* 18        Reply-Message                             */
+	if ( c == 18) return "Reply-Message   ";
+		/* 19        Callback-Number                           */
+	if ( c == 19) return "Callback-Number   ";
+		/* 20        Callback-Id                               */
+	if ( c == 20) return "Callback-Id   ";
+		/* 21        Unassigned */
+	if ( c == 21) return "Unassigned   ";
+		/* 22        Framed-Route                              */
+	if ( c == 22) return "Framed-Route   ";
+		/* 23        Framed-IPX-Network                        */
+	if ( c == 23) return "Framed-IPX-Network   ";
+		/* 24        State                                     */
+	if ( c == 24) return "State   ";
+		/* 25        Class                                     */
+	if ( c == 25) return "Class   ";
+		/* 26        Vendor-Specific                           */
+	if ( c == 26) return "Vendor-Specific   ";
+		/* 27        Session-Timeout                           */
+	if ( c == 27) return "Session-Timeout   ";
+		/* 28        Idle-Timeout                              */
+	if ( c == 28) return "Idle-Timeout   ";
+		/* 29        Termination-Action                        */
+	if ( c == 29) return "Termination-Action   ";
+		/* 30        Called-Station-Id                         */
+	if ( c == 30) return "Called-Station-Id   ";
+		/* 31        Calling-Station-Id                        */
+	if ( c == 31) return "Calling-Station-Id   ";
+		/* 32        NAS-Identifier                            */
+	if ( c == 32) return "NAS-Identifier   ";
+		/* 33        Proxy-State                               */
+	if ( c == 33) return "Proxy-State   ";
+		/* 34        Login-LAT-Service                         */
+	if ( c == 34) return "Login-LAT-Service   ";
+		/* 35        Login-LAT-Node                            */
+	if ( c == 35) return "Login-LAT-Node   ";
+		/* 36        Login-LAT-Group                           */
+	if ( c == 36) return "Login-LAT-Group   ";
+		/* 37        Framed-AppleTalk-Link                     */
+	if ( c == 37) return "Framed-AppleTalk-Link   ";
+		/* 38        Framed-AppleTalk-Network                  */
+	if ( c == 38) return "Framed-AppleTalk-Network   ";
+		/* 39        Framed-AppleTalk-Zone                     */
+	if ( c == 39) return "Framed-AppleTalk-Zone   ";
+		/* 40        Acct-Status-Type                         [RFC2866] */
+	if ( c == 40) return "Acct-Status-Type [RFC2866]  ";
+		/* 41        Acct-Delay-Time                          [RFC2866] */
+	if ( c == 41) return "Acct-Delay-Time [RFC2866]  ";
+		/* 42        Acct-Input-Octets                        [RFC2866] */
+	if ( c == 42) return "Acct-Input-Octets [RFC2866]  ";
+		/* 43        Acct-Output-Octets                       [RFC2866] */
+	if ( c == 43) return "Acct-Output-Octets [RFC2866]  ";
+		/* 44        Acct-Session-Id                          [RFC2866] */
+	if ( c == 44) return "Acct-Session-Id [RFC2866]  ";
+		/* 45        Acct-Authentic                           [RFC2866] */
+	if ( c == 45) return "Acct-Authentic [RFC2866]  ";
+		/* 46        Acct-Session-Time                        [RFC2866] */
+	if ( c == 46) return "Acct-Session-Time [RFC2866]  ";
+		/* 47        Acct-Input-Packets                       [RFC2866] */
+	if ( c == 47) return "Acct-Input-Packets [RFC2866]  ";
+		/* 48        Acct-Output-Packets                      [RFC2866] */
+	if ( c == 48) return "Acct-Output-Packets [RFC2866]  ";
+		/* 49        Acct-Terminate-Cause                     [RFC2866] */
+	if ( c == 49) return "Acct-Terminate-Cause [RFC2866]  ";
+		/* 50        Acct-Multi-Session-Id                    [RFC2866] */
+	if ( c == 50) return "Acct-Multi-Session-Id [RFC2866]  ";
+		/* 51        Acct-Link-Count                          [RFC2866] */
+	if ( c == 51) return "Acct-Link-Count [RFC2866]  ";
+		/* 52        Acct-Input-Gigawords                     [RFC2869] */
+	if ( c == 52) return "Acct-Input-Gigawords [RFC2869]  ";
+		/* 53        Acct-Output-Gigawords                    [RFC2869] */
+	if ( c == 53) return "Acct-Output-Gigawords [RFC2869]  ";
+		/* 54        Unassigned */
+	if ( c == 54) return "Unassigned   ";
+		/* 55        Event-Timestamp                          [RFC2869] */
+	if ( c == 55) return "Event-Timestamp [RFC2869]  ";
+		/* 56        Egress-VLANID                            [RFC4675] */
+	if ( c == 56) return "Egress-VLANID [RFC4675]  ";
+		/* 57        Ingress-Filters                          [RFC4675] */
+	if ( c == 57) return "Ingress-Filters [RFC4675]  ";
+		/* 58        Egress-VLAN-Name                         [RFC4675] */
+	if ( c == 58) return "Egress-VLAN-Name [RFC4675]  ";
+		/* 59        User-Priority-Table                      [RFC4675] */
+	if ( c == 59) return "User-Priority-Table [RFC4675]  ";
+		/* 60        CHAP-Challenge */
+	if ( c == 60) return "CHAP-Challenge   ";
+		/* 61        NAS-Port-Type */
+	if ( c == 61) return "NAS-Port-Type   ";
+		/* 62        Port-Limit */
+	if ( c == 62) return "Port-Limit   ";
+		/* 63        Login-LAT-Port */
+	if ( c == 63) return "Login-LAT-Port   ";
+		/* 64        Tunnel-Type                              [RFC2868] */
+	if ( c == 64) return "Tunnel-Type [RFC2868]  ";
+		/* 65        Tunnel-Medium-Type                       [RFC2868] */
+	if ( c == 65) return "Tunnel-Medium-Type [RFC2868]  ";
+		/* 66        Tunnel-Client-Endpoint                   [RFC2868] */
+	if ( c == 66) return "Tunnel-Client-Endpoint [RFC2868]  ";
+		/* 67        Tunnel-Server-Endpoint                   [RFC2868] */
+	if ( c == 67) return "Tunnel-Server-Endpoint [RFC2868]  ";
+		/* 68        Acct-Tunnel-Connection                   [RFC2867] */
+	if ( c == 68) return "Acct-Tunnel-Connection [RFC2867]  ";
+		/* 69        Tunnel-Password                          [RFC2868] */
+	if ( c == 69) return "Tunnel-Password [RFC2868]  ";
+		/* 70        ARAP-Password                            [RFC2869] */
+	if ( c == 70) return "ARAP-Password [RFC2869]  ";
+		/* 71        ARAP-Features                            [RFC2869] */
+	if ( c == 71) return "ARAP-Features [RFC2869]  ";
+		/* 72        ARAP-Zone-Access                         [RFC2869] */
+	if ( c == 72) return "ARAP-Zone-Access [RFC2869]  ";
+		/* 73        ARAP-Security                            [RFC2869] */
+	if ( c == 73) return "ARAP-Security [RFC2869]  ";
+		/* 74        ARAP-Security-Data                       [RFC2869] */
+	if ( c == 74) return "ARAP-Security-Data [RFC2869]  ";
+		/* 75        Password-Retry                           [RFC2869] */
+	if ( c == 75) return "Password-Retry [RFC2869]  ";
+		/* 76        Prompt                                   [RFC2869] */
+	if ( c == 76) return "Prompt [RFC2869]  ";
+		/* 77        Connect-Info                             [RFC2869] */
+	if ( c == 77) return "Connect-Info [RFC2869]  ";
+		/* 78        Configuration-Token                      [RFC2869] */
+	if ( c == 78) return "Configuration-Token [RFC2869]  ";
+		/* 79        EAP-Message                              [RFC2869] */
+	if ( c == 79) return "EAP-Message [RFC2869]  ";
+		/* 80        Message-Authenticator                    [RFC2869] */
+	if ( c == 80) return "Message-Authenticator [RFC2869]  ";
+		/* 81        Tunnel-Private-Group-ID                  [RFC2868] */
+	if ( c == 81) return "Tunnel-Private-Group-ID [RFC2868]  ";
+		/* 82        Tunnel-Assignment-ID                     [RFC2868] */
+	if ( c == 82) return "Tunnel-Assignment-ID [RFC2868]  ";
+		/* 83        Tunnel-Preference                        [RFC2868] */
+	if ( c == 83) return "Tunnel-Preference [RFC2868]  ";
+		/* 84        ARAP-Challenge-Response                  [RFC2869] */
+	if ( c == 84) return "ARAP-Challenge-Response [RFC2869]  ";
+		/* 85        Acct-Interim-Interval                    [RFC2869] */
+	if ( c == 85) return "Acct-Interim-Interval [RFC2869]  ";
+		/* 86        Acct-Tunnel-Packets-Lost                 [RFC2867] */
+	if ( c == 86) return "Acct-Tunnel-Packets-Lost [RFC2867]  ";
+		/* 87        NAS-Port-Id                              [RFC2869] */
+	if ( c == 87) return "NAS-Port-Id [RFC2869]  ";
+		/* 88        Framed-Pool                              [RFC2869] */
+	if ( c == 88) return "Framed-Pool [RFC2869]  ";
+		/* 89        CUI                                      [RFC4372] */
+	if ( c == 89) return "CUI [RFC4372]  ";
+		/* 90        Tunnel-Client-Auth-ID                    [RFC2868] */
+	if ( c == 90) return "Tunnel-Client-Auth-ID [RFC2868]  ";
+		/* 91        Tunnel-Server-Auth-ID                    [RFC2868] */
+	if ( c == 91) return "Tunnel-Server-Auth-ID [RFC2868]  ";
+		/* 92        NAS-Filter-Rule                          [RFC4849] */
+	if ( c == 92) return "NAS-Filter-Rule [RFC4849]  ";
+		/* 93        Unassigned */
+	if ( c == 93) return "Unassigned   ";
+		/* 94        Originating-Line-Info                    [RFC4005] */
+	if ( c == 94) return "Originating-Line-Info [RFC4005]  ";
+		/* 95        NAS-IPv6-Address                         [RFC3162] */
+	if ( c == 95) return "NAS-IPv6-Address [RFC3162]  ";
+		/* 96        Framed-Interface-Id                      [RFC3162] */
+	if ( c == 96) return "Framed-Interface-Id [RFC3162]  ";
+		/* 97        Framed-IPv6-Prefix                       [RFC3162] */
+	if ( c == 97) return "Framed-IPv6-Prefix [RFC3162]  ";
+		/* 98        Login-IPv6-Host                          [RFC3162] */
+	if ( c == 98) return "Login-IPv6-Host [RFC3162]  ";
+		/* 99        Framed-IPv6-Route                        [RFC3162] */
+	if ( c == 99) return "Framed-IPv6-Route [RFC3162]  ";
+		/* 100       Framed-IPv6-Pool                         [RFC3162] */
+	if ( c == 100) return "Framed-IPv6-Pool [RFC3162]  ";
+		/* 101       Error-Cause Attribute                    [RFC3576] */
+	if ( c == 101) return "Error-Cause Attribute [RFC3576] ";
+		/* 102       EAP-Key-Name                             [RFC4072] */
+	if ( c == 102) return "EAP-Key-Name [RFC4072]  ";
+		/* 103       Digest-Response                          [RFC5090] */
+	if ( c == 103) return "Digest-Response [RFC5090]  ";
+		/* 104       Digest-Realm                             [RFC5090] */
+	if ( c == 104) return "Digest-Realm [RFC5090]  ";
+		/* 105       Digest-Nonce                             [RFC5090]   */
+	if ( c == 105) return "Digest-Nonce [RFC5090]  ";
+		/* 106       Digest-Response-Auth                     [RFC5090] */
+	if ( c == 106) return "Digest-Response-Auth [RFC5090]  ";
+		/* 107       Digest-Nextnonce                         [RFC5090] */
+	if ( c == 107) return "Digest-Nextnonce [RFC5090]  ";
+		/* 108       Digest-Method                            [RFC5090] */
+	if ( c == 108) return "Digest-Method [RFC5090]  ";
+		/* 109       Digest-URI                               [RFC5090]  */
+	if ( c == 109) return "Digest-URI [RFC5090]  ";
+		/* 110       Digest-Qop                               [RFC5090]  */
+	if ( c == 110) return "Digest-Qop [RFC5090]  ";
+		/* 111       Digest-Algorithm                         [RFC5090]  */
+	if ( c == 111) return "Digest-Algorithm [RFC5090]  ";
+		/* 112       Digest-Entity-Body-Hash                  [RFC5090]  */
+	if ( c == 112) return "Digest-Entity-Body-Hash [RFC5090]  ";
+		/* 113       Digest-CNonce                            [RFC5090]  */
+	if ( c == 113) return "Digest-CNonce [RFC5090]  ";
+		/* 114       Digest-Nonce-Count                       [RFC5090]  */
+	if ( c == 114) return "Digest-Nonce-Count [RFC5090]  ";
+		/* 115       Digest-Username                          [RFC5090]  */
+	if ( c == 115) return "Digest-Username [RFC5090]  ";
+		/* 116       Digest-Opaque                            [RFC5090]  */
+	if ( c == 116) return "Digest-Opaque [RFC5090]  ";
+		/* 117       Digest-Auth-Param                        [RFC5090]  */
+	if ( c == 117) return "Digest-Auth-Param [RFC5090]  ";
+		/* 118       Digest-AKA-Auts                          [RFC5090]  */
+	if ( c == 118) return "Digest-AKA-Auts [RFC5090]  ";
+		/* 119       Digest-Domain                            [RFC5090]  */
+	if ( c == 119) return "Digest-Domain [RFC5090]  ";
+		/* 120       Digest-Stale                             [RFC5090]  */
+	if ( c == 120) return "Digest-Stale [RFC5090]  ";
+		/* 121       Digest-HA1                               [RFC5090]  */
+	if ( c == 121) return "Digest-HA1 [RFC5090]  ";
+		/* 122       SIP-AOR                                  [RFC5090]  */
+	if ( c == 122) return "SIP-AOR [RFC5090]  ";
+		/* 123       Delegated-IPv6-Prefix                    [RFC4818] */
+	if ( c == 123) return "Delegated-IPv6-Prefix [RFC4818]  ";
+		/* 124       MIP6-Feature-Vector                      [RFC5447] */
+	if ( c == 124) return "MIP6-Feature-Vector [RFC5447]  ";
+		/* 125       MIP6-Home-Link-Prefix                    [RFC5447] */
+	if ( c == 125) return "MIP6-Home-Link-Prefix [RFC5447]  ";
+		/* 126-191   Unassigned */
+	if ((c >= 126) && (c <= 191)) return "Unassigned   ";
+		/* 192-223   Experimental Use                         [RFC3575] */
+	if ((c >= 192) && (c <= 223)) return "Experimental Use [RFC3575] ";
+		/* 224-240   Implementation Specific                  [RFC3575] */
+	if ((c >= 224) && (c <= 240)) return "Implementation Specific [RFC3575] ";
+		/* 241-255   Reserved                                 [RFC3575]    */
+	if ((c >= 241) && (c <= 255)) return "Reserved [RFC3575]  ";
+	/* fallback */ return "[Unknown]";
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/rgw_msg_attrtypes.c	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,258 @@
+		/* 1         User-Name                                 */
+	if ( c == 1) return "User-Name   ";
+		/* 2         User-Password                             */
+	if ( c == 2) return "User-Password   ";
+		/* 3         CHAP-Password                             */
+	if ( c == 3) return "CHAP-Password   ";
+		/* 4         NAS-IP-Address                            */
+	if ( c == 4) return "NAS-IP-Address   ";
+		/* 5         NAS-Port                                  */
+	if ( c == 5) return "NAS-Port   ";
+		/* 6         Service-Type                              */
+	if ( c == 6) return "Service-Type   ";
+		/* 7         Framed-Protocol                           */
+	if ( c == 7) return "Framed-Protocol   ";
+		/* 8         Framed-IP-Address                         */
+	if ( c == 8) return "Framed-IP-Address   ";
+		/* 9         Framed-IP-Netmask                         */
+	if ( c == 9) return "Framed-IP-Netmask   ";
+		/* 10        Framed-Routing                            */
+	if ( c == 10) return "Framed-Routing   ";
+		/* 11        Filter-Id                                 */
+	if ( c == 11) return "Filter-Id   ";
+		/* 12        Framed-MTU                                */
+	if ( c == 12) return "Framed-MTU   ";
+		/* 13        Framed-Compression                        */
+	if ( c == 13) return "Framed-Compression   ";
+		/* 14        Login-IP-Host                             */
+	if ( c == 14) return "Login-IP-Host   ";
+		/* 15        Login-Service                             */
+	if ( c == 15) return "Login-Service   ";
+		/* 16        Login-TCP-Port                            */
+	if ( c == 16) return "Login-TCP-Port   ";
+		/* 17        Unassigned */
+	if ( c == 17) return "Unassigned   ";
+		/* 18        Reply-Message                             */
+	if ( c == 18) return "Reply-Message   ";
+		/* 19        Callback-Number                           */
+	if ( c == 19) return "Callback-Number   ";
+		/* 20        Callback-Id                               */
+	if ( c == 20) return "Callback-Id   ";
+		/* 21        Unassigned */
+	if ( c == 21) return "Unassigned   ";
+		/* 22        Framed-Route                              */
+	if ( c == 22) return "Framed-Route   ";
+		/* 23        Framed-IPX-Network                        */
+	if ( c == 23) return "Framed-IPX-Network   ";
+		/* 24        State                                     */
+	if ( c == 24) return "State   ";
+		/* 25        Class                                     */
+	if ( c == 25) return "Class   ";
+		/* 26        Vendor-Specific                           */
+	if ( c == 26) return "Vendor-Specific   ";
+		/* 27        Session-Timeout                           */
+	if ( c == 27) return "Session-Timeout   ";
+		/* 28        Idle-Timeout                              */
+	if ( c == 28) return "Idle-Timeout   ";
+		/* 29        Termination-Action                        */
+	if ( c == 29) return "Termination-Action   ";
+		/* 30        Called-Station-Id                         */
+	if ( c == 30) return "Called-Station-Id   ";
+		/* 31        Calling-Station-Id                        */
+	if ( c == 31) return "Calling-Station-Id   ";
+		/* 32        NAS-Identifier                            */
+	if ( c == 32) return "NAS-Identifier   ";
+		/* 33        Proxy-State                               */
+	if ( c == 33) return "Proxy-State   ";
+		/* 34        Login-LAT-Service                         */
+	if ( c == 34) return "Login-LAT-Service   ";
+		/* 35        Login-LAT-Node                            */
+	if ( c == 35) return "Login-LAT-Node   ";
+		/* 36        Login-LAT-Group                           */
+	if ( c == 36) return "Login-LAT-Group   ";
+		/* 37        Framed-AppleTalk-Link                     */
+	if ( c == 37) return "Framed-AppleTalk-Link   ";
+		/* 38        Framed-AppleTalk-Network                  */
+	if ( c == 38) return "Framed-AppleTalk-Network   ";
+		/* 39        Framed-AppleTalk-Zone                     */
+	if ( c == 39) return "Framed-AppleTalk-Zone   ";
+		/* 40        Acct-Status-Type                         [RFC2866] */
+	if ( c == 40) return "Acct-Status-Type [RFC2866]  ";
+		/* 41        Acct-Delay-Time                          [RFC2866] */
+	if ( c == 41) return "Acct-Delay-Time [RFC2866]  ";
+		/* 42        Acct-Input-Octets                        [RFC2866] */
+	if ( c == 42) return "Acct-Input-Octets [RFC2866]  ";
+		/* 43        Acct-Output-Octets                       [RFC2866] */
+	if ( c == 43) return "Acct-Output-Octets [RFC2866]  ";
+		/* 44        Acct-Session-Id                          [RFC2866] */
+	if ( c == 44) return "Acct-Session-Id [RFC2866]  ";
+		/* 45        Acct-Authentic                           [RFC2866] */
+	if ( c == 45) return "Acct-Authentic [RFC2866]  ";
+		/* 46        Acct-Session-Time                        [RFC2866] */
+	if ( c == 46) return "Acct-Session-Time [RFC2866]  ";
+		/* 47        Acct-Input-Packets                       [RFC2866] */
+	if ( c == 47) return "Acct-Input-Packets [RFC2866]  ";
+		/* 48        Acct-Output-Packets                      [RFC2866] */
+	if ( c == 48) return "Acct-Output-Packets [RFC2866]  ";
+		/* 49        Acct-Terminate-Cause                     [RFC2866] */
+	if ( c == 49) return "Acct-Terminate-Cause [RFC2866]  ";
+		/* 50        Acct-Multi-Session-Id                    [RFC2866] */
+	if ( c == 50) return "Acct-Multi-Session-Id [RFC2866]  ";
+		/* 51        Acct-Link-Count                          [RFC2866] */
+	if ( c == 51) return "Acct-Link-Count [RFC2866]  ";
+		/* 52        Acct-Input-Gigawords                     [RFC2869] */
+	if ( c == 52) return "Acct-Input-Gigawords [RFC2869]  ";
+		/* 53        Acct-Output-Gigawords                    [RFC2869] */
+	if ( c == 53) return "Acct-Output-Gigawords [RFC2869]  ";
+		/* 54        Unassigned */
+	if ( c == 54) return "Unassigned   ";
+		/* 55        Event-Timestamp                          [RFC2869] */
+	if ( c == 55) return "Event-Timestamp [RFC2869]  ";
+		/* 56        Egress-VLANID                            [RFC4675] */
+	if ( c == 56) return "Egress-VLANID [RFC4675]  ";
+		/* 57        Ingress-Filters                          [RFC4675] */
+	if ( c == 57) return "Ingress-Filters [RFC4675]  ";
+		/* 58        Egress-VLAN-Name                         [RFC4675] */
+	if ( c == 58) return "Egress-VLAN-Name [RFC4675]  ";
+		/* 59        User-Priority-Table                      [RFC4675] */
+	if ( c == 59) return "User-Priority-Table [RFC4675]  ";
+		/* 60        CHAP-Challenge */
+	if ( c == 60) return "CHAP-Challenge   ";
+		/* 61        NAS-Port-Type */
+	if ( c == 61) return "NAS-Port-Type   ";
+		/* 62        Port-Limit */
+	if ( c == 62) return "Port-Limit   ";
+		/* 63        Login-LAT-Port */
+	if ( c == 63) return "Login-LAT-Port   ";
+		/* 64        Tunnel-Type                              [RFC2868] */
+	if ( c == 64) return "Tunnel-Type [RFC2868]  ";
+		/* 65        Tunnel-Medium-Type                       [RFC2868] */
+	if ( c == 65) return "Tunnel-Medium-Type [RFC2868]  ";
+		/* 66        Tunnel-Client-Endpoint                   [RFC2868] */
+	if ( c == 66) return "Tunnel-Client-Endpoint [RFC2868]  ";
+		/* 67        Tunnel-Server-Endpoint                   [RFC2868] */
+	if ( c == 67) return "Tunnel-Server-Endpoint [RFC2868]  ";
+		/* 68        Acct-Tunnel-Connection                   [RFC2867] */
+	if ( c == 68) return "Acct-Tunnel-Connection [RFC2867]  ";
+		/* 69        Tunnel-Password                          [RFC2868] */
+	if ( c == 69) return "Tunnel-Password [RFC2868]  ";
+		/* 70        ARAP-Password                            [RFC2869] */
+	if ( c == 70) return "ARAP-Password [RFC2869]  ";
+		/* 71        ARAP-Features                            [RFC2869] */
+	if ( c == 71) return "ARAP-Features [RFC2869]  ";
+		/* 72        ARAP-Zone-Access                         [RFC2869] */
+	if ( c == 72) return "ARAP-Zone-Access [RFC2869]  ";
+		/* 73        ARAP-Security                            [RFC2869] */
+	if ( c == 73) return "ARAP-Security [RFC2869]  ";
+		/* 74        ARAP-Security-Data                       [RFC2869] */
+	if ( c == 74) return "ARAP-Security-Data [RFC2869]  ";
+		/* 75        Password-Retry                           [RFC2869] */
+	if ( c == 75) return "Password-Retry [RFC2869]  ";
+		/* 76        Prompt                                   [RFC2869] */
+	if ( c == 76) return "Prompt [RFC2869]  ";
+		/* 77        Connect-Info                             [RFC2869] */
+	if ( c == 77) return "Connect-Info [RFC2869]  ";
+		/* 78        Configuration-Token                      [RFC2869] */
+	if ( c == 78) return "Configuration-Token [RFC2869]  ";
+		/* 79        EAP-Message                              [RFC2869] */
+	if ( c == 79) return "EAP-Message [RFC2869]  ";
+		/* 80        Message-Authenticator                    [RFC2869] */
+	if ( c == 80) return "Message-Authenticator [RFC2869]  ";
+		/* 81        Tunnel-Private-Group-ID                  [RFC2868] */
+	if ( c == 81) return "Tunnel-Private-Group-ID [RFC2868]  ";
+		/* 82        Tunnel-Assignment-ID                     [RFC2868] */
+	if ( c == 82) return "Tunnel-Assignment-ID [RFC2868]  ";
+		/* 83        Tunnel-Preference                        [RFC2868] */
+	if ( c == 83) return "Tunnel-Preference [RFC2868]  ";
+		/* 84        ARAP-Challenge-Response                  [RFC2869] */
+	if ( c == 84) return "ARAP-Challenge-Response [RFC2869]  ";
+		/* 85        Acct-Interim-Interval                    [RFC2869] */
+	if ( c == 85) return "Acct-Interim-Interval [RFC2869]  ";
+		/* 86        Acct-Tunnel-Packets-Lost                 [RFC2867] */
+	if ( c == 86) return "Acct-Tunnel-Packets-Lost [RFC2867]  ";
+		/* 87        NAS-Port-Id                              [RFC2869] */
+	if ( c == 87) return "NAS-Port-Id [RFC2869]  ";
+		/* 88        Framed-Pool                              [RFC2869] */
+	if ( c == 88) return "Framed-Pool [RFC2869]  ";
+		/* 89        CUI                                      [RFC4372] */
+	if ( c == 89) return "CUI [RFC4372]  ";
+		/* 90        Tunnel-Client-Auth-ID                    [RFC2868] */
+	if ( c == 90) return "Tunnel-Client-Auth-ID [RFC2868]  ";
+		/* 91        Tunnel-Server-Auth-ID                    [RFC2868] */
+	if ( c == 91) return "Tunnel-Server-Auth-ID [RFC2868]  ";
+		/* 92        NAS-Filter-Rule                          [RFC4849] */
+	if ( c == 92) return "NAS-Filter-Rule [RFC4849]  ";
+		/* 93        Unassigned */
+	if ( c == 93) return "Unassigned   ";
+		/* 94        Originating-Line-Info                    [RFC4005] */
+	if ( c == 94) return "Originating-Line-Info [RFC4005]  ";
+		/* 95        NAS-IPv6-Address                         [RFC3162] */
+	if ( c == 95) return "NAS-IPv6-Address [RFC3162]  ";
+		/* 96        Framed-Interface-Id                      [RFC3162] */
+	if ( c == 96) return "Framed-Interface-Id [RFC3162]  ";
+		/* 97        Framed-IPv6-Prefix                       [RFC3162] */
+	if ( c == 97) return "Framed-IPv6-Prefix [RFC3162]  ";
+		/* 98        Login-IPv6-Host                          [RFC3162] */
+	if ( c == 98) return "Login-IPv6-Host [RFC3162]  ";
+		/* 99        Framed-IPv6-Route                        [RFC3162] */
+	if ( c == 99) return "Framed-IPv6-Route [RFC3162]  ";
+		/* 100       Framed-IPv6-Pool                         [RFC3162] */
+	if ( c == 100) return "Framed-IPv6-Pool [RFC3162]  ";
+		/* 101       Error-Cause Attribute                    [RFC3576] */
+	if ( c == 101) return "Error-Cause Attribute [RFC3576] ";
+		/* 102       EAP-Key-Name                             [RFC4072] */
+	if ( c == 102) return "EAP-Key-Name [RFC4072]  ";
+		/* 103       Digest-Response                          [RFC5090] */
+	if ( c == 103) return "Digest-Response [RFC5090]  ";
+		/* 104       Digest-Realm                             [RFC5090] */
+	if ( c == 104) return "Digest-Realm [RFC5090]  ";
+		/* 105       Digest-Nonce                             [RFC5090]   */
+	if ( c == 105) return "Digest-Nonce [RFC5090]  ";
+		/* 106       Digest-Response-Auth                     [RFC5090] */
+	if ( c == 106) return "Digest-Response-Auth [RFC5090]  ";
+		/* 107       Digest-Nextnonce                         [RFC5090] */
+	if ( c == 107) return "Digest-Nextnonce [RFC5090]  ";
+		/* 108       Digest-Method                            [RFC5090] */
+	if ( c == 108) return "Digest-Method [RFC5090]  ";
+		/* 109       Digest-URI                               [RFC5090]  */
+	if ( c == 109) return "Digest-URI [RFC5090]  ";
+		/* 110       Digest-Qop                               [RFC5090]  */
+	if ( c == 110) return "Digest-Qop [RFC5090]  ";
+		/* 111       Digest-Algorithm                         [RFC5090]  */
+	if ( c == 111) return "Digest-Algorithm [RFC5090]  ";
+		/* 112       Digest-Entity-Body-Hash                  [RFC5090]  */
+	if ( c == 112) return "Digest-Entity-Body-Hash [RFC5090]  ";
+		/* 113       Digest-CNonce                            [RFC5090]  */
+	if ( c == 113) return "Digest-CNonce [RFC5090]  ";
+		/* 114       Digest-Nonce-Count                       [RFC5090]  */
+	if ( c == 114) return "Digest-Nonce-Count [RFC5090]  ";
+		/* 115       Digest-Username                          [RFC5090]  */
+	if ( c == 115) return "Digest-Username [RFC5090]  ";
+		/* 116       Digest-Opaque                            [RFC5090]  */
+	if ( c == 116) return "Digest-Opaque [RFC5090]  ";
+		/* 117       Digest-Auth-Param                        [RFC5090]  */
+	if ( c == 117) return "Digest-Auth-Param [RFC5090]  ";
+		/* 118       Digest-AKA-Auts                          [RFC5090]  */
+	if ( c == 118) return "Digest-AKA-Auts [RFC5090]  ";
+		/* 119       Digest-Domain                            [RFC5090]  */
+	if ( c == 119) return "Digest-Domain [RFC5090]  ";
+		/* 120       Digest-Stale                             [RFC5090]  */
+	if ( c == 120) return "Digest-Stale [RFC5090]  ";
+		/* 121       Digest-HA1                               [RFC5090]  */
+	if ( c == 121) return "Digest-HA1 [RFC5090]  ";
+		/* 122       SIP-AOR                                  [RFC5090]  */
+	if ( c == 122) return "SIP-AOR [RFC5090]  ";
+		/* 123       Delegated-IPv6-Prefix                    [RFC4818] */
+	if ( c == 123) return "Delegated-IPv6-Prefix [RFC4818]  ";
+		/* 124       MIP6-Feature-Vector                      [RFC5447] */
+	if ( c == 124) return "MIP6-Feature-Vector [RFC5447]  ";
+		/* 125       MIP6-Home-Link-Prefix                    [RFC5447] */
+	if ( c == 125) return "MIP6-Home-Link-Prefix [RFC5447]  ";
+		/* 126-191   Unassigned */
+	if ((c >= 126) && (c <= 191)) return "Unassigned   ";
+		/* 192-223   Experimental Use                         [RFC3575] */
+	if ((c >= 192) && (c <= 223)) return "Experimental Use [RFC3575] ";
+		/* 224-240   Implementation Specific                  [RFC3575] */
+	if ((c >= 224) && (c <= 240)) return "Implementation Specific [RFC3575] ";
+		/* 241-255   Reserved                                 [RFC3575]    */
+	if ((c >= 241) && (c <= 255)) return "Reserved [RFC3575]  ";
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/radius_gw/rgw_msg_codes.c	Fri May 22 18:11:49 2009 +0900
@@ -0,0 +1,82 @@
+/*  Name of RADIUS command from its command code */
+const char * rgw_msg_code_str(unsigned char c) {
+		/* 1        Access-Request                           [RFC2865] */
+	if ( c == 1) return "Access-Request [RFC2865]  ";
+		/* 2        Access-Accept                            [RFC2865] */
+	if ( c == 2) return "Access-Accept [RFC2865]  ";
+		/* 3        Access-Reject                            [RFC2865] */
+	if ( c == 3) return "Access-Reject [RFC2865]  ";
+		/* 4        Accounting-Request                       [RFC2865] */
+	if ( c == 4) return "Accounting-Request [RFC2865]  ";
+		/* 5        Accounting-Response                      [RFC2865] */
+	if ( c == 5) return "Accounting-Response [RFC2865]  ";
+		/* 6        Accounting-Status                        [RFC3575] */
+	if ( c == 6) return "Accounting-Status [RFC3575]  ";
+		/* 7        Password-Request                         [RFC3575] */
+	if ( c == 7) return "Password-Request [RFC3575]  ";
+		/* 8        Password-Ack                             [RFC3575] */
+	if ( c == 8) return "Password-Ack [RFC3575]  ";
+		/* 9        Password-Reject                          [RFC3575] */
+	if ( c == 9) return "Password-Reject [RFC3575]  ";
+		/* 10       Accounting-Message                       [RFC3575] */
+	if ( c == 10) return "Accounting-Message [RFC3575]  ";
+		/* 11       Access-Challenge                         [RFC2865] */
+	if ( c == 11) return "Access-Challenge [RFC2865]  ";
+		/* 12       Status-Server (experimental)             [RFC2865] */
+	if ( c == 12) return "Status-Server (experimental) [RFC2865] ";
+		/* 13       Status-Client (experimental)             [RFC2865] */
+	if ( c == 13) return "Status-Client (experimental) [RFC2865] ";
+		/* 21       Resource-Free-Request                    [RFC3575] */
+	if ( c == 21) return "Resource-Free-Request [RFC3575]  ";
+		/* 22       Resource-Free-Response                   [RFC3575] */
+	if ( c == 22) return "Resource-Free-Response [RFC3575]  ";
+		/* 23       Resource-Query-Request                   [RFC3575] */
+	if ( c == 23) return "Resource-Query-Request [RFC3575]  ";
+		/* 24       Resource-Query-Response                  [RFC3575] */
+	if ( c == 24) return "Resource-Query-Response [RFC3575]  ";
+		/* 25       Alternate-Resource-Reclaim-Request       [RFC3575] */
+	if ( c == 25) return "Alternate-Resource-Reclaim-Request [RFC3575]  ";
+		/* 26       NAS-Reboot-Request                       [RFC3575] */
+	if ( c == 26) return "NAS-Reboot-Request [RFC3575]  ";
+		/* 27       NAS-Reboot-Response                      [RFC3575] */
+	if ( c == 27) return "NAS-Reboot-Response [RFC3575]  ";
+		/* 28       Reserved */
+	if ( c == 28) return "Reserved   ";
+		/* 29       Next-Passcode                            [RFC3575] */
+	if ( c == 29) return "Next-Passcode [RFC3575]  ";
+		/* 30       New-Pin                                  [RFC3575] */
+	if ( c == 30) return "New-Pin [RFC3575]  ";
+		/* 31       Terminate-Session                        [RFC3575] */
+	if ( c == 31) return "Terminate-Session [RFC3575]  ";
+		/* 32       Password-Expired                         [RFC3575] */
+	if ( c == 32) return "Password-Expired [RFC3575]  ";
+		/* 33       Event-Request                            [RFC3575] */
+	if ( c == 33) return "Event-Request [RFC3575]  ";
+		/* 34       Event-Response                           [RFC3575] */
+	if ( c == 34) return "Event-Response [RFC3575]  ";
+		/* 40       Disconnect-Request                       [RFC3575][RFC5176] */
+	if ( c == 40) return "Disconnect-Request [RFC3575][RFC5176]  ";
+		/* 41       Disconnect-ACK                           [RFC3575][RFC5176] */
+	if ( c == 41) return "Disconnect-ACK [RFC3575][RFC5176]  ";
+		/* 42       Disconnect-NAK                           [RFC3575][RFC5176] */
+	if ( c == 42) return "Disconnect-NAK [RFC3575][RFC5176]  ";
+		/* 43       CoA-Request                              [RFC3575][RFC5176] */
+	if ( c == 43) return "CoA-Request [RFC3575][RFC5176]  ";
+		/* 44       CoA-ACK                                  [RFC3575][RFC5176] */
+	if ( c == 44) return "CoA-ACK [RFC3575][RFC5176]  ";
+		/* 45       CoA-NAK                                  [RFC3575][RFC5176] */
+	if ( c == 45) return "CoA-NAK [RFC3575][RFC5176]  ";
+		/* 50       IP-Address-Allocate                      [RFC3575] */
+	if ( c == 50) return "IP-Address-Allocate [RFC3575]  ";
+		/* 51       IP-Address-Release                       [RFC3575] */
+	if ( c == 51) return "IP-Address-Release [RFC3575]  ";
+		/* 52-249   Unassigned */
+	if ((c >= 52) && (c <= 249)) return "Unassigned   ";
+		/* 250-253  Experimental Use                         [RFC3575] */
+	if ((c >= 250) && (c <= 253)) return "Experimental Use [RFC3575] ";
+		/* 254      Reserved                                 [RFC3575] */
+	if ( c == 254) return "Reserved [RFC3575]  ";
+		/* 255      Reserved                                 [RFC3575] */
+	if ( c == 255) return "Reserved [RFC3575]  ";
+	/* fallback */ return "[Unknown]";
+}
--- a/extensions/radius_gw/rgw_servers.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/rgw_servers.c	Fri May 22 18:11:49 2009 +0900
@@ -35,8 +35,9 @@
 
 /* Manage the server(s): opening sockets, receiving messages, ... */
 
-#include "radius_gw_internal.h"
+#include "radius_gw.h"
 
+#define RADIUS_MAX_MSG_LEN 3000
 
 /* Declare the rgw_servers */
 struct rgw_servs rgw_servers;
@@ -109,59 +110,64 @@
 		struct sockaddr_storage from;
 		socklen_t fromlen = sizeof(from);
 		int len;
-		rad_t * msg = NULL;
-		void * nas_info = NULL;
-		uint16_t port;
+		struct rgw_client * nas_info = NULL;
+		uint16_t port = 0;
 		unsigned char buf[RADIUS_MAX_MSG_LEN];
+		struct rgw_radius_msg_meta *msg = NULL;
 		
 		pthread_testcancel();
 		
-		/* read the next message */
+		/* receive the next message */
 		CHECK_SYS_DO( len = recvfrom( me->sock, &buf[0], sizeof(buf), 0, (struct sockaddr *) &from, &fromlen),  break );
-		{
+		
+		/* Get the port */
+		if (from.ss_family == AF_INET)
+			port = ((struct sockaddr_in *)&from)->sin_port;
+		if (from.ss_family == AF_INET6)
+			port = ((struct sockaddr_in6 *)&from)->sin6_port;
+		if (!port) {
+			TRACE_DEBUG(INFO, "Invalid port (family: %d), discarding...", from.ss_family);
+			continue;
+		}
+		
+		if (TRACE_BOOL(FULL)) {
 			char ipstr[INET6_ADDRSTRLEN];
 			
 			switch (from.ss_family) {
 				case AF_INET:
 					inet_ntop(AF_INET, &((struct sockaddr_in *)&from)->sin_addr,ipstr,sizeof(ipstr));
-					port = ((struct sockaddr_in *)&from)->sin_port;
 					break;
 				case AF_INET6:
 					inet_ntop(AF_INET6, &((struct sockaddr_in6 *)&from)->sin6_addr,ipstr,sizeof(ipstr));
-					port = ((struct sockaddr_in6 *)&from)->sin6_port;
 					break;
 				default:
 					snprintf(ipstr,sizeof(ipstr),"(unknown AF:%d)", from.ss_family);
-					port = 0;
 			}
 			
 			TRACE_DEBUG(FULL, "Received %d bytes from [%s]:%hu", len, ipstr, ntohs(port));
 		}
 		
-		if (!port)
-			continue;
+		/* Search the associated client definition, if any */
+		CHECK_FCT_DO( rgw_clients_search((struct sockaddr *) &from, &nas_info),
+			{
+				TRACE_DEBUG(FULL, "Discarding message from unknown RADIUS client");
+				continue;
+			} );
+				
 		
 		/* parse the message or loop if message is bad */
 		CHECK_FCT_DO( rgw_msg_parse(&buf[0], len, &msg), 
 			{ 
 				TRACE_DEBUG(INFO, "Discarding invalid RADIUS message");
+				rgw_clients_dispose(&nas_info);
 				continue; 
 			} );
 		
-		msg->flags.serv_type = me->type;
+		msg->serv_type = me->type;
 		msg->port = port;
 		
 		if (TRACE_BOOL(FULL))
-			rg_msg_dump(FULL, msg);
-		
-		/* Search the associated client definition, if any */
-		CHECK_FCT_DO( rgw_clients_search((struct sockaddr *) &from, &nas_info),
-			{
-				TRACE_DEBUG(INFO, "Discarding message from unknown RADIUS client");
-				rg_msg_free(msg);
-				continue;
-			} );
-				
+			radius_msg_dump(&msg->radius);
 		
 		/* queue the message for a worker thread */
 		CHECK_FCT_DO( rgw_work_add(msg, nas_info), break );
@@ -169,6 +175,7 @@
 		/* Then wait for next incoming message */
 	}
 	
+	TRACE_DEBUG(INFO, "Error: server thread terminated!!!");
 	return NULL;
 	
 }
@@ -226,10 +233,10 @@
 	
 	TRACE_ENTRY();
 	
-	UDPSERV( auth, RGW_EXT_PORT_AUTH,  );
-	UDPSERV( auth, RGW_EXT_PORT_AUTH, 6 );
-	UDPSERV( acct, RGW_EXT_PORT_ACCT,  );
-	UDPSERV( acct, RGW_EXT_PORT_ACCT, 6 );
+	UDPSERV( auth, RGW_EXT_TYPE_AUTH,  );
+	UDPSERV( auth, RGW_EXT_TYPE_AUTH, 6 );
+	UDPSERV( acct, RGW_EXT_TYPE_ACCT,  );
+	UDPSERV( acct, RGW_EXT_TYPE_ACCT, 6 );
 	
 	TRACE_DEBUG(FULL, "%d UDP servers started succesfully.", idx);
 	return 0;
--- a/extensions/radius_gw/rgw_work.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/rgw_work.c	Fri May 22 18:11:49 2009 +0900
@@ -35,7 +35,7 @@
 
 /* Manage incoming RADIUS message. */
 
-#include "radius_gw_internal.h"
+#include "radius_gw.h"
 
 /* How many threads to work on messages ? */
 #define NB_WORKERS	2
@@ -43,105 +43,25 @@
 
 static pthread_mutex_t work_mtx = PTHREAD_MUTEX_INITIALIZER;
 static pthread_cond_t work_cond = PTHREAD_COND_INITIALIZER;
+static sess_reg_t * sess_hdl = NULL;
+static pthread_t workers[NB_WORKERS];
+static struct rg_list work_data;
 
-static struct rg_list work_data;
+/* List of pending messages to be handled */
 struct work_item {
-	struct rg_list chain;
-	rad_t * msg;
-	void * cli;
-};
-
-struct pending_answer {
-	rad_t     * rad;
-	void      * cli;
-	sess_id_t * sess;
+	struct rg_list 		     chain;
+	struct rgw_radius_msg_meta * msg;
+	struct rgw_client 	   * cli;
 };
 
-static sess_reg_t * sess_hdl = NULL;
-
-static pthread_t workers[NB_WORKERS];
-
-static void cleanup_release_mtx(void * mtx)
-{
-	CHECK_POSIX_DO( pthread_mutex_unlock((pthread_mutex_t *)mtx), );
-}
+/* Structure stored in waaad when waiting for a Diameter answer */
+struct pending_answer {
+	struct rgw_radius_msg_meta * rad;
+	struct rgw_client          * cli;
+	sess_id_t 		   * sess;
+};
 
-/* This function is strongly inspired from radius_msg_verify_msg_auth in hostap package (BSD licensed) */
-static int work_auth_check(rad_t * rad, void * cli, unsigned char * req_auth)
-{
-	unsigned char buf[RADIUS_MAX_MSG_LEN];
-	unsigned char * key;
-	size_t key_len;
-	struct rg_list * attr_li;
-	struct rad_attr * msg_mac = NULL;
-	unsigned char msg_mac_save[MD5_MAC_LEN];
-	unsigned char msg_mac_calc[MD5_MAC_LEN];
-	unsigned char msg_auth_orig[16];
-	size_t buflen = RADIUS_MAX_MSG_LEN;
-	
-	TRACE_ENTRY("%p %p", rad, cli);
-	
-	/* Find the authenticator attribute */
-	for (attr_li = rad->attributes.next; attr_li != &rad->attributes; attr_li = attr_li->next) {
-		struct rad_attr * attr = (struct rad_attr *)attr_li;
-		
-		if (attr->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {
-			if (msg_mac != NULL) {
-				TRACE_DEBUG(INFO, "RADIUS message with several Message-Authenticator attributes, invalid.");
-				return EINVAL;
-			}
-			msg_mac = attr;
-		}
-	}
-	if (msg_mac == NULL) {
-		TRACE_DEBUG(FULL, "RADIUS message without Message-Authenticator attribute.");
-		return 0;
-	}
-	if (msg_mac->length != (2 + sizeof(msg_mac_save))) {
-		TRACE_DEBUG(INFO, "Unexpected size of Message-Authenticator attribute, discarding.");
-		return EINVAL;
-	}
-	
-	/* Save and clear the authenticator value */
-	memcpy( &msg_mac_save[0], &msg_mac->data.buf[0], sizeof(msg_mac_save) );
-	memset( &msg_mac->data.buf[0], 0, sizeof(msg_mac_save) );
-	if (req_auth) {
-		/* compute the MAC with the authenticator from the request */
-		memcpy( &msg_auth_orig[0], &rad->authenticator[0], 16 );
-		memcpy( &rad->authenticator[0], req_auth, 16 );
-	}
-	
-	/* Recreate a false message to compute the md5 sum. This is very bad design, optimization possible here... */
-	memset(buf, 0, sizeof(buf));
-	key = &buf[0]; /* use key here to avoid declarataion of another var */
-	CHECK_FCT( rgw_msg_gen(rad, &key, &buflen) );
-	
-	/* Get the shared secret associated with this client */
-	CHECK_FCT( rgw_clients_getkey(cli, &key, &key_len) );
-	
-	/* Now compute the MAC with our shared key */
-	hmac_md5( key, key_len, &buf[0], buflen, &msg_mac_calc[0] );
-	
-	/* Restore the original msg */
-	memcpy( &msg_mac->data.buf[0], &msg_mac_save[0], sizeof(msg_mac_save) );
-	if (req_auth) {
-		/* also restore the authenticator */
-		memcpy( &rad->authenticator[0], &msg_auth_orig[0], 16 );
-	}
-	
-	/* Finally, check if the MAC is correct (validates the common shared secret) */
-	if (memcmp(&msg_mac_save[0], &msg_mac_calc[0], sizeof(msg_mac_save) )) {
-		TRACE_DEBUG(INFO, "Invalid Message-Authenticator attribute (bad shared secret?).");
-		return EINVAL;
-	} else {
-		rad->flags.auth_ok = 1;
-		TRACE_DEBUG(FULL, "Valid Message-Authenticator attribute found.");
-	}
-	
-	return 0;
-}
-
-
+/* Callback when a Diameter answer is received */
 static void work_receive_diam_answer(void * paback, msg_t **ans)
 {
 	struct pending_answer * pa = (struct pending_answer *)paback;
@@ -152,6 +72,7 @@
 	
 }
 
+/* Worker thread, processing incoming RADIUS messages (after parsing) */
 static void * work_th(void * arg)
 {
 	char thname[10];
@@ -163,21 +84,18 @@
 	
 	while (1) { /* The thread will be cancelled */
 		
-		rad_t * msg;
-		void * cli;
+		struct rgw_radius_msg_meta * msg;
+		struct rgw_client * cli;
 		struct work_item * wi;
-		struct rg_list * li;
 		sess_id_t * session;
 		msg_t * diam_msg;
-		int pb;
+		int pb, a;
 		struct pending_answer * pa;
 	
-		/* Pick the next message */
-		CHECK_POSIX_DO( pthread_mutex_lock(&work_mtx), return NULL );
+		/* Wait for the next incoming RADIUS message */
 		
-		pthread_cleanup_push(cleanup_release_mtx, &work_mtx);
-
-		/* wait for new work data */
+		CHECK_POSIX_DO( pthread_mutex_lock(&work_mtx), break );
+		pthread_cleanup_push(rg_cleanup_mutex, &work_mtx);
 		while (rg_list_is_empty(&work_data)) {
 			CHECK_POSIX_DO( pthread_cond_wait( &work_cond, &work_mtx ), 
 				{
@@ -185,36 +103,32 @@
 					return NULL;
 				}  );
 		}
-		
-		/* Retrieve the next element */
 		wi = (struct work_item *)(work_data.next);
 		rg_list_unlink(&wi->chain);
 		msg = wi->msg;
 		cli = wi->cli;
 		free(wi);
+		pthread_cleanup_pop(0);
+		CHECK_POSIX_DO( pthread_mutex_unlock(&work_mtx), break );
 		
-		/* Release the mutex */
-		pthread_cleanup_pop(0);
-		CHECK_POSIX_DO( pthread_mutex_unlock(&work_mtx), return NULL );
-		
-		TRACE_DEBUG(FULL, "Processing next message: %p received on client: %p", msg, cli);
+		TRACE_DEBUG(ANNOYING, "Processing next RADIUS message: %p received on client: %p", msg, cli);
 	
 		/* process the data */
 		
-		/* Check authenticator */
-		CHECK_FCT_DO( work_auth_check(msg, cli, NULL),
+		/* Check authenticator, if any */
+		CHECK_FCT_DO( rgw_msg_auth_check(msg, cli, NULL),
 			{
 				/* An error occurred, discard message */
-				rg_msg_free(msg);
+				rgw_msg_free(&msg);
 				rgw_clients_dispose(&cli);
 				continue;
 			}  );
 		
 		/* Check duplicate */
-		CHECK_FCT_DO( rgw_clients_checkdup(&msg, cli),
+		CHECK_FCT_DO( rgw_clients_check_dup(&msg, cli),
 			{
 				/* An error occurred, discard message */
-				rg_msg_free(msg);
+				rgw_msg_free(&msg);
 				rgw_clients_dispose(&cli);
 				continue;
 			}  );
@@ -229,41 +143,40 @@
 		CHECK_FCT_DO( rgw_extensions_loop_req(&msg, &session, &diam_msg, cli), 
 			{
 				/* An error occurred, discard message */
-				rg_msg_free(msg);
+				rgw_msg_free(&msg);
 				rgw_clients_dispose(&cli);
 				continue;
 			}  );
 		if (msg == NULL) {
 			rgw_clients_dispose(&cli);
-			continue; /* the message was a duplicate */
+			continue; /* the message was handled already */
+		}
+		
+		pb = 0;
+		
+		/* Check the created Diameter message */
+		if ((diam_msg == NULL) || ( msg_parse_rules(diam_msg, NULL) ) ) {
+			log_error("No or invalid Diameter generated after processing of RADIUS command %hhd (%s).\n"
+					" Turn on advanced log for detail.\n",
+					msg->radius.hdr->code, rgw_msg_code_str(msg->radius.hdr->code));
+			/* We might also dump the conflicting rule here if useful */
+			pb++;
 		}
 		
 		/* Check if the full content of the RADIUS message was handled */
-		pb = 0;
-		for (li = msg->attributes.next; li != &msg->attributes; li = li->next) {
-			struct rad_attr * attr = (struct rad_attr *)li;
-			if (! attr->flags.handled) {
-				pb++;
-				log_error("No extension available to handle attribute %hhd (%s) in command %hhd (%s)!\n",
-						attr->type, rg_msg_attrtype_str(attr->type),
-						msg->code, rg_msg_code_str(msg->code));
-			}
-		}
-		
-		/* Check the created Diameter message */
-		if ((diam_msg == NULL) || ( msg_parse_rules(diam_msg, NULL) ) ) {
-			log_error("No or invalid Diameter generated from RADIUS command %hhd (%s).\n"
-					" Turn on advanced log for detail.\n",
-					msg->code, rg_msg_code_str(msg->code));
-			/* We might also dump the conflicting rule here if useful */
+		for (a = 0; a < msg->radius.attr_used; a++) {
+			struct radius_attr_hdr *attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[a]);
 			pb++;
+			log_error("No extension available to handle attribute %hhd (%s) in command %hhd (%s)!\n",
+					attr->type, rgw_msg_attrtype_str(attr->type),
+					msg->radius.hdr->code, rgw_msg_code_str(msg->radius.hdr->code));
 		}
 		
 		/* Check the session is correct */
 		if (session == NULL) {
 			log_error("No session has been created to store RADIUS state (command %hhd (%s)).\n"
 					" Please check your configuration and documentation.\n",
-					msg->code, rg_msg_code_str(msg->code));
+					msg->radius.hdr->code, rgw_msg_code_str(msg->radius.hdr->code));
 			pb++;
 		}
 		
@@ -279,13 +192,13 @@
 				diam_msg = NULL;
 			}
 			
-			rg_msg_free(msg);
+			rgw_msg_free(&msg);
 			rgw_clients_dispose(&cli);
 			
-			TRACE_DEBUG(INFO, "A problem occurred while translating a RADIUS message, data discarded.\n");
+			TRACE_DEBUG(INFO, "%d problem(s) occurred while translating a RADIUS message, data discarded.\n", pb);
 			continue;
 		}
-				
+		
 		/* Send the radius message and register for answer */
 		CHECK_MALLOC_DO( pa = malloc(sizeof(struct pending_answer)), break );
 		memset(pa, 0, sizeof(*pa));
@@ -307,7 +220,7 @@
 					diam_msg = NULL;
 				}
 
-				rg_msg_free(msg);
+				rgw_msg_free(&msg);
 				rgw_clients_dispose(&cli);
 				
 				free(pa);
@@ -341,7 +254,7 @@
 	return 0;
 }
 
-int rgw_work_add(rad_t * msg, void * client)
+int rgw_work_add(struct rgw_radius_msg_meta * msg, struct rgw_client * client)
 {
 	struct work_item * new;
 	
--- a/extensions/radius_gw/rsc/rebuild_inc.sh	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/rsc/rebuild_inc.sh	Fri May 22 18:11:49 2009 +0900
@@ -1,33 +1,49 @@
 #/bin/bash
 
-# This script rebuilds the files rg_utils_*.inc.
-# It should be called when the radius-types file is updated with:
-# wget http://www.iana.org/assignments/radius-types
+# This script rebuilds the files rgw_msg_*.c.
+# It should be called when the radius-types file is updated with
+# cd rsc && wget http://www.iana.org/assignments/radius-types
 
-if [ ! -f radius-types ];
+if [ ! -f rsc/radius-types ];
 then echo "Missing file radius-types, please get a fresh copy first.";
 exit 2;
 fi
 
-if [ -f rg_utils_codes.inc ];
-then mv -f rg_utils_codes.inc rg_utils_codes.inc.bak;
-fi
+
 
-if [ -f rg_utils_attrtype.inc ];
-then mv -f rg_utils_attrtype.inc rg_utils_attrtype.inc.bak;
+echo "Rebuilding rgw_msg_codes.c..."
+
+if [ -f rgw_msg_codes.c ];
+then mv -f rgw_msg_codes.c rgw_msg_codes.c.bak;
 fi
 
-echo "Rebuilding rg_utils_codes.inc..."
+# Not too sure how to rebuid rsc/radius-types-codes from radius-types, skipping...
+echo "WARNING: rsc/radius-types-codes has not been rebuilt"
 
-# Not too sure how to rebuid radius-types-codes from radius-types, skipping...
-echo "WARNING: radius-types-codes has not been rebuilt"
+# Regenerate the file
+echo "/*  Name of RADIUS command from its command code */" 	> rgw_msg_codes.c
+echo "const char * rgw_msg_code_str(unsigned char c) {"		>>rgw_msg_codes.c
+awk -f rsc/register-parse.awk rsc/radius-types-codes 		>>rgw_msg_codes.c
+echo "	/* fallback */ return \"[Unknown]\";"			>>rgw_msg_codes.c
+echo "}"							>>rgw_msg_codes.c
 
-awk -f register-parse.awk radius-types-codes > rg_utils_codes.inc
+
+
+echo "Rebuilding rgw_msg_attrtype.c..."
 
-echo "Rebuilding rg_utils_attrtype.inc..."
-echo "WARNING: radius-types-attrtypes has not been rebuilt"
+if [ -f rgw_msg_attrtype.c ];
+then mv -f rgw_msg_attrtype.c rgw_msg_attrtype.c.bak;
+fi
+
+# Same problem...
+echo "WARNING: rsc/radius-types-attrtypes has not been rebuilt"
 
-awk -f register-parse.awk radius-types-attrtypes > rg_utils_attrtype.inc
+echo "/*  Name of RADIUS attribute from its code */"	 	> rgw_msg_attrtype.c
+echo "const char * rgw_msg_attrtype_str(unsigned char c) {"	>>rgw_msg_attrtype.c
+awk -f rsc/register-parse.awk rsc/radius-types-attrtypes	>>rgw_msg_attrtype.c
+echo "	/* fallback */ return \"[Unknown]\";"			>>rgw_msg_attrtype.c
+echo "}"							>>rgw_msg_attrtype.c
 
-echo "Finished."
+
 
+echo "done."
--- a/extensions/radius_gw/sub_sample.c	Thu May 21 15:20:38 2009 +0900
+++ b/extensions/radius_gw/sub_sample.c	Fri May 22 18:11:49 2009 +0900
@@ -40,53 +40,54 @@
 #define DECLARE_API_POINTERS
 #include <waaad/waaad.h>
 
-#include "radius_gw.h"
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
+#include "rg_common.h"
 
 int sub_sample_verbosity = 2;
 
-struct sample_state {
+struct rga_conf_state {
 	char * conffile;
 };
 
-static void * sample_conf_parse(char * conffile)
+static struct rga_conf_state * sample_conf_parse(char * conffile)
 {
-	struct sample_state * ret = NULL;
+	struct rga_conf_state * ret = NULL;
 	
 	TRACE_ENTRY("%p", conffile);
 	
-	CHECK_MALLOC_DO( ret = malloc(sizeof(struct sample_state)), return NULL );
+	CHECK_MALLOC_DO( ret = malloc(sizeof(struct rga_conf_state)), return NULL );
 	
-	ret->conffile = conffile;
+	ret->conffile = conffile ?: "(NULL)";
 	
 	return ret;
 }
 
-static void sample_conf_free(void * conf)
+static void sample_conf_free(struct rga_conf_state * cs)
 {
-	TRACE_ENTRY("%p", conf);
-	CHECK_PARAMS_DO( conf, );
-	free(conf);
+	TRACE_ENTRY("%p", cs);
+	CHECK_PARAMS_DO( cs, );
+	free(cs);
 	return;
 }
 
-static int sample_rad_req(void * conf, sess_id_t ** session, rad_t ** rad_req, msg_t ** diam_fw )
+static int sample_rad_req(struct rga_conf_state * cs, sess_id_t ** session, struct radius_msg * rad_req, struct radius_msg ** rad_ans, msg_t ** diam_fw )
 {
-	TRACE_ENTRY("%p %p %p %p", conf, session, rad_req, diam_fw);
-	return ENOTSUP;
+	TRACE_ENTRY("%p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw);
+	CHECK_PARAMS(cs);
+	TRACE_DEBUG(INFO, "sample(%s): in rga_rad_req_cb...", cs->conffile);
+	return 0;
 }
 
-static int sample_diam_ans(void * conf, sess_id_t ** session, msg_t ** diam_ans, rad_t ** rad_fw )
+static int sample_diam_ans(struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw )
 {
-	TRACE_ENTRY("%p %p %p %p", conf, session, diam_ans, rad_fw);
-	return ENOTSUP;
+	TRACE_ENTRY("%p %p %p %p", cs, session, diam_ans, rad_fw);
+	CHECK_PARAMS(cs);
+	TRACE_DEBUG(INFO, "sample(%s): in rga_diam_ans_cb...", cs->conffile);
+	return 0;
 }
 
 int rga_register(int version, waaad_api_t * waaad_api, struct radius_gw_api * api)
 {
-	TRACE_ENTRY("%d %p", version, api);
+	TRACE_ENTRY("%d %p %p", version, waaad_api, api);
 	CHECK_PARAMS( waaad_api && api );
 	
 	if (version != RADIUS_GW_API_VER) {
@@ -94,12 +95,15 @@
 		return EINVAL;
 	}
 	
+	/* Required to use the waaad api from this sub-extension: */
 	EXTENSION_API_INIT_INTERN( API_MODULE_ALL, "sub_sample", waaad_api );
 	
+	/* Initialize the radius_gw api callbacks */
 	api->rga_conf_parse_cb = sample_conf_parse;
 	api->rga_conf_free_cb  = sample_conf_free;
 	api->rga_rad_req_cb    = sample_rad_req;
 	api->rga_diam_ans_cb   = sample_diam_ans;
 	
+	/* We're done, we must not initialize any state here since the extension must be re-entrant, but in sample_conf_parse */
 	return 0;
 }
"Welcome to our mercurial repository"