changeset 385:03b512313cc1

Added code to handle sessions
author Sebastien Decugis <sdecugis@nict.go.jp>
date Thu, 28 May 2009 13:32:37 +0900
parents 2bb3642696ec
children 31c6b1e0294d
files doc/sub_echo_drop.conf.sample extensions/radius_gw/CMakeLists.txt extensions/radius_gw/radius_gw.c extensions/radius_gw/radius_gw.h extensions/radius_gw/rg_api.h extensions/radius_gw/rg_common.h extensions/radius_gw/rg_utils.c extensions/radius_gw/rgw_clients.c extensions/radius_gw/rgw_extensions.c extensions/radius_gw/rgw_msg.c extensions/radius_gw/rgw_work.c extensions/radius_gw/sub_debug.c extensions/radius_gw/sub_echo_drop.c extensions/radius_gw/sub_sample.c
diffstat 14 files changed, 260 insertions(+), 39 deletions(-) [+]
line wrap: on
line diff
--- a/doc/sub_echo_drop.conf.sample	Thu May 28 11:29:24 2009 +0900
+++ b/doc/sub_echo_drop.conf.sample	Thu May 28 13:32:37 2009 +0900
@@ -35,3 +35,4 @@
 # DROP code 26 vendor 9 ; # Drop any Cisco-specific attribute
 # ECHO code 26 vendor 0 ext 256 ; # Echo any extended attribute with the type 256.
 
+ECHO code 33 ; # RADIUS Proxy-State attribute
--- a/extensions/radius_gw/CMakeLists.txt	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/CMakeLists.txt	Thu May 28 13:32:37 2009 +0900
@@ -59,6 +59,12 @@
 #  	   ADD_LIBRARY(sub_sample MODULE ${RG_COMMON_HEADER} sub_sample.c)
 # 	   TARGET_LINK_LIBRARIES(sub_sample rg_common)
 #  	ENDIF (BUILD_RADIUS_GW_SAMPLE)
+	
+OPTION(BUILD_SUB_DEBUG "Build debug sub-extension? (display status of RADIUS and Diameter messages)" ON)
+ 	IF (BUILD_SUB_DEBUG)
+ 	   ADD_LIBRARY(sub_debug MODULE ${RG_COMMON_HEADER} sub_debug.c)
+	   TARGET_LINK_LIBRARIES(sub_debug rg_common)
+ 	ENDIF (BUILD_SUB_DEBUG)
 
 OPTION(BUILD_SUB_ECHO_DROP "Build 'echo/drop' sub-extension? (echo or drop specific RADIUS attributes, no Diameter translation)" ON)
  	IF (BUILD_SUB_ECHO_DROP)
@@ -74,9 +80,3 @@
 		sub_echo_drop.tab.h)
 	   TARGET_LINK_LIBRARIES(sub_echo_drop rg_common)
  	ENDIF (BUILD_SUB_ECHO_DROP)
-	
-OPTION(BUILD_SUB_DEBUG "Build debug sub-extension? (display status of RADIUS and Diameter messages)" ON)
- 	IF (BUILD_SUB_DEBUG)
- 	   ADD_LIBRARY(sub_debug MODULE ${RG_COMMON_HEADER} sub_debug.c)
-	   TARGET_LINK_LIBRARIES(sub_debug rg_common)
- 	ENDIF (BUILD_SUB_DEBUG)
--- a/extensions/radius_gw/radius_gw.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/radius_gw.c	Thu May 28 13:32:37 2009 +0900
@@ -44,6 +44,8 @@
 
 static int rgw_init(void)
 {
+	CHECK_FCT( rgw_msg_init() );
+	
 	CHECK_FCT( rgw_servers_init() );
 	
 	CHECK_FCT( rgw_clients_init() );
--- a/extensions/radius_gw/radius_gw.h	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/radius_gw.h	Thu May 28 13:32:37 2009 +0900
@@ -96,6 +96,9 @@
 int rgw_msg_parse(unsigned char * buf, size_t len, struct rgw_radius_msg_meta ** msg);
 void rgw_msg_dump(struct rgw_radius_msg_meta * msg);
 int rgw_msg_auth_check(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, uint8_t * req_auth);
+int rgw_msg_create_base(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, sess_id_t ** session, msg_t ** diam);
+int rgw_msg_init(void);
+
 
 /* The clients allowed to connect to these servers */
 int rgw_clients_init(void);
@@ -103,6 +106,8 @@
 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);
+int rgw_clients_check_origin(struct rgw_radius_msg_meta *msg, struct rgw_client *cli);
+int rgw_clients_get_origin(struct rgw_client *cli, char * oh, size_t oh_len, char * or, size_t or_len,  char **fqdn, char **realm);
 void rgw_clients_dispose(struct rgw_client ** ref);
 void rgw_clients_dump(void);
 void rgw_clients_fini(void);
--- a/extensions/radius_gw/rg_api.h	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/rg_api.h	Thu May 28 13:32:37 2009 +0900
@@ -49,7 +49,7 @@
 	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 );
+	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, void * cli );
 	/* 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)
@@ -61,7 +61,7 @@
 	 */
 	
 	/* 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 );
+	int	(*rga_diam_ans_cb) ( struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw, void * cli );
 	/* ret 0: continue; ret >0: error; ret: -1 ... (tbd) */
 };
 
--- a/extensions/radius_gw/rg_common.h	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/rg_common.h	Thu May 28 13:32:37 2009 +0900
@@ -44,6 +44,8 @@
 #include <stdlib.h>
 #include <errno.h>
 #include <stdint.h>
+#include <dlfcn.h>
+
 
 /* This should be overwritten before including this file */
 #ifndef DEFINE_DEBUG_MACRO
@@ -95,6 +97,16 @@
 int rg_thread_term(pthread_t * th);
 void rg_cleanup_mutex(void * mtx);
 
+int rg_pointers_init(void ** hdl);
+void rg_pointers_fini(void **hdl);
+#define rg_pointers_resolve( ptr, hdl, fct, ret ) {				\
+	ptr = dlsym(hdl, #fct);							\
+	if (!ptr) {								\
+		TRACE_DEBUG(INFO, "Error in dlsym(" #fct "): %s", dlerror());	\
+		return ret;							\
+	}									\
+}
+
 
 /****************************************/
 /*      Debug and related stuff         */
--- a/extensions/radius_gw/rg_utils.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/rg_utils.c	Thu May 28 13:32:37 2009 +0900
@@ -126,4 +126,23 @@
 }
 
 
+/* Global functions not exported through the API (bad practice since no ABI control...) */
+int rg_pointers_init(void ** hdl)
+{
+	CHECK_PARAMS(hdl);
+	*hdl = dlopen(0, RTLD_LAZY);
+	if (!*hdl) {
+		TRACE_DEBUG(INFO, "Error in dlopen(0): %s", dlerror());
+		return ENOTSUP;
+	}
+	return 0;
+}
+void rg_pointers_fini(void **hdl)
+{
+	CHECK_PARAMS_DO(hdl, return);
+	dlclose(*hdl);
+	*hdl = NULL;
+	return;
+}
 
+
--- a/extensions/radius_gw/rgw_clients.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/rgw_clients.c	Thu May 28 13:32:37 2009 +0900
@@ -268,6 +268,22 @@
 	return 0;
 }
 
+int rgw_clients_check_origin(struct rgw_radius_msg_meta *msg, struct rgw_client *cli)
+{
+	/* Check that the NAS-IP-Adress or NAS-Identifier is coherent with the IP the packet was received from */
+	/* Also update the client FQDN and list of aliases if needed */
+	
+	ASSERT(0);
+	return ENOTSUP;
+}
+
+int rgw_clients_get_origin(struct rgw_client *cli, char * oh, size_t oh_len, char * or, size_t or_len,  char **fqdn, char **realm)
+{
+	ASSERT(0);
+	return ENOTSUP;
+}
+
+
 void rgw_clients_dispose(struct rgw_client ** ref)
 {
 	TRACE_ENTRY("%p", ref);
--- a/extensions/radius_gw/rgw_extensions.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/rgw_extensions.c	Thu May 28 13:32:37 2009 +0900
@@ -353,16 +353,17 @@
 	struct radius_msg * rad_ans = NULL;
 	
 	TRACE_ENTRY("%p %p %p %p", rad, session, diam_msg, cli);
-	CHECK_PARAMS( rad && *rad && session && diam_msg && cli );
+	CHECK_PARAMS( rad && *rad && session && *session && diam_msg && *diam_msg && cli);
 	
 	/* First, get the list of extensions for this message */
 	CHECK_FCT( get_accelerator(&head, (*rad)->radius.hdr->code, (*rad)->serv_type) );
 	
+	/* Loop in the list of extensions */
 	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->cs, session, &(*rad)->radius, &rad_ans, diam_msg);
+		ret = (*ext->api.rga_rad_req_cb)(ext->cs, session, &(*rad)->radius, &rad_ans, diam_msg, (void *)cli);
 		if (ret)
 			break;
 	}
--- a/extensions/radius_gw/rgw_msg.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/rgw_msg.c	Thu May 28 13:32:37 2009 +0900
@@ -86,6 +86,7 @@
 {
 	unsigned char * key;
 	size_t keylen;
+	int count;
 	
 	TRACE_ENTRY("%p %p %p", msg, cli, req_auth);
 	
@@ -93,7 +94,21 @@
 	
 	CHECK_FCT(rgw_clients_getkey(cli, &key, &keylen));
 	
-	msg->valid_mac = ! radius_msg_verify_msg_auth( &msg->radius, key, keylen, req_auth );
+	count = radius_msg_count_attr(&msg->radius, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, 0);
+	if (count > 1) {
+		TRACE_DEBUG(INFO, "Too many Message-Authenticator attributes (%d), discarding message.", count);
+		return EINVAL;
+	}
+	if (count == 0) {
+		TRACE_DEBUG(FULL, "Message does not contain a Message-Authenticator attributes.");
+		msg->valid_mac = 0;
+	} else {
+		if (radius_msg_verify_msg_auth( &msg->radius, key, keylen, req_auth )) {
+			TRACE_DEBUG(INFO, "Invalid Message-Authenticator received, discarding message.");
+			return EINVAL;
+		}
+		msg->valid_mac = 1;
+	}
 	
 	return 0;
 }
@@ -123,3 +138,137 @@
 	}
 	log_debug("-----------------------------\n");
 }
+
+static dict_object_t * rm_sess_id;
+static dict_object_t * rm_orig_host;
+static dict_object_t * rm_orig_realm;
+
+int rgw_msg_init(void)
+{
+	TRACE_ENTRY();
+	CHECK_FCT( dict_search(DICT_AVP, AVP_BY_NAME, "Session-Id", &rm_sess_id) );
+	CHECK_FCT( dict_search(DICT_AVP, AVP_BY_NAME, "Origin-Host", &rm_orig_host) );
+	CHECK_FCT( dict_search(DICT_AVP, AVP_BY_NAME, "Origin-Realm", &rm_orig_realm) );
+	return 0;
+}
+
+/* Create a msg with origin-host & realm, and session-id, and a session object from a RADIUS request message */
+int rgw_msg_create_base(struct rgw_radius_msg_meta * msg, struct rgw_client * cli, sess_id_t ** session, msg_t ** diam)
+{
+	int idx;
+	const char * prefix = "Diameter/";
+	size_t pref_len;
+	char * oh = NULL;
+	size_t oh_len = 0;
+	char * or = NULL;
+	size_t or_len = 0;
+	char * si = NULL;
+	size_t si_len = 0;
+	
+	char * fqdn;
+	char * realm;
+	char * sess_str = NULL;
+	
+	msg_avp_t *avp = NULL;
+	avp_value_t avp_val;
+	
+	TRACE_ENTRY("%p %p %p %p", msg, cli, session, diam);
+	CHECK_PARAMS( msg && cli && session && (*session == NULL) && diam && (*diam == NULL) );
+	
+	pref_len = strlen(prefix);
+	
+	/* Is there a State attribute with prefix "Diameter/" in the message? (in that case: Diameter/Origin-Host/Origin-Realm/Session-Id) */
+	/* Is there a Class attribute with prefix "Diameter/" in the message? (in that case: Diameter/Session-Id) */
+	for (idx = 0; idx < msg->radius.attr_used; idx++) {
+		struct radius_attr_hdr * attr = (struct radius_attr_hdr *)(msg->radius.buf + msg->radius.attr_pos[idx]);
+		char * attr_val = (char *)(attr + 1);
+		size_t attr_len = attr->length - sizeof(struct radius_attr_hdr);
+		
+		if ((attr->type == RADIUS_ATTR_STATE) 
+				&& (attr_len > pref_len + 5 /* for the '/'s and non empty strings */ ) 
+				&& ! strncmp(attr_val, prefix, pref_len)) { /* should we make it strncasecmp? */
+			int i, start;
+		
+			TRACE_DEBUG(ANNOYING, "Found a State attribute with '%s' prefix (attr #%d).", prefix, idx);
+
+			/* Now parse the value and check its content is valid. Unfortunately we cannot use strchr here since strings are not \0-terminated */
+
+			i = start = pref_len;
+			oh = attr_val + i;
+			for (; (i < attr_len - 2) && (attr_val[i] != '/'); i++) /* loop */;
+			if ( i >= attr_len - 2 ) continue; /* the attribute format is not good */
+			oh_len = i - 1 - start;
+
+			start = ++i;
+			or = attr_val + i;
+			for (; (i < attr_len - 1) && (attr_val[i] != '/'); i++) /* loop */;
+			if ( i >= attr_len - 1 ) continue; /* the attribute format is not good */
+			or_len = i - 1 - start;
+
+			i++;
+			si = attr_val + i;
+			si_len = attr_len - i;
+
+			TRACE_DEBUG(ANNOYING, "Attribute parsed successfully: OH:'%.*s' OR:'%.*s' SI:'%.*s'.", oh_len, oh, or_len, or, si_len, si);
+			break;
+		}
+		
+		if ((attr->type == RADIUS_ATTR_CLASS) 
+				&& (attr_len > pref_len ) 
+				&& ! strncmp(attr_val, prefix, pref_len)) {
+			si = attr_val + pref_len;
+			si_len = attr_len - pref_len;
+			TRACE_DEBUG(ANNOYING, "Found Class attribute with '%s' prefix (attr #%d), SI:'%.*s'.", prefix, idx, si_len, si);
+			break;
+		}
+	}
+	
+	/* Get information on this peer */
+	CHECK_FCT( rgw_clients_get_origin(cli, oh, oh_len, or, or_len, &fqdn, &realm) );
+	
+	/* Create the session object */
+	if (si_len) {
+		CHECK_FCT( sess_fromsid ( si, si_len, session, &idx) );
+	} else {
+		/* If not found, create a new Session-Id. The format is: {fqdn;hi32;lo32;gateway@localhost} */
+		const char * pfx = "gateway@";
+		CHECK_MALLOC( sess_str = malloc(strlen(fqdn) + 1 /* ';' */ + strlen(pfx) + strlen(g_pconf->diameter_identity) + 1 /* '\0' */) );
+		sprintf(sess_str, "%s;%s%s", fqdn, pfx, g_pconf->diameter_identity);
+		CHECK_FCT( sess_new(session, SESSION_NEW_OTHER, sess_str) );
+		free(sess_str);
+		idx = 1;
+	}
+	
+	CHECK_FCT( sess_getsid(*session, &sess_str) );
+	TRACE_DEBUG(FULL, "Session '%s' has been successfully %s.", sess_str, idx ? "created" : "retrieved");
+	
+	/* Create an empty Diameter message so that extensions can store their AVPs */
+	CHECK_FCT(  msg_new ( NULL, MSGFL_ALLOW_ETEID, diam )  );
+	
+	/* Add the Session-Id AVP as first AVP */
+	CHECK_FCT( msg_avp_new ( rm_sess_id, 0, &avp ) );
+	memset(&avp_val, 0, sizeof(avp_val));
+	avp_val.os.data = (unsigned char *)sess_str;
+	avp_val.os.len = strlen(sess_str);
+	CHECK_FCT( msg_avp_setvalue ( avp, &avp_val ) );
+	CHECK_FCT( msg_avp_add ( *diam, MSG_BRW_FIRST_CHILD, avp) );
+	
+	/* Add the Origin-Host as next AVP */
+	CHECK_FCT( msg_avp_new ( rm_orig_host, 0, &avp ) );
+	memset(&avp_val, 0, sizeof(avp_val));
+	avp_val.os.data = (unsigned char *)fqdn;
+	avp_val.os.len = strlen(fqdn);
+	CHECK_FCT( msg_avp_setvalue ( avp, &avp_val ) );
+	CHECK_FCT( msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
+	
+	/* Add the Origin-Realm as next AVP */
+	CHECK_FCT( msg_avp_new ( rm_orig_realm, 0, &avp ) );
+	memset(&avp_val, 0, sizeof(avp_val));
+	avp_val.os.data = (unsigned char *)realm;
+	avp_val.os.len = strlen(realm);
+	CHECK_FCT( msg_avp_setvalue ( avp, &avp_val ) );
+	CHECK_FCT( msg_avp_add ( *diam, MSG_BRW_LAST_CHILD, avp) );
+	
+	/* Done! */
+	return 0;
+}
--- a/extensions/radius_gw/rgw_work.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/rgw_work.c	Thu May 28 13:32:37 2009 +0900
@@ -137,11 +137,29 @@
 			continue; /* the message was a duplicate */
 		}
 		
-		/* Note: after this point, the radius message buffer may not be consistent with the array of attributes! */
+		/* Check that IP is coherent with the identity in the message */
+		CHECK_FCT_DO( rgw_clients_check_origin(msg, cli),
+			{
+				/* An error occurred, discard message */
+				rgw_msg_free(&msg);
+				rgw_clients_dispose(&cli);
+				continue;
+			}  );
+		
+		/* Note: after this point, the radius message buffer may not be consistent with the array of attributes anymore! */
+		
+		session = NULL;
+		diam_msg = NULL;
+		/* Create the session and empty message with some common AVPs */
+		CHECK_FCT_DO( rgw_msg_create_base(msg, cli, &session, &diam_msg),
+			{
+				/* An error occurred, discard message */
+				rgw_msg_free(&msg);
+				rgw_clients_dispose(&cli);
+				continue;
+			}  );
 		
 		/* Pass the message to the list of registered extensions */
-		session = NULL;
-		diam_msg = NULL;
 		CHECK_FCT_DO( rgw_extensions_loop_req(&msg, &session, &diam_msg, cli), 
 			{
 				/* An error occurred, discard message */
--- a/extensions/radius_gw/sub_debug.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/sub_debug.c	Thu May 28 13:32:37 2009 +0900
@@ -42,8 +42,6 @@
 
 #include "rg_common.h"
 
-#include <dlfcn.h>
-
 int sub_debug_verbosity = 2;
 
 struct rga_conf_state {
@@ -54,32 +52,32 @@
 
 static struct rga_conf_state * debug_conf_parse(char * conffile)
 {
-	struct rga_conf_state * ret;
+	struct rga_conf_state * cs;
 	
 	TRACE_ENTRY("%p", conffile);
 	
-	CHECK_MALLOC_DO( ret = malloc(sizeof(struct rga_conf_state)), return NULL );
-	memset(ret, 0, sizeof(struct rga_conf_state));
+	CHECK_MALLOC_DO( cs = malloc(sizeof(struct rga_conf_state)), return NULL );
+	memset(cs, 0, sizeof(struct rga_conf_state));
 	
 	if (conffile)
-		ret->conffile = conffile;
+		cs->conffile = conffile;
 	else
-		ret->conffile = "-";
+		cs->conffile = "-";
 	
-	CHECK_MALLOC_DO(ret->waaad_handle = dlopen(0, RTLD_LAZY), return NULL);
-
-	CHECK_MALLOC_DO(ret->waaad_msg_dump_walk = dlsym(ret->waaad_handle, "msg_dump_walk"), return NULL);
+	/* Resolve the msg_dump_walk function from main waaad image */
+	CHECK_FCT_DO( rg_pointers_init(&cs->waaad_handle), return NULL );
+	rg_pointers_resolve(cs->waaad_msg_dump_walk, cs->waaad_handle, msg_dump_walk, NULL);
 	
-	TRACE_DEBUG(INFO, "Sub extension Debug initialized with id: '%s'", ret->conffile);
+	TRACE_DEBUG(INFO, "Sub extension Debug initialized with id: '%s'", cs->conffile);
 	
-	return ret;
+	return cs;
 }
 
 static void debug_conf_free(struct rga_conf_state * cs)
 {
 	TRACE_ENTRY("%p", cs);
 	CHECK_PARAMS_DO(cs, return);
-	dlclose(cs->waaad_handle);
+	rg_pointers_fini(&cs->waaad_handle);
 	free(cs);
 	return;
 }
@@ -112,9 +110,9 @@
 	radius_msg_dump(msg);
 }
 
-static int debug_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 )
+static int debug_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, void * cli )
 {
-	TRACE_ENTRY("%p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw);
+	TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
 	
 	log_debug("sub_debug ( c:'%s' ) state dump start for incoming RADIUS message (session: %p->%p)\n", cs->conffile, session, session?*session:NULL);
 	
@@ -144,9 +142,9 @@
 	return 0;
 }
 
-static int debug_diam_ans(struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw )
+static int debug_diam_ans(struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw, void * cli )
 {
-	TRACE_ENTRY("%p %p %p %p", cs, session, diam_ans, rad_fw);
+	TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
 	CHECK_PARAMS(cs);
 	log_debug("sub_debug ( c:'%s' ) state dump start for incoming Diameter answer (session: %p->%p)\n", cs->conffile, session, session?*session:NULL);
 	
--- a/extensions/radius_gw/sub_echo_drop.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/sub_echo_drop.c	Thu May 28 13:32:37 2009 +0900
@@ -127,7 +127,7 @@
 }
 
 /* Handle attributes from a RADIUS request as specified in the configuration */
-static int sed_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 )
+static int sed_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, void * cli )
 {
 	size_t *nattr_pos;
 	size_t nattr_used = 0;
@@ -136,7 +136,7 @@
 	struct rg_list echo_list;
 	struct rg_list *li;
 	
-	TRACE_ENTRY("%p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw);
+	TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
 	CHECK_PARAMS(cs && rad_req);
 	
 	rg_list_init(&echo_list);
@@ -248,12 +248,12 @@
 }
 
 /* Process an answer: add back the ECHO attributes, if any */
-static int sed_diam_ans(struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw )
+static int sed_diam_ans(struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** rad_fw, void * cli )
 {
 	int ret;
 	struct rg_list * list = NULL;
 	
-	TRACE_ENTRY("%p %p %p %p", cs, session, diam_ans, rad_fw);
+	TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
 	CHECK_PARAMS(cs);
 	
 	/* If there is no session associated, just give up */
--- a/extensions/radius_gw/sub_sample.c	Thu May 28 11:29:24 2009 +0900
+++ b/extensions/radius_gw/sub_sample.c	Thu May 28 13:32:37 2009 +0900
@@ -70,17 +70,17 @@
 	return;
 }
 
-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 )
+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, void * cli )
 {
-	TRACE_ENTRY("%p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw);
+	TRACE_ENTRY("%p %p %p %p %p %p", cs, session, rad_req, rad_ans, diam_fw, cli);
 	CHECK_PARAMS(cs);
 	TRACE_DEBUG(INFO, "sample(%s): in rga_rad_req_cb...", cs->conffile);
 	return 0;
 }
 
-static int sample_diam_ans(struct rga_conf_state * cs, sess_id_t ** session, msg_t ** diam_ans, struct radius_msg ** 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, void * cli )
 {
-	TRACE_ENTRY("%p %p %p %p", cs, session, diam_ans, rad_fw);
+	TRACE_ENTRY("%p %p %p %p %p", cs, session, diam_ans, rad_fw, cli);
 	CHECK_PARAMS(cs);
 	TRACE_DEBUG(INFO, "sample(%s): in rga_diam_ans_cb...", cs->conffile);
 	return 0;
"Welcome to our mercurial repository"