changeset 1104:757df62cadb6

Merge
author Sebastien Decugis <sdecugis@freediameter.net>
date Fri, 10 May 2013 18:49:19 +0800
parents d8591b1c56cd (diff) a1d6e1980132 (current diff)
children 8401adfb58f5
files libfdcore/p_psm.c libfdproto/fifo.c
diffstat 82 files changed, 7925 insertions(+), 2234 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Fri May 10 09:50:09 2013 +0800
+++ b/CMakeLists.txt	Fri May 10 18:49:19 2013 +0800
@@ -6,15 +6,15 @@
 # Informations to display in daemon's help
 SET(FD_PROJECT_NAME freeDiameter)
 SET(FD_PROJECT_BINARY freeDiameterd)
-SET(FD_PROJECT_COPYRIGHT "Copyright (c) 2008-2011, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)")
+SET(FD_PROJECT_COPYRIGHT "Copyright (c) 2008-2013, WIDE Project (www.wide.ad.jp) and NICT (www.nict.go.jp)")
 
 # Version of the source code
 SET(FD_PROJECT_VERSION_MAJOR 1)
-SET(FD_PROJECT_VERSION_MINOR 1)
-SET(FD_PROJECT_VERSION_REV 6)
+SET(FD_PROJECT_VERSION_MINOR 2)
+SET(FD_PROJECT_VERSION_REV 0)
 
 # Version of the API with the library
-SET(FD_PROJECT_VERSION_API 5)
+SET(FD_PROJECT_VERSION_API 6)
 
 # The test framework, using CTest and CDash.
 INCLUDE(CTest)
--- a/contrib/debian/changelog	Fri May 10 09:50:09 2013 +0800
+++ b/contrib/debian/changelog	Fri May 10 18:49:19 2013 +0800
@@ -1,4 +1,4 @@
-freediameter (1.1.7) UNRELEASED; urgency=low
+freediameter (1.2.0) UNRELEASED; urgency=low
 
   * Major changes in the logging system to be more syslog and user friendly
   * New extension: dict_dcca_3gpp
@@ -6,6 +6,10 @@
   * New extension: rt_ignore_dh (hide network topology by proxying Destination-Host).
   * New extension: rt_load_balance (load balancer based on pending queue size).
   * New extension: rt_busypeers. See doc/rt_busypeers.conf.sample.
+  * New API (fd_hook_*) for extensions to control messages logging & profiling
+  * New API (fd_stats_*) for extensions to monitor framework state (e.g. SNMP implem)
+  * API changes: all the fd_*_dump functions now return strings instead of logging directly.
+  * Updated dbg_monitoring extension to use the new API
   * New script to generate dictionary extensions from org file (see contrib/tools)
   * New compilation option: WORKAROUND_ACCEPT_INVALID_VSAI to improve interoperability.
   * New compilation option: DISABLE_PEER_EXPIRY for use in test environments.
@@ -13,9 +17,10 @@
   * Copy Proxy-Info AVP automatically in new answers.
   * Port value 0 allowed in configuration to disable local server (e.g. disable non-secure port).
   * API change: fd_msg_send_timeout now takes a separate callback for timeout situation.
-  * New function: fd_msg_dump_full
+  * Function changes: fd_msg_dump_* now split in three different type of output.
+  * New test testmesg_stress to measure message parser performance
 
- -- Sebastien Decugis <sdecugis@freediameter.net>  Tue, 23 Apr 2013 16:30:28 +0800
+ -- Sebastien Decugis <sdecugis@freediameter.net>  Mon, 06 May 2013 10:45:26 +0800
 
 freediameter (1.1.6) UNRELEASED; urgency=low
 
--- a/doc/dbg_interactive.py.sample	Fri May 10 09:50:09 2013 +0800
+++ b/doc/dbg_interactive.py.sample	Fri May 10 18:49:19 2013 +0800
@@ -363,7 +363,6 @@
 # Create empt (as for avps, pass None or a dictionary object as 1st param, and flags as optional 2nd param)y
 a_msg = msg()
 a_msg.dump()
-a_msg.log(FD_MSG_LOG_DROPPED, "Check libfdproto for more details. Configure with fd_msg_log_config.")
 del a_msg
 
 # It is also possible to pass MSGFL_* flags in second parameter (ALLOC_ETEID is default)
--- a/extensions/CMakeLists.txt	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/CMakeLists.txt	Fri May 10 18:49:19 2013 +0800
@@ -85,6 +85,7 @@
 # Debug & test extensions
 
 FD_EXTENSION_SUBDIR(dbg_monitor "Outputs periodical status information"              OFF)
+FD_EXTENSION_SUBDIR(dbg_msg_timings "Show some timing information for messages"      OFF)
 FD_EXTENSION_SUBDIR(dbg_rt      "Routing extension for debugging the routing module" OFF)
 FD_EXTENSION_SUBDIR(test_app    "Testing application to send dummy message to another peer, like a Diameter 'ping'" OFF)
 FD_EXTENSION_SUBDIR(test_sip    "Testing application to simulate Diameter-SIP client (RFC4740)" OFF)
--- a/extensions/_sample/sample.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/_sample/sample.c	Fri May 10 18:49:19 2013 +0800
@@ -84,7 +84,6 @@
 		rule_data.rule_max = -1;
 		CHECK_FCT( fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ));
 		
-		fd_dict_dump_object(example_avp_avp);
 	}
 	TRACE_DEBUG(INFO, "'Example-AVP' created without error");
 	
--- a/extensions/app_diameap/diameap_eap.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_diameap/diameap_eap.c	Fri May 10 18:49:19 2013 +0800
@@ -372,7 +372,7 @@
 
 		case EAP_INTEGRITY_CHECK:
 			if ((*eap_sm->selectedMethod->eap_method_check)(eap_sm,
-					eap_i->aaaEapRespData) == FALSE)
+					&eap_i->aaaEapRespData) == FALSE)
 			{
 				TRACE_DEBUG(INFO,"%s[EAP Protocol] Invalid EAP packet received {Type=%d, Vendor=%d}. Integrity check failed (non fatal error).",DIAMEAP_EXTENSION,eap_sm->currentMethod,eap_sm->currentVendor);
 				//non_fata_error
@@ -433,7 +433,7 @@
 				}
 			}
 			if ((*eap_sm->selectedMethod->eap_method_process)(eap_sm,
-					eap_i->aaaEapRespData))
+					&eap_i->aaaEapRespData))
 			{
 				TRACE_DEBUG(INFO,"%s[EAP Protocol] [%s plugin] Authentication process failed.",DIAMEAP_EXTENSION,eap_sm->selectedMethod->methodname);
 				*non_fatal_error = TRUE;
--- a/extensions/app_diameap/diameap_plugins.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_diameap/diameap_plugins.c	Fri May 10 18:49:19 2013 +0800
@@ -262,7 +262,7 @@
 		if (registerplugin->check)
 		{
 			plugin->eap_method_check = (boolean(*)(struct eap_state_machine *,
-					struct eap_packet)) dlsym(plugin->handler,
+					struct eap_packet*)) dlsym(plugin->handler,
 					registerplugin->check);
 			if (plugin->eap_method_check == NULL)
 			{
@@ -284,7 +284,7 @@
 		if (registerplugin->process)
 		{
 			plugin->eap_method_process = (int(*)(struct eap_state_machine *,
-					struct eap_packet)) dlsym(plugin->handler,
+					struct eap_packet*)) dlsym(plugin->handler,
 					registerplugin->process);
 			if (plugin->eap_method_process == NULL)
 			{
--- a/extensions/app_diameap/diameap_server.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_diameap/diameap_server.c	Fri May 10 18:49:19 2013 +0800
@@ -84,11 +84,9 @@
 
 
 
-void diameap_cli_sess_cleanup(void * arg, char * sid, void * opaque)
+void diameap_cli_sess_cleanup(struct sess_state * diameap_sess_data, os0_t sid, void * opaque)
 {
 
-	struct diameap_sess_data_sm * diameap_sess_data =
-			(struct diameap_sess_data_sm *) arg;
 	CHECK_PARAMS_DO( diameap_sess_data, return );
 
 	if (diameap_sess_data != NULL)
@@ -140,7 +138,7 @@
 
 static int diameap_initialize_diameap_sm(
 		struct diameap_state_machine * diameap_sm,
-		struct diameap_sess_data_sm * diameap_sess_data)
+		struct sess_state * diameap_sess_data)
 {
 	TRACE_ENTRY("%p %p", diameap_sm, diameap_sess_data);
 
@@ -1016,7 +1014,7 @@
 
 
 static int diameap_sess_data_new(
-		struct diameap_sess_data_sm *diameap_sess_data,
+		struct sess_state *diameap_sess_data,
 		struct diameap_state_machine *diameap_sm)
 {
 	if (!diameap_sm)
@@ -3063,7 +3061,7 @@
 {
 	TRACE_ENTRY("%p %p %p %p", rmsg, ravp, sess, action);
 
-	struct diameap_sess_data_sm * diameap_sess_data = NULL;
+	struct sess_state * diameap_sess_data = NULL;
 	struct diameap_state_machine * diameap_sm = NULL;
 	struct diameap_eap_interface eap_i;
 	struct msg *req, *ans;
@@ -3257,9 +3255,9 @@
 			;
 			TRACE_DEBUG(FULL+1,"%sStoring DiamEAP session data.",DIAMEAP_EXTENSION)
 			;
-			CHECK_MALLOC(diameap_sess_data = malloc(sizeof(struct diameap_sess_data_sm)))
+			CHECK_MALLOC(diameap_sess_data = malloc(sizeof(struct sess_state)))
 			;
-			memset(diameap_sess_data, 0, sizeof(struct diameap_sess_data_sm));
+			memset(diameap_sess_data, 0, sizeof(struct sess_state));
 			diameap_sess_data_new(diameap_sess_data, diameap_sm);
 
 			CHECK_FCT_DO(fd_sess_state_store(diameap_server_reg, sess, &diameap_sess_data),
@@ -3388,7 +3386,7 @@
 	struct disp_when when;
 
 	/*create handler for sessions */
-	CHECK_FCT(fd_sess_handler_create(&diameap_server_reg, diameap_cli_sess_cleanup, NULL));
+	CHECK_FCT(fd_sess_handler_create(&diameap_server_reg, diameap_cli_sess_cleanup, NULL, NULL));
 
 	/* Register the callback */
 	memset(&when, 0, sizeof(when));
--- a/extensions/app_diameap/diameap_server.h	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_diameap/diameap_server.h	Fri May 10 18:49:19 2013 +0800
@@ -39,9 +39,9 @@
 #ifndef DIAMEAP_SERVER_H_
 #define DIAMEAP_SERVER_H_
 
-
+ 
 /* session data structure to store */
-struct diameap_sess_data_sm
+struct sess_state
 {
 	int invalid_eappackets; /* Number of invalid EAP Packet received*/
 
--- a/extensions/app_diameap/libdiameap.h	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_diameap/libdiameap.h	Fri May 10 18:49:19 2013 +0800
@@ -109,9 +109,9 @@
 			u8 identifier,struct eap_packet * eapPacket); /* address of the eap_method_buildReq method */
 	int (*eap_method_getTimeout)(struct eap_state_machine *smd, int * timeout); /* address of the eap_method_getTimeout method */
 	boolean (*eap_method_check)(struct eap_state_machine *smd,
-			struct eap_packet eapRespData); /* address of the eap_method_check method */
+			struct eap_packet * eapRespData); /* address of the eap_method_check method */
 	int (*eap_method_process)(struct eap_state_machine *smd,
-			struct eap_packet eapRespData); /* address of the eap_method_process method */
+			struct eap_packet * eapRespData); /* address of the eap_method_process method */
 	boolean (*eap_method_isDone)(struct eap_state_machine *smd); /* address of the eap_method_isDone method */
 	int (*eap_method_getKey)(struct eap_state_machine *smd, u8 ** msk,int *msklength, 
 			u8 ** emsk,int *emsklength); /* address of the eap_method_getKey method */
--- a/extensions/app_radgw/rgwx_acct.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_radgw/rgwx_acct.c	Fri May 10 18:49:19 2013 +0800
@@ -159,6 +159,11 @@
 	uint32_t	 term_cause;	/* If not 0, the Termination-Cause to put in the STR. */
 };
 
+static DECLARE_FD_DUMP_PROTOTYPE(acct_conf_session_state_dump, struct sess_state * st)
+{
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "[rgwx sess_state](@%p): aai:%x str:%d TC:%u", st, st->auth_appl, st->send_str, st->term_cause);
+}
+
 /* Initialize the plugin */
 static int acct_conf_parse(char * conffile, struct rgwp_config ** state)
 {
@@ -171,7 +176,7 @@
 	CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
 	memset(new, 0, sizeof(struct rgwp_config));
 	
-	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
+	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, (void *)free, acct_conf_session_state_dump, NULL ) );
 	new->confstr = conffile;
 	
 	if (conffile && strstr(conffile, "nonai"))
--- a/extensions/app_radgw/rgwx_auth.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_radgw/rgwx_auth.c	Fri May 10 18:49:19 2013 +0800
@@ -124,6 +124,11 @@
 	int ignore_nai;
 };
 
+struct sess_state {
+	char req_auth[16];
+};
+
+
 /* Initialize the plugin */
 static int auth_conf_parse(char * confstr, struct rgwp_config ** state)
 {
@@ -136,7 +141,7 @@
 	CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
 	memset(new, 0, sizeof(struct rgwp_config));
 	
-	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
+	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, (void *)free, NULL, NULL ) );
 	new->confstr = confstr;
 	
 	if (confstr && strstr(confstr, "nonai"))
@@ -1056,11 +1061,11 @@
 
 	/* Store the request identifier in the session (if provided) */
 	{
-		unsigned char * req_auth;
-		CHECK_MALLOC(req_auth = malloc(16));
-		memcpy(req_auth, &rad_req->hdr->authenticator[0], 16);
+		struct sess_state  *st;
+		CHECK_MALLOC(st = malloc(sizeof(struct sess_state)));
+		memcpy(st->req_auth, &rad_req->hdr->authenticator[0], 16);
 		
-		CHECK_FCT( fd_sess_state_store( cs->sess_hdl, sess, &req_auth ) );
+		CHECK_FCT( fd_sess_state_store( cs->sess_hdl, sess, &st ) );
 	}
 	
 	return 0;
@@ -1076,7 +1081,7 @@
 	int ta_set = 0;
 	int no_str = 0; /* indicate if an STR is required for this server */
 	uint8_t	tuntag = 0;
-	unsigned char * req_auth = NULL;
+	struct sess_state  *st;
 	int error_cause = 0;
 	struct session * sess;
 	os0_t sid = NULL;
@@ -1088,7 +1093,7 @@
 	/* Retrieve the request identified which was stored in the session */
 	CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, *diam_ans, &sess, NULL) );
 	if (sess) {
-		CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, sess, &req_auth ) );
+		CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, sess, &st ) );
 		CHECK_FCT( fd_sess_getsid(sess, &sid, &sidlen) );
 	} /* else ? */
 	
@@ -1758,7 +1763,7 @@
 											size_t len[3];
 											
 											/* We need the request authenticator */
-											CHECK_PARAMS(req_auth);
+											CHECK_PARAMS(st);
 
 											/* Retrieve the shared secret */
 											CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
@@ -1777,7 +1782,7 @@
 											/* Initial b1 = MD5(S + R + A) */
 											addr[0] = secret;
 											len[0] = secret_len;
-											addr[1] = req_auth;
+											addr[1] = st->req_auth;
 											len[1] = 16;
 											addr[2] = &buf[1];
 											len[2] = 2;
@@ -1852,7 +1857,7 @@
 						size_t recv_len, send_len;
 
 						/* We need the request authenticator */
-						CHECK_PARAMS(req_auth);
+						CHECK_PARAMS(st);
 
 						/* Retrieve the shared secret */
 						CHECK_FCT(rgw_clients_getkey(cli, &secret, &secret_len));
@@ -1865,7 +1870,7 @@
 						recv_len = ahdr->avp_value->os.len >= 32 ? 32 : ahdr->avp_value->os.len;
 						send_len = ahdr->avp_value->os.len - recv_len;
 						
-						if ( ! radius_msg_add_mppe_keys(*rad_fw, req_auth, secret, secret_len, 
+						if ( ! radius_msg_add_mppe_keys(*rad_fw, st->req_auth, secret, secret_len, 
 								ahdr->avp_value->os.data + recv_len, send_len,
 								ahdr->avp_value->os.data, recv_len) ) {
 							TRACE_DEBUG(INFO, "Error while converting EAP-Master-Session-Key to RADIUS message");
@@ -1924,7 +1929,7 @@
 	}
 	
 	CHECK_FCT( fd_msg_free( aoh ) );
-	free(req_auth);
+	free(st);
 	
 	if (error_cause) {
 		if ( ! radius_msg_add_attr_int32(*rad_fw, RADIUS_ATTR_ERROR_CAUSE, error_cause) ) {
--- a/extensions/app_radgw/rgwx_echodrop.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_radgw/rgwx_echodrop.c	Fri May 10 18:49:19 2013 +0800
@@ -37,20 +37,31 @@
 
 #include "rgwx_echodrop.h"
 
+struct sess_state {
+	struct fd_list sentinel;
+};
+
 /* If a session is destroyed, empty the list of ed_saved_attribute */
-static void state_delete(void * arg, char * sid, void * opaque) {
-	struct fd_list * list = (struct fd_list *)arg;
-	
-	CHECK_PARAMS_DO( list, return );
-	
-	while (!FD_IS_LIST_EMPTY(list)) {
-		struct ed_saved_attribute * esa = (struct ed_saved_attribute *)(list->next);
+static void state_delete(struct sess_state * arg, os0_t sid, void * opaque) {
+	while (!FD_IS_LIST_EMPTY(&arg->sentinel)) {
+		struct ed_saved_attribute * esa = (struct ed_saved_attribute *)(arg->sentinel.next);
 		fd_list_unlink(&esa->chain);
 		free(esa);
 	}
-	free(list);
+	free(arg);
 }
 
+static DECLARE_FD_DUMP_PROTOTYPE(ed_session_state_dump, struct sess_state * st)
+{
+	struct fd_list * li;
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "[rgwx sess_state](@%p):\n", st), return NULL);	
+	for (li = st->sentinel.next; li != &st->sentinel; li = li->next) {
+		struct ed_saved_attribute * esa = (struct ed_saved_attribute *)(li);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "[rgwx sess_state {esa}] t:%2hhx l:%2hhx d:", esa->attr.type, esa->attr.length), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend_hexdump(FD_DUMP_STD_PARAMS, (&esa->attr.length) + 1, esa->attr.length - 2, 0,0), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+	}
+}
 
 /* Initialize the plugin and parse the configuration. */
 static int ed_conf_parse(char * conffile, struct rgwp_config ** state)
@@ -68,7 +79,7 @@
 	fd_list_init(&new->attributes, NULL);
 	
 	/* Create the session handler */
-	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, state_delete, NULL ) );
+	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, state_delete, ed_session_state_dump, NULL ) );
 	
 	/* Parse the configuration file */
 	CHECK_FCT( ed_conffile_parse(conffile, new) );
@@ -216,6 +227,7 @@
 	/* Save the echoed values in the session, if any */
 	if (!FD_IS_LIST_EMPTY(&echo_list)) {
 		struct session * sess;
+		struct sess_state * st;
 		
 		CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, *diam_fw, &sess, NULL) );
 
@@ -228,12 +240,12 @@
 			} );
 		
 		/* Move the values in a dynamically allocated list */
-		CHECK_MALLOC( li = malloc(sizeof(struct fd_list)) );
-		fd_list_init(li, NULL);
-		fd_list_move_end(li, &echo_list);
+		CHECK_MALLOC( st = malloc(sizeof(struct sess_state)) );
+		fd_list_init(&st->sentinel, NULL);
+		fd_list_move_end(&st->sentinel, &echo_list);
 		
 		/* Save the list in the session */
-		CHECK_FCT( fd_sess_state_store( cs->sess_hdl, sess, &li ) );
+		CHECK_FCT( fd_sess_state_store( cs->sess_hdl, sess, &st ) );
 	}
 	
 	return 0;
@@ -242,8 +254,8 @@
 /* Process an answer: add the ECHO attributes back, if any */
 static int ed_diam_ans( struct rgwp_config * cs, struct msg ** diam_ans, struct radius_msg ** rad_fw, struct rgw_client * cli )
 {
-	struct fd_list * list = NULL;
 	struct session * sess;
+	struct sess_state * st;
 	
 	TRACE_ENTRY("%p %p %p %p", cs, diam_ans, rad_fw, cli);
 	CHECK_PARAMS(cs);
@@ -257,8 +269,8 @@
 	}
 	
 	/* Now try and retrieve any data from the session */
-	CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, sess, &list ) );
-	if (list == NULL) {
+	CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, sess, &st ) );
+	if (st == NULL) {
 		/* No attribute saved in the session, just return */
 		return 0;
 	}
@@ -267,8 +279,8 @@
 	
 	CHECK_PARAMS( rad_fw && *rad_fw);
 	
-	while (! FD_IS_LIST_EMPTY(list) ) {
-		struct ed_saved_attribute * esa = (struct ed_saved_attribute *)(list->next);
+	while (! FD_IS_LIST_EMPTY(&st->sentinel) ) {
+		struct ed_saved_attribute * esa = (struct ed_saved_attribute *)(st->sentinel.next);
 		
 		fd_list_unlink(&esa->chain);
 		
@@ -279,7 +291,7 @@
 		
 		free(esa);
 	}
-	free(list);
+	free(st);
 
 	return 0;
 }
--- a/extensions/app_radgw/rgwx_sip.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_radgw/rgwx_sip.c	Fri May 10 18:49:19 2013 +0800
@@ -133,7 +133,6 @@
 		
 		
 	} dict; /* cache of the dictionary objects we use */
-	struct session_handler * sess_hdl; /* We store RADIUS request authenticator information in the session */
 	char * confstr;
 	//Chained list of nonce
 	struct fd_list listnonce;
@@ -257,7 +256,6 @@
 	CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
 	memset(new, 0, sizeof(struct rgwp_config));
 	
-	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
 	new->confstr = conffile;
 	
 	/* Resolve all dictionary objects we use */
@@ -311,8 +309,6 @@
 	TRACE_ENTRY("%p", state);
 	CHECK_PARAMS_DO( state, return );
 	
-	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl, NULL ),  );
-	
 	nonce_deletelistnonce(state);
 	CHECK_POSIX_DO(pthread_mutex_destroy(&state->nonce_mutex), /*continue*/);
 	
@@ -320,7 +316,6 @@
 	return;
 }
 
-
 /* Handle an incoming RADIUS request */
 static int sip_rad_req( struct rgwp_config * cs, struct radius_msg * rad_req, struct radius_msg ** rad_ans, struct msg ** diam_fw, struct rgw_client * cli )
 {
@@ -716,15 +711,6 @@
 
 	//fd_msg_dump_walk(1,*diam_fw);
 	
-	/* Store the request identifier in the session */
-	{
-		unsigned char * req_sip;
-		CHECK_MALLOC(req_sip = malloc(16));
-		memcpy(req_sip, &rad_req->hdr->authenticator[0], 16);
-		
-		CHECK_FCT( fd_sess_state_store( cs->sess_hdl, sess, &req_sip ) );
-	}
-	
 	
 	return 0;
 }
@@ -856,9 +842,6 @@
 		}
 	}
 	
-	CHECK_FCT( fd_sess_state_retrieve( cs->sess_hdl, sess, &req_sip ) );
-	free(req_sip);
-	
 	return 0;
 }
 
--- a/extensions/app_sip/app_sip.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_sip/app_sip.c	Fri May 10 18:49:19 2013 +0800
@@ -212,7 +212,7 @@
 	if(start_mysql_connection())
 		return EINVAL;
 	
-	CHECK_FCT(fd_sess_handler_create(&ds_sess_hdl, free, NULL));
+	CHECK_FCT(fd_sess_handler_create(&ds_sess_hdl, (void *)free, NULL, NULL));
 	
 	//Creation of thread for Registration Termination	
 	if(pthread_create(&rtr_thread, NULL,rtr_socket, NULL))
--- a/extensions/app_sip/app_sip.h	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_sip/app_sip.h	Fri May 10 18:49:19 2013 +0800
@@ -212,11 +212,6 @@
 #define CODE_SIP_USER_DATA_TYPE	388
 #define CODE_SIP_AOR	122
 
-struct ds_nonce
-{
-	char *nonce;
-};
-
 //Storage for some useful AVPs
 struct app_sip_dict{
 	struct dict_object * Auth_Session_State;
--- a/extensions/app_sip/multimediaauth.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/app_sip/multimediaauth.c	Fri May 10 18:49:19 2013 +0800
@@ -35,6 +35,11 @@
 *********************************************************************************************************/
 #include "app_sip.h"
 
+struct sess_state
+{
+	char *nonce;
+};
+
 
 int app_sip_MAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
@@ -55,7 +60,7 @@
 	unsigned char *username=NULL;
 	
 	//The nonce we will store and retrieve in session
-	struct ds_nonce *storednonce=NULL;
+	struct sess_state *storednonce=NULL;
 	
 	
 	TRACE_ENTRY("%p %p %p %p", msg, paramavp, sess, act);
@@ -361,8 +366,8 @@
 									
 									
 									//We store the nonce (storednonce structure) inside the session
-									storednonce=malloc(sizeof(struct ds_nonce));
-									memset(storednonce,0,sizeof(struct ds_nonce));
+									storednonce=malloc(sizeof(struct sess_state));
+									memset(storednonce,0,sizeof(struct sess_state));
 									CHECK_MALLOC(storednonce->nonce=malloc(NONCE_SIZE*2+1));
 									memcpy(storednonce->nonce,(char *)nonce,NONCE_SIZE*2+1);
 									CHECK_FCT( fd_sess_state_store ( ds_sess_hdl, sess, &storednonce ));  
--- a/extensions/dbg_interactive/dictionary.i	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dbg_interactive/dictionary.i	Fri May 10 18:49:19 2013 +0800
@@ -59,7 +59,10 @@
 		return;
 	}
 	void dump() {
-		fd_dict_dump($self);
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_dict_dump(&buf, &len, NULL, $self));
+		free(buf);
 	}
 	PyObject * vendors_list() {
 		uint32_t *list = NULL, *li;
@@ -127,7 +130,10 @@
 
 %extend dict_object {
 	void dump() {
-		fd_dict_dump_object($self);
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_dict_dump_object(&buf, &len, NULL, $self));
+		free(buf);
 	}
 	enum dict_object_type gettype() {
 		enum dict_object_type t;
--- a/extensions/dbg_interactive/endpoints.i	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dbg_interactive/endpoints.i	Fri May 10 18:49:19 2013 +0800
@@ -125,6 +125,9 @@
 	}
 	
 	void dump() {
-		fd_ep_dump_one( "", $self );
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_ep_dump_one(&buf, &len, NULL, $self));
+		free(buf);
 	}
 }
--- a/extensions/dbg_interactive/messages.i	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dbg_interactive/messages.i	Fri May 10 18:49:19 2013 +0800
@@ -290,15 +290,10 @@
 	
 	/* Dump */
 	void dump (int tree = 1) {
-		if (tree)
-			fd_msg_dump_walk(0, $self);
-		else
-			fd_msg_dump_one(0, $self);
-	}
-	
-	/* Log to file (depending on config)  */
-	void log ( enum fd_msg_log_cause cause, char * message ) {
-		fd_msg_log( cause, $self, message );
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_msg_dump_treeview(&buf, &len, NULL, $self, NULL, 0, tree));
+		free(buf);
 	}
 	
 	/* Model */
@@ -574,10 +569,10 @@
 	
 	/* Dump */
 	void dump (int tree = 1) {
-		if (tree)
-			fd_msg_dump_walk(0, $self);
-		else
-			fd_msg_dump_one(0, $self);
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_msg_dump_treeview(&buf, &len, NULL, $self, NULL, 0, tree));
+		free(buf);
 	}
 	
 	/* Model */
--- a/extensions/dbg_interactive/queues.i	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dbg_interactive/queues.i	Fri May 10 18:49:19 2013 +0800
@@ -65,12 +65,7 @@
 	
 	/* Get the length of the queue (nb elements) */
 	int length() {
-		int l;
-		int ret = fd_fifo_length ( $self, &l );
-		if (ret != 0) {
-			DI_ERROR(ret, NULL, NULL);
-		}
-		return l;
+		return fd_fifo_length ( $self ) ;
 	}
 
 	/* Is the threashold function useful here? TODO... */
--- a/extensions/dbg_interactive/sessions.i	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dbg_interactive/sessions.i	Fri May 10 18:49:19 2013 +0800
@@ -38,8 +38,12 @@
 /****** SESSIONS *********/
 
 %{
+struct sess_state {
+	PyObject * pystate;
+};
+
 /* call it (might be called from a different thread than the interpreter, when session times out) */
-static void call_the_python_cleanup_callback(session_state * state, os0_t sid, void * cb) {
+static void call_the_python_cleanup_callback(struct sess_state * state, os0_t sid, void * cb) {
 	PyObject *result;
 	if (!cb) {
 		fd_log_debug("Internal error: missing callback object!");
@@ -66,7 +70,7 @@
 		
 		Py_XINCREF(PyCb);
 		
-		ret = fd_sess_handler_create_internal ( &hdl, call_the_python_cleanup_callback, PyCb );
+		ret = fd_sess_handler_create ( &hdl, call_the_python_cleanup_callback, NULL, PyCb );
 		if (ret != 0) {
 			DI_ERROR(ret, NULL, NULL);
 			return NULL;
@@ -86,7 +90,10 @@
 		return;
 	}
 	void dump() {
-		fd_sess_dump_hdl(0, $self);
+		char * buf = NULL;
+		size_t len;
+		printf("%s", fd_sess_dump_hdl(&buf, &len, NULL, $self));
+		free(buf);
 	}
 }
 
@@ -165,13 +172,18 @@
 		}
 	}
 	void dump() {
-		fd_sess_dump(0, $self);
+		char * buf = NULL;
+		size_t len = 0;
+		printf("%s", fd_sess_dump(&buf, &len, NULL, $self, 1) );
+		free(buf);
 	}
 	void store(struct session_handler * handler, PyObject * DISOWN) {
 		int ret;
-		void * store = DISOWN;
+		struct sess_state * st = NULL;
+		st = malloc(sizeof(struct sess_state));
+		st->pystate = DISOWN;
 		Py_XINCREF(DISOWN);
-		ret = fd_sess_state_store_internal(handler, $self, (void *) &store);
+		ret = fd_sess_state_store(handler, $self, (void *) &st);
 		if (ret != 0) {
 			DI_ERROR(ret, NULL, NULL);
 		}
@@ -179,16 +191,19 @@
 	%newobject retrieve;
 	PyObject * retrieve(struct session_handler * handler) {
 		int ret;
+		struct sess_state * st = NULL;
 		PyObject * state = NULL;
-		ret = fd_sess_state_retrieve_internal(handler, $self, (void *) &state);
+		ret = fd_sess_state_retrieve(handler, $self, (void *) &st);
 		if (ret != 0) {
 			DI_ERROR(ret, NULL, NULL);
 			return NULL;
 		}
-		if (state == NULL) {
+		if (st == NULL) {
 			Py_INCREF(Py_None);
 			return Py_None;
 		}
+		state = st->pystate;
+		free(st);
 		return state;
 	}
 }	
--- a/extensions/dbg_monitor/dbg_monitor.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dbg_monitor/dbg_monitor.c	Fri May 10 18:49:19 2013 +0800
@@ -49,40 +49,103 @@
 
 EXTENSION_ENTRY("dbg_monitor", monitor_main);
 
+
+
+/* Display information about a queue */
+static void display_info(char * queue_desc, char * peer, int current_count, int limit_count, int highest_count, long long total_count,
+			struct timespec * total, struct timespec * blocking, struct timespec * last)
+{
+	long long us = (total->tv_sec * 1000000) + (total->tv_nsec / 1000);
+	long double throughput = (long double)total_count * 1000000;
+	throughput /= us;
+	if (peer) {
+		TRACE_DEBUG(INFO, "'%s'@'%s': cur:%d/%d, h:%d, T:%lld in %ld.%06lds (%.2LFitems/s), blocked:%ld.%06lds, last processing:%ld.%06lds",
+			queue_desc, peer, current_count, limit_count, highest_count,
+			total_count, total->tv_sec, total->tv_nsec/1000, throughput,
+			blocking->tv_sec, blocking->tv_nsec/1000, last->tv_sec, last->tv_nsec/1000);
+	} else {
+		TRACE_DEBUG(INFO, "Global '%s': cur:%d/%d, h:%d, T:%lld in %ld.%06lds (%.2LFitems/s), blocked:%ld.%06lds, last processing:%ld.%06lds",
+			queue_desc, current_count, limit_count, highest_count,
+			total_count, total->tv_sec, total->tv_nsec/1000, throughput,
+			blocking->tv_sec, blocking->tv_nsec/1000, last->tv_sec, last->tv_nsec/1000);
+	}
+}
+
 /* Thread to display periodical debug information */
 static pthread_t thr;
 static void * mn_thr(void * arg)
 {
 	int i = 0;
 	fd_log_threadname("Monitor thread");
+	char * buf = NULL;
+	size_t len;
 	
 	/* Loop */
 	while (1) {
+		int current_count, limit_count, highest_count;
+		long long total_count;
+		struct timespec total, blocking, last;
+		struct fd_list * li;
+	
 		#ifdef DEBUG
 		for (i++; i % 30; i++) {
 			fd_log_debug("[dbg_monitor] %ih%*im%*is", i/3600, 2, (i/60) % 60 , 2, i%60); /* This makes it easier to detect inactivity periods in the log file */
 			sleep(1);
 		}
 		#else /* DEBUG */
-		sleep(3600); /* 1 hour */
+		sleep(3599); /* 1 hour */
 		#endif /* DEBUG */
-		fd_log_debug("[dbg_monitor] Dumping current information");
-		CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, 0, NULL), /* continue */);
-		CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_SERV, 0, NULL), /* continue */);
-		CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, 0, NULL), /* continue */);
+		TRACE_DEBUG(INFO, "[dbg_monitor] Dumping queues statistics");
+		
+		CHECK_FCT_DO( fd_stat_getstats(STAT_G_LOCAL, NULL, &current_count, &limit_count, &highest_count, &total_count, &total, &blocking, &last), );
+		display_info("Local delivery", NULL, current_count, limit_count, highest_count, total_count, &total, &blocking, &last);
+		
+		CHECK_FCT_DO( fd_stat_getstats(STAT_G_INCOMING, NULL, &current_count, &limit_count, &highest_count, &total_count, &total, &blocking, &last), );
+		display_info("Total received", NULL, current_count, limit_count, highest_count, total_count, &total, &blocking, &last);
+		
+		CHECK_FCT_DO( fd_stat_getstats(STAT_G_OUTGOING, NULL, &current_count, &limit_count, &highest_count, &total_count, &total, &blocking, &last), );
+		display_info("Total sending", NULL, current_count, limit_count, highest_count, total_count, &total, &blocking, &last);
+		
+		
+		CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
+
+		for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
+			struct peer_hdr * p = (struct peer_hdr *)li->o;
+			
+			TRACE_DEBUG(INFO, "%s", fd_peer_dump(&buf, &len, NULL, p, 1));
+			
+			CHECK_FCT_DO( fd_stat_getstats(STAT_P_PSM, p, &current_count, &limit_count, &highest_count, &total_count, &total, &blocking, &last), );
+			display_info("Events, incl. recept", p->info.pi_diamid, current_count, limit_count, highest_count, total_count, &total, &blocking, &last);
+			
+			CHECK_FCT_DO( fd_stat_getstats(STAT_P_TOSEND, p, &current_count, &limit_count, &highest_count, &total_count, &total, &blocking, &last), );
+			display_info("Outgoing", p->info.pi_diamid, current_count, limit_count, highest_count, total_count, &total, &blocking, &last);
+			
+		}
+
+		CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
+		
+		TRACE_DEBUG(INFO, "[dbg_monitor] Dumping servers information");
+		TRACE_DEBUG(INFO, "%s", fd_servers_dump(&buf, &len, NULL));
+		
 		sleep(1);
 	}
 	
+	free(buf);
 	return NULL;
 }
 
 /* Function called on receipt of MONITOR_SIGNAL */
 static void got_sig()
 {
-	fd_log_debug("[dbg_monitor] Dumping extra information");
-	CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, 0, NULL), /* continue */);
-	CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, 0, NULL), /* continue */);
-	CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, 0, NULL), /* continue */);
+	char * buf = NULL;
+	size_t len;
+	TRACE_DEBUG(INFO, "[dbg_monitor] Dumping config information");
+	TRACE_DEBUG(INFO, "%s", fd_conf_dump(&buf, &len, NULL));
+	TRACE_DEBUG(INFO, "[dbg_monitor] Dumping extensions information");
+	TRACE_DEBUG(INFO, "%s", fd_ext_dump(&buf, &len, NULL));
+	TRACE_DEBUG(INFO, "[dbg_monitor] Dumping dictionary information");
+	TRACE_DEBUG(INFO, "%s", fd_dict_dump(&buf, &len, NULL, fd_g_config->cnf_dict));
+	free(buf);
 }
 
 /* Entry point */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/dbg_msg_timings/CMakeLists.txt	Fri May 10 18:49:19 2013 +0800
@@ -0,0 +1,12 @@
+# Messages timing extension
+PROJECT("Messages timing extension" C)
+FD_ADD_EXTENSION(dbg_msg_timings dbg_msg_timings.c)
+
+
+####
+## INSTALL section ##
+
+INSTALL(TARGETS dbg_msg_timings
+	LIBRARY DESTINATION ${INSTALL_EXTENSIONS_SUFFIX}
+	COMPONENT freeDiameter-debug-tools)
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/dbg_msg_timings/dbg_msg_timings.c	Fri May 10 18:49:19 2013 +0800
@@ -0,0 +1,134 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, 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 extension uses the hooks mechanism to compute some timing information related to messages */
+
+#include <freeDiameter/extension.h>
+
+struct fd_hook_permsgdata {
+	struct timespec received_on;
+	struct timespec sent_on;
+};
+
+static struct fd_hook_data_hdl *mt_data_hdl = NULL;
+static struct fd_hook_hdl *mt_hdl = NULL;
+
+/* The callback called when messages are received and sent */
+static void mt_hook_cb(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata)
+{
+	struct msg_hdr * hdr;
+	char * buf = NULL;
+	size_t len;
+	
+	ASSERT(pmd);
+	
+	if (type == HOOK_DATA_RECEIVED) {
+		/* We just store the timestamp it was received on */
+		(void)clock_gettime(CLOCK_REALTIME, &pmd->received_on);
+		return;
+	}
+	
+	ASSERT(msg);
+	
+	/* Check if this message is request or answer */
+	CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), return);
+	
+	if (type == HOOK_MESSAGE_RECEIVED) {
+		ASSERT(pmd->received_on.tv_sec); /* otherwise it means the HOOK_DATA_RECEIVED hook was not trigged for this message */
+		if (hdr->msg_flags & CMD_FLAG_REQUEST) {
+			/* We have received a new request, nothing special to do */
+		} else {
+			/* This is an answer, check how long it took to get it */
+			struct fd_hook_permsgdata *qpmd = fd_hook_get_request_pmd(mt_data_hdl, msg);
+			struct timespec delay;
+			ASSERT(qpmd); /* If we do not have it, we must find out why */
+			ASSERT(qpmd->sent_on.tv_sec); /* same, would mean the HOOK_MESSAGE_SENT hook was not trigged */
+			TS_DIFFERENCE( &delay, &qpmd->sent_on, &pmd->received_on );
+			CHECK_MALLOC_DO( fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 1), return );
+			LOG_N("[TIMING] RCV ANS %ld.%06ld sec: %s", (long)delay.tv_sec, delay.tv_nsec / 1000, buf);
+		}
+	} else if (type == HOOK_MESSAGE_SENT) {
+		DiamId_t source = NULL;
+		size_t slen = 0;
+		
+		(void)clock_gettime(CLOCK_REALTIME, &pmd->sent_on);
+		
+		/* Is this a forwarded message ? */
+		CHECK_FCT_DO( fd_msg_source_get(msg, &source, &slen), return );
+		if (source) {
+			struct timespec delay;
+			ASSERT(pmd->received_on.tv_sec);
+			TS_DIFFERENCE( &delay, &pmd->received_on, &pmd->sent_on );
+			CHECK_MALLOC_DO( fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 1), return );
+			LOG_N("[TIMING] FWD %ld.%06ld sec: %s", (long)delay.tv_sec, delay.tv_nsec / 1000, buf);
+		} else if (hdr->msg_flags & CMD_FLAG_REQUEST) {
+			/* We are sending a request issued locally, nothing special to log */
+		} else {
+			/* We have generated an anwer, log the time it took since the corresponding request was received */
+			struct fd_hook_permsgdata *qpmd = fd_hook_get_request_pmd(mt_data_hdl, msg);
+			if (qpmd->received_on.tv_sec) {
+				struct timespec delay;
+				TS_DIFFERENCE( &delay, &qpmd->received_on, &pmd->sent_on );
+				CHECK_MALLOC_DO( fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 1), return );
+				LOG_N("[TIMING] ANS %ld.%06ld sec: %s", (long)delay.tv_sec, delay.tv_nsec / 1000, buf);
+			}
+		}
+	}
+		
+	free(buf);
+}
+
+/* Entry point */
+static int mt_main(char * conffile)
+{
+	TRACE_ENTRY("%p", conffile);
+	
+	CHECK_FCT( fd_hook_data_register( sizeof(struct fd_hook_permsgdata), NULL, NULL, &mt_data_hdl ) );
+	
+	CHECK_FCT( fd_hook_register( ((1 << HOOK_MESSAGE_RECEIVED) | (1 << HOOK_MESSAGE_SENT) | (1 << HOOK_DATA_RECEIVED)), 
+					mt_hook_cb, NULL, mt_data_hdl, &mt_hdl) );
+	
+	return 0;
+}
+
+/* Cleanup */
+void fd_ext_fini(void)
+{
+	TRACE_ENTRY();
+	CHECK_FCT_DO( fd_hook_unregister( mt_hdl ), );
+	return ;
+}
+
+EXTENSION_ENTRY("dbg_msg_timing", mt_main);
--- a/extensions/dict_dcca_3gpp/dict_dcca_3gpp.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dict_dcca_3gpp/dict_dcca_3gpp.c	Fri May 10 18:49:19 2013 +0800
@@ -1,6 +1,91 @@
+/*********************************************************************************************************
+ * Software License Agreement (BSD License)                                                               *
+ * Author: Thomas Klausner <tk@giga.or.at>                                                                *
+ *                                                                                                        *
+ * Copyright (c) 2013, Thomas Klausner                                                                    *
+ * All rights reserved.                                                                                   *
+ *                                                                                                        *
+ * Written under contract by nfotex IT GmbH, http://nfotex.com/                                           *
+ *                                                                                                        *
+ * 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.                                                            *
+ *                                                                                                        *
+ * 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.                                                             *
+ *********************************************************************************************************/
+
 /* 
- * Dictionary definitions of objects specified in DCCA (Nokia, 3GPP).
+ * Dictionary definitions for objects specified for DCCA by 3GPP.
+ *
+ * This extensions contains a lot of AVPs from various 3GPP standards
+ * documents, and some rules for the grouped AVPs described therein.
+ *
+ * This extension does not contain ALL AVPs described by 3GPP, but
+ * quite a big number of them.
+ *
+ * When extending the AVPs, please edit dict_dcca_3gpp.org instead and
+ * create pastable code with contrib/tools/org_to_fd.pl.
+ *
+ * Some points of consideration:
+ * 1. This dictionary could be split up per document.
+ *
+ * + pro: you can only load the AVPs/Rules you're interested in ->
+ * smaller memory size
+ *
+ * - con: the documents use AVPs from each other A LOT, so setting the
+ * dependencies correctly will be annoying
+ *
+ * - con: you need to load all of them as extensions
+ *
+ * 2. This dictionary contains ONE AVP in the "3GPP2" vendor space,
+ * since I found it wasteful to write a separate dictionary just for
+ * one AVP. Also, it is defined in a 3GPP document.
+ *
+ * 3. While there are quite a number of rules here already, many more
+ * are missing. I've only added rules for those grouped AVPs or
+ * commands in which I was concretely interested so far; many more
+ * will need to be added to make this complete.
+ *
+ * That being said, I hope this will be useful for you.
+ *
  */
+
+
+/*
+ * Some comments on the 3GPP Standards documents themselves:
+ *
+ * 1. It would be good if 29.061 was reviewed to check for each AVP if
+ * it is Mandatory or not. The data currently in the document does not
+ * match what was in the previous version of the freeDiameter
+ * extension (the one that existedbefore I rewrote it) or what I saw
+ * so far. IIRC, even the table and the document contradict each
+ * other. The AVP table is also missing an entry for
+ * "External-Identifier", 28.
+ *
+ * 2. 29.140 has conflicting AVP names with other documents:
+ *   - Sequence-Number is also in 32.329
+ *   - Recipient-Address is also in 32.299
+ *   - Status is also in 32.299
+ *
+ * 3. 29.229 has name conflict with 29.329 about User-Data (different
+ * AVP code 702, instead of 606) -- the weird thing is, the latter
+ * uses some AVPs from the former, but not this one.
+*/
 #include <freeDiameter/extension.h>
 
 
@@ -13,7 +98,7 @@
 	CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) );
 
 struct local_rules_definition {
-	char 			*avp_name;
+	struct dict_avp_request avp_vendor_plus_name;
 	enum rule_position	position;
 	int 			min;
 	int			max;
@@ -21,6 +106,7 @@
 
 #define RULE_ORDER( _position ) ((((_position) == RULE_FIXED_HEAD) || ((_position) == RULE_FIXED_TAIL)) ? 1 : 0 )
 
+/* Attention! This version of the macro uses AVP_BY_NAME_AND_VENDOR, in contrast to most other copies! */
 #define PARSE_loc_rules( _rulearray, _parent) {								\
 	int __ar;											\
 	for (__ar=0; __ar < sizeof(_rulearray) / sizeof((_rulearray)[0]); __ar++) {			\
@@ -33,17 +119,17 @@
 		CHECK_FCT(  fd_dict_search( 								\
 			fd_g_config->cnf_dict,								\
 			DICT_AVP, 									\
-			AVP_BY_NAME, 									\
-			(_rulearray)[__ar].avp_name, 							\
+			AVP_BY_NAME_AND_VENDOR, 							\
+			&(_rulearray)[__ar].avp_vendor_plus_name,					\
 			&__data.rule_avp, 0 ) );							\
 		if ( !__data.rule_avp ) {								\
-			TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_name );		\
+			TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_vendor_plus_name.avp_name);		\
 			return ENOENT;									\
 		}											\
 		CHECK_FCT_DO( fd_dict_new( fd_g_config->cnf_dict, DICT_RULE, &__data, _parent, NULL),	\
 			{							        		\
 				TRACE_DEBUG(INFO, "Error on rule with AVP '%s'",      			\
-					 (_rulearray)[__ar].avp_name );		      			\
+					    (_rulearray)[__ar].avp_vendor_plus_name.avp_name);		\
 				return EINVAL;					      			\
 			} );							      			\
 	}									      			\
@@ -64,8 +150,12 @@
                 {
                         struct dict_vendor_data vendor_data = { 10415, "3GPP" };
                         CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_VENDOR, &vendor_data, NULL, NULL));
-                }                                
-  
+                }
+                {
+                        struct dict_vendor_data vendor_data = { 5535, "3GPP2" };
+                        CHECK_FCT(fd_dict_new(fd_g_config->cnf_dict, DICT_VENDOR, &vendor_data, NULL, NULL));
+                }
+
 	}
 	
 
@@ -80,9 +170,10 @@
 	CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "DiameterIdentity", &DiameterIdentity_type);
 	CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "DiameterURI", &DiameterURI_type);
 	CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "IPFilterRule", &IPFilterRule_type);
-	CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Time", &Time_type);                                
+	CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Time", &Time_type);
 	CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "UTF8String", &UTF8String_type);
 	
+
 	/* The following is created automatically. Do not modify. */
 	/* Changes will be lost during the next update. Modify the source org file instead. */
 
@@ -786,7 +877,436 @@
 		CHECK_dict_new(DICT_AVP, &data, type, NULL);
 	};
 
-	/* 3GPP 29.212-b70 (11.7.0 2012.12.20)                          */
+	/* 3GPP 29.140-700 (7.0.0 2007.07.05)                           */
+	/* Served-User-Identity */
+	{
+		struct dict_avp_data data = {
+			1100,	/* Code */
+			10415,	/* Vendor */
+			"Served-User-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* reuses: MSISDN                                               */
+	/* VASP-ID */
+	{
+		struct dict_avp_data data = {
+			1101,	/* Code */
+			10415,	/* Vendor */
+			"VASP-ID",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* VAS-ID */
+	{
+		struct dict_avp_data data = {
+			1102,	/* Code */
+			10415,	/* Vendor */
+			"VAS-ID",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Trigger-Event */
+	{
+		struct dict_avp_data data = {
+			1103,	/* Code */
+			10415,	/* Vendor */
+			"Trigger-Event",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Trigger-Event)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* reuses: 3GPP-IMSI                                            */
+	/* Sender-Address */
+	{
+		struct dict_avp_data data = {
+			1104,	/* Code */
+			10415,	/* Vendor */
+			"Sender-Address",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Initial-Recipient-Address */
+	{
+		struct dict_avp_data data = {
+			1105,	/* Code */
+			10415,	/* Vendor */
+			"Initial-Recipient-Address",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Result-Recipient-Address */
+	{
+		struct dict_avp_data data = {
+			1106,	/* Code */
+			10415,	/* Vendor */
+			"Result-Recipient-Address",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* conflicts with one in (more common) 32.329                   */
+	/* Sequence-Number-29.140 */
+	{
+		struct dict_avp_data data = {
+			1107,	/* Code */
+			10415,	/* Vendor */
+			"Sequence-Number-29.140",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* conflicts with one in (more common) 32.299                   */
+	/* Recipient-Address-29.140 */
+	{
+		struct dict_avp_data data = {
+			1108,	/* Code */
+			10415,	/* Vendor */
+			"Recipient-Address-29.140",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Routeing-Address */
+	{
+		struct dict_avp_data data = {
+			1109,	/* Code */
+			10415,	/* Vendor */
+			"Routeing-Address",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Originating-Interface */
+	{
+		struct dict_avp_data data = {
+			1110,	/* Code */
+			10415,	/* Vendor */
+			"Originating-Interface",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Originating-Interface)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Delivery-Report */
+	{
+		struct dict_avp_data data = {
+			1111,	/* Code */
+			10415,	/* Vendor */
+			"Delivery-Report",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Delivery-Report)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Read-Reply */
+	{
+		struct dict_avp_data data = {
+			1112,	/* Code */
+			10415,	/* Vendor */
+			"Read-Reply",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Read-Reply)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Sender-Visibility */
+	{
+		struct dict_avp_data data = {
+			1113,	/* Code */
+			10415,	/* Vendor */
+			"Sender-Visibility",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Sender-Visibility)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Service-Key */
+	{
+		struct dict_avp_data data = {
+			1114,	/* Code */
+			10415,	/* Vendor */
+			"Service-Key",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Billing-Information */
+	{
+		struct dict_avp_data data = {
+			1115,	/* Code */
+			10415,	/* Vendor */
+			"Billing-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* conflicts with one in (more common) 32.299                   */
+	/* Status-29.140 */
+	{
+		struct dict_avp_data data = {
+			1116,	/* Code */
+			10415,	/* Vendor */
+			"Status-29.140",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Status-Code */
+	{
+		struct dict_avp_data data = {
+			1117,	/* Code */
+			10415,	/* Vendor */
+			"Status-Code",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Status-Text */
+	{
+		struct dict_avp_data data = {
+			1118,	/* Code */
+			10415,	/* Vendor */
+			"Status-Text",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Routeing-Address-Resolution */
+	{
+		struct dict_avp_data data = {
+			1119,	/* Code */
+			10415,	/* Vendor */
+			"Routeing-Address-Resolution",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Routeing-Address-Resolution)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* 3GPP 29.173-c00 (12.0.0 2013.03.13)                          */
+	/* LMSI */
+	{
+		struct dict_avp_data data = {
+			2400,	/* Code */
+			10415,	/* Vendor */
+			"LMSI",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Serving-Node */
+	{
+		struct dict_avp_data data = {
+			2401,	/* Code */
+			10415,	/* Vendor */
+			"Serving-Node",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* MME-Name */
+	{
+		struct dict_avp_data data = {
+			2402,	/* Code */
+			10415,	/* Vendor */
+			"MME-Name",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, DiameterIdentity_type, NULL);
+	};
+
+	/* MSC-Number */
+	{
+		struct dict_avp_data data = {
+			2403,	/* Code */
+			10415,	/* Vendor */
+			"MSC-Number",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* LCS-Capabilities-Sets */
+	{
+		struct dict_avp_data data = {
+			2404,	/* Code */
+			10415,	/* Vendor */
+			"LCS-Capabilities-Sets",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* GMLC-Address */
+	{
+		struct dict_avp_data data = {
+			2405,	/* Code */
+			10415,	/* Vendor */
+			"GMLC-Address",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, Address_type, NULL);
+	};
+
+	/* Additional-Serving-Node */
+	{
+		struct dict_avp_data data = {
+			2406,	/* Code */
+			10415,	/* Vendor */
+			"Additional-Serving-Node",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* PPR-Address */
+	{
+		struct dict_avp_data data = {
+			2407,	/* Code */
+			10415,	/* Vendor */
+			"PPR-Address",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, Address_type, NULL);
+	};
+
+	/* MME-Realm */
+	{
+		struct dict_avp_data data = {
+			2408,	/* Code */
+			10415,	/* Vendor */
+			"MME-Realm",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, DiameterIdentity_type, NULL);
+	};
+
+	/* SGSN-Name */
+	{
+		struct dict_avp_data data = {
+			2409,	/* Code */
+			10415,	/* Vendor */
+			"SGSN-Name",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, DiameterIdentity_type, NULL);
+	};
+
+	/* SGSN-Realm */
+	{
+		struct dict_avp_data data = {
+			2410,	/* Code */
+			10415,	/* Vendor */
+			"SGSN-Realm",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, DiameterIdentity_type, NULL);
+	};
+
+	/* 3GPP 29.212-c00 (12.0.0 2013.03.15)                          */
+	/* Gx-specific                                                  */
 	/* ADC-Revalidation-Time */
 	{
 		struct dict_avp_data data = {
@@ -1279,19 +1799,6 @@
 		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
 	};
 
-	/* HeNB-BBF-FQDN */
-	{
-		struct dict_avp_data data = {
-			2803,	/* Code */
-			10415,	/* Vendor */
-			"HeNB-BBF-FQDN",	/* Name */
-			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
-			AVP_FLAG_VENDOR,	/* Fixed flag values */
-			AVP_TYPE_OCTETSTRING	/* base type of data */
-		};
-		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
-	};
-
 	/* HeNB-Local-IP-Address */
 	{
 		struct dict_avp_data data = {
@@ -1773,12 +2280,12 @@
 		CHECK_dict_new(DICT_AVP, &data, DiameterIdentity_type, NULL);
 	};
 
-	/* TDF-IP-address */
+	/* TDF-IP-Address */
 	{
 		struct dict_avp_data data = {
 			1091,	/* Code */
 			10415,	/* Vendor */
-			"TDF-IP-address",	/* Name */
+			"TDF-IP-Address",	/* Name */
 			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
 			AVP_FLAG_VENDOR,	/* Fixed flag values */
 			AVP_TYPE_OCTETSTRING	/* base type of data */
@@ -1831,18 +2338,18 @@
 		CHECK_dict_new(DICT_AVP, &data, type, NULL);
 	};
 
-	/* Qos-Upgrade */
+	/* QoS-Upgrade */
 	{
 		struct dict_avp_data data = {
 			1030,	/* Code */
 			10415,	/* Vendor */
-			"Qos-Upgrade",	/* Name */
-			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
-			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
-			AVP_TYPE_INTEGER32	/* base type of data */
-		};
-		struct dict_object		*type;
-		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Qos-Upgrade)", NULL, NULL, NULL };
+			"QoS-Upgrade",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(QoS-Upgrade)", NULL, NULL, NULL };
 		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
 		CHECK_dict_new(DICT_AVP, &data, type, NULL);
 	};
@@ -2067,12 +2574,12 @@
 		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
 	};
 
-	/* Rule-DeActivation-Time */
+	/* Rule-Deactivation-Time */
 	{
 		struct dict_avp_data data = {
 			1044,	/* Code */
 			10415,	/* Vendor */
-			"Rule-DeActivation-Time",	/* Name */
+			"Rule-Deactivation-Time",	/* Name */
 			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
 			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
 			AVP_TYPE_OCTETSTRING	/* base type of data */
@@ -2128,6 +2635,7 @@
 		CHECK_dict_new(DICT_AVP, &data, type, NULL);
 	};
 
+	/* Gxx-specific                                                 */
 	/* QoS-Rule-Install */
 	{
 		struct dict_avp_data data = {
@@ -2222,6 +2730,7 @@
 		CHECK_dict_new(DICT_AVP, &data, type, NULL);
 	};
 
+	/* S15-specific                                                 */
 	/* CS-Service-Qos-Request-Identifier */
 	{
 		struct dict_avp_data data = {
@@ -2251,6 +2760,492 @@
 		CHECK_dict_new(DICT_AVP, &data, type, NULL);
 	};
 
+	/* 3GPP 29.214-b80 (11.8.0 2013.03.15)                          */
+	/* Abort-Cause */
+	{
+		struct dict_avp_data data = {
+			500,	/* Code */
+			10415,	/* Vendor */
+			"Abort-Cause",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Abort-Cause)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Access-Network-Charging-Address */
+	{
+		struct dict_avp_data data = {
+			501,	/* Code */
+			10415,	/* Vendor */
+			"Access-Network-Charging-Address",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, Address_type, NULL);
+	};
+
+	/* Access-Network-Charging-Identifier */
+	{
+		struct dict_avp_data data = {
+			502,	/* Code */
+			10415,	/* Vendor */
+			"Access-Network-Charging-Identifier",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Access-Network-Charging-Identifier-Value */
+	{
+		struct dict_avp_data data = {
+			503,	/* Code */
+			10415,	/* Vendor */
+			"Access-Network-Charging-Identifier-Value",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Acceptable-Service-Info */
+	{
+		struct dict_avp_data data = {
+			526,	/* Code */
+			10415,	/* Vendor */
+			"Acceptable-Service-Info",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* AF-Application-Identifier */
+	{
+		struct dict_avp_data data = {
+			504,	/* Code */
+			10415,	/* Vendor */
+			"AF-Application-Identifier",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* AF-Charging-Identifier */
+	{
+		struct dict_avp_data data = {
+			505,	/* Code */
+			10415,	/* Vendor */
+			"AF-Charging-Identifier",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Application-Service-Provider-Identity */
+	{
+		struct dict_avp_data data = {
+			532,	/* Code */
+			10415,	/* Vendor */
+			"Application-Service-Provider-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Codec-Data */
+	{
+		struct dict_avp_data data = {
+			524,	/* Code */
+			10415,	/* Vendor */
+			"Codec-Data",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Flow-Description */
+	{
+		struct dict_avp_data data = {
+			507,	/* Code */
+			10415,	/* Vendor */
+			"Flow-Description",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, IPFilterRule_type, NULL);
+	};
+
+	/* Flow-Number */
+	{
+		struct dict_avp_data data = {
+			509,	/* Code */
+			10415,	/* Vendor */
+			"Flow-Number",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Flows */
+	{
+		struct dict_avp_data data = {
+			510,	/* Code */
+			10415,	/* Vendor */
+			"Flows",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Flow-Status */
+	{
+		struct dict_avp_data data = {
+			511,	/* Code */
+			10415,	/* Vendor */
+			"Flow-Status",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Flow-Status)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Flow-Usage */
+	{
+		struct dict_avp_data data = {
+			512,	/* Code */
+			10415,	/* Vendor */
+			"Flow-Usage",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Flow-Usage)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Service-URN */
+	{
+		struct dict_avp_data data = {
+			525,	/* Code */
+			10415,	/* Vendor */
+			"Service-URN",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Specific-Action */
+	{
+		struct dict_avp_data data = {
+			513,	/* Code */
+			10415,	/* Vendor */
+			"Specific-Action",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Specific-Action)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Max-Requested-Bandwidth-DL */
+	{
+		struct dict_avp_data data = {
+			515,	/* Code */
+			10415,	/* Vendor */
+			"Max-Requested-Bandwidth-DL",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Max-Requested-Bandwidth-UL */
+	{
+		struct dict_avp_data data = {
+			516,	/* Code */
+			10415,	/* Vendor */
+			"Max-Requested-Bandwidth-UL",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Media-Component-Description */
+	{
+		struct dict_avp_data data = {
+			517,	/* Code */
+			10415,	/* Vendor */
+			"Media-Component-Description",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Media-Component-Number */
+	{
+		struct dict_avp_data data = {
+			518,	/* Code */
+			10415,	/* Vendor */
+			"Media-Component-Number",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Media-Sub-Component */
+	{
+		struct dict_avp_data data = {
+			519,	/* Code */
+			10415,	/* Vendor */
+			"Media-Sub-Component",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Media-Type */
+	{
+		struct dict_avp_data data = {
+			520,	/* Code */
+			10415,	/* Vendor */
+			"Media-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Media-Type)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* MPS-Identifier */
+	{
+		struct dict_avp_data data = {
+			528,	/* Code */
+			10415,	/* Vendor */
+			"MPS-Identifier",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Min-Requested-Bandwidth-DL */
+	{
+		struct dict_avp_data data = {
+			534,	/* Code */
+			10415,	/* Vendor */
+			"Min-Requested-Bandwidth-DL",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Min-Requested-Bandwidth-UL */
+	{
+		struct dict_avp_data data = {
+			535,	/* Code */
+			10415,	/* Vendor */
+			"Min-Requested-Bandwidth-UL",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* RR-Bandwidth */
+	{
+		struct dict_avp_data data = {
+			521,	/* Code */
+			10415,	/* Vendor */
+			"RR-Bandwidth",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* RS-Bandwidth */
+	{
+		struct dict_avp_data data = {
+			522,	/* Code */
+			10415,	/* Vendor */
+			"RS-Bandwidth",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Service-Info-Status */
+	{
+		struct dict_avp_data data = {
+			527,	/* Code */
+			10415,	/* Vendor */
+			"Service-Info-Status",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Service-Info-Status)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* SIP-Forking-Indication */
+	{
+		struct dict_avp_data data = {
+			523,	/* Code */
+			10415,	/* Vendor */
+			"SIP-Forking-Indication",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(SIP-Forking-Indication)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Sponsor-Identity */
+	{
+		struct dict_avp_data data = {
+			531,	/* Code */
+			10415,	/* Vendor */
+			"Sponsor-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Sponsored-Connectivity-Data */
+	{
+		struct dict_avp_data data = {
+			530,	/* Code */
+			10415,	/* Vendor */
+			"Sponsored-Connectivity-Data",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* AF-Signalling-Protocol */
+	{
+		struct dict_avp_data data = {
+			529,	/* Code */
+			10415,	/* Vendor */
+			"AF-Signalling-Protocol",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(AF-Signalling-Protocol)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Required-Access-Info */
+	{
+		struct dict_avp_data data = {
+			536,	/* Code */
+			10415,	/* Vendor */
+			"Required-Access-Info",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Required-Access-Info)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Rx-Request-Type */
+	{
+		struct dict_avp_data data = {
+			533,	/* Code */
+			10415,	/* Vendor */
+			"Rx-Request-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Rx-Request-Type)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* IP-Domain-Id */
+	{
+		struct dict_avp_data data = {
+			537,	/* Code */
+			10415,	/* Vendor */
+			"IP-Domain-Id",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
 	/* 3GPP 29.229-b20 (11.2.0 2012.12.21)                          */
 	/* Associated-Identities */
 	{
@@ -3357,12 +4352,12 @@
 		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
 	};
 
-	/* Application-provided-called-party-address */
+	/* Application-Provided-Called-Party-Address */
 	{
 		struct dict_avp_data data = {
 			837,	/* Code */
 			10415,	/* Vendor */
-			"Application-provided-called-party-address",	/* Name */
+			"Application-Provided-Called-Party-Address",	/* Name */
 			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
 			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
 			AVP_TYPE_OCTETSTRING	/* base type of data */
@@ -6722,6 +7717,2113 @@
 		CHECK_dict_new(DICT_AVP, &data, Address_type, NULL);
 	};
 
+	/* 3GPP 29.272-c00 (12.0.0 2013.03.13)                          */
+	/* Subscription-Data */
+	{
+		struct dict_avp_data data = {
+			1400,	/* Code */
+			10415,	/* Vendor */
+			"Subscription-Data",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Terminal-Information */
+	{
+		struct dict_avp_data data = {
+			1401,	/* Code */
+			10415,	/* Vendor */
+			"Terminal-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* IMEI */
+	{
+		struct dict_avp_data data = {
+			1402,	/* Code */
+			10415,	/* Vendor */
+			"IMEI",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Software-Version */
+	{
+		struct dict_avp_data data = {
+			1403,	/* Code */
+			10415,	/* Vendor */
+			"Software-Version",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* QoS-Subscribed */
+	{
+		struct dict_avp_data data = {
+			1404,	/* Code */
+			10415,	/* Vendor */
+			"QoS-Subscribed",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* ULR-Flags */
+	{
+		struct dict_avp_data data = {
+			1405,	/* Code */
+			10415,	/* Vendor */
+			"ULR-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* ULA-Flags */
+	{
+		struct dict_avp_data data = {
+			1406,	/* Code */
+			10415,	/* Vendor */
+			"ULA-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Visited-PLMN-Id */
+	{
+		struct dict_avp_data data = {
+			1407,	/* Code */
+			10415,	/* Vendor */
+			"Visited-PLMN-Id",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Requested-EUTRAN-Authentication-Info */
+	{
+		struct dict_avp_data data = {
+			1408,	/* Code */
+			10415,	/* Vendor */
+			"Requested-EUTRAN-Authentication-Info",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Requested-UTRAN-GERAN-Authentication-Info */
+	{
+		struct dict_avp_data data = {
+			1409,	/* Code */
+			10415,	/* Vendor */
+			"Requested-UTRAN-GERAN-Authentication-Info",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Number-Of-Requested-Vectors */
+	{
+		struct dict_avp_data data = {
+			1410,	/* Code */
+			10415,	/* Vendor */
+			"Number-Of-Requested-Vectors",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Re-Synchronization-Info */
+	{
+		struct dict_avp_data data = {
+			1411,	/* Code */
+			10415,	/* Vendor */
+			"Re-Synchronization-Info",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Immediate-Response-Preferred */
+	{
+		struct dict_avp_data data = {
+			1412,	/* Code */
+			10415,	/* Vendor */
+			"Immediate-Response-Preferred",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Authentication-Info */
+	{
+		struct dict_avp_data data = {
+			1413,	/* Code */
+			10415,	/* Vendor */
+			"Authentication-Info",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* E-UTRAN-Vector */
+	{
+		struct dict_avp_data data = {
+			1414,	/* Code */
+			10415,	/* Vendor */
+			"E-UTRAN-Vector",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* UTRAN-Vector */
+	{
+		struct dict_avp_data data = {
+			1415,	/* Code */
+			10415,	/* Vendor */
+			"UTRAN-Vector",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* GERAN-Vector */
+	{
+		struct dict_avp_data data = {
+			1416,	/* Code */
+			10415,	/* Vendor */
+			"GERAN-Vector",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Network-Access-Mode */
+	{
+		struct dict_avp_data data = {
+			1417,	/* Code */
+			10415,	/* Vendor */
+			"Network-Access-Mode",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Network-Access-Mode)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* HPLMN-ODB */
+	{
+		struct dict_avp_data data = {
+			1418,	/* Code */
+			10415,	/* Vendor */
+			"HPLMN-ODB",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Item-Number */
+	{
+		struct dict_avp_data data = {
+			1419,	/* Code */
+			10415,	/* Vendor */
+			"Item-Number",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Cancellation-Type */
+	{
+		struct dict_avp_data data = {
+			1420,	/* Code */
+			10415,	/* Vendor */
+			"Cancellation-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Cancellation-Type)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* DSR-Flags */
+	{
+		struct dict_avp_data data = {
+			1421,	/* Code */
+			10415,	/* Vendor */
+			"DSR-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* DSA-Flags */
+	{
+		struct dict_avp_data data = {
+			1422,	/* Code */
+			10415,	/* Vendor */
+			"DSA-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Context-Identifier */
+	{
+		struct dict_avp_data data = {
+			1423,	/* Code */
+			10415,	/* Vendor */
+			"Context-Identifier",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Subscriber-Status */
+	{
+		struct dict_avp_data data = {
+			1424,	/* Code */
+			10415,	/* Vendor */
+			"Subscriber-Status",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Subscriber-Status)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Operator-Determined-Barring */
+	{
+		struct dict_avp_data data = {
+			1425,	/* Code */
+			10415,	/* Vendor */
+			"Operator-Determined-Barring",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Access-Restriction-Data */
+	{
+		struct dict_avp_data data = {
+			1426,	/* Code */
+			10415,	/* Vendor */
+			"Access-Restriction-Data",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* APN-OI-Replacement */
+	{
+		struct dict_avp_data data = {
+			1427,	/* Code */
+			10415,	/* Vendor */
+			"APN-OI-Replacement",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* All-APN-Configurations-Included-Indicator */
+	{
+		struct dict_avp_data data = {
+			1428,	/* Code */
+			10415,	/* Vendor */
+			"All-APN-Configurations-Included-Indicator",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(All-APN-Configurations-Included-Indicator)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* APN-Configuration-Profile */
+	{
+		struct dict_avp_data data = {
+			1429,	/* Code */
+			10415,	/* Vendor */
+			"APN-Configuration-Profile",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* APN-Configuration */
+	{
+		struct dict_avp_data data = {
+			1430,	/* Code */
+			10415,	/* Vendor */
+			"APN-Configuration",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* EPS-Subscribed-QoS-Profile */
+	{
+		struct dict_avp_data data = {
+			1431,	/* Code */
+			10415,	/* Vendor */
+			"EPS-Subscribed-QoS-Profile",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* VPLMN-Dynamic-Address-Allowed */
+	{
+		struct dict_avp_data data = {
+			1432,	/* Code */
+			10415,	/* Vendor */
+			"VPLMN-Dynamic-Address-Allowed",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(VPLMN-Dynamic-Address-Allowed)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* STN-SR */
+	{
+		struct dict_avp_data data = {
+			1433,	/* Code */
+			10415,	/* Vendor */
+			"STN-SR",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Alert-Reason */
+	{
+		struct dict_avp_data data = {
+			1434,	/* Code */
+			10415,	/* Vendor */
+			"Alert-Reason",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Alert-Reason)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* AMBR */
+	{
+		struct dict_avp_data data = {
+			1435,	/* Code */
+			10415,	/* Vendor */
+			"AMBR",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* CSG-Subscription-Data */
+	{
+		struct dict_avp_data data = {
+			1436,	/* Code */
+			10415,	/* Vendor */
+			"CSG-Subscription-Data",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* CSG-Id */
+	{
+		struct dict_avp_data data = {
+			1437,	/* Code */
+			10415,	/* Vendor */
+			"CSG-Id",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* PDN-GW-Allocation-Type */
+	{
+		struct dict_avp_data data = {
+			1438,	/* Code */
+			10415,	/* Vendor */
+			"PDN-GW-Allocation-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(PDN-GW-Allocation-Type)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Expiration-Date */
+	{
+		struct dict_avp_data data = {
+			1439,	/* Code */
+			10415,	/* Vendor */
+			"Expiration-Date",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, Time_type, NULL);
+	};
+
+	/* RAT-Frequency-Selection-Priority-ID */
+	{
+		struct dict_avp_data data = {
+			1440,	/* Code */
+			10415,	/* Vendor */
+			"RAT-Frequency-Selection-Priority-ID",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* IDA-Flags */
+	{
+		struct dict_avp_data data = {
+			1441,	/* Code */
+			10415,	/* Vendor */
+			"IDA-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* PUA-Flags */
+	{
+		struct dict_avp_data data = {
+			1442,	/* Code */
+			10415,	/* Vendor */
+			"PUA-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* NOR-Flags */
+	{
+		struct dict_avp_data data = {
+			1443,	/* Code */
+			10415,	/* Vendor */
+			"NOR-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* User-Id */
+	{
+		struct dict_avp_data data = {
+			1444,	/* Code */
+			10415,	/* Vendor */
+			"User-Id",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Equipment-Status */
+	{
+		struct dict_avp_data data = {
+			1445,	/* Code */
+			10415,	/* Vendor */
+			"Equipment-Status",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Equipment-Status)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Regional-Subscription-Zone-Code */
+	{
+		struct dict_avp_data data = {
+			1446,	/* Code */
+			10415,	/* Vendor */
+			"Regional-Subscription-Zone-Code",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* RAND */
+	{
+		struct dict_avp_data data = {
+			1447,	/* Code */
+			10415,	/* Vendor */
+			"RAND",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* XRES */
+	{
+		struct dict_avp_data data = {
+			1448,	/* Code */
+			10415,	/* Vendor */
+			"XRES",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* AUTN */
+	{
+		struct dict_avp_data data = {
+			1449,	/* Code */
+			10415,	/* Vendor */
+			"AUTN",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* KASME */
+	{
+		struct dict_avp_data data = {
+			1450,	/* Code */
+			10415,	/* Vendor */
+			"KASME",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Trace-Collection-Entity */
+	{
+		struct dict_avp_data data = {
+			1452,	/* Code */
+			10415,	/* Vendor */
+			"Trace-Collection-Entity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, Address_type, NULL);
+	};
+
+	/* Kc */
+	{
+		struct dict_avp_data data = {
+			1453,	/* Code */
+			10415,	/* Vendor */
+			"Kc",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* SRES */
+	{
+		struct dict_avp_data data = {
+			1454,	/* Code */
+			10415,	/* Vendor */
+			"SRES",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* PDN-Type */
+	{
+		struct dict_avp_data data = {
+			1456,	/* Code */
+			10415,	/* Vendor */
+			"PDN-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(PDN-Type)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Roaming-Restricted-Due-To-Unsupported-Feature */
+	{
+		struct dict_avp_data data = {
+			1457,	/* Code */
+			10415,	/* Vendor */
+			"Roaming-Restricted-Due-To-Unsupported-Feature",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Roaming-Restricted-Due-To-Unsupported-Feature)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Trace-Data */
+	{
+		struct dict_avp_data data = {
+			1458,	/* Code */
+			10415,	/* Vendor */
+			"Trace-Data",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Trace-Reference */
+	{
+		struct dict_avp_data data = {
+			1459,	/* Code */
+			10415,	/* Vendor */
+			"Trace-Reference",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Trace-Depth */
+	{
+		struct dict_avp_data data = {
+			1462,	/* Code */
+			10415,	/* Vendor */
+			"Trace-Depth",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Trace-Depth)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Trace-NE-Type-List */
+	{
+		struct dict_avp_data data = {
+			1463,	/* Code */
+			10415,	/* Vendor */
+			"Trace-NE-Type-List",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Trace-Interface-List */
+	{
+		struct dict_avp_data data = {
+			1464,	/* Code */
+			10415,	/* Vendor */
+			"Trace-Interface-List",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Trace-Event-List */
+	{
+		struct dict_avp_data data = {
+			1465,	/* Code */
+			10415,	/* Vendor */
+			"Trace-Event-List",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* OMC-Id */
+	{
+		struct dict_avp_data data = {
+			1466,	/* Code */
+			10415,	/* Vendor */
+			"OMC-Id",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* GPRS-Subscription-Data */
+	{
+		struct dict_avp_data data = {
+			1467,	/* Code */
+			10415,	/* Vendor */
+			"GPRS-Subscription-Data",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Complete-Data-List-Included-Indicator */
+	{
+		struct dict_avp_data data = {
+			1468,	/* Code */
+			10415,	/* Vendor */
+			"Complete-Data-List-Included-Indicator",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Complete-Data-List-Included-Indicator)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* PDP-Context */
+	{
+		struct dict_avp_data data = {
+			1469,	/* Code */
+			10415,	/* Vendor */
+			"PDP-Context",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* PDP-Type */
+	{
+		struct dict_avp_data data = {
+			1470,	/* Code */
+			10415,	/* Vendor */
+			"PDP-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* 3GPP2-MEID */
+	{
+		struct dict_avp_data data = {
+			1471,	/* Code */
+			10415,	/* Vendor */
+			"3GPP2-MEID",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Specific-APN-Info */
+	{
+		struct dict_avp_data data = {
+			1472,	/* Code */
+			10415,	/* Vendor */
+			"Specific-APN-Info",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* LCS-Info */
+	{
+		struct dict_avp_data data = {
+			1473,	/* Code */
+			10415,	/* Vendor */
+			"LCS-Info",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* GMLC-Number */
+	{
+		struct dict_avp_data data = {
+			1474,	/* Code */
+			10415,	/* Vendor */
+			"GMLC-Number",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* LCS-PrivacyException */
+	{
+		struct dict_avp_data data = {
+			1475,	/* Code */
+			10415,	/* Vendor */
+			"LCS-PrivacyException",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* SS-Code */
+	{
+		struct dict_avp_data data = {
+			1476,	/* Code */
+			10415,	/* Vendor */
+			"SS-Code",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* SS-Status */
+	{
+		struct dict_avp_data data = {
+			1477,	/* Code */
+			10415,	/* Vendor */
+			"SS-Status",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Notification-To-UE-User */
+	{
+		struct dict_avp_data data = {
+			1478,	/* Code */
+			10415,	/* Vendor */
+			"Notification-To-UE-User",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Notification-To-UE-User)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* External-Client */
+	{
+		struct dict_avp_data data = {
+			1479,	/* Code */
+			10415,	/* Vendor */
+			"External-Client",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Client-Identity */
+	{
+		struct dict_avp_data data = {
+			1480,	/* Code */
+			10415,	/* Vendor */
+			"Client-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* GMLC-Restriction */
+	{
+		struct dict_avp_data data = {
+			1481,	/* Code */
+			10415,	/* Vendor */
+			"GMLC-Restriction",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(GMLC-Restriction)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* PLMN-Client */
+	{
+		struct dict_avp_data data = {
+			1482,	/* Code */
+			10415,	/* Vendor */
+			"PLMN-Client",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(PLMN-Client)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Service-Type */
+	{
+		struct dict_avp_data data = {
+			1483,	/* Code */
+			10415,	/* Vendor */
+			"Service-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* ServiceTypeIdentity */
+	{
+		struct dict_avp_data data = {
+			1484,	/* Code */
+			10415,	/* Vendor */
+			"ServiceTypeIdentity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* MO-LR */
+	{
+		struct dict_avp_data data = {
+			1485,	/* Code */
+			10415,	/* Vendor */
+			"MO-LR",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Teleservice-List */
+	{
+		struct dict_avp_data data = {
+			1486,	/* Code */
+			10415,	/* Vendor */
+			"Teleservice-List",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* TS-Code */
+	{
+		struct dict_avp_data data = {
+			1487,	/* Code */
+			10415,	/* Vendor */
+			"TS-Code",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Call-Barring-Infor-List */
+	{
+		struct dict_avp_data data = {
+			1488,	/* Code */
+			10415,	/* Vendor */
+			"Call-Barring-Infor-List",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* SGSN-Number */
+	{
+		struct dict_avp_data data = {
+			1489,	/* Code */
+			10415,	/* Vendor */
+			"SGSN-Number",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* IDR-Flags */
+	{
+		struct dict_avp_data data = {
+			1490,	/* Code */
+			10415,	/* Vendor */
+			"IDR-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* ICS-Indicator */
+	{
+		struct dict_avp_data data = {
+			1491,	/* Code */
+			10415,	/* Vendor */
+			"ICS-Indicator",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(ICS-Indicator)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* IMS-Voice-Over-PS-Sessions-Supported */
+	{
+		struct dict_avp_data data = {
+			1492,	/* Code */
+			10415,	/* Vendor */
+			"IMS-Voice-Over-PS-Sessions-Supported",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(IMS-Voice-Over-PS-Sessions-Supported)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Homogeneous-Support-of-IMS-Voice-Over-PS-Sessions */
+	{
+		struct dict_avp_data data = {
+			1493,	/* Code */
+			10415,	/* Vendor */
+			"Homogeneous-Support-of-IMS-Voice-Over-PS-Sessions",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Homogeneous-Support-of-IMS-Voice-Over-PS-Sessions)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Last-UE-Activity-Time */
+	{
+		struct dict_avp_data data = {
+			1494,	/* Code */
+			10415,	/* Vendor */
+			"Last-UE-Activity-Time",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, Time_type, NULL);
+	};
+
+	/* EPS-User-State */
+	{
+		struct dict_avp_data data = {
+			1495,	/* Code */
+			10415,	/* Vendor */
+			"EPS-User-State",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* EPS-Location-Information */
+	{
+		struct dict_avp_data data = {
+			1496,	/* Code */
+			10415,	/* Vendor */
+			"EPS-Location-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* MME-User-State */
+	{
+		struct dict_avp_data data = {
+			1497,	/* Code */
+			10415,	/* Vendor */
+			"MME-User-State",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* SGSN-User-State */
+	{
+		struct dict_avp_data data = {
+			1498,	/* Code */
+			10415,	/* Vendor */
+			"SGSN-User-State",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* User-State */
+	{
+		struct dict_avp_data data = {
+			1499,	/* Code */
+			10415,	/* Vendor */
+			"User-State",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(User-State)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* MME-LocationInformation */
+	{
+		struct dict_avp_data data = {
+			1600,	/* Code */
+			10415,	/* Vendor */
+			"MME-LocationInformation",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* SGSN-Location-Information */
+	{
+		struct dict_avp_data data = {
+			1601,	/* Code */
+			10415,	/* Vendor */
+			"SGSN-Location-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* E-UTRAN-Cell-Global-Identity */
+	{
+		struct dict_avp_data data = {
+			1602,	/* Code */
+			10415,	/* Vendor */
+			"E-UTRAN-Cell-Global-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Tracking-Area-Identity */
+	{
+		struct dict_avp_data data = {
+			1603,	/* Code */
+			10415,	/* Vendor */
+			"Tracking-Area-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Cell-Global-Identity */
+	{
+		struct dict_avp_data data = {
+			1604,	/* Code */
+			10415,	/* Vendor */
+			"Cell-Global-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Routing-Area-Identity */
+	{
+		struct dict_avp_data data = {
+			1605,	/* Code */
+			10415,	/* Vendor */
+			"Routing-Area-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Location-Area-Identity */
+	{
+		struct dict_avp_data data = {
+			1606,	/* Code */
+			10415,	/* Vendor */
+			"Location-Area-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Service-Area-Identity */
+	{
+		struct dict_avp_data data = {
+			1607,	/* Code */
+			10415,	/* Vendor */
+			"Service-Area-Identity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Geographical-Information */
+	{
+		struct dict_avp_data data = {
+			1608,	/* Code */
+			10415,	/* Vendor */
+			"Geographical-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Geodetic-Information */
+	{
+		struct dict_avp_data data = {
+			1609,	/* Code */
+			10415,	/* Vendor */
+			"Geodetic-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Current-Location-Retrieved */
+	{
+		struct dict_avp_data data = {
+			1610,	/* Code */
+			10415,	/* Vendor */
+			"Current-Location-Retrieved",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Current-Location-Retrieved)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Age-Of-Location-Information */
+	{
+		struct dict_avp_data data = {
+			1611,	/* Code */
+			10415,	/* Vendor */
+			"Age-Of-Location-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Active-APN */
+	{
+		struct dict_avp_data data = {
+			1612,	/* Code */
+			10415,	/* Vendor */
+			"Active-APN",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Error-Diagnostic */
+	{
+		struct dict_avp_data data = {
+			1614,	/* Code */
+			10415,	/* Vendor */
+			"Error-Diagnostic",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Error-Diagnostic)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Ext-PDP-Address */
+	{
+		struct dict_avp_data data = {
+			1621,	/* Code */
+			10415,	/* Vendor */
+			"Ext-PDP-Address",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, Address_type, NULL);
+	};
+
+	/* UE-SRVCC-Capability */
+	{
+		struct dict_avp_data data = {
+			1615,	/* Code */
+			10415,	/* Vendor */
+			"UE-SRVCC-Capability",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(UE-SRVCC-Capability)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* MPS-Priority */
+	{
+		struct dict_avp_data data = {
+			1616,	/* Code */
+			10415,	/* Vendor */
+			"MPS-Priority",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* VPLMN-LIPA-Allowed */
+	{
+		struct dict_avp_data data = {
+			1617,	/* Code */
+			10415,	/* Vendor */
+			"VPLMN-LIPA-Allowed",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(VPLMN-LIPA-Allowed)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* LIPA-Permission */
+	{
+		struct dict_avp_data data = {
+			1618,	/* Code */
+			10415,	/* Vendor */
+			"LIPA-Permission",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(LIPA-Permission)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Subscribed-Periodic-RAU-TAU-Timer */
+	{
+		struct dict_avp_data data = {
+			1619,	/* Code */
+			10415,	/* Vendor */
+			"Subscribed-Periodic-RAU-TAU-Timer",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Ext-PDP-Type */
+	{
+		struct dict_avp_data data = {
+			1620,	/* Code */
+			10415,	/* Vendor */
+			"Ext-PDP-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* SIPTO-Permission */
+	{
+		struct dict_avp_data data = {
+			1613,	/* Code */
+			10415,	/* Vendor */
+			"SIPTO-Permission",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(SIPTO-Permission)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* MDT-Configuration */
+	{
+		struct dict_avp_data data = {
+			1622,	/* Code */
+			10415,	/* Vendor */
+			"MDT-Configuration",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Job-Type */
+	{
+		struct dict_avp_data data = {
+			1623,	/* Code */
+			10415,	/* Vendor */
+			"Job-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Job-Type)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Area-Scope */
+	{
+		struct dict_avp_data data = {
+			1624,	/* Code */
+			10415,	/* Vendor */
+			"Area-Scope",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* List-Of-Measurements */
+	{
+		struct dict_avp_data data = {
+			1625,	/* Code */
+			10415,	/* Vendor */
+			"List-Of-Measurements",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Reporting-Trigger */
+	{
+		struct dict_avp_data data = {
+			1626,	/* Code */
+			10415,	/* Vendor */
+			"Reporting-Trigger",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Report-Interval */
+	{
+		struct dict_avp_data data = {
+			1627,	/* Code */
+			10415,	/* Vendor */
+			"Report-Interval",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Report-Interval)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Report-Amount */
+	{
+		struct dict_avp_data data = {
+			1628,	/* Code */
+			10415,	/* Vendor */
+			"Report-Amount",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Report-Amount)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Event-Threshold-RSRP */
+	{
+		struct dict_avp_data data = {
+			1629,	/* Code */
+			10415,	/* Vendor */
+			"Event-Threshold-RSRP",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Event-Threshold-RSRQ */
+	{
+		struct dict_avp_data data = {
+			1630,	/* Code */
+			10415,	/* Vendor */
+			"Event-Threshold-RSRQ",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Logging-Interval */
+	{
+		struct dict_avp_data data = {
+			1631,	/* Code */
+			10415,	/* Vendor */
+			"Logging-Interval",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Logging-Interval)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Logging-Duration */
+	{
+		struct dict_avp_data data = {
+			1632,	/* Code */
+			10415,	/* Vendor */
+			"Logging-Duration",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Logging-Duration)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Relay-Node-Indicator */
+	{
+		struct dict_avp_data data = {
+			1633,	/* Code */
+			10415,	/* Vendor */
+			"Relay-Node-Indicator",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Relay-Node-Indicator)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* MDT-User-Consent */
+	{
+		struct dict_avp_data data = {
+			1634,	/* Code */
+			10415,	/* Vendor */
+			"MDT-User-Consent",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(MDT-User-Consent)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* PUR-Flags */
+	{
+		struct dict_avp_data data = {
+			1635,	/* Code */
+			10415,	/* Vendor */
+			"PUR-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Subscribed-VSRVCC */
+	{
+		struct dict_avp_data data = {
+			1636,	/* Code */
+			10415,	/* Vendor */
+			"Subscribed-VSRVCC",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Subscribed-VSRVCC)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Equivalent-PLMN-List */
+	{
+		struct dict_avp_data data = {
+			1637,	/* Code */
+			10415,	/* Vendor */
+			"Equivalent-PLMN-List",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* CLR-Flags */
+	{
+		struct dict_avp_data data = {
+			1638,	/* Code */
+			10415,	/* Vendor */
+			"CLR-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* UVR-Flags */
+	{
+		struct dict_avp_data data = {
+			1639,	/* Code */
+			10415,	/* Vendor */
+			"UVR-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* UVA-Flags */
+	{
+		struct dict_avp_data data = {
+			1640,	/* Code */
+			10415,	/* Vendor */
+			"UVA-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* VPLMN-CSG-Subscription-Data */
+	{
+		struct dict_avp_data data = {
+			1641,	/* Code */
+			10415,	/* Vendor */
+			"VPLMN-CSG-Subscription-Data",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Time-Zone */
+	{
+		struct dict_avp_data data = {
+			1642,	/* Code */
+			10415,	/* Vendor */
+			"Time-Zone",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* A-MSISDN */
+	{
+		struct dict_avp_data data = {
+			1643,	/* Code */
+			10415,	/* Vendor */
+			"A-MSISDN",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* MME-Number-for-MT-SMS */
+	{
+		struct dict_avp_data data = {
+			1645,	/* Code */
+			10415,	/* Vendor */
+			"MME-Number-for-MT-SMS",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* SMS-Register-Request */
+	{
+		struct dict_avp_data data = {
+			1648,	/* Code */
+			10415,	/* Vendor */
+			"SMS-Register-Request",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(SMS-Register-Request)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Local-Time-Zone */
+	{
+		struct dict_avp_data data = {
+			1649,	/* Code */
+			10415,	/* Vendor */
+			"Local-Time-Zone",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Daylight-Saving-Time */
+	{
+		struct dict_avp_data data = {
+			1650,	/* Code */
+			10415,	/* Vendor */
+			"Daylight-Saving-Time",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Daylight-Saving-Time)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Subscription-Data-Flags */
+	{
+		struct dict_avp_data data = {
+			1654,	/* Code */
+			10415,	/* Vendor */
+			"Subscription-Data-Flags",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Measurement-Period-UMTS */
+	{
+		struct dict_avp_data data = {
+			1655,	/* Code */
+			10415,	/* Vendor */
+			"Measurement-Period-UMTS",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Measurement-Period-UMTS)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Measurement-Period-LTE */
+	{
+		struct dict_avp_data data = {
+			1656,	/* Code */
+			10415,	/* Vendor */
+			"Measurement-Period-LTE",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Measurement-Period-LTE)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Collection-Period-RRM-LTE */
+	{
+		struct dict_avp_data data = {
+			1657,	/* Code */
+			10415,	/* Vendor */
+			"Collection-Period-RRM-LTE",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Collection-Period-RRM-LTE)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Collection-Period-RRM-UMTS */
+	{
+		struct dict_avp_data data = {
+			1658,	/* Code */
+			10415,	/* Vendor */
+			"Collection-Period-RRM-UMTS",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		struct dict_object		*type;
+		struct dict_type_data	 tdata = { AVP_TYPE_INTEGER32, "3GPP/Enumerated(Collection-Period-RRM-UMTS)", NULL, NULL, NULL };
+		CHECK_dict_new(DICT_TYPE, &tdata, NULL, &type);
+		CHECK_dict_new(DICT_AVP, &data, type, NULL);
+	};
+
+	/* Positioning-Method */
+	{
+		struct dict_avp_data data = {
+			1659,	/* Code */
+			10415,	/* Vendor */
+			"Positioning-Method",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Measurement-Quantity */
+	{
+		struct dict_avp_data data = {
+			1660,	/* Code */
+			10415,	/* Vendor */
+			"Measurement-Quantity",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Event-Threshold-Event-1F */
+	{
+		struct dict_avp_data data = {
+			1661,	/* Code */
+			10415,	/* Vendor */
+			"Event-Threshold-Event-1F",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Event-Threshold-Event-1I */
+	{
+		struct dict_avp_data data = {
+			1662,	/* Code */
+			10415,	/* Vendor */
+			"Event-Threshold-Event-1I",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_INTEGER32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
 	/* 3GPP 29.329-b50 (11.5.0 2012.12.21)                          */
 	/* User-Identity */
 	{
@@ -6750,12 +9852,12 @@
 	};
 
 	/* Name conflict with 29.229 User-Data (606), renamed           */
-	/* User-Data-Sh */
+	/* User-Data-29.329 */
 	{
 		struct dict_avp_data data = {
 			702,	/* Code */
 			10415,	/* Vendor */
-			"User-Data-Sh",	/* Name */
+			"User-Data-29.329",	/* Name */
 			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
 			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
 			AVP_TYPE_OCTETSTRING	/* base type of data */
@@ -7006,6 +10108,653 @@
 		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
 	};
 
+	/* OMA DDS Charging_Data V1.0 20110201-A                        */
+	/* Application-Server-Id */
+	{
+		struct dict_avp_data data = {
+			2101,	/* Code */
+			10415,	/* Vendor */
+			"Application-Server-Id",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Application-Service-Type */
+	{
+		struct dict_avp_data data = {
+			2102,	/* Code */
+			10415,	/* Vendor */
+			"Application-Service-Type",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Application-Session-Id */
+	{
+		struct dict_avp_data data = {
+			2103,	/* Code */
+			10415,	/* Vendor */
+			"Application-Session-Id",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Content-ID */
+	{
+		struct dict_avp_data data = {
+			2116,	/* Code */
+			10415,	/* Vendor */
+			"Content-ID",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* Content-provider-ID */
+	{
+		struct dict_avp_data data = {
+			2117,	/* Code */
+			10415,	/* Vendor */
+			"Content-provider-ID",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* DCD-Information */
+	{
+		struct dict_avp_data data = {
+			2115,	/* Code */
+			10415,	/* Vendor */
+			"DCD-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Delivery-Status */
+	{
+		struct dict_avp_data data = {
+			2104,	/* Code */
+			10415,	/* Vendor */
+			"Delivery-Status",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, UTF8String_type, NULL);
+	};
+
+	/* IM-Information */
+	{
+		struct dict_avp_data data = {
+			2110,	/* Code */
+			10415,	/* Vendor */
+			"IM-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Number-Of-Messages-Successfully-Exploded */
+	{
+		struct dict_avp_data data = {
+			2111,	/* Code */
+			10415,	/* Vendor */
+			"Number-Of-Messages-Successfully-Exploded",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Number-Of-Messages-Successfully-Sent */
+	{
+		struct dict_avp_data data = {
+			2112,	/* Code */
+			10415,	/* Vendor */
+			"Number-Of-Messages-Successfully-Sent",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Service-Generic-Information */
+	{
+		struct dict_avp_data data = {
+			1256,	/* Code */
+			10415,	/* Vendor */
+			"Service-Generic-Information",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_GROUPED	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Total-Number-Of-Messages-Exploded */
+	{
+		struct dict_avp_data data = {
+			2113,	/* Code */
+			10415,	/* Vendor */
+			"Total-Number-Of-Messages-Exploded",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* Total-Number-Of-Messages-Sent */
+	{
+		struct dict_avp_data data = {
+			2114,	/* Code */
+			10415,	/* Vendor */
+			"Total-Number-Of-Messages-Sent",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flag values */
+			AVP_TYPE_UNSIGNED32	/* base type of data */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+
+
+	/*****************************************************/
+	/* end of generated data, rules below added manually */
+	/*****************************************************/
+
+
+	
+	/* 3GPP2-BSID */
+	{
+		struct dict_avp_data data = {
+			9010,	/* Code */
+			5535,	/* Vendor */
+			"3GPP2-BSID",	/* Name */
+			AVP_FLAG_VENDOR |AVP_FLAG_MANDATORY,	/* Fixed flags */
+			AVP_FLAG_VENDOR,	/* Fixed flag values */
+			AVP_TYPE_OCTETSTRING	/* base type of data */ /* XXX: guessed */
+		};
+		CHECK_dict_new(DICT_AVP, &data, NULL, NULL);
+	};
+
+	/* 29.212 */
+	
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Allocation-Retention-Priority";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Priority-Level" }, RULE_REQUIRED, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Pre-emption-Capability" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Pre-emption-Vulnerability" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "QoS-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "QoS-Class-Identifier" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Max-Requested-Bandwidth-UL" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Max-Requested-Bandwidth-DL" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Guaranteed-Bitrate-UL" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Guaranteed-Bitrate-DL" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Bearer-Identifier" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Allocation-Retention-Priority" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "APN-Aggregate-Max-Bitrate-UL" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "APN-Aggregate-Max-Bitrate-DL" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	/* 32.299 */
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Application-Server-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Application-Server" }, RULE_REQUIRED, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Application-Provided-Called-Party-Address" }, RULE_OPTIONAL, -1, -1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Envelope";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Envelope-Start-Time" }, RULE_REQUIRED, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Envelope-End-Time" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 0,     .avp_name = "CC-Total-Octets" }, RULE_REQUIRED, -1, 1 },
+				{ { .avp_vendor = 0,     .avp_name = "CC-Input-Octets" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 0,     .avp_name = "CC-Output-Octets" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 0,     .avp_name = "CC-Service-Specific-Units" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "IMS-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Event-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Role-Of-Node" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Node-Functionality" }, RULE_REQUIRED, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "User-Session-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Outgoing-Session-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Session-Priority" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Calling-Party-Address" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Called-Party-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Called-Asserted-Identity" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Number-Portability-Routing-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Carrier-Select-Routing-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Alternate-Charged-Party-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Requested-Party-Address" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Associated-URI" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Time-Stamps" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Application-Server-Information" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Inter-Operator-Identifier" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Transit-IOI-List" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "IMS-Charging-Identifier" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SDP-Session-Description" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "SDP-Media-Component" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Served-Party-IP-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Server-Capabilities" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Trunk-Group-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Bearer-Service" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Service-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Service-Specific-Info" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Message-Body" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Cause-Code" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Access-Network-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Early-Media-Description" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "IMS-Communication-Service-Identifier" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "IMS-Application-Reference-Identifier" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Online-Charging-Flag" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Real-Time-Tariff-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Account-Expiration" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Initial-IMS-Charging-Identifier" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "NNI-Information" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "From-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "IMS-Emergency-Indicator" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Access-Transfer-Information" }, RULE_OPTIONAL, -1, -1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "MMS-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Originator-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Recipient-Address" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Submission-Time" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "MM-Content-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Priority" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Message-ID" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Message-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Message-Size" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Message-Class" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Delivery-Report-Requested" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Read-Reply-Report-Requested" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "MMBox-Storage-Requested" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Applic-ID" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Reply-Applic-ID" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Aux-Applic-Info" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Content-Class" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "DRM-Content" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Adaptations" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "VASP-ID" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "VAS-ID" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+        {
+		/* Multiple-Services-Credit-Control */
+		/* additional allowed AVPs */
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 0;
+		vpa.avp_name = "Multiple-Services-Credit-Control";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Time-Quota-Threshold" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Volume-Quota-Threshold" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Unit-Quota-Threshold" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Quota-Holding-Time" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Quota-Consumption-Time" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Reporting-Reason" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Trigger" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PS-Furnish-Charging-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Refund-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "AF-Correlation-Information" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Envelope" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Envelope-Reporting" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Time-Quota-Mechanism" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Service-Specific-Info" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "QoS-Information" }, RULE_OPTIONAL, -1, 1 },
+			};
+		PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Offline-Charging";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Quota-Consumption-Time" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Time-Quota-Mechanism" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Envelope-Reporting" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 0,     .avp_name = "Multiple-Services-Credit-Control" }, RULE_OPTIONAL, -1, -1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Originator-Address";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Address-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Address-Data" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Address-Domain" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "PS-Furnish-Charging-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-Charging-Id" }, RULE_REQUIRED, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PS-Free-Format-Data" }, RULE_REQUIRED, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PS-Append-Free-Format-Data" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "PS-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-Charging-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PDN-Connection-Charging-ID" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Node-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-PDP-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PDP-Address" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "PDP-Address-Prefix-Length" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Dynamic-Address-Flag" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Dynamic-Address-Flag-Extension" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "QoS-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SGSN-Address" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "GGSN-Address" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "SGW-Address" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "CG-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Serving-Node-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SGW-Change" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-IMSI-MCC-MNC" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "IMSI-Unauthenticated-Flag" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-GGSN-MCC-MNC" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-NSAPI" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 0,     .avp_name = "Called-Station-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-Session-Stop-Indicator" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-Selection-Mode" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-Charging-Characteristics" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Charging-Characteristics-Selection-Mode" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-SGSN-MCC-MNC" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-MS-TimeZone" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Charging-Rule-Base-Name" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-User-Location-Info" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "User-CSG-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 5535, .avp_name = "3GPP2-BSID" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-RAT-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PS-Furnish-Charging-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PDP-Context-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Offline-Charging" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Traffic-Data-Volumes" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Service-Data-Container" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 0,     .avp_name = "User-Equipment-Info" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Terminal-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Start-Time" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Stop-Time" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Change-Condition" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Diagnostics" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Low-Priority-Indicator" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "MME-Number-for-MT-SMS" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "MME-Name" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "MME-Realm" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Recipient-Address";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Address-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Address-Data" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Address-Domain" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Addressee-Type" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "SDP-Media-Component";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "SDP-Media-Name" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SDP-Media-Description" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Local-GW-Inserted-Indication" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "IP-Realm-Default-Indication" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Transcoder-Inserted-Indication" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Media-Initiator-Flag" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Media-Initiator-Party" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "3GPP-Charging-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Access-Network-Charging-Identifier-Value" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SDP-Type" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Service-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 0,     .avp_name = "Subscription-Id" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "AoC-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PS-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "WLAN-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "IMS-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "MMS-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "LCS-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "PoC-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "MBMS-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SMS-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "MMTel-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Service-Generic-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "IM-Information" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "DCD-Information" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "SMS-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "SMS-Node" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Client-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Originator-SCCP-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SMSC-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Data-Coding-Scheme" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SM-Discharge-Time" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SM-Message-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Originator-Interface" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SM-Protocol-ID" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Reply-Path-Requested" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SM-Status" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SM-User-Data-Header" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Number-Of-Messages-Sent" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Recipient-Info" }, RULE_OPTIONAL, -1, -1 },
+				{ { .avp_vendor = 10415, .avp_name = "Originator-Received-Address" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SM-Service-Type" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Time-Quota-Mechanism";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Time-Quota-Type" }, RULE_REQUIRED, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Base-Time-Interval" }, RULE_REQUIRED, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Time-Stamps";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "SIP-Request-Timestamp" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SIP-Response-Timestamp" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SIP-Request-Timestamp-Fraction" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "SIP-Response-Timestamp-Fraction" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+
+	/* OMA */
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "DCD-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Content-ID" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Content-provider-ID" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "IM-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Total-Number-Of-Messages-Sent" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Total-Number-Of-Messages-Exploded" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Number-Of-Messages-Successfully-Sent" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Number-Of-Messages-Successfully-Exploded" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
+	{
+		struct dict_object *rule_avp;
+		struct dict_avp_request vpa;
+		vpa.avp_vendor = 10415;
+		vpa.avp_name = "Service-Generic-Information";
+		CHECK_dict_search(DICT_AVP, AVP_BY_NAME_AND_VENDOR, &vpa, &rule_avp);
+		struct local_rules_definition rules[] =
+			{
+				{ { .avp_vendor = 10415, .avp_name = "Application-Server-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Application-Service-Type" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Application-Session-Id" }, RULE_OPTIONAL, -1, 1 },
+				{ { .avp_vendor = 10415, .avp_name = "Delivery-Status" }, RULE_OPTIONAL, -1, 1 },
+			};
+			PARSE_loc_rules(rules, rule_avp);
+        }
 	
 	TRACE_DEBUG(INFO, "Extension 'Dictionary definitions for DCCA 3GPP' initialized");
 	return 0;
--- a/extensions/dict_dcca_3gpp/dict_dcca_3gpp.org	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dict_dcca_3gpp/dict_dcca_3gpp.org	Fri May 10 18:49:19 2013 +0800
@@ -75,7 +75,46 @@
 | MBMS-Flow-Identifier                                          |  920 |         17.7.23 | OctetString      | M,V  | P   |          |          |      |
 | CN-IP-Multicast-Distribution                                  |  921 |         17.7.24 | Enumerated       | M,V  | P   |          |          |      |
 | MBMS-HC-Indicator                                             |  922 |         17.7.25 | Enumerated       | M,V  | P   |          |          |      |
-| # 3GPP 29.212-b70 (11.7.0 2012.12.20)                         |      |                 |                  |      |     |          |          |      |
+| # 3GPP 29.140-700 (7.0.0 2007.07.05)                          |      |                 |                  |      |     |          |          |      |
+| Served-User-Identity                                          | 1100 |           6.3.1 | Grouped          | M,V  |     |          |          | N    |
+| # reuses: MSISDN                                              |  701 |           6.3.2 | OctetString      | M,V  |     |          |          | N    |
+| VASP-ID                                                       | 1101 |           6.3.3 | UTF8String       | M,V  |     |          |          | N    |
+| VAS-ID                                                        | 1102 |           6.3.4 | UTF8String       | M,V  |     |          |          | N    |
+| Trigger-Event                                                 | 1103 |           6.3.5 | Enumerated       | M,V  |     |          |          | N    |
+| # reuses: 3GPP-IMSI                                           |    1 |           6.3.6 | UTF8String       | M,V  |     |          |          | N    |
+| Sender-Address                                                | 1104 |           6.3.7 | UTF8String       | M,V  |     |          |          | N    |
+| Initial-Recipient-Address                                     | 1105 |           6.3.8 | Grouped          | M,V  |     |          |          | N    |
+| Result-Recipient-Address                                      | 1106 |           6.3.9 | Grouped          | M,V  |     |          |          | N    |
+| # conflicts with one in (more common) 32.329                  |      |                 |                  |      |     |          |          |      |
+| Sequence-Number-29.140                                        | 1107 |          6.3.10 | Unsigned32       | M,V  |     |          |          | N    |
+| # conflicts with one in (more common) 32.299                  |      |                 |                  |      |     |          |          |      |
+| Recipient-Address-29.140                                      | 1108 |          6.3.11 | UTF8String       | M,V  |     |          |          | N    |
+| Routeing-Address                                              | 1109 |          6.3.12 | UTF8String       | M,V  |     |          |          | N    |
+| Originating-Interface                                         | 1110 |          6.3.13 | Enumerated       | M,V  |     |          |          | N    |
+| Delivery-Report                                               | 1111 |          6.3.14 | Enumerated       | M,V  |     |          |          | N    |
+| Read-Reply                                                    | 1112 |          6.3.15 | Enumerated       | M,V  |     |          |          | N    |
+| Sender-Visibility                                             | 1113 |          6.3.16 | Enumerated       | M,V  |     |          |          | N    |
+| Service-Key                                                   | 1114 |          6.3.17 | UTF8String       | M,V  |     |          |          | N    |
+| Billing-Information                                           | 1115 |          6.3.18 | UTF8String       | M,V  |     |          |          | N    |
+| # conflicts with one in (more common) 32.299                  |      |                 |                  |      |     |          |          |      |
+| Status-29.140                                                 | 1116 |          6.3.19 | Grouped          | M,V  |     |          |          | N    |
+| Status-Code                                                   | 1117 |          6.3.20 | UTF8String       | M,V  |     |          |          | N    |
+| Status-Text                                                   | 1118 |          6.3.21 | UTF8String       | M,V  |     |          |          | N    |
+| Routeing-Address-Resolution                                   | 1119 |          6.3.22 | Enumerated       | M,V  |     |          |          | N    |
+| # 3GPP 29.173-c00 (12.0.0 2013.03.13)                         |      |                 |                  |      |     |          |          |      |
+| LMSI                                                          | 2400 |           6.4.2 | OctetString      | M,V  |     |          |          | N    |
+| Serving-Node                                                  | 2401 |           6.4.3 | Grouped          | M,V  |     |          |          | N    |
+| MME-Name                                                      | 2402 |           6.4.4 | DiameterIdentity | M,V  |     |          |          | N    |
+| MSC-Number                                                    | 2403 |           6.4.5 | OctetString      | M,V  |     |          |          | N    |
+| LCS-Capabilities-Sets                                         | 2404 |           6.4.6 | Unsigned32       | M,V  |     |          |          | N    |
+| GMLC-Address                                                  | 2405 |           6.4.7 | Address          | M,V  |     |          |          | N    |
+| Additional-Serving-Node                                       | 2406 |           6.4.8 | Grouped          | M,V  |     |          |          | N    |
+| PPR-Address                                                   | 2407 |           6.4.9 | Address          | M,V  |     |          |          | N    |
+| MME-Realm                                                     | 2408 |          6.4.12 | DiameterIdentity | V    |     |          | M        | N    |
+| SGSN-Name                                                     | 2409 |          6.4.13 | DiameterIdentity | V    |     |          | M        | N    |
+| SGSN-Realm                                                    | 2410 |          6.4.14 | DiameterIdentity | V    |     |          | M        | N    |
+| # 3GPP 29.212-c00 (12.0.0 2013.03.15)                         |      |                 |                  |      |     |          |          |      |
+| # Gx-specific                                                 |      |                 |                  |      |     |          |          |      |
 | ADC-Revalidation-Time                                         | 2801 |          5.3.93 | Time             | V    | P   |          | M        | Y    |
 | ADC-Rule-Install                                              | 1092 |          5.3.85 | Grouped          | V    | P   |          | M        | Y    |
 | ADC-Rule-Remove                                               | 1093 |          5.3.86 | Grouped          | V    | P   |          | M        | Y    |
@@ -112,7 +151,6 @@
 | IP-CAN-Type                                                   | 1027 |          5.3.27 | Enumerated       | M,V  | P   |          |          | Y    |
 | Guaranteed-Bitrate-DL                                         | 1025 |          5.3.25 | Unsigned32       | M,V  | P   |          |          | Y    |
 | Guaranteed-Bitrate-UL                                         | 1026 |          5.3.26 | Unsigned32       | M,V  | P   |          |          | Y    |
-| HeNB-BBF-FQDN                                                 | 2803 |          5.3.94 | UTF8String       | V    | P   |          | M        | Y    |
 | HeNB-Local-IP-Address                                         | 2804 |          5.3.95 | Address          | V    | P   |          | M        | Y    |
 | Metering-Method                                               | 1007 |           5.3.8 | Enumerated       | M,V  | P   |          |          | Y    |
 | Monitoring-Key                                                | 1066 |          5.3.59 | OctetString      | V    | P   |          | M        | Y    |
@@ -132,7 +170,7 @@
 | Pre-emption-Vulnerability                                     | 1048 |          5.3.47 | Enumerated       | V    | P   |          | M        | Y    |
 | Priority-Level                                                | 1046 |          5.3.45 | Unsigned32       | V    | P   |          | M        | Y    |
 | Redirect-Information                                          | 1085 |          5.3.82 | Grouped          | V    | P   |          | M        | Y    |
-| Redirect- Support                                             | 1086 |          5.3.83 | Enumerated       | V    | P   |          | M        | Y    |
+| Redirect-Support                                              | 1086 |          5.3.83 | Enumerated       | V    | P   |          | M        | Y    |
 | Reporting-Level                                               | 1011 |          5.3.12 | Enumerated       | M,V  | P   |          |          | Y    |
 | Routing-Filter                                                | 1078 |          5.3.72 | Grouped          | V    | P   |          | M        | Y    |
 | Routing-IP-Address                                            | 1079 |          5.3.73 | Address          | V    | P   |          | M        | Y    |
@@ -147,11 +185,11 @@
 | TDF-Application-Instance-Identifier                           | 2802 |          5.3.92 | OctetString      | V    | P   |          | M        | Y    |
 | TDF-Destination-Host                                          | 1089 |          5.3.80 | DiameterIdentity | V    | P   |          | M        | Y    |
 | TDF-Destination-Realm                                         | 1090 |          5.3.79 | DiameterIdentity | V    | P   |          | M        | Y    |
-| TDF-IP-address                                                | 1091 |          5.3.81 | Address          | V    | P   |          | M        | Y    |
+| TDF-IP-Address                                                | 1091 |          5.3.81 | Address          | V    | P   |          | M        | Y    |
 | QoS-Class-Identifier                                          | 1028 |          5.3.17 | Enumerated       | M,V  | P   |          |          | Y    |
 | QoS-Information                                               | 1016 |          5.3.16 | Grouped          | M.V  | P   |          |          | Y    |
 | QoS-Negotiation                                               | 1029 |          5.3.28 | Enumerated       | M,V  | P   |          |          | Y    |
-| Qos-Upgrade                                                   | 1030 |          5.3.29 | Enumerated       | M.V  | P   |          |          | Y    |
+| QoS-Upgrade                                                   | 1030 |          5.3.29 | Enumerated       | M.V  | P   |          |          | Y    |
 | PS-to-CS-Session-Continuity                                   | 1099 |          5.3.84 | Enumerated       | V    | P   |          |          | Y    |
 | Resource-Allocation-Notification                              | 1063 |          5.3.50 | Enumerated       | V    | P   |          | M        | Y    |
 | Rule-Failure-Code                                             | 1031 |          5.3.38 | Enumerated       | M.V  | P   |          |          | Y    |
@@ -168,10 +206,11 @@
 | UDP-Source-Port                                               | 2806 |          5.3.97 | Unsigned32       | V    | P   |          | M        | Y    |
 | UE-Local-IP-Address                                           | 2805 |          5.3.96 | Address          | V    | P   |          | M        | Y    |
 | Usage-Monitoring-Information                                  | 1067 |          5.3.60 | Grouped          | V    | P   |          | M        | Y    |
-| Rule-DeActivation-Time                                        | 1044 |          5.3.43 | Time             | M,V  | P   |          |          | Y    |
+| Rule-Deactivation-Time                                        | 1044 |          5.3.43 | Time             | M,V  | P   |          |          | Y    |
 | Usage-Monitoring-Level                                        | 1068 |          5.3.61 | Enumerated       | V    | P   |          | M        | Y    |
 | Usage-Monitoring-Report                                       | 1069 |          5.3.62 | Enumerated       | V    | P   |          | M        | Y    |
 | Usage-Monitoring-Support                                      | 1070 |          5.3.63 | Enumerated       | V    | P   |          | M        | Y    |
+| # Gxx-specific                                                |      |                 |                  |      |     |          |          |      |
 | QoS-Rule-Install                                              | 1051 |          5a.3.1 | Grouped          | M,V  | P   |          |          | Y    |
 | QoS-Rule-Remove                                               | 1052 |          5a.3.2 | Grouped          | M,V  | P   |          |          | Y    |
 | QoS-Rule-Definition                                           | 1053 |          5a.3.3 | Grouped          | M,V  | P   |          |          | Y    |
@@ -179,8 +218,45 @@
 | QoS-Rule-Base-Name                                            | 1074 |          5a.3.7 | UTF8String       | V    | P   |          | M        | Y    |
 | QoS-Rule-Report                                               | 1055 |          5a.3.5 | Grouped          | M,V  | P   |          |          | Y    |
 | Session-Linking-Indicator                                     | 1064 |          5a.3.6 | Enumerated       | M,V  | P   |          |          | Y    |
+| # S15-specific                                                |      |                 |                  |      |     |          |          |      |
 | CS-Service-Qos-Request-Identifier                             | 2807 |         E.6.3.2 | OctetString      | M,V  | P   |          |          | Y    |
 | CS-Service-QoS-Request-Operation                              | 2808 |         E.6.3.3 | Enumerated       | M.V  | P   |          |          | Y    |
+| # 3GPP 29.214-b80 (11.8.0 2013.03.15)                         |      |                 |                  |      |     |          |          |      |
+| Abort-Cause                                                   |  500 |           5.3.1 | Enumerated       | M,V  | P   |          |          | Y    |
+| Access-Network-Charging-Address                               |  501 |           5.3.2 | Address          | M,V  | P   |          |          | Y    |
+| Access-Network-Charging-Identifier                            |  502 |           5.3.3 | Grouped          | M,V  | P   |          |          | Y    |
+| Access-Network-Charging-Identifier-Value                      |  503 |           5.3.4 | OctetString      | M,V  | P   |          |          | Y    |
+| Acceptable-Service-Info                                       |  526 |          5.3.24 | Grouped          | M,V  | P   |          |          | Y    |
+| AF-Application-Identifier                                     |  504 |           5.3.5 | OctetString      | M,V  | P   |          |          | Y    |
+| AF-Charging-Identifier                                        |  505 |           5.3.6 | OctetString      | M,V  | P   |          |          | Y    |
+| Application-Service-Provider-Identity                         |  532 |          5.3.29 | UTF8String       | V    | P   |          | M        | Y    |
+| Codec-Data                                                    |  524 |           5.3.7 | OctetString      | M,V  | P   |          |          | Y    |
+| Flow-Description                                              |  507 |           5.3.8 | IPFilterRule     | M,V  | P   |          |          | Y    |
+| Flow-Number                                                   |  509 |           5.3.9 | Unsigned32       | M,V  | P   |          |          | Y    |
+| Flows                                                         |  510 |          5.3.10 | Grouped          | M,V  | P   |          |          | Y    |
+| Flow-Status                                                   |  511 |          5.3.11 | Enumerated       | M,V  | P   |          |          | Y    |
+| Flow-Usage                                                    |  512 |          5.3.12 | Enumerated       | M,V  | P   |          |          | Y    |
+| Service-URN                                                   |  525 |          5.3.23 | OctetString      | M,V  | P   |          |          | Y    |
+| Specific-Action                                               |  513 |          5.3.13 | Enumerated       | M,V  | P   |          |          | Y    |
+| Max-Requested-Bandwidth-DL                                    |  515 |          5.3.14 | Unsigned32       | M,V  | P   |          |          | Y    |
+| Max-Requested-Bandwidth-UL                                    |  516 |          5.3.15 | Unsigned32       | M,V  | P   |          |          | Y    |
+| Media-Component-Description                                   |  517 |          5.3.16 | Grouped          | M,V  | P   |          |          | Y    |
+| Media-Component-Number                                        |  518 |          5.3.17 | Unsigned32       | M,V  | P   |          |          | Y    |
+| Media-Sub-Component                                           |  519 |          5.3.18 | Grouped          | M,V  | P   |          |          | Y    |
+| Media-Type                                                    |  520 |          5.3.19 | Enumerated       | M,V  | P   |          |          | Y    |
+| MPS-Identifier                                                |  528 |          5.3.30 | OctetString      | V    | P   |          | M        | Y    |
+| Min-Requested-Bandwidth-DL                                    |  534 |          5.3.32 | Unsigned32       | V    | P   |          | M        | Y    |
+| Min-Requested-Bandwidth-UL                                    |  535 |          5.3.33 | Unsigned32       | V    | P   |          | M        | Y    |
+| RR-Bandwidth                                                  |  521 |          5.3.20 | Unsigned32       | M,V  | P   |          |          | Y    |
+| RS-Bandwidth                                                  |  522 |          5.3.21 | Unsigned32       | M,V  | P   |          |          | Y    |
+| Service-Info-Status                                           |  527 |          5.3.25 | Enumerated       | M,V  | P   |          |          | Y    |
+| SIP-Forking-Indication                                        |  523 |          5.3.22 | Enumerated       | M,V  | P   |          |          | Y    |
+| Sponsor-Identity                                              |  531 |          5.3.28 | UTF8String       | V    | P   |          | M        | Y    |
+| Sponsored-Connectivity-Data                                   |  530 |          5.3.27 | Grouped          | V    | P   |          | M        | Y    |
+| AF-Signalling-Protocol                                        |  529 |          5.3.26 | Enumerated       | V    | P   |          | M        | Y    |
+| Required-Access-Info                                          |  536 |          5.3.34 | Enumerated       | V    | P   |          | M        | Y    |
+| Rx-Request-Type                                               |  533 |          5.3.31 | Enumerated       | V    | P   |          | M        | Y    |
+| IP-Domain-Id                                                  |  537 |          5.3.35 | OctetString      | V    | P   |          | M        | Y    |
 | # 3GPP 29.229-b20 (11.2.0 2012.12.21)                         |      |                 |                  |      |     |          |          |      |
 | Associated-Identities                                         |  632 |          6.3.33 | Grouped          | V    |     |          | M        | N    |
 | Associated-Registered-Identities                              |  647 |          6.3.50 | Grouped          | V    |     |          | M        | N    |
@@ -264,7 +340,7 @@
 | Applic-ID                                                     | 1218 |                 | UTF8String       | M,V  | P   |          |          | N    |
 | Application-Server                                            |  836 |                 | UTF8String       | M,V  | P   |          |          | N    |
 | Application-Server-Information                                |  850 |                 | Grouped          | M,V  | P   |          |          | N    |
-| Application-provided-called-party-address                     |  837 |                 | UTF8String       | M,V  | P   |          |          | N    |
+| Application-Provided-Called-Party-Address                     |  837 |                 | UTF8String       | M,V  | P   |          |          | N    |
 | Associated-Party-Address                                      | 2035 |                 | UTF8String       | M,V  | P   |          |          | N    |
 | Associated-URI                                                |  856 |                 | UTF8String       | M,V  | P   |          |          | N    |
 | Aux-Applic-Info                                               | 1219 |                 | UTF8String       | M,V  | P   |          |          | N    |
@@ -509,11 +585,165 @@
 | WLAN-Session-Id                                               | 1246 |                 | UTF8String       | M,V  | P   |          |          | N    |
 | WLAN-Technology                                               |  893 |                 | Unsigned32       | M,V  | P   |          |          | N    |
 | WLAN-UE-Local-IPAddress                                       |  894 |                 | Address          | M,V  | P   |          |          | N    |
+| # 3GPP 29.272-c00 (12.0.0 2013.03.13)                         |      |                 |                  |      |     |          |          |      |
+| Subscription-Data                                             | 1400 |           7.3.2 | Grouped          | M,V  |     |          |          | N    |
+| Terminal-Information                                          | 1401 |           7.3.3 | Grouped          | M,V  |     |          |          | N    |
+| IMEI                                                          | 1402 |           7.3.4 | UTF8String       | M,V  |     |          |          | N    |
+| Software-Version                                              | 1403 |           7.3.5 | UTF8String       | M,V  |     |          |          | N    |
+| QoS-Subscribed                                                | 1404 |          7.3.77 | OctetString      | M,V  |     |          |          | N    |
+| ULR-Flags                                                     | 1405 |           7.3.7 | Unsigned32       | M,V  |     |          |          | N    |
+| ULA-Flags                                                     | 1406 |           7.3.8 | Unsigned32       | M,V  |     |          |          | N    |
+| Visited-PLMN-Id                                               | 1407 |           7.3.9 | OctetString      | M,V  |     |          |          | N    |
+| Requested-EUTRAN-Authentication-Info                          | 1408 |          7.3.11 | Grouped          | M,V  |     |          |          | N    |
+| Requested-UTRAN- GERAN-Authentication-Info                    | 1409 |          7.3.12 | Grouped          | M,V  |     |          |          | N    |
+| Number-Of-Requested-Vectors                                   | 1410 |          7.3.14 | Unsigned32       | M,V  |     |          |          | N    |
+| Re-Synchronization-Info                                       | 1411 |          7.3.15 | OctetString      | M,V  |     |          |          | N    |
+| Immediate-Response-Preferred                                  | 1412 |          7.3.16 | Unsigned32       | M,V  |     |          |          | N    |
+| Authentication-Info                                           | 1413 |          7.3.17 | Grouped          | M,V  |     |          |          | N    |
+| E-UTRAN-Vector                                                | 1414 |          7.3.18 | Grouped          | M,V  |     |          |          | N    |
+| UTRAN-Vector                                                  | 1415 |          7.3.19 | Grouped          | M,V  |     |          |          | N    |
+| GERAN-Vector                                                  | 1416 |          7.3.20 | Grouped          | M,V  |     |          |          | N    |
+| Network-Access-Mode                                           | 1417 |          7.3.21 | Enumerated       | M,V  |     |          |          | N    |
+| HPLMN-ODB                                                     | 1418 |          7.3.22 | Unsigned32       | M,V  |     |          |          | N    |
+| Item-Number                                                   | 1419 |          7.3.23 | Unsigned32       | M,V  |     |          |          | N    |
+| Cancellation-Type                                             | 1420 |          7.3.24 | Enumerated       | M,V  |     |          |          | N    |
+| DSR-Flags                                                     | 1421 |          7.3.25 | Unsigned32       | M,V  |     |          |          | N    |
+| DSA-Flags                                                     | 1422 |          7.3.26 | Unsigned32       | M,V  |     |          |          | N    |
+| Context-Identifier                                            | 1423 |          7.3.27 | Unsigned32       | M,V  |     |          |          | N    |
+| Subscriber-Status                                             | 1424 |          7.3.29 | Enumerated       | M,V  |     |          |          | N    |
+| Operator-Determined-Barring                                   | 1425 |          7.3.30 | Unsigned32       | M,V  |     |          |          | N    |
+| Access-Restriction-Data                                       | 1426 |          7.3.31 | Unsigned32       | M,V  |     |          |          | N    |
+| APN-OI-Replacement                                            | 1427 |          7.3.32 | UTF8String       | M,V  |     |          |          | N    |
+| All-APN-Configurations-Included-Indicator                     | 1428 |          7.3.33 | Enumerated       | M,V  |     |          |          | N    |
+| APN-Configuration-Profile                                     | 1429 |          7.3.34 | Grouped          | M,V  |     |          |          | N    |
+| APN-Configuration                                             | 1430 |          7.3.35 | Grouped          | M,V  |     |          |          | N    |
+| EPS-Subscribed-QoS-Profile                                    | 1431 |          7.3.37 | Grouped          | M,V  |     |          |          | N    |
+| VPLMN-Dynamic-Address-Allowed                                 | 1432 |          7.3.38 | Enumerated       | M,V  |     |          |          | N    |
+| STN-SR                                                        | 1433 |          7.3.39 | OctetString      | M,V  |     |          |          | N    |
+| Alert-Reason                                                  | 1434 |          7.3.83 | Enumerated       | M,V  |     |          |          | N    |
+| AMBR                                                          | 1435 |          7.3.41 | Grouped          | M,V  |     |          |          | N    |
+| CSG-Subscription-Data                                         | 1436 |          7.3.78 | Grouped          | M. V |     |          |          | N    |
+| CSG-Id                                                        | 1437 |          7.3.79 | Unsigned32       | M,V  |     |          |          | N    |
+| PDN-GW-Allocation-Type                                        | 1438 |          7.3.44 | Enumerated       | M,V  |     |          |          | N    |
+| Expiration-Date                                               | 1439 |          7.3.80 | Time             | M,V  |     |          |          | N    |
+| RAT-Frequency-Selection-Priority-ID                           | 1440 |          7.3.46 | Unsigned32       | M,V  |     |          |          | N    |
+| IDA-Flags                                                     | 1441 |          7.3.47 | Unsigned32       | M,V  |     |          |          | N    |
+| PUA-Flags                                                     | 1442 |          7.3.48 | Unsigned32       | M,V  |     |          |          | N    |
+| NOR-Flags                                                     | 1443 |          7.3.49 | Unsigned32       | M,V  |     |          |          | N    |
+| User-Id                                                       | 1444 |          7.3.50 | UTF8String       | V    |     |          | M        | N    |
+| Equipment-Status                                              | 1445 |          7.3.51 | Enumerated       | M,V  |     |          |          | N    |
+| Regional-Subscription-Zone-Code                               | 1446 |          7.3.52 | OctetString      | M,V  |     |          |          | N    |
+| RAND                                                          | 1447 |          7.3.53 | OctetString      | M,V  |     |          |          | N    |
+| XRES                                                          | 1448 |          7.3.54 | OctetString      | M,V  |     |          |          | N    |
+| AUTN                                                          | 1449 |          7.3.55 | OctetString      | M,V  |     |          |          | N    |
+| KASME                                                         | 1450 |          7.3.56 | OctetString      | M,V  |     |          |          | N    |
+| Trace-Collection-Entity                                       | 1452 |          7.3.98 | Address          | M,V  |     |          |          | N    |
+| Kc                                                            | 1453 |          7.3.59 | OctetString      | M,V  |     |          |          | N    |
+| SRES                                                          | 1454 |          7.3.60 | OctetString      | M,V  |     |          |          | N    |
+| PDN-Type                                                      | 1456 |          7.3.62 | Enumerated       | M,V  |     |          |          | N    |
+| Roaming-Restricted-Due-To-Unsupported-Feature                 | 1457 |          7.3.81 | Enumerated       | M,V  |     |          |          | N    |
+| Trace-Data                                                    | 1458 |          7.3.63 | Grouped          | M,V  |     |          |          | N    |
+| Trace-Reference                                               | 1459 |          7.3.64 | OctetString      | M,V  |     |          |          | N    |
+| Trace-Depth                                                   | 1462 |          7.3.67 | Enumerated       | M,V  |     |          |          | N    |
+| Trace-NE-Type-List                                            | 1463 |          7.3.68 | OctetString      | M,V  |     |          |          | N    |
+| Trace-Interface-List                                          | 1464 |          7.3.69 | OctetString      | M,V  |     |          |          | N    |
+| Trace-Event-List                                              | 1465 |          7.3.70 | OctetString      | M,V  |     |          |          | N    |
+| OMC-Id                                                        | 1466 |          7.3.71 | OctetString      | M,V  |     |          |          | N    |
+| GPRS-Subscription-Data                                        | 1467 |          7.3.72 | Grouped          | M,V  |     |          |          | N    |
+| Complete-Data-List-Included-Indicator                         | 1468 |          7.3.73 | Enumerated       | M,V  |     |          |          | N    |
+| PDP-Context                                                   | 1469 |          7.3.74 | Grouped          | M,V  |     |          |          | N    |
+| PDP-Type                                                      | 1470 |          7.3.75 | OctetString      | M,V  |     |          |          | N    |
+| 3GPP2-MEID                                                    | 1471 |           7.3.6 | OctetString      | M,V  |     |          |          | N    |
+| Specific-APN-Info                                             | 1472 |          7.3.82 | Grouped          | M,V  |     |          |          | N    |
+| LCS-Info                                                      | 1473 |          7.3.84 | Grouped          | M,V  |     |          |          | N    |
+| GMLC-Number                                                   | 1474 |          7.3.85 | OctetString      | M,V  |     |          |          | N    |
+| LCS-PrivacyException                                          | 1475 |          7.3.86 | Grouped          | M,V  |     |          |          | N    |
+| SS-Code                                                       | 1476 |          7.3.87 | OctetString      | M,V  |     |          |          | N    |
+| SS-Status                                                     | 1477 |          7.3.88 | Grouped          | M,V  |     |          |          | N    |
+| Notification-To-UE-User                                       | 1478 |          7.3.89 | Enumerated       | M,V  |     |          |          | N    |
+| External-Client                                               | 1479 |          7.3.90 | Grouped          | M,V  |     |          |          | N    |
+| Client-Identity                                               | 1480 |          7.3.91 | OctetString      | M,V  |     |          |          | N    |
+| GMLC-Restriction                                              | 1481 |          7.3.92 | Enumerated       | M,V  |     |          |          | N    |
+| PLMN-Client                                                   | 1482 |          7.3.93 | Enumerated       | M,V  |     |          |          | N    |
+| Service-Type                                                  | 1483 |          7.3.94 | Grouped          | M,V  |     |          |          | N    |
+| ServiceTypeIdentity                                           | 1484 |          7.3.95 | Unsigned32       | M,V  |     |          |          | N    |
+| MO-LR                                                         | 1485 |          7.3.96 | Grouped          | M,V  |     |          |          | N    |
+| Teleservice-List                                              | 1486 |          7.3.99 | Grouped          | M,V  |     |          |          | N    |
+| TS-Code                                                       | 1487 |         7.3.100 | OctetString      | M,V  |     |          |          | N    |
+| Call-Barring-Infor-List                                       | 1488 |         7.3.101 | Grouped          | M,V  |     |          |          | N    |
+| SGSN-Number                                                   | 1489 |         7.3.102 | OctetString      | M,V  |     |          |          | N    |
+| IDR-Flags                                                     | 1490 |         7.3.103 | Unsigned32       | M,V  |     |          |          | N    |
+| ICS-Indicator                                                 | 1491 |         7.3.104 | Enumerated       | V    |     |          | M        | N    |
+| IMS-Voice-Over-PS-Sessions-Supported                          | 1492 |         7.3.106 | Enumerated       | V    |     |          | M        | N    |
+| Homogeneous-Support-of-IMS-Voice-Over-PS-Sessions             | 1493 |         7.3.107 | Enumerated       | V    |     |          | M        | N    |
+| Last-UE-Activity-Time                                         | 1494 |         7.3.108 | Time             | V    |     |          | M        | N    |
+| EPS-User-State                                                | 1495 |         7.3.110 | Grouped          | V    |     |          | M        | N    |
+| EPS-Location-Information                                      | 1496 |         7.3.111 | Grouped          | V    |     |          | M        | N    |
+| MME-User-State                                                | 1497 |         7.3.112 | Grouped          | V    |     |          | M        | N    |
+| SGSN-User-State                                               | 1498 |         7.3.113 | Grouped          | V    |     |          | M        | N    |
+| User-State                                                    | 1499 |         7.3.114 | Enumerated       | V    |     |          | M        | N    |
+| MME-Location Information                                      | 1600 |         7.3.115 | Grouped          | V    |     |          | M        | N    |
+| SGSN-Location-Information                                     | 1601 |         7.3.116 | Grouped          | V    |     |          | M        | N    |
+| E-UTRAN-Cell-Global-Identity                                  | 1602 |         7.3.117 | OctetString      | V    |     |          | M        | N    |
+| Tracking-Area-Identity                                        | 1603 |         7.3.118 | OctetString      | V    |     |          | M        | N    |
+| Cell-Global-Identity                                          | 1604 |         7.3.119 | OctetString      | V    |     |          | M        | N    |
+| Routing-Area-Identity                                         | 1605 |         7.3.120 | OctetString      | V    |     |          | M        | N    |
+| Location-Area-Identity                                        | 1606 |         7.3.121 | OctetString      | V    |     |          | M        | N    |
+| Service-Area-Identity                                         | 1607 |         7.3.122 | OctetString      | V    |     |          | M        | N    |
+| Geographical-Information                                      | 1608 |         7.3.123 | OctetString      | V    |     |          | M        | N    |
+| Geodetic-Information                                          | 1609 |         7.3.124 | OctetString      | V    |     |          | M        | N    |
+| Current-Location-Retrieved                                    | 1610 |         7.3.125 | Enumerated       | V    |     |          | M        | N    |
+| Age-Of-Location-Information                                   | 1611 |         7.3.126 | Unsigned32       | V    |     |          | M        | N    |
+| Active-APN                                                    | 1612 |         7.3.127 | Grouped          | V    |     |          | M        | N    |
+| Error-Diagnostic                                              | 1614 |         7.3.128 | Enumerated       | V    |     |          | M        | N    |
+| Ext-PDP-Address                                               | 1621 |         7.3.129 | Address          | V    |     |          | M        | N    |
+| UE-SRVCC-Capability                                           | 1615 |         7.3.130 | Enumerated       | V    |     |          | M        | N    |
+| MPS-Priority                                                  | 1616 |         7.3.131 | Unsigned32       | V    |     |          | M        | N    |
+| VPLMN-LIPA-Allowed                                            | 1617 |         7.3.132 | Enumerated       | V    |     |          | M        | N    |
+| LIPA-Permission                                               | 1618 |         7.3.133 | Enumerated       | V    |     |          | M        | N    |
+| Subscribed-Periodic-RAU-TAU-Timer                             | 1619 |         7.3.134 | Unsigned32       | V    |     |          | M        | N    |
+| Ext-PDP-Type                                                  | 1620 |         7.3.75A | OctetString      | V    |     |          | M        | N    |
+| SIPTO-Permission                                              | 1613 |         7.3.135 | Enumerated       | V    |     |          | M        | N    |
+| MDT-Configuration                                             | 1622 |         7.3.136 | Grouped          | V    |     |          | M        | N    |
+| Job-Type                                                      | 1623 |         7.3.137 | Enumerated       | V    |     |          | M        | N    |
+| Area-Scope                                                    | 1624 |         7.3.138 | Grouped          | V    |     |          | M        | N    |
+| List-Of-Measurements                                          | 1625 |         7.3.139 | Unsigned32       | V    |     |          | M        | N    |
+| Reporting-Trigger                                             | 1626 |         7.3.140 | Unsigned32       | V    |     |          | M        | N    |
+| Report-Interval                                               | 1627 |         7.3.141 | Enumerated       | V    |     |          | M        | N    |
+| Report-Amount                                                 | 1628 |         7.3.142 | Enumerated       | V    |     |          | M        | N    |
+| Event-Threshold-RSRP                                          | 1629 |         7.3.143 | Unsigned32       | V    |     |          | M        | N    |
+| Event-Threshold-RSRQ                                          | 1630 |         7.3.144 | Unsigned32       | V    |     |          | M        | N    |
+| Logging-Interval                                              | 1631 |         7.3.145 | Enumerated       | V    |     |          | M        | N    |
+| Logging-Duration                                              | 1632 |         7.3.146 | Enumerated       | V    |     |          | M        | N    |
+| Relay-Node-Indicator                                          | 1633 |         7.3.147 | Enumerated       | V    |     |          | M        | N    |
+| MDT-User-Consent                                              | 1634 |         7.3.148 | Enumerated       | V    |     |          | M        | N    |
+| PUR-Flags                                                     | 1635 |         7.3.149 | Unsigned32       | V    |     |          | M        | N    |
+| Subscribed-VSRVCC                                             | 1636 |         7.3.150 | Enumerated       | V    |     |          | M        | N    |
+| Equivalent-PLMN-List                                          | 1637 |         7.3.151 | Grouped          | V    |     |          | M        | N    |
+| CLR-Flags                                                     | 1638 |         7.3.152 | Unsigned32       | V    |     |          | M        | N    |
+| UVR-Flags                                                     | 1639 |         7.3.153 | Unsigned32       | M,V  |     |          |          | N    |
+| UVA-Flags                                                     | 1640 |         7.3.154 | Unsigned32       | M,V  |     |          |          | N    |
+| VPLMN-CSG-Subscription-Data                                   | 1641 |         7.3.155 | Grouped          | M,V  |     |          |          | N    |
+| Time-Zone                                                     | 1642 |         7.3.163 | UTF8String       | V    |     |          | M        | N    |
+| A-MSISDN                                                      | 1643 |         7.3.157 | OctetString      | V    |     |          | M        | N    |
+| MME-Number-for-MT-SMS                                         | 1645 |         7.3.159 | OctetString      | V    |     |          | M        | N    |
+| SMS-Register-Request                                          | 1648 |         7.3.162 | Enumerated       | V    |     |          | M        | N    |
+| Local-Time-Zone                                               | 1649 |         7.3.156 | Grouped          | V    |     |          | M        | N    |
+| Daylight-Saving-Time                                          | 1650 |         7.3.164 | Enumerated       | V    |     |          | M        | N    |
+| Subscription-Data-Flags                                       | 1654 |         7.3.165 | Unsigned32       | V    |     |          | M        | N    |
+| Measurement-Period-UMTS                                       | 1655 |         7.3.166 | Enumerated       | V    |     |          | M        | N    |
+| Measurement-Period-LTE                                        | 1656 |         7.3.167 | Enumerated       | V    |     |          | M        | N    |
+| Collection-Period-RRM-LTE                                     | 1657 |         7.3.168 | Enumerated       | V    |     |          | M        | N    |
+| Collection-Period-RRM-UMTS                                    | 1658 |         7.3.169 | Enumerated       | V    |     |          | M        | N    |
+| Positioning-Method                                            | 1659 |         7.3.170 | OctetString      | V    |     |          | M        | N    |
+| Measurement-Quantity                                          | 1660 |         7.3.171 | OctetString      | V    |     |          | M        | N    |
+| Event-Threshold-Event-1F                                      | 1661 |         7.3.172 | Integer32        | V    |     |          | M        | N    |
+| Event-Threshold-Event-1I                                      | 1662 |         7.3.173 | Integer32        | V    |     |          | M        | N    |
 | # 3GPP 29.329-b50 (11.5.0 2012.12.21)                         |      |                 |                  |      |     |          |          |      |
 | User-Identity                                                 |  700 |           6.3.1 | Grouped          | M,V  |     |          |          | N    |
 | MSISDN                                                        |  701 |           6.3.2 | OctetString      | M,V  |     |          |          | N    |
 | # Name conflict with 29.229 User-Data (606), renamed          |      |                 |                  |      |     |          |          |      |
-| User-Data-Sh                                                  |  702 |           6.3.3 | OctetString      | M,V  |     |          |          | N    |
+| User-Data-29.329                                              |  702 |           6.3.3 | OctetString      | M,V  |     |          |          | N    |
 | Data-Reference                                                |  703 |           6.3.4 | Enumerated       | M,V  |     |          |          | N    |
 | Service-Indication                                            |  704 |           6.3.5 | OctetString      | M,V  |     |          |          | N    |
 | Subs-Req-Type                                                 |  705 |           6.3.6 | Enumerated       | M,V  |     |          |          | N    |
@@ -541,3 +771,17 @@
 | Repository-Data-ID                                            |  715 |          6.3.24 | Grouped          | V    |     |          | M        | N    |
 | Sequence-Number                                               |  716 |          6.3.25 | Unsigned32       | V    |     |          | M        | N    |
 | UDR-Flags                                                     |  719 |          6.3.28 | Unsigned32       | V    |     |          | M        | N    |
+| # OMA DDS Charging_Data V1.0 20110201-A                       |      |                 |                  |      |     |          |          |      |
+| Application-Server-Id                                         | 2101 |             8.4 | UTF8String       | M,V  |     |          |          | Y    |
+| Application-Service-Type                                      | 2102 |             8.4 | UTF8String       | M,V  |     |          |          | Y    |
+| Application-Session-Id                                        | 2103 |             8.4 | UTF8String       | M,V  |     |          |          | Y    |
+| Content-ID                                                    | 2116 |             8.4 | UTF8String       | M,V  |     |          |          | Y    |
+| Content-provider-ID                                           | 2117 |             8.4 | UTF8String       | M,V  |     |          |          | Y    |
+| DCD-Information                                               | 2115 |           8.5.5 | Grouped          | M,V  |     |          |          | Y    |
+| Delivery-Status                                               | 2104 |             8.4 | UTF8String       | M,V  |     |          |          | Y    |
+| IM-Information                                                | 2110 |           8.5.6 | Grouped          | M,V  |     |          |          | Y    |
+| Number-Of-Messages-Successfully-Exploded                      | 2111 |             8.4 | Unsigned32       | M,V  |     |          |          | Y    |
+| Number-Of-Messages-Successfully-Sent                          | 2112 |             8.4 | Unsigned32       | M,V  |     |          |          | Y    |
+| Service-Generic-Information                                   | 1256 |          8.5.10 | Grouped          | M,V  |     |          |          | Y    |
+| Total-Number-Of-Messages-Exploded                             | 2113 |             8.4 | Unsigned32       | M,V  |     |          |          | Y    |
+| Total-Number-Of-Messages-Sent                                 | 2114 |             8.4 | Unsigned32       | M,V  |     |          |          | Y    |
--- a/extensions/dict_legacy_xml/dict_lxml_xml.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/dict_legacy_xml/dict_lxml_xml.c	Fri May 10 18:49:19 2013 +0800
@@ -1808,9 +1808,6 @@
 		} );
 	
 	TRACE_DEBUG(FULL, "Conversion from '%s' to freeDiameter internal format complete.", xmlfilename);
-	if (TRACE_BOOL(ANNOYING)) {
-		fd_dict_dump(fd_g_config->cnf_dict);
-	}
 	
 	/* Done */
 	del_dict_contents(&data.dict);
--- a/extensions/test_app/ta_cli.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/test_app/ta_cli.c	Fri May 10 18:49:19 2013 +0800
@@ -45,7 +45,7 @@
 
 static struct session_handler * ta_cli_reg = NULL;
 
-struct ta_mess_info {
+struct sess_state {
 	int32_t		randval;	/* a random value to store in Test-AVP */
 	struct timespec ts;		/* Time of sending the message */
 } ;
@@ -53,7 +53,7 @@
 /* Cb called when an answer is received */
 static void ta_cb_ans(void * data, struct msg ** msg)
 {
-	struct ta_mess_info * mi = NULL;
+	struct sess_state * mi = NULL;
 	struct timespec ts;
 	struct session * sess;
 	struct avp * avp;
@@ -176,7 +176,7 @@
 	struct msg * req = NULL;
 	struct avp * avp;
 	union avp_value val;
-	struct ta_mess_info * mi = NULL, *svg;
+	struct sess_state * mi = NULL, *svg;
 	struct session *sess = NULL;
 	
 	TRACE_DEBUG(FULL, "Creating a new message for sending.");
@@ -190,7 +190,7 @@
 	CHECK_FCT_DO( fd_msg_sess_get(fd_g_config->cnf_dict, req, &sess, NULL), goto out );
 	
 	/* Create the random value to store with the session */
-	mi = malloc(sizeof(struct ta_mess_info));
+	mi = malloc(sizeof(struct sess_state));
 	if (mi == NULL) {
 		fd_log_debug("malloc failed: %s", strerror(errno));
 		goto out;
@@ -264,7 +264,7 @@
 
 int ta_cli_init(void)
 {
-	CHECK_FCT( fd_sess_handler_create(&ta_cli_reg, free, NULL) );
+	CHECK_FCT( fd_sess_handler_create(&ta_cli_reg, (void *)free, NULL, NULL) );
 	
 	CHECK_FCT( fd_event_trig_regcb(ta_conf->signal, "test_app.cli", ta_cli_test_message ) );
 	
--- a/extensions/test_sip/test_sip.c	Fri May 10 09:50:09 2013 +0800
+++ b/extensions/test_sip/test_sip.c	Fri May 10 18:49:19 2013 +0800
@@ -53,7 +53,6 @@
 
 
 struct disp_hdl * test_sip_default_hdl=NULL;
-struct session_handler * ts_sess_hdl;
 
 //configuration stucture
 struct ts_conf * ts_conf=NULL;
@@ -213,7 +212,6 @@
 		return 1;
 	*/
 	
-	CHECK_FCT(fd_sess_handler_create(&ts_sess_hdl, free, NULL));
 	//CHECK_FCT( fd_event_trig_regcb(30, "test_sip", (void *)test_sipSL_LIR_cb ) );
 	CHECK_FCT( fd_event_trig_regcb(30, "test_sip", (void *)test_sip_SAR_cb ) );
 	CHECK_FCT( fd_event_trig_regcb(31, "test_sip", (void *)test_sip_LIR_cb ) );
--- a/freeDiameterd/main.c	Fri May 10 09:50:09 2013 +0800
+++ b/freeDiameterd/main.c	Fri May 10 18:49:19 2013 +0800
@@ -48,7 +48,6 @@
 
 static char *conffile = NULL;
 static int gnutls_debug = 0;
-static int fd_msg_log_enabled = 0; /* all logs disabled by default, this field is a bitfield of enabled FD_MSG_LOG_* */
 
 /* gnutls debug */
 static void fd_gnutls_debug(int level, const char * str) {
@@ -87,25 +86,6 @@
 		TRACE_DEBUG(INFO, "Enabled GNUTLS debug at level %d", gnutls_debug);
 	}
 	
-	/* set messages logging */
-	if (fd_msg_log_enabled) {
-		if (fd_msg_log_enabled & (1 << FD_MSG_LOG_DROPPED)) {
-			CHECK_FCT( fd_msg_log_config(FD_MSG_LOG_DROPPED, FD_MSG_LOGTO_DEBUGONLY, NULL) );
-		}
-		if (fd_msg_log_enabled & (1 << FD_MSG_LOG_RECEIVED)) {
-			CHECK_FCT( fd_msg_log_config(FD_MSG_LOG_RECEIVED, FD_MSG_LOGTO_DEBUGONLY, NULL) );
-		}
-		if (fd_msg_log_enabled & (1 << FD_MSG_LOG_SENT)) {
-			CHECK_FCT( fd_msg_log_config(FD_MSG_LOG_SENT, FD_MSG_LOGTO_DEBUGONLY, NULL) );
-		}
-		if (fd_msg_log_enabled & (1 << FD_MSG_LOG_NODELIVER)) {
-			CHECK_FCT( fd_msg_log_config(FD_MSG_LOG_NODELIVER, FD_MSG_LOGTO_DEBUGONLY, NULL) );
-		}
-		if (fd_msg_log_enabled & (1 << FD_MSG_LOG_TIMING)) {
-			CHECK_FCT( fd_msg_log_config(FD_MSG_LOG_TIMING, FD_MSG_LOGTO_DEBUGONLY, NULL) );
-		}
-	}
-		
 	/* Allow SIGINT and SIGTERM from this point to terminate the application */
 	CHECK_POSIX( pthread_create(&signals_thr, NULL, catch_signals, NULL) );
 	
@@ -168,14 +148,12 @@
 	printf( "  -h, --help             Print help and exit\n"
   		"  -V, --version          Print version and exit\n"
   		"  -c, --config=filename  Read configuration from this file instead of the \n"
-		"                           default location (" DEFAULT_CONF_PATH "/" FD_DEFAULT_CONF_FILENAME ").\n"
-		"  -M, --enable_msg_log=( DROPPED | RECEIVED | SENT | NODELIVER | TIMING )\n"
-		"                         Enable logging of these messages in the output.\n");
+		"                           default location (" DEFAULT_CONF_PATH "/" FD_DEFAULT_CONF_FILENAME ").\n");
  	printf( "\nDebug:\n"
   		"  These options are mostly useful for developers\n"
   		"  -l, --dbglocale        Set the locale for error messages\n"
-  		"  -d, --debug            Increase verbosity of debug messages\n"
-  		"  -q, --quiet            Decrease verbosity then remove debug messages\n"
+  		"  -d, --debug            Increase verbosity of debug messages if default logger is used\n"
+  		"  -q, --quiet            Decrease verbosity if default logger is used\n"
   		"  --dbg_gnutls <int>     Enable GNU TLS debug at level <int>\n");
 }
 
@@ -196,7 +174,6 @@
 		{ "dbg_func",	required_argument, 	NULL, 'f' },
 		{ "dbg_file",	required_argument, 	NULL, 'F' },
 		{ "dbg_gnutls",	required_argument, 	NULL, 'g' },
-		{ "enable_msg_log",	optional_argument, 	NULL, 'M' },
 		{ NULL,		0, 			NULL, 0 }
 	};
 	
@@ -231,32 +208,8 @@
 				}
 				break;
 				
-			case 'M':	/* disable logging of these messages */
-				if (optarg) {
-					if (!strcmp(optarg, "DROPPED")) {
-						fd_msg_log_enabled |= 1 << FD_MSG_LOG_DROPPED;
-					} else
-					if (!strcmp(optarg, "RECEIVED")) {
-						fd_msg_log_enabled |= 1 << FD_MSG_LOG_RECEIVED;
-					} else
-					if (!strcmp(optarg, "SENT")) {
-						fd_msg_log_enabled |= 1 << FD_MSG_LOG_SENT;
-					} else
-					if (!strcmp(optarg, "NODELIVER")) {
-						fd_msg_log_enabled |= 1 << FD_MSG_LOG_NODELIVER;
-					} else
-					if (!strcmp(optarg, "TIMING")) {
-						fd_msg_log_enabled |= 1 << FD_MSG_LOG_TIMING;
-					} else {
-						main_help();
-						exit(0);
-					}
-				} else {
-					fd_msg_log_enabled = -1; /* all logs enabled */
-				}
-
 			case 'd':	/* Increase verbosity of debug messages.  */
-				fd_g_debug_lvl++;
+				fd_g_debug_lvl--;
 				break;
 				
 			case 'f':	/* Full debug for the function with this name.  */
@@ -282,7 +235,7 @@
 				break;
 				
 			case 'q':	/* Decrease verbosity then remove debug messages.  */
-				fd_g_debug_lvl--;
+				fd_g_debug_lvl++;
 				break;
 
 			case '?':	/* Invalid option.  */
--- a/include/freeDiameter/freeDiameter-host.h.in	Fri May 10 09:50:09 2013 +0800
+++ b/include/freeDiameter/freeDiameter-host.h.in	Fri May 10 18:49:19 2013 +0800
@@ -94,6 +94,9 @@
 #define FD_DEFAULT_CONF_FILENAME "freeDiameter.conf"
 #endif /* FD_DEFAULT_CONF_FILENAME */
 
+/* Maximum number of hooks handlers that can be registered. Make this compilation option if needed */
+#define FD_HOOK_HANDLE_LIMIT	5
+
 #ifdef __cplusplus
 }
 #endif
--- a/include/freeDiameter/libfdcore.h	Fri May 10 09:50:09 2013 +0800
+++ b/include/freeDiameter/libfdcore.h	Fri May 10 18:49:19 2013 +0800
@@ -57,23 +57,36 @@
 
 
 /* Check the return value of a GNUTLS function, log and propagate */
-#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {						\
-	int __ret__;										\
-	TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: %s", #__call__ );				\
-	__ret__ = (__call__);									\
-	if (__ret__ < 0) {									\
-		TRACE_DEBUG(INFO, "Error in '%s':\t%s", #__call__ , gnutls_strerror(__ret__));	\
-		__fallback__;									\
-	}											\
+#define CHECK_GNUTLS_GEN( faillevel, __call__, __fallback__  ) { 					\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ < 0) {									\
+			__ret__ = errno;								\
+			LOG(faillevel, "ERROR: in '%s' :\t%s",  #__call__ ,  gnutls_strerror(__ret__)); \
+			__fallback__;									\
+		}											\
 }
 
-/* For GNUTLS routines that do not return a value */
+/* we use this macro to help debugging gnutls usage issues -- just change the content to display what you need */
 #define GNUTLS_TRACE( __call__) {					\
-	TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: " #__call__ );	\
+	TRACE_CALL("Check: %s", #__call__ );				\
 	(__call__);							\
 }
 
 
+#ifndef EXCLUDE_DEPRECATED
+/* Macro for transition, replace with CHECK_GNUTLS_GEN */
+#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {						        \
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ < 0) {									\
+			__ret__ = errno;								\
+			TRACE_ERROR("ERROR: in '%s' :\t%s",  #__call__ ,  gnutls_strerror(__ret__));    \
+			__fallback__;									\
+		}											\
+}
+
+#endif /* EXCLUDE_DEPRECATED */
+
+
 /*============================================================*/
 /*                      INITIALIZATION                        */
 /*============================================================*/
@@ -539,8 +552,13 @@
 int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen );
 
 
-/* Parse a message against our dictionary, and in case of error log and eventually build the error reply (on return and EBADMSG, *msg == NULL or *msg is the error message ready to send) */
-int fd_msg_parse_or_error( struct msg ** msg );
+/* Parse a message against our dictionary, 
+	return 0 in case of success.
+	log parsing error & return error code in case of failure in parsing. 
+	In addition, if the error code is EBADMSG (the message does not follow our dictionary) 
+		if *msg was a request, *msg is NULL and *error contains the error message ready to send back on return
+		if *msg was an answer, *msg is untouched and *error==*msg if *msg was an error message, *error is null otherwise */
+int fd_msg_parse_or_error( struct msg ** msg, struct msg **error );
 
 
 
@@ -777,12 +795,6 @@
 /* Daemon's codespace: 1000->1999 (1500->1999 defined in fdcore-internal.h) */
 enum {
 	 FDEV_TERMINATE	= 1000	/* request to terminate */
-	,FDEV_DUMP_DICT		/* Dump the content of the dictionary */
-	,FDEV_DUMP_EXT		/* Dump state of extensions */
-	,FDEV_DUMP_SERV		/* Dump the server socket status */
-	,FDEV_DUMP_QUEUES	/* Dump the message queues */
-	,FDEV_DUMP_CONFIG	/* Dump the configuration */
-	,FDEV_DUMP_PEERS	/* Dump the list of peers */
 	,FDEV_TRIGGER		/* Trigger available for extensions. size is sizeof(int), data is int * */
 };
 
@@ -794,8 +806,17 @@
 
 /* for extensions */
 int fd_event_trig_regcb(int trigger_val, const char * module, void (*cb)(void));
-void fd_event_trig_dump();
+
+#ifndef SWIG
+DECLARE_FD_DUMP_PROTOTYPE(fd_event_trig_dump);
 
+/* The "old" FD_EV_DUMP_* events are replaced with direct calls to the following dump functions */
+DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump);
+DECLARE_FD_DUMP_PROTOTYPE(fd_ext_dump);
+DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump);
+#endif /* SWIG */
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump_list, int details);
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump, struct peer_hdr * p, int details);
 
 /*============================================================*/
 /*                         ENDPOINTS                          */
@@ -831,8 +852,8 @@
 int fd_ep_filter_family( struct fd_list * list, int af );
 int fd_ep_filter_list( struct fd_list * list, struct fd_list * exclude_list );
 int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
-void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep );
-void fd_ep_dump( int indent, struct fd_list * eps );
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, struct fd_endpoint * ep );
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int indent, struct fd_list * eps  );
 
 
 /*============================================================*/
@@ -854,6 +875,289 @@
 int fd_app_check_common(struct fd_list * list1, struct fd_list * list2, int * common_found);
 int fd_app_empty(struct fd_list * list);
 
+
+
+/*============================================================*/
+/*                         MONITORING                         */
+/*============================================================*/
+
+/* These functions allow an extension to collect state information about the
+ * framework, as well as being hooked at some key checkpoints in the processing
+ * for logging or statistics purpose.
+ */
+ 
+
+/* CALLBACK: 	fd_hook_cb
+ *
+ * PARAMETERS:
+ *  type	: The type of hook that triggered this call, in case same cb is registered for several hooks.
+ *  msg 	: If relevant, the pointer to the message triggering the call. NULL otherwise.
+ *  peer        : If relevant, the pointer to the peer associated with the call. NULL otherwise.
+ *  other	: For some callbacks, the remaining information is passed in this parameter. See each hook detail.
+ *  permsgdata  : Structure associated with a given message, across several hooks. 
+ *                 A different structure is associated with requests and corresponding answers. 
+ *                 See fd_hook_data_hdl below for details.
+ *                 If no fd_hook_data_hdl is registered with this callback, this parameter is always NULL
+ *  regdata     : Data pointer stored at registration, opaque for the framework.
+ *
+ * DESCRIPTION: 
+ *   When such callback is registered with fd_hook_register function, it will be called on matching events with 
+ * the parameters as described in the list of fd_hook_type below. One can use this mechanism for e.g.:
+ *  - log completely the messages for safety / backup
+ *  - create statistics information on the throughput
+ *  - ...
+ *
+ *  IMPORTANT: the callback MUST NOT change the memory pointed by the different parameters (peer, message, ...)
+ *
+ * RETURN VALUE:
+ *  none.
+ */
+ 
+/* The available hooks in the framework */
+enum fd_hook_type {
+
+	HOOK_DATA_RECEIVED = 0,
+		/* Hook called as soon as a message has been received from the network, after TLS & boundary processing.
+		 - {msg} is NULL.
+		 - {peer} is NULL.
+		 - {other} is a pointer to a struct fd_cnx_rcvdata containing the received buffer.
+		 - {permsgdata} points to either a new empty structure allocated for this message (cf. fd_hook_data_hdl), or NULL if no hdl is registered.
+		 */
+		 
+	HOOK_MESSAGE_RECEIVED,
+		/* Hook called when a message has been received and the structure has been parsed successfully (list of AVPs).
+		 - {msg} points to the parsed message. At this time, the objects have not been dictionary resolved. If you
+		   try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
+		 - {peer} is set if the message is received from a peer's connection, and NULL if the message is from a new client
+		   connected and not yet identified
+		 - {other} is NULL, or a char * identifying the connection when {peer} is null.
+		 - {permsgdata} points to either a new empty structure allocated for this message or the one passed to HOOK_DATA_RECEIVED if used.
+		 */
+	
+	HOOK_MESSAGE_LOCAL,
+		/* Hook called when a request message has been created locally and is being sent.
+		 - {msg} points to the message.
+		 - {peer} is NULL
+		 - {other} is NULL
+		 - {permsgdata} points to a new empty structure allocated for this request (cf. fd_hook_data_hdl)
+		 */
+	
+	HOOK_MESSAGE_SENT,
+		/* Hook called when a message has been sent to a peer. The message might be freed as soon as the hook function returns,
+		   so it is not safe to store the pointer for asynchronous processing.
+		 - {msg} points to the sent message. Again, the objects may not have been dictionary resolved. If you
+		   try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
+		 - {peer} is set if the message is sent to a peer's connection, and NULL if the message is sent to a new client
+		   connected and not yet identified, or being rejected
+		 - {other} is NULL.
+		 - {permsgdata} points to existing structure if any, or a new structure otherwise. 
+		 */
+	
+	HOOK_MESSAGE_FAILOVER,
+		/* Hook called when a message that was sent to a peer is being requeued, because e.g. the connection was torn down.
+		   In that case the message will go again through the routing process.
+		 - {msg} points to the corresponding request message (the answer is discarded). Again, the objects may not have been dictionary resolved. If you
+		   try to call fd_msg_parse_dict, it might slow down the operation of a relay agent, although this hook is not on the normal execution path.
+		 - {peer} is the peer this message was previously sent to.
+		 - {other} is NULL.
+		 - {permsgdata} points to existing structure if any, or a new structure otherwise. 
+		 */
+	
+	HOOK_MESSAGE_PARSING_ERROR,
+		/* Hook called when a message being processed cannot be parsed successfully.
+		 - {msg} points to the message if buffer was parsed successfully, or NULL otherwise. You should not call fd_msg_parse_dict on this in any case.
+		 - {peer} is NULL or the peer that received the message. If NULL and the message is not NULL, you can still retrieve the source from the message itself.
+		 - {other} is a char * pointer to the error message (human-readable) if {msg} is not NULL, a pointer to struct fd_cnx_rcvdata containing the received buffer otherwise.
+		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered). 
+		 */
+	
+	HOOK_MESSAGE_ROUTING_ERROR,
+		/* Hook called when a message being processed by the routing thread meets an error such as no remaining available peer for sending, based on routing callbacks decisions (maybe after retries).
+		 - {msg} points to the message. Again, the objects may not have been dictionary resolved. If you
+		   try to call fd_msg_parse_dict, it might slow down the operation of a relay agent, although this hook is not on the normal execution path.
+		 - {peer} is NULL.
+		 - {other} is a char * pointer to the error message (human-readable).
+		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered). 
+		 */
+	
+	HOOK_MESSAGE_ROUTING_FORWARD,
+		/* Hook called when a received message is deemed to be not handled locally by the routing_dispatch process.
+		   The decision of knowing which peer it will be sent to is not made yet (or if an error will be returned).
+		   The hook is trigged before the callbacks registered with fd_rt_fwd_register are called.
+		 - {msg} points to the message. Again, the objects may not have been dictionary resolved. 
+		    If you try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
+		 - {peer} is NULL.
+		 - {other} is NULL.
+		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered). 
+		 */
+	
+	HOOK_MESSAGE_ROUTING_LOCAL,
+		/* Hook called when a received message is handled locally by the routing_dispatch process (i.e., not forwarded).
+		   The hook is trigged before the callbacks registered with fd_disp_register are called.
+		 - {msg} points to the message. Here, the message has been already parsed completely & successfully.
+		 - {peer} is NULL.
+		 - {other} is NULL.
+		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered). 
+		 */
+	
+	HOOK_MESSAGE_DROPPED,
+		/* Hook called when a message is being discarded by the framework because of some error condition (normal or abnormal).
+		   It is probably a good idea to log this for analysis / backup.
+		 - {msg} points to the message, which will be freed as soon as the hook returns.
+		 - {peer} may be NULL or a peer related to the event.
+		 - {other} is a char * pointer to the error message (human-readable).
+		 - {permsgdata} points to existing structure associated with this message (or new structure if no previous hook was registered).
+		 */
+	
+	HOOK_PEER_CONNECT_FAILED,
+		/* Hook called when a connection attempt to/from a remote peer has failed. This hook is also called when the peer was in OPEN state and the connection is broken.
+		 - {msg} may be NULL (lower layer error, e.g. connection timeout) or points to a message showing the error (either invalid incoming message, or the CEA message sent or received with an error code).
+		 - {peer} may be NULL for incoming requests from unknown peers being rejected, otherwise it points to the peer structure associated with the attempt.
+		 - {other} is a char * pointer to the error message (human-readable).
+		 - {permsgdata} is always NULL for this hook.
+		 */
+	
+	HOOK_PEER_CONNECT_SUCCESS,
+		/* Hook called when a connection attempt to/from a remote peer has succeeded (the peer moves to OPEN_HANDSHAKE or OPEN state).
+		    In case of deprecated TLS handshake after the CER/CEA exchange, this hook can still be followed by HOOK_PEER_CONNECT_FAILED if TLS handshake fails.
+		 - {msg} points to the CEA message sent or received (with a success code) -- in case it is sent, you can always get access to the matching CER.
+		 - {peer} points to the peer structure.
+		 - {other} is NULL.
+		 - {permsgdata} is always NULL for this hook.
+		 */
+	
+#define HOOK_PEER_LAST	HOOK_PEER_CONNECT_SUCCESS
+};
+
+
+/* Type of the {permsgdata} pointer. It is up to each extension to define its own structure. This is opaque for the framework. */
+struct fd_hook_permsgdata;
+
+/* A handle that will be associated with the extension, and with the permsgdata structures. */
+struct fd_hook_data_hdl;
+
+/* The following structure is what is passed to the HOOK_DATA_RECEIVED hook */
+struct fd_cnx_rcvdata {
+	size_t  length;
+	uint8_t * buffer; /* internal note: the buffer is padded with a struct fd_msg_pmdl, not accounted for in length */
+};
+
+/* Function to register a new fd_hook_data_hdl. Should be called by your extension init function.
+ * The arguments are the functions called to initialize a new fd_hook_permsgdata and to free this structure when the corresponding message is being freed.
+ */
+/*
+ * FUNCTION:	fd_hook_data_register
+ *
+ * PARAMETERS:
+ *  permsgdata_size     : the size of the fd_hook_permsgdata structure. 
+ *  permsgdata_init_cb  : function called to initialize a new fd_hook_permsgdata structure, when a hook will be called for a message that does not have such structure yet. 
+ *                           The memory is already allocated and blanked, so you can pass NULL if no further handling is required.
+ *  permsgdata_fini_cb  : function called when a message is being disposed. It should free the resources associated with the fd_hook_permsgdata. 
+ *                           You can pass NULL if no special handling is required. The memory of the permsgdata structure itself will be freed by the framework.
+ *  new_handle          : On success, a handler to the registered callback is stored here. 
+ *		             This handler will be used to unregister the cb.
+ *
+ * DESCRIPTION: 
+ *   Register a new fd_hook_data_hdl. This handle is used during hooks registration (see below) in order to associate data with the messages, to allow keeping tracking of the message easily.
+ *  Note that these handlers are statically allocated and cannot be unregistered. FD_HOOK_HANDLE_LIMIT handlers can be registered at maximum (recompile libfdproto if you change this value)
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is registered.
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOSPC	: Too many handles already registered. You may need to increase the limit in the code.
+ */
+int fd_hook_data_register(
+	size_t permsgdata_size,
+	void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
+        void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
+        struct fd_hook_data_hdl **new_handle
+);
+
+/* A handler associated with a registered hook callback (for cleanup) */
+struct fd_hook_hdl; 
+
+/*
+ * FUNCTION:	fd_hook_register
+ *
+ * PARAMETERS:
+ *  type_mask	  : A bitmask of fd_hook_type bits for which this cb is registered, e.g. ((1 << HOOK_MESSAGE_RECEIVED) | (1 << HOOK_MESSAGE_SENT))
+ *  fd_hook_cb	  : The callback function to register (see prototype above).
+ *  regdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
+ *  data_hdl      : If permsgdata is requested for the hooks, a handler registered with fd_hook_data_register. NULL otherwise.
+ *  handler       : On success, a handler to the registered callback is stored here. 
+ *		   This handler can be used to unregister the cb.
+ *
+ * DESCRIPTION: 
+ *   Register a new hook in the framework. See explanations above.
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is registered.
+ *  EEXIST      : Another callback is already registered for this type of hook (HOOK_DATA_RECEIVED).
+ *  EINVAL 	: A parameter is invalid.
+ *  ENOMEM	: Not enough memory to complete the operation
+ */
+int fd_hook_register (  uint32_t type_mask, 
+			void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata), 
+			void  *regdata, 
+			struct fd_hook_data_hdl *data_hdl,
+			struct fd_hook_hdl ** handler );
+
+/* Remove a hook registration */
+int fd_hook_unregister( struct fd_hook_hdl * handler );
+
+
+/* Use the following function to retrieve any pmd structure associated with a request matching the current answer. Returns NULL in case of error / no such structure */
+struct fd_hook_permsgdata * fd_hook_get_request_pmd(struct fd_hook_data_hdl *data_hdl, struct msg * answer);
+
+
+/*============================================================*/
+
+/*
+ * The following allows an extension to retrieve stat information on the different fifo queues involved in the freeDiameter framework.
+ * There are three global queues, plus per-peer queues.
+ * This information can be used to build SNMP-like data for example, or quickly get a status of the framework to find the loaded path of execution / bottlenecks.
+ */
+enum fd_stat_type {
+	/* For the following, no peer is associated with the stat */
+	STAT_G_LOCAL= 1,	/* Get statistics for the global queue of messages processed by local extensions */
+	STAT_G_INCOMING,	/* Get statistics for the global queue of received messages to be processed by routing_in thread */
+	STAT_G_OUTGOING,	/* Get statistics for the global queue of messages to be processed by routing_out thread */
+	
+	/* For the following, the peer must be provided */
+	STAT_P_PSM,		/* Peer state machine queue (events to be processed for this peer, including received messages) */
+	STAT_P_TOSEND,		/* Queue of messages for sending to this peer */
+};
+
+/*
+ * FUNCTION:	fd_stat_getstats
+ *
+ * PARAMETERS:
+ *  stat	  : Which queue is being queried
+ *  peer	  : (depending on the stat parameter) which peer is being queried
+ *  current_count : (out) The number of items in the queue currently
+ *  limit_count   : (out) The max number of items the queue accepts before becoming blocking -- 0 means no max.
+ *  highest_count : (out) The highest count the queue has reached since startup
+ *  total_count	  : (out) Total number of items that this queue has processed (always growing, use deltas for monitoring)
+ *  total	  : (out) Cumulated time all items spent in this queue, including blocking time (always growing, use deltas for monitoring)
+ *  blocking      : (out) Cumulated time threads trying to post new items were blocked (queue full).
+ *  last          : (out) For the last element retrieved from the queue, how long it took between posting (including blocking) and poping
+ *  
+ * DESCRIPTION: 
+ *   Get statistics information about a given queue. 
+ *  Any of the (out) parameters can be NULL if not requested.
+ *
+ * RETURN VALUE:
+ *  0      	: The callback is registered.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_stat_getstats(enum fd_stat_type stat, struct peer_hdr * peer, 
+			int * current_count, int * limit_count, int * highest_count, long long * total_count,
+			struct timespec * total, struct timespec * blocking, struct timespec * last);
+
+/*============================================================*/
+/*                         EOF                                */
+/*============================================================*/
+
 #ifdef __cplusplus
 }
 #endif
--- a/include/freeDiameter/libfdproto.h	Fri May 10 09:50:09 2013 +0800
+++ b/include/freeDiameter/libfdproto.h	Fri May 10 18:49:19 2013 +0800
@@ -79,9 +79,7 @@
 #include <unistd.h>
 #include <stdarg.h>
 
-#ifdef DEBUG
-#include <libgen.h>	/* for basename if --dbg_file is specified */
-#endif /* DEBUG */
+#include <libgen.h>	/* for basename */
 
 #ifdef SWIG
 #define _ATTRIBUTE_PRINTFLIKE_(_f,_v)
@@ -132,12 +130,9 @@
 
 /*
  * FUNCTION:	fd_log
- * MACRO:	fd_log_debug
- * MACRO:	fd_log_notice
- * MACRO:	fd_log_error
  *
  * PARAMETERS:
- *  loglevel	: Integer, how important the message is
+ *  loglevel	: Integer, how important the message is. Valid values are macros FD_LOG_*
  *  format 	: Same format string as in the printf function
  *  ...		: Same list as printf
  *
@@ -150,11 +145,9 @@
  *  None.
  */
 void fd_log ( int, const char *, ... ) _ATTRIBUTE_PRINTFLIKE_(2,3);
-#define fd_log_debug(format,args...)  fd_log(FD_LOG_DEBUG, format, ## args)
-#define fd_log_notice(format,args...) fd_log(FD_LOG_NOTICE, format, ## args)
-#define fd_log_error(format,args...)  fd_log(FD_LOG_ERROR, format, ## args)
-
-void fd_log_debug_fstr( FILE *, const char *, ... );
+#ifndef SWIG
+void fd_log_va( int, const char *, va_list args );
+#endif /* SWIG */
 
 /* these are internal objects of the debug facility, 
 might be useful to control the behavior from outside */
@@ -228,6 +221,35 @@
 int fd_log_handler_unregister ( void );
 
 
+/* All dump functions follow this same prototype:
+ * PARAMETERS:
+ *   buf   : *buf can be NULL on entry, it will be malloc'd. Otherwise it is realloc'd if needed.
+ *   len   : the current size of the buffer (in/out)
+ *   offset: (optional) if provided, starts writing dump at offset in the buffer, and updated upon exit. if NULL, starts at offset O.
+ *
+ * RETURN VALUE:
+ *   *buf upon success, NULL upon failure.
+ *
+ * REMARKS:
+ *  - After the buffer has been used, it should be freed.
+ *  - Depending on the function, the created string may be multi-line. However, it should never be terminated with a '\n'.
+ */
+#define DECLARE_FD_DUMP_PROTOTYPE( function_name, args... )	\
+	char * function_name(char ** buf, size_t *len, size_t *offset, ##args)
+	
+
+/* Helper functions for the *dump functions that add into a buffer */
+DECLARE_FD_DUMP_PROTOTYPE( fd_dump_extend, const char * format, ... ) _ATTRIBUTE_PRINTFLIKE_(4,5);
+DECLARE_FD_DUMP_PROTOTYPE( fd_dump_extend_hexdump, uint8_t *data, size_t datalen, size_t trunc, size_t wrap );
+
+
+/* Some helpers macro for writing such *_dump routine */
+#define FD_DUMP_STD_PARAMS  buf, len, offset
+#define FD_DUMP_HANDLE_OFFSET()  size_t o = 0; if (!offset) offset = &o
+#define FD_DUMP_HANDLE_TRAIL()	while ((*buf) && (*offset > 0) && ((*buf)[*offset - 1] == '\n')) { *offset -= 1; (*buf)[*offset] = '\0'; }
+
+
+
 /*============================================================*/
 /*                    DEBUG MACROS                            */
 /*============================================================*/
@@ -236,20 +258,14 @@
 #define ASSERT(x) assert(x)
 #endif /* ASSERT */
 
-/* log levels definitions */
-#define FD_LOG_DEBUG  0  /* Verbose information for developers use */
-#define FD_LOG_NOTICE 3  /* Normal execution states worth noting */
-#define FD_LOG_ERROR  5  /* Error conditions, both recoverable or not */
-
-/* print level definitions */
-#define NONE 0	/* Display no debug message */
-#define INFO 1	/* Display errors only */
-#define FULL 2  /* Display additional information to follow code execution */
-#define ANNOYING 4 /* Very verbose, for example in loops */
-#define FCTS 6  /* Display entry parameters of most functions */
-#define CALL 9  /* Display calls to most functions (with CHECK macros) */
-
-/* A global level, changed by configuration or cmd line for example. Default is INFO (in libfdproto/log.c). */
+/* log levels definitions, that are passed to the logger */
+#define FD_LOG_ANNOYING  0  /* very verbose loops and such "overkill" traces. Only active when the framework is compiled in DEBUG mode. */
+#define FD_LOG_DEBUG     1  /* Get a detailed sense of what is going on in the framework. Use this level for normal debug */
+#define FD_LOG_NOTICE    3  /* Normal execution states worth noting */
+#define FD_LOG_ERROR     5  /* Recoverable or expected error conditions */
+#define FD_LOG_FATAL     6  /* Unrecoverable error, e.g. malloc fail, etc. that requires the framework to shutdown */
+
+/* The level used by the default logger, can be changed by command-line arguments. Ignored for other loggers. */
 extern int fd_g_debug_lvl;
 
 /* Some portability code to get nice function name in __PRETTY_FUNCTION__ */
@@ -264,121 +280,321 @@
 #define __PRETTY_FUNCTION__ __func__
 #endif /* __PRETTY_FUNCTION__ */
 
-#ifdef DEBUG
 /* A version of __FILE__ without the full path */
 static char * file_bname = NULL;
 static char * file_bname_init(char * full) { file_bname = basename(full); return file_bname; }
 #define __STRIPPED_FILE__	(file_bname ?: file_bname_init((char *)__FILE__))
 
-/* Boolean for tracing at a certain level */
-#define TRACE_BOOL(_level_) ( ((_level_) <= fd_g_debug_lvl) 					\
-				|| (fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__)) 	\
-				|| (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ) )
-#else /* DEBUG */
-#define TRACE_BOOL(_level_) ((_level_) <= fd_g_debug_lvl)
-#define __STRIPPED_FILE__ __FILE__
-#endif /* DEBUG */
-
-
-#define STD_TRACE_FMT_STRING "pid:%s in %s@%s:%d: "
-/*************
- The general debug macro, each call results in two lines of debug messages (change the macro for more compact output) 
- *************/
+
+
+/* In DEBUG mode, we add meta-information along each trace. This makes multi-threading problems easier to debug. */
 #ifdef DEBUG
-/* In DEBUG mode, we add (a lot of) meta-information along each trace. This makes multi-threading problems easier to debug. */
-#define TRACE(printlevel,level,format,args... ) {										\
-	if ( TRACE_BOOL(level) ) {												\
-		const char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		fd_log((printlevel), STD_TRACE_FMT_STRING format, 								\
-					__thn, __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__, ## args); 			\
-	}															\
-}
+# define STD_TRACE_FMT_STRING "pid:%s in %s@%s:%d: "
+# define STD_TRACE_FMT_ARGS   , ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"), __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__
 #else /* DEBUG */
-/* Do not print thread, function, ... only the message itself in this case */
-#define TRACE(printlevel,level,format,args... ) {					\
-	if ( TRACE_BOOL(level) ) {							\
-		fd_log((printlevel), format, ## args);    				\
-	}										\
-}
+# define STD_TRACE_FMT_STRING ""
+# define STD_TRACE_FMT_ARGS
 #endif /* DEBUG */
 
-/* Report debug information */
-#define TRACE_DEBUG(level,format,args... ) \
-	TRACE(FD_LOG_DEBUG,(level),format,##args)
+/*************************
+  The general debug macro
+ *************************/
+#define LOG(printlevel,format,args... ) \
+	fd_log((printlevel), STD_TRACE_FMT_STRING format STD_TRACE_FMT_ARGS, ## args)
+
+/*
+ * Use the following macros in the code to get traces with location & pid in debug mode: 
+ */
+#ifdef DEBUG
+# define LOG_A(format,args... ) \
+		LOG(FD_LOG_ANNOYING,format,##args)
+#else /* DEBUG */
+# define LOG_A(format,args... ) /* not defined in release */
+#endif /* DEBUG */
+
+/* Debug information useful to follow in detail what is going on */
+#define LOG_D(format,args... ) \
+		LOG(FD_LOG_DEBUG, format, ##args)
 
 /* Report a normal message that is useful for normal admin monitoring */
-#define TRACE_NOTICE(format,args... ) \
-	TRACE(FD_LOG_NOTICE,INFO,format,##args)
+#define LOG_N(format,args... ) \
+		LOG(FD_LOG_NOTICE, format,##args)
 
 /* Report an error */
-#define TRACE_ERROR(format,args... ) \
-	TRACE(FD_LOG_ERROR, NONE, format, ##args)
-
-/* 
-TRACE_NOTICE(...) and fd_log_notice(...) are equivalent when the code is not compiled in DEBUG mode,
-but there is more contextual information when compiled in DEBUG with the TRACE_NOTICE macro,
-hence it is recommended to use this one except for formatted output (e.g. fd_*_dump function)
-
-resp. TRACE_DEBUG and TRACE_ERROR.
-*/
+#define LOG_E(format,args... ) \
+		LOG(FD_LOG_ERROR, format, ##args)
+
+/* Report a fatal error */
+#define LOG_F(format,args... ) \
+		LOG(FD_LOG_FATAL, format, ##args)
+
 
 /*************
- Derivatives for debug
+ Derivatives
  ************/
+/* Trace a binary buffer content */
+#define LOG_BUFFER(printlevel, prefix, buf, bufsz, suffix ) {								\
+	int __i;													\
+	size_t __sz = (size_t)(bufsz);											\
+	uint8_t * __buf = (uint8_t *)(buf);										\
+	char __strbuf[1024+1];												\
+	for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2)); __i++) {						\
+		sprintf(__strbuf + (2 * __i), "%02hhx", __buf[__i]);     						\
+	}														\
+        fd_log(printlevel, STD_TRACE_FMT_STRING "%s%s%s" STD_TRACE_FMT_ARGS,  						\
+               (prefix), __strbuf, (suffix));										\
+}
+
 /* Helper for function entry -- for very detailed trace of the execution */
 #define TRACE_ENTRY(_format,_args... ) \
-	TRACE_DEBUG(FCTS, "[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
+		LOG_A("[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
 
 /* Helper for debugging by adding traces -- for debuging a specific location of the code */
 #define TRACE_HERE()	\
-	TRACE_DEBUG(NONE, " -- debug checkpoint %d -- ", fd_breakhere());
+		LOG_F(" -- debug checkpoint %d -- ", fd_breakhere());
 int fd_breakhere(void);
 
 /* Helper for tracing the CHECK_* macros below -- very very verbose code execution! */
-#define TRACE_DEBUG_ALL( str... ) 	\
-	TRACE_DEBUG(CALL, str );
+#define TRACE_CALL( str... ) 	\
+		if ((fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__)) 	\
+		 || (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ) ) {		\
+		 	LOG_A( str );									\
+		}
 
 /* For development only, to keep track of TODO locations in the code */
 #ifndef ERRORS_ON_TODO
-#define TODO( _msg, _args... ) \
-	TRACE_DEBUG(NONE, "TODO: " _msg , ##_args);
+# define TODO( _msg, _args... ) \
+		LOG_F( "TODO: " _msg , ##_args);
 #else /* ERRORS_ON_TODO */
-#define TODO( _msg, _args... ) \
-	"TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
+# define TODO( _msg, _args... ) \
+		"TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
 #endif /* ERRORS_ON_TODO */
 
-/* Trace a binary buffer content */
-#ifdef DEBUG
-/* In DEBUG mode, we add (a lot of) meta-information along each trace. This makes multi-threading problems easier to debug. */
-#define TRACE_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) {								\
-	if ( TRACE_BOOL(level) ) {												\
+
+/*============================================================*/
+/*                  ERROR CHECKING MACRO                      */
+/*============================================================*/
+
+/* Macros to check a return value and branch out in case of error.
+ * These macro additionally provide the logging information.
+ *
+ * The name "__ret__" is always available in the __fallback__ parameter and contains the error code.
+ */
+ 
+#define CHECK_PRELUDE(__call__) 			\
+		int __ret__; 				\
+		TRACE_CALL("Check: %s", #__call__ );	\
+		__ret__ = (__call__)
+	
+#define DEFAULT_FB	return __ret__;
+
+/* System check: error case if < 0, error value in errno */
+#define CHECK_SYS_GEN( faillevel, __call__, __fallback__  ) { 						\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ < 0) {									\
+			__ret__ = errno;								\
+			LOG(faillevel, "ERROR: in '%s' :\t%s",  #__call__ , strerror(__ret__));    	\
+			__fallback__;									\
+		}											\
+}
+
+
+/* Check the return value of a function and execute fallback in case of error or special value */
+#define CHECK_FCT_GEN2( faillevel, __call__, __speval__, __fallback1__, __fallback2__ ) {		\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ != 0) {									\
+			if (__ret__ == (__speval__)) {							\
+				__fallback1__;								\
+			} else {									\
+				LOG(faillevel, "ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__));	\
+				__fallback2__;								\
+			}										\
+		}											\
+}
+
+/* Check the return value of a function and execute fallback in case of error (return value different from 0) */
+#define CHECK_FCT_GEN( faillevel, __call__, __fallback__) \
+	       CHECK_FCT_GEN2( faillevel, (__call__), 0, , (__fallback__) )
+
+/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
+#define CHECK_MALLOC_GEN( faillevel, __call__, __fallback__ ) { 				       \
+	       void *  __ptr__; 								       \
+	       TRACE_CALL("Check: %s", #__call__ );						       \
+	       __ptr__ = (void *)(__call__);							       \
+	       if (__ptr__ == NULL) {								       \
+		       int __ret__ = errno;							       \
+		       LOG(faillevel, "ERROR: in '%s' :\t%s",  #__call__ , strerror(__ret__));         \
+		       __fallback__;								       \
+	       }										       \
+}
+
+/* Check parameters at function entry, execute fallback on error */
+#define CHECK_PARAMS_GEN( faillevel, __bool__, __fallback__ ) {					       \
+	       TRACE_CALL("Check: %s", #__bool__ );						       \
+	       if ( ! (__bool__) ) {								       \
+		       int __ret__ = EINVAL;							       \
+		       LOG(faillevel, "ERROR: invalid parameter '%s'",  #__bool__ );  	       	       \
+		       __fallback__;								       \
+	       }										       \
+}
+
+
+/*============================================================*/
+/*          COMPATIBILITY MACROS, TO BE REMOVED		      */
+/*============================================================*/
+/* Redefine the old macros for transition of the code */
+#ifndef EXCLUDE_DEPRECATED
+
+#define MARK_DEPRECATED	/* __attribute__ ((deprecated)) */
+
+enum old_levels {
+	NONE = 0,
+	INFO = 1,
+	FULL = 2,
+	ANNOYING = 4,
+	FCTS = 6,
+	CALL = 9
+} MARK_DEPRECATED;
+
+static __inline__ int TRACE_BOOL( enum old_levels level ) MARK_DEPRECATED
+{ 
+	return (level <= fd_g_debug_lvl)
+		|| (fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__))
+		|| (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ); 
+}
+
+static __inline__ void fd_log_deprecated( int level, const char *format, ... ) MARK_DEPRECATED
+{ 
+	va_list ap;
+	va_start(ap, format);
+	fd_log_va(level, format, ap);
+	va_end(ap);	
+}
+static __inline__ void replace_me() MARK_DEPRECATED { }
+
+#define TRACE_sSA(...) replace_me();
+#define sSA_DUMP_NODE_SERV(...) replace_me();
+#define sSA_DUMP_NODE(...) replace_me();
+#define TRACE_BUFFER(...) replace_me();
+#define TRACE_NOTICE(...) replace_me();
+
+
+/* Use the LOG_* instead, or use the new *_dump functions when dumping an object */
+#define fd_log_debug(format,args...)  fd_log_deprecated(FD_LOG_DEBUG, format, ## args)
+#define fd_log_notice(format,args...) fd_log_deprecated(FD_LOG_NOTICE, format, ## args)
+#define fd_log_error(format,args...)  fd_log_deprecated(FD_LOG_ERROR, format, ## args)
+
+/* old macro for traces. To be replaced by appropriate LOG_* macros. */
+# define TRACE_DEBUG(oldlevel, format,args... ) {					\
+		if (TRACE_BOOL(oldlevel)) {						\
+			if      (oldlevel == NONE) { LOG_E(format,##args); }		\
+			else if (oldlevel == INFO) { LOG_N(format,##args); }		\
+			else                       { LOG_D(format,##args); }		\
+}		}
+
+/* the following macro must be replaced with LOG_E or LOG_F */
+# define TRACE_ERROR	fd_log_error
+
+
+/* The following macros are missing the faillevel information, which indicates at what log level the error case should be displayed. */
+# define CHECK_SYS_DO( __call__, __fallback__  ) { 							\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ < 0) {									\
+			__ret__ = errno;								\
+			TRACE_ERROR("ERROR: in '%s' :\t%s",  #__call__ , strerror(__ret__));    	\
+			__fallback__;									\
+		}											\
+}
+
+# define CHECK_SYS( __call__  ) \
+		CHECK_SYS_DO( (__call__), return __ret__  )
+
+
+# define CHECK_POSIX_DO2( __call__, __speval__, __fallback1__, __fallback2__ ) {			\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ != 0) {									\
+			if (__ret__ == (__speval__)) {							\
+				__fallback1__;								\
+			} else {									\
+				TRACE_ERROR("ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__));	\
+				__fallback2__;								\
+			}										\
+		}											\
+}
+
+# define CHECK_POSIX_DO( __call__, __fallback__ )	\
+		CHECK_POSIX_DO2( (__call__), 0, , __fallback__ )
+
+# define CHECK_POSIX( __call__ )	\
+		CHECK_POSIX_DO( (__call__), return __ret__ )
+		
+# define CHECK_MALLOC_DO( __call__, __fallback__ ) { 				   		       \
+	       void *  __ptr__; 								       \
+	       TRACE_CALL("Check: %s", #__call__ );						       \
+	       __ptr__ = (void *)(__call__);							       \
+	       if (__ptr__ == NULL) {								       \
+		       int __ret__ = errno;							       \
+		      TRACE_ERROR("ERROR: in '%s' :\t%s",  #__call__ , strerror(__ret__));             \
+		       __fallback__;								       \
+	       }										       \
+}
+
+# define CHECK_MALLOC( __call__ )	\
+		CHECK_MALLOC_DO( (__call__), return __ret__ )
+	
+# define CHECK_PARAMS_DO( __bool__, __fallback__ ) {					       	       \
+	       TRACE_CALL("Check: %s", #__bool__ );						       \
+	       if ( ! (__bool__) ) {								       \
+		       int __ret__ = EINVAL;							       \
+		       TRACE_ERROR("ERROR: invalid parameter '%s'",  #__bool__ );  	               \
+		       __fallback__;								       \
+	       }										       \
+}
+
+# define CHECK_PARAMS( __bool__ )	\
+		CHECK_PARAMS_DO( (__bool__), return __ret__ )
+
+# define CHECK_FCT_DO	CHECK_POSIX_DO
+# define CHECK_FCT	CHECK_POSIX
+
+#endif /* EXCLUDE_DEPRECATED */
+	       
+
+/*============================================================*/
+/*	Optimized code: remove all debugging code	      */
+/*============================================================*/
+#ifdef STRIP_DEBUG_CODE
+#undef LOG_D
+#undef LOG_N
+#undef LOG_E
+#undef LOG_F
+#undef LOG_BUFFER
+
+#define LOG_D(format,args... ) /* noop */
+#define LOG_N(format,args...) fd_log(FD_LOG_NOTICE, format, ## args)
+#define LOG_E(format,args...) fd_log(FD_LOG_ERROR, format, ## args)
+#define LOG_F(format,args...) fd_log(FD_LOG_FATAL, format, ## args)
+#define LOG_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) {								\
+	if (printlevel > FD_LOG_DEBUG) {											\
 		int __i;													\
 		size_t __sz = (size_t)(bufsz);											\
 		uint8_t * __buf = (uint8_t *)(buf);										\
-		char __strbuf[1024+1];												\
-		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2)); __i++) {						\
-			sprintf(__strbuf + (2 * __i), "%2.2hhx", __buf[__i]);     						\
+		char * __strbuf[1024+1];											\
+		for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2); __i++) {						\
+			sprintf(__strbuf + (2 * __i), "%02.2hhx", __buf[__i]);     						\
 		}														\
-                fd_log(printlevel, STD_TRACE_FMT_STRING "%s%s%s",      								\
-                       __thn, __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__, (prefix), __strbuf, (suffix));			\
-	}															\
-}
-#else /* DEBUG */
-/* Do not print thread, function, ... only the message itself in this case */
-#define TRACE_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) {								\
-	if ( TRACE_BOOL(level) ) {												\
-		int __i;													\
-		size_t __sz = (size_t)(bufsz);											\
-		uint8_t * __buf = (uint8_t *)(buf);										\
-		char __strbuf[1024+1];												\
-		for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2)); __i++) {						\
-			sprintf(__strbuf + (2 * __i), "%2.2hhx", __buf[__i]);     						\
-		}														\
-                fd_log(printlevel, "%s%s%s", (prefix), __strbuf, (suffix));							\
-	}															\
-}
-#endif /* DEBUG */
+                fd_log(printlevel, prefix"%s"suffix, __strbuf);									\
+	}
+#endif /* STRIP_DEBUG_CODE */
+
+/*============================================================*/
+/*		    OTHER MACROS			      */
+/*============================================================*/
+/* helper macros (pre-processor hacks to allow macro arguments) */
+#define __tostr( arg )  #arg
+#define _stringize( arg ) __tostr( arg )
+#define __agr( arg1, arg2 ) arg1 ## arg2
+#define _aggregate( arg1, arg2 ) __agr( arg1, arg2 )
 
 /* Some aliases to socket addresses structures */
 #define sSS	struct sockaddr_storage
@@ -392,217 +608,10 @@
 				((((sSA *)_sa_)->sa_family == AF_INET6) ? (sizeof(sSA6)) :	\
 					0 ) ) )
 
-/* Dump one sockaddr Node information */
-#define sSA_DUMP_NODE( buf, bufsize, sa, flag ) {                	\
-	sSA * __sa = (sSA *)(sa);					\
-	char __addrbuf[INET6_ADDRSTRLEN];				\
-	if (__sa) {							\
-	  int __rc = getnameinfo(__sa, 					\
-	  		sSAlen(__sa),					\
-			__addrbuf,					\
-			sizeof(__addrbuf),				\
-			NULL,						\
-			0,						\
-			(flag));					\
-	  if (__rc)							\
-		snprintf(buf, bufsize, "%s", gai_strerror(__rc));	\
-	  else								\
-		snprintf(buf, bufsize, "%s", &__addrbuf[0]);       	\
-	} else {							\
-		snprintf(buf, bufsize, "(NULL / ANY)");             	\
-	}								\
-}
-/* Same but with the port (service) also */
-#define sSA_DUMP_NODE_SERV( buf, bufsize, sa, flag ) {                  \
-	sSA * __sa = (sSA *)(sa);					\
-	char __addrbuf[INET6_ADDRSTRLEN];				\
-	char __servbuf[32];						\
-	if (__sa) {							\
-	  int __rc = getnameinfo(__sa, 					\
-	  		sSAlen(__sa),					\
-			__addrbuf,					\
-			sizeof(__addrbuf),				\
-			__servbuf,					\
-			sizeof(__servbuf),				\
-			(flag));					\
-	  if (__rc)							\
-		snprintf(buf, bufsize, "%s", gai_strerror(__rc));  \
-	  else								\
-		snprintf(buf, bufsize, "[%s]:%s", &__addrbuf[0],&__servbuf[0]); \
-	} else {							\
-		snprintf(buf, bufsize,"(NULL / ANY)");         \
-	}								\
-}
-
-#ifdef DEBUG
-/* In DEBUG mode, we add (a lot of) meta-information along each trace. This makes multi-threading problems easier to debug. */
-#define TRACE_sSA(printlevel, level, prefix, sa, flags, suffix ) {										\
-	if ( TRACE_BOOL(level) ) {												\
-		char __buf[1024]; 												\
-		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		sSA_DUMP_NODE_SERV(__buf, sizeof(__buf), sa, flags );       							\
-		fd_log(printlevel, STD_TRACE_FMT_STRING "%s%s%s" ,     								\
-                       __thn, __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__, (prefix), __buf, (suffix)); 			\
-	}															\
-}
-#else /* DEBUG */
-/* Do not print thread, function, ... only the message itself in this case */
-#define TRACE_sSA(printlevel, level, prefix, sa, flags, suffix ) {										\
-	if ( TRACE_BOOL(level) ) {												\
-		char __buf[1024]; 												\
-		sSA_DUMP_NODE_SERV(__buf, sizeof(__buf), sa, flags );       							\
-		fd_log(printlevel, "%s%s%s" , (prefix), __buf, (suffix)); 							\
-	}															\
-}
-#endif /* DEBUG */
-
-/******************
- Optimized code: remove all debugging code
- **/
-#ifdef STRIP_DEBUG_CODE
-#undef TRACE_DEBUG
-#undef TRACE_NOTICE
-#undef TRACE_ERROR
-#undef TRACE_BOOL
-#undef TRACE_BUFFER
-#undef TRACE_sSA
-
-#define TRACE_DEBUG(level,format,args... ) /* noop */
-#define TRACE_BOOL(_level_) (0)	/* always false */
-#define TRACE_NOTICE fd_log_notice
-#define TRACE_ERROR fd_log_error
-#define TRACE_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) {								\
-	if (printlevel > FD_LOG_DEBUG) {											\
-		int __i;													\
-		size_t __sz = (size_t)(bufsz);											\
-		uint8_t * __buf = (uint8_t *)(buf);										\
-		char * __strbuf[1024+1];											\
-		for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2); __i++) {						\
-			sprintf(__strbuf + (2 * __i), "%02.2hhx", __buf[__i]);     						\
-		}														\
-                fd_log(printlevel, prefix"%s"suffix, __strbuf);									\
-	}
-#define TRACE_sSA(printlevel, level, prefix, sa, flags, suffix )  {								\
-	if (printlevel > FD_LOG_DEBUG) {											\
-		char __buf[1024]; 												\
-		sSA_DUMP_NODE_SERV(__buf, sizeof(__buf), sa, flags );       							\
-		fd_log(printlevel, prefix "%s" suffix, __buf);				 					\
-	}
-#endif /* STRIP_DEBUG_CODE */
-
-
-/*============================================================*/
-/*                  ERROR CHECKING MACRO                      */
-/*============================================================*/
-
-/* Macros to check a return value and branch out in case of error.
- * These macro should be used only when errors are 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: %s", #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ < 0) {								\
-		int __err__ = errno;	/* We may handle EINTR here */			\
-		TRACE_ERROR("ERROR: in '%s' :\t%s",  #__call__ , 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: %s", #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ < 0) {								\
-		int __err__ = errno;	/* We may handle EINTR here */			\
-		TRACE_ERROR("ERROR: in '%s' :\t%s", #__call__ , 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__, __speval__, __fallback1__, __fallback2__ ) {			\
-	int __ret__;										\
-	TRACE_DEBUG_ALL( "Check POSIX: %s", #__call__ );					\
-	__ret__ = (__call__);									\
-	if (__ret__ != 0) {									\
-		if (__ret__ == (__speval__)) {							\
-			__fallback1__;								\
-		} else {									\
-			TRACE_ERROR("ERROR: in '%s':\t%s", #__call__, 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: %s", #__call__ );				\
-	__ret__ = (void *)( __call__ );							\
-	if (__ret__ == NULL) {								\
-		int __err__ = errno;							\
-		TRACE_ERROR("ERROR: in '%s':\t%s", #__call__, 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 );
-
-
-/* Check parameters at function entry, execute fallback on error */
-#define CHECK_PARAMS_DO( __bool__, __fallback__ )						\
-	TRACE_DEBUG_ALL( "Check PARAMS: %s", #__bool__ );					\
-	if ( ! (__bool__) ) {									\
-		TRACE_ERROR("Warning: Invalid parameter received in '%s'", #__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: %s", #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ != 0) {								\
-		TRACE_ERROR("ERROR: in '%s':\t%s", #__call__, 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__ );				\
-}
-
-
-
-/*============================================================*/
-/*                  OTHER MACROS                              */
-/*============================================================*/
-
-
-/* helper macros (pre-processor hacks to allow macro arguments) */
-#define __tostr( arg )  #arg
-#define _stringize( arg ) __tostr( arg )
-#define __agr( arg1, arg2 ) arg1 ## arg2
-#define _aggregate( arg1, arg2 ) __agr( arg1, arg2 )
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node, sSA * sa, int flags);
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node_serv, sSA * sa, int flags);
+#define sSA_DUMP_STRLEN	(INET6_ADDRSTRLEN + 1 + 32 + 2)
+void fd_sa_sdump_numeric(char * buf /* must be at least sSA_DUMP_STRLEN */, sSA * sa);
 
 
 /* A l4 protocol name (TCP / SCTP) */
@@ -983,8 +992,8 @@
 int fd_dict_getdict ( struct dict_object * object, struct dictionary ** dict);
 
 /* Debug functions */
-void fd_dict_dump_object(struct dict_object * obj);
-void fd_dict_dump(struct dictionary * dict);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_object, struct dict_object * obj);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump, struct dictionary * dict);
 
 /* Function to access full contents of the dictionary, see doc in dictionary.c */
 int fd_dict_getlistof(int criteria, void * parent, struct fd_list ** sentinel);
@@ -1017,7 +1026,8 @@
 enum {
 	VENDOR_BY_ID = 10,	/* "what" points to a vendor_id_t */
 	VENDOR_BY_NAME,		/* "what" points to a char * */
-	VENDOR_OF_APPLICATION	/* "what" points to a struct dict_object containing an application (see below) */
+	VENDOR_OF_APPLICATION,	/* "what" points to a struct dict_object containing an application (see below) */
+	VENDOR_OF_AVP,		/* "what" points to a struct dict_object containing an avp (see below) */
 };
 
 /***
@@ -1222,7 +1232,7 @@
 	char *	 		 type_name;	/* The name of this type */
 	dict_avpdata_interpret	 type_interpret;/* cb to convert the AVP value in more comprehensive format (or NULL) */
 	dict_avpdata_encode	 type_encode;	/* cb to convert formatted data into an AVP value (or NULL) */
-	char * 			(*type_dump)(union avp_value * val);	/* cb called by fd_msg_dump_one for this type of data (if != NULL). Returned string must be freed.  */
+	DECLARE_FD_DUMP_PROTOTYPE((*type_dump), union avp_value * val); /* cb called by fd_msg_dump_one for this type of data (if != NULL). Returned string must be freed.  */
 };
 
 /* The criteria for searching a type object in the dictionary */
@@ -1239,15 +1249,15 @@
 /* Convert an Address type AVP into a struct sockaddr_storage */
 int fd_dictfct_Address_encode(void * data, union avp_value * avp_value);
 int fd_dictfct_Address_interpret(union avp_value * avp_value, void * interpreted);
-char * fd_dictfct_Address_dump(union avp_value * avp_value);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Address_dump, union avp_value * avp_value);
 
 /* Display the content of an AVP of type UTF8String in the log file */
-char * fd_dictfct_UTF8String_dump(union avp_value * avp_value);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_UTF8String_dump, union avp_value * avp_value);
 
 /* For Time AVPs, map with time_t value directly */
 int fd_dictfct_Time_encode(void * data, union avp_value * avp_value);
 int fd_dictfct_Time_interpret(union avp_value * avp_value, void * interpreted);
-char * fd_dictfct_Time_dump(union avp_value * avp_value);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump, union avp_value * avp_value);
 
 
 
@@ -1406,8 +1416,10 @@
 #define	AVP_FLAG_RESERVED8	0x01
 
 /* For dumping flags and values */
-#define DUMP_AVPFL_str	"%c%c"
-#define DUMP_AVPFL_val(_val) (_val & AVP_FLAG_VENDOR)?'V':'-' , (_val & AVP_FLAG_MANDATORY)?'M':'-'
+#define DUMP_AVPFL_str	"%c%c%s%s%s%s%s%s"
+#define DUMP_AVPFL_val(_val) (_val & AVP_FLAG_VENDOR)?'V':'-' , (_val & AVP_FLAG_MANDATORY)?'M':'-',	\
+				(_val & AVP_FLAG_RESERVED3)?"3":"", (_val & AVP_FLAG_RESERVED4)?"4":"", \
+				(_val & AVP_FLAG_RESERVED5)?"5":"", (_val & AVP_FLAG_RESERVED6)?"6":"", (_val & AVP_FLAG_RESERVED7)?"7":"", (_val & AVP_FLAG_RESERVED8)?"8":""
 
 /* Type to hold data associated to an avp */
 struct dict_avp_data {
@@ -1556,8 +1568,9 @@
 #define CMD_FLAG_RESERVED8	0x01
 
 /* For dumping flags and values */
-#define DUMP_CMDFL_str	"%c%c%c%c"
-#define DUMP_CMDFL_val(_val) (_val & CMD_FLAG_REQUEST)?'R':'-' , (_val & CMD_FLAG_PROXIABLE)?'P':'-' , (_val & CMD_FLAG_ERROR)?'E':'-' , (_val & CMD_FLAG_RETRANSMIT)?'T':'-'
+#define DUMP_CMDFL_str	"%c%c%c%c%s%s%s%s"
+#define DUMP_CMDFL_val(_val) (_val & CMD_FLAG_REQUEST)?'R':'-' , (_val & CMD_FLAG_PROXIABLE)?'P':'-' , (_val & CMD_FLAG_ERROR)?'E':'-' , (_val & CMD_FLAG_RETRANSMIT)?'T':'-', \
+				(_val & CMD_FLAG_RESERVED5)?"5":"", (_val & CMD_FLAG_RESERVED6)?"6":"", (_val & CMD_FLAG_RESERVED7)?"7":"", (_val & CMD_FLAG_RESERVED8)?"8":""
 
 /* Type to hold data associated to a command */
 struct dict_cmd_data {
@@ -1819,7 +1832,9 @@
 struct session;
 
 /* The state information that a module associate with a session -- each module defines its own data format */
-typedef void session_state;
+struct sess_state; /* declare this in your own extension */
+
+typedef DECLARE_FD_DUMP_PROTOTYPE((*session_state_dump), struct sess_state * st);
 
 /* The following function must be called to activate the session expiry mechanism */
 int fd_sess_start(void);
@@ -1830,6 +1845,7 @@
  * PARAMETERS:
  *  handler	: location where the new handler must be stored.
  *  cleanup	: a callback function that must be called when the session with associated data is destroyed.
+ *  dumper      : if not NULL, will be called during fd_sess_dump to display the data associated with a session. NULL otherwise.
  *  opaque      : A pointer that is passed to the cleanup callback -- the content is never examined by the framework.
  *
  * DESCRIPTION: 
@@ -1842,10 +1858,7 @@
  *  EINVAL 	: A parameter is invalid.
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, os0_t sid, void * opaque), void * opaque );
-/* Macro to avoid casting everywhere */
-#define fd_sess_handler_create( _handler, _cleanup, _opaque ) \
-	fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, os0_t, void *))(_cleanup), (void *)(_opaque) )
+int fd_sess_handler_create ( struct session_handler ** handler, void (*cleanup)(struct sess_state * state, os0_t sid, void * opaque), session_state_dump dumper, void * opaque );
 
 	
 /*
@@ -2017,9 +2030,7 @@
  *  EALREADY	: Data was already associated with this session and client.
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_sess_state_store_internal ( struct session_handler * handler, struct session * session, session_state ** state );
-#define fd_sess_state_store( _handler, _session, _state ) \
-	fd_sess_state_store_internal( (_handler), (_session), (void *)(_state) )
+int fd_sess_state_store ( struct session_handler * handler, struct session * session, struct sess_state ** state );
 
 /*
  * FUNCTION:	fd_sess_state_retrieve
@@ -2039,14 +2050,12 @@
  *  0      	: *state is updated (NULL or points to the state if it was found).
  *  EINVAL 	: A parameter is invalid.
  */
-int fd_sess_state_retrieve_internal ( struct session_handler * handler, struct session * session, session_state ** state ); 
-#define fd_sess_state_retrieve( _handler, _session, _state ) \
-	fd_sess_state_retrieve_internal( (_handler), (_session), (void *)(_state) )
+int fd_sess_state_retrieve ( struct session_handler * handler, struct session * session, struct sess_state ** state ); 
 
 
 /* For debug */
-void fd_sess_dump(int level, struct session * session);
-void fd_sess_dump_hdl(int level, struct session_handler * handler);
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump, struct session * session, int with_states);
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump_hdl, struct session_handler * handler);
 
 /* For statistics / monitoring: get the number of struct session in memory */
 int fd_sess_getcount(uint32_t *cnt);
@@ -2077,6 +2086,9 @@
 /* If a peer returned a protocol error for this message, save it so that we don't try to send it there again. Optionally retrieve the current list of candidates. */
 int  fd_rtd_error_add(struct rt_data * rtd, DiamId_t sentto, size_t senttolen, uint8_t * origin, size_t originsz, uint32_t rcode, struct fd_list ** candidates, int * sendingattemtps);
 
+/* Only retrieve the number of times this message has been processed by the routing-out mechanism (i.e. number of times it was failed over) */
+int  fd_rtd_get_nb_attempts(struct rt_data * rtd, int * sendingattemtps);
+
 /* The extracted list items have the following structure: */
 struct rtd_candidate {
 	struct fd_list	chain;	/* link in the list returned by the previous fcts */
@@ -2327,55 +2339,27 @@
  * FUNCTION:	fd_msg_dump_*
  *
  * PARAMETERS:
- *  level	: the log level (INFO, FULL, ...) at which the object is dumped
- *  obj		: A msg or avp object.
+ *  see definition of DECLARE_FD_DUMP_PROTOTYPE,
+ *  obj		 : A msg or avp object to dump.
+ *  dict         : the dictionary to use if parsing is requested (optional)
+ *  force_parsing: by default these functions do not parse the object but dump hexa values in that case.
+ *                 use !0 to force parsing. If parsing fails, the hexa dump is still provided.
+ *  recurse      : allow the function to go through the children objects if any to dump more information. might require parsing.
  *
  * DESCRIPTION: 
- *   These functions dump the content of a message to the debug log
+ *   These functions dump the content of a message or avp into a buffer
  * either recursively or only the object itself.
  *
  * RETURN VALUE:
- *   -
+ *   - see DECLARE_FD_DUMP_PROTOTYPE,
  */
-void fd_msg_dump_walk ( int level, msg_or_avp *obj );
-void fd_msg_dump_one  ( int level, msg_or_avp *obj );
-/* Dump full message to log */
-void fd_msg_dump_full ( int level, struct dictionary *dict, const char *prefix, msg_or_avp *obj );
-
-/*
- * FUNCTION:	fd_msg_log
- *
- * PARAMETERS:
- *  cause	 : Context for calling this function. This allows the log facility to be configured precisely.
- *  msg		 : The message to log.
- *  prefix_format: Printf-style format message that is printed ahead of the message. Might be reason for drop or so.
- *
- * DESCRIPTION: 
- *   This function is called when a Diameter message reaches some particular points in the fD framework.
- * The actual effect is configurable: log in a separate file, dump in the debug log, etc.
- *
- * RETURN VALUE:
- *   -
- */
-enum fd_msg_log_cause {
-	FD_MSG_LOG_DROPPED = 1,  /* message has been dropped by the framework */ 
-	FD_MSG_LOG_RECEIVED,     /* message received from the network */ 
-	FD_MSG_LOG_SENT,         /* message sent to another peer */ 
-	FD_MSG_LOG_NODELIVER,    /* message could not be delivered to any peer */
-	FD_MSG_LOG_TIMING	 /* profiling messages */
-};
-#define FD_MSG_LOG_MAX FD_MSG_LOG_TIMING
-void fd_msg_log( enum fd_msg_log_cause cause, struct msg * msg, const char * prefix_format, ... ) _ATTRIBUTE_PRINTFLIKE_(3,4);
-
-/* configure the msg_log facility */
-enum fd_msg_log_method {
-	FD_MSG_LOGTO_NONE = 0, /* The message is not dumped. This is the default. */
-	FD_MSG_LOGTO_DEBUGONLY, /* Simply log the message with other debug information, at the INFO level. */
-	FD_MSG_LOGTO_FILE,    /* Messages are dumped in a single file, defined in arg */
-	FD_MSG_LOGTO_DIR    /* Messages are dumped in different files within one directory defined in arg. */
-};
-int fd_msg_log_config(enum fd_msg_log_cause cause, enum fd_msg_log_method method, const char * arg);
-void fd_msg_log_init(struct dictionary *dict);
+/* one-line dump with only short information */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_summary, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
+/* one-line dump with all the contents of the message */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_full, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
+/* multi-line human-readable dump similar to wireshark output */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_treeview, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
+
 
 /*********************************************/
 /*   Message metadata management functions   */
@@ -2529,28 +2513,6 @@
 int fd_msg_source_get( struct msg * msg, DiamId_t *diamid, size_t * diamidlen );
 
 /*
- * FUNCTION:	fd_msg_ts_*
- *
- * PARAMETERS:
- *  msg		: A msg object.
- *  ts		: A struct timespec pointer, indexed on CLOCK_REALTIME
- *
- * DESCRIPTION: 
- *   Associate or retrieve timestamps meaningful for the message.
- *  A timestamp with a value of { 0, 0 } means: not set.
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0      	: an error occurred.
- */
-/* when msg was received from network */
-int fd_msg_ts_set_recv( struct msg * msg, struct timespec * ts );
-int fd_msg_ts_get_recv( struct msg * msg, struct timespec * ts );
-int fd_msg_ts_set_sent( struct msg * msg, struct timespec * ts );
-int fd_msg_ts_get_sent( struct msg * msg, struct timespec * ts );
-
-
-/*
  * FUNCTION:	fd_msg_eteid_get
  *
  * PARAMETERS:
@@ -2589,6 +2551,14 @@
 int fd_msg_sess_set(struct msg * msg, struct session * session);
 
 
+/* Helper for the hooks mechanism, for use from libfdcore */
+struct fd_msg_pmdl {
+	struct fd_list sentinel; /* if the sentinel.o field is NULL, the structure is not initialized. Otherwise it points to the cleanup function in libfdcore. */
+	pthread_mutex_t lock;
+};
+struct fd_msg_pmdl * fd_msg_pmdl_get(struct msg * msg);
+
+
 /***************************************/
 /*   Manage AVP values                 */
 /***************************************/
@@ -3031,21 +3001,41 @@
 int fd_fifo_move ( struct fifo * oldq, struct fifo * newq, struct fifo ** loc_update );
 
 /*
+ * FUNCTION:	fd_fifo_getstats
+ *
+ * PARAMETERS:
+ *  queue	  : The queue from which to retrieve the information.
+ *  current_count : How many items in the queue at the time of execution. This changes each time an item is pushed or poped.
+ *  limit_count   : The maximum number of items allowed in this queue. This is specified during queue creation.
+ *  highest_count : The maximum number of items this queue has contained. This enables to see if limit_count count was reached.
+ *  total_count   : the total number of items that went through the queue (already pop'd). Always increasing.
+ *  total	  : Cumulated time all items spent in this queue, including blocking time (always growing, use deltas for monitoring)
+ *  blocking      : Cumulated time threads trying to post new items were blocked (queue full).
+ *  last          : For the last element retrieved from the queue, how long it take between posting (including blocking) and poping
+ *  
+ * DESCRIPTION: 
+ *  Retrieve the timing information associated with a queue, for monitoring purpose.
+ *
+ * RETURN VALUE:
+ *  0		: The statistics have been updated.
+ *  EINVAL 	: A parameter is invalid.
+ */
+int fd_fifo_getstats( struct fifo * queue, int * current_count, int * limit_count, int * highest_count, long long * total_count, 
+				           struct timespec * total, struct timespec * blocking, struct timespec * last);
+
+/*
  * FUNCTION:	fd_fifo_length
  *
  * PARAMETERS:
  *  queue	: The queue from which to retrieve the number of elements.
- *  length	: Upon success, the current number of elements in the queue is stored here.
  *
  * DESCRIPTION: 
- *  Retrieve the number of elements in a queue.
+ *  Retrieve the number of elements in a queue, without error checking.
  *
  * RETURN VALUE:
- *  0		: The length of the queue has been written.
- *  EINVAL 	: A parameter is invalid.
+ *  The number of items currently queued.
  */
-int fd_fifo_length ( struct fifo * queue, int * length );
-int fd_fifo_length_noerr ( struct fifo * queue ); /* no error checking version */
+int fd_fifo_length ( struct fifo * queue );
 
 /*
  * FUNCTION:	fd_fifo_setthrhd
@@ -3163,7 +3153,8 @@
 	fd_fifo_timedget_int((queue), (void *)(item), (abstime))
 
 /* Dump a fifo list and optionally its inner elements -- beware of deadlocks! */
-void fd_fifo_dump(int level, char * name, struct fifo * queue, void (*dump_item)(int level, void * item));
+typedef DECLARE_FD_DUMP_PROTOTYPE((*fd_fifo_dump_item_cb), void * item); /* This function should be 1 line if possible, or use indent level. Ends with '\n' */
+DECLARE_FD_DUMP_PROTOTYPE(fd_fifo_dump, char * name, struct fifo * queue, fd_fifo_dump_item_cb dump_item);
 
 #ifdef __cplusplus
 }
--- a/libfdcore/CMakeLists.txt	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/CMakeLists.txt	Fri May 10 18:49:19 2013 +0800
@@ -17,6 +17,8 @@
 	endpoints.c
 	events.c
 	extensions.c
+	fifo_stats.c
+	hooks.c
 	dict_base_proto.c
 	messages.c
 	queues.c
--- a/libfdcore/cnxctx.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/cnxctx.c	Fri May 10 18:49:19 2013 +0800
@@ -227,12 +227,6 @@
 	/* Accept the new connection -- this is blocking until new client enters or until cancellation */
 	CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL );
 	
-	if (TRACE_BOOL(INFO)) {
-		char buf[1024];
-		sSA_DUMP_NODE( buf, sizeof(buf), &ss, NI_NUMERICHOST );
-		fd_log_debug("%s : accepted new client [%s].", fd_cnx_getid(serv), buf);
-	}
-	
 	CHECK_MALLOC_DO( cli = fd_cnx_init(1), { shutdown(cli_sock, SHUT_RDWR); close(cli_sock); return NULL; } );
 	cli->cc_socket = cli_sock;
 	cli->cc_family = serv->cc_family;
@@ -263,6 +257,8 @@
 		if (rc)
 			snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc));
 	}
+	
+	LOG_D("Incoming connection: '%s' <- '%s'   {%s}", fd_cnx_getid(serv), cli->cc_remid, cli->cc_id);
 
 #ifndef DISABLE_SCTP
 	/* SCTP-specific handlings */
@@ -274,7 +270,7 @@
 		else
 			cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_in;
 		
-		TRACE_DEBUG(FULL,"%s : client '%s' (SCTP:%d, %d/%d streams)", fd_cnx_getid(serv), fd_cnx_getid(cli), cli->cc_socket, cli->cc_sctp_para.str_in, cli->cc_sctp_para.str_out);
+		LOG_A( "%s : client '%s' (SCTP:%d, %d/%d streams)", fd_cnx_getid(serv), fd_cnx_getid(cli), cli->cc_socket, cli->cc_sctp_para.str_in, cli->cc_sctp_para.str_out);
 	}
 #endif /* DISABLE_SCTP */
 
@@ -286,36 +282,22 @@
 {
 	int sock = 0;
 	struct cnxctx * cnx = NULL;
+	char sa_buf[sSA_DUMP_STRLEN];
 	
 	TRACE_ENTRY("%p %d", sa, addrlen);
 	CHECK_PARAMS_DO( sa && addrlen, return NULL );
 	
+	fd_sa_sdump_numeric(sa_buf, sa);
+	
 	/* Create the socket and connect, which can take some time and/or fail */
 	{
 		int ret = fd_tcp_client( &sock, sa, addrlen );
 		if (ret != 0) {
-			int lvl;
-			switch (ret) {
-				case ECONNREFUSED:
-
-					/* "Normal" errors */
-					lvl = FULL;
-					break;
-				default:
-					lvl = INFO;
-			}
-			/* Some errors are expected, we log at different level */
-			TRACE_DEBUG( lvl, "fd_tcp_client returned an error: %s", strerror(ret));
+			LOG_A("TCP connection to %s failed: %s", sa_buf, strerror(ret));
 			return NULL;
 		}
 	}
 	
-	if (TRACE_BOOL(INFO)) {
-		char buf[1024];
-		sSA_DUMP_NODE_SERV( buf, sizeof(buf), sa, NI_NUMERICSERV);
-		fd_log_debug("Connection established to server '%s' (TCP:%d).", buf, sock);
-	}
-	
 	/* Once the socket is created successfuly, prepare the remaining of the cnx */
 	CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); close(sock); return NULL; } );
 	
@@ -328,18 +310,9 @@
 	
 	/* Generate the names for the object */
 	{
-		char addrbuf[INET6_ADDRSTRLEN];
-		char portbuf[10];
 		int  rc;
 		
-		/* Numeric values for debug... */
-		rc = getnameinfo(sa, addrlen, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
-		if (rc) {
-			snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
-			portbuf[0] = '\0';
-		}
-		
-		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP to [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
+		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "TCP,#%d->%s", cnx->cc_socket, sa_buf);
 		
 		/* ...Name for log messages */
 		rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
@@ -347,6 +320,8 @@
 			snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
 	}
 	
+	LOG_A("TCP connection to %s succeed (socket:%d).", sa_buf, sock);
+	
 	return cnx;
 }
 
@@ -361,26 +336,18 @@
 #else /* DISABLE_SCTP */
 	int sock = 0;
 	struct cnxctx * cnx = NULL;
+	char sa_buf[sSA_DUMP_STRLEN];
 	sSS primary;
 	
 	TRACE_ENTRY("%p", list);
 	CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL );
 	
+	fd_sa_sdump_numeric(sa_buf, &((struct fd_endpoint *)(list->next))->sa);
+	
 	{
 		int ret = fd_sctp_client( &sock, no_ip6, port, list );
 		if (ret != 0) {
-			int lvl;
-			switch (ret) {
-				case ECONNREFUSED:
-
-					/* "Normal" errors */
-					lvl = FULL;
-					break;
-				default:
-					lvl = INFO;
-			}
-			/* Some errors are expected, we log at different level */
-			TRACE_DEBUG( lvl, "fd_sctp_client returned an error: %s", strerror(ret));
+			LOG_A("SCTP connection to [%s,...] failed: %s", sa_buf, strerror(ret));
 			return NULL;
 		}
 	}
@@ -402,26 +369,13 @@
 	else
 		cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in;
 	
-	if (TRACE_BOOL(INFO)) {
-		char buf[1024];
-		sSA_DUMP_NODE_SERV( buf, sizeof(buf), &primary, NI_NUMERICSERV);
-		fd_log_debug("Connection established to server '%s' (SCTP:%d, %d/%d streams).", buf, sock, cnx->cc_sctp_para.str_in, cnx->cc_sctp_para.str_out);
-	}
+	fd_sa_sdump_numeric(sa_buf, (sSA *)&primary);
 	
 	/* Generate the names for the object */
 	{
-		char addrbuf[INET6_ADDRSTRLEN];
-		char portbuf[10];
 		int  rc;
 		
-		/* Numeric values for debug... */
-		rc = getnameinfo((sSA *)&primary, sSAlen(&primary), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
-		if (rc) {
-			snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
-			portbuf[0] = '\0';
-		}
-		
-		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP to [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
+		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "SCTP,#%d->%s", cnx->cc_socket, sa_buf);
 		
 		/* ...Name for log messages */
 		rc = getnameinfo((sSA *)&primary, sSAlen(&primary), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
@@ -429,6 +383,8 @@
 			snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
 	}
 	
+	LOG_A("SCTP connection to %s succeed (socket:%d, %d/%d streams).", sa_buf, sock, cnx->cc_sctp_para.str_in, cnx->cc_sctp_para.str_out);
+	
 	return cnx;
 
 error:
@@ -643,8 +599,6 @@
 		fd_cnx_markerror(conn);
 	}
 	
-	CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &conn->cc_tls_para.recvon), /* continue */ );
-	
 	return ret;
 }
 
@@ -674,6 +628,53 @@
 	return ret;
 }
 
+#define ALIGNOF(t) ((char *)(&((struct { char c; t _h; } *)0)->_h) - (char *)0)  /* Could use __alignof__(t) on some systems but this is more portable probably */
+#define PMDL_PADDED(len) ( ((len) + ALIGNOF(struct fd_msg_pmdl) - 1) & ~(ALIGNOF(struct fd_msg_pmdl) - 1) )
+
+size_t fd_msg_pmdl_sizewithoverhead(size_t datalen)
+{
+	return PMDL_PADDED(datalen) + sizeof(struct fd_msg_pmdl);
+}
+
+struct fd_msg_pmdl * fd_msg_pmdl_get_inbuf(uint8_t * buf, size_t datalen)
+{
+	return (struct fd_msg_pmdl *)(buf + PMDL_PADDED(datalen));
+} 
+
+static int fd_cnx_init_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl)
+{
+	*pmdl = fd_msg_pmdl_get_inbuf(buffer, expected_len);
+	fd_list_init(&(*pmdl)->sentinel, NULL);
+	CHECK_POSIX(pthread_mutex_init(&(*pmdl)->lock, NULL) );
+	return 0;
+}
+
+static uint8_t * fd_cnx_alloc_msg_buffer(size_t expected_len, struct fd_msg_pmdl ** pmdl)
+{
+	uint8_t * ret = NULL;
+	
+	CHECK_MALLOC_DO(  ret = malloc( fd_msg_pmdl_sizewithoverhead(expected_len) ), return NULL );
+	CHECK_FCT_DO( fd_cnx_init_msg_buffer(ret, expected_len, pmdl), {free(ret); return NULL;} );
+	return ret;
+}
+
+static uint8_t * fd_cnx_realloc_msg_buffer(uint8_t * buffer, size_t expected_len, struct fd_msg_pmdl ** pmdl)
+{
+	uint8_t * ret = NULL;
+	
+	CHECK_MALLOC_DO(  ret = realloc( buffer, fd_msg_pmdl_sizewithoverhead(expected_len) ), return NULL );
+	CHECK_FCT_DO( fd_cnx_init_msg_buffer(ret, expected_len, pmdl), {free(ret); return NULL;} );
+	return ret;
+}
+
+static void free_rcvdata(void * arg) 
+{
+	struct fd_cnx_rcvdata * data = arg;
+	struct fd_msg_pmdl * pmdl = fd_msg_pmdl_get_inbuf(data->buffer, data->length);
+	(void) pthread_mutex_destroy(&pmdl->lock);
+	free(data->buffer);
+}
+
 /* Receiver thread (TCP & noTLS) : incoming message is directly saved into the target queue */
 static void * rcvthr_notls_tcp(void * arg)
 {
@@ -696,11 +697,10 @@
 	/* Receive from a TCP connection: we have to rebuild the message boundaries */
 	do {
 		uint8_t header[4];
-		uint8_t * newmsg;
-		size_t  length;
+		struct fd_cnx_rcvdata rcv_data;
+		struct fd_msg_pmdl *pmdl=NULL;
 		ssize_t ret = 0;
 		size_t	received = 0;
-		struct timespec recv_on;
 
 		do {
 			ret = fd_cnx_s_recv(conn, &header[received], sizeof(header) - received);
@@ -711,39 +711,42 @@
 			received += ret;
 		} while (received < sizeof(header));
 
-		length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
+		rcv_data.length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
 
 		/* Check the received word is a valid begining of a Diameter message */
 		if ((header[0] != DIAMETER_VERSION)	/* defined in <libfdproto.h> */
-		   || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
+		   || (rcv_data.length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
 			/* The message is suspect */
-			TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length);
+			LOG_E( "Received suspect header [ver: %d, size: %zd] from '%s', assuming disconnection", (int)header[0], rcv_data.length, conn->cc_remid);
 			fd_cnx_markerror(conn);
 			goto out; /* Stop the thread, the recipient of the event will cleanup */
 		}
 
 		/* Ok, now we can really receive the data */
-		CHECK_MALLOC_DO(  newmsg = malloc( length + sizeof(struct timespec) ), goto fatal );
-		memcpy(newmsg, header, sizeof(header));
+		CHECK_MALLOC_DO(  rcv_data.buffer = fd_cnx_alloc_msg_buffer( rcv_data.length, &pmdl ), goto fatal );
+		memcpy(rcv_data.buffer, header, sizeof(header));
 
-		while (received < length) {
-			pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
-			ret = fd_cnx_s_recv(conn, newmsg + received, length - received);
+		while (received < rcv_data.length) {
+			pthread_cleanup_push(free_rcvdata, &rcv_data); /* In case we are canceled, clean the partialy built buffer */
+			ret = fd_cnx_s_recv(conn, rcv_data.buffer + received, rcv_data.length - received);
 			pthread_cleanup_pop(0);
 
 			if (ret <= 0) {
-				free(newmsg);
+				free_rcvdata(&rcv_data);
 				goto out;
 			}
 			received += ret;
 		}
 		
-		/* Piggy-tail the timestamp of reception */
-		CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &recv_on), /* continue */ );
-		memcpy(newmsg + length, &recv_on, sizeof(struct timespec));
+		fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl);
 		
 		/* We have received a complete message, pass it to the daemon */
-		CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
+		CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer), 
+			{ 
+				free_rcvdata(&rcv_data);
+				CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
+				return NULL; 
+			} );
 		
 	} while (conn->cc_loop);
 	
@@ -762,8 +765,7 @@
 static void * rcvthr_notls_sctp(void * arg)
 {
 	struct cnxctx * conn = arg;
-	uint8_t * buf;
-	size_t    bufsz;
+	struct fd_cnx_rcvdata rcv_data;
 	int	  event;
 	
 	TRACE_ENTRY("%p", arg);
@@ -781,7 +783,8 @@
 	ASSERT( fd_cnx_target_queue(conn) );
 	
 	do {
-		CHECK_FCT_DO( fd_sctp_recvmeta(conn, NULL, &buf, &bufsz, &event), goto fatal );
+		struct fd_msg_pmdl *pmdl=NULL;
+		CHECK_FCT_DO( fd_sctp_recvmeta(conn, NULL, &rcv_data.buffer, &rcv_data.length, &event), goto fatal );
 		if (event == FDEVP_CNX_ERROR) {
 			fd_cnx_markerror(conn);
 			goto out;
@@ -791,8 +794,12 @@
 			/* Just ignore the notification for now, we will get another error later anyway */
 			continue;
 		}
-		/* Note: the real size of buf is bufsz + struct timespec */
-		CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, bufsz, buf), goto fatal );
+
+		if (event == FDEVP_CNX_MSG_RECV) {
+			CHECK_MALLOC_DO( rcv_data.buffer = fd_cnx_realloc_msg_buffer(rcv_data.buffer, rcv_data.length, &pmdl), goto fatal );
+			fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl);
+		}
+		CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), event, rcv_data.length, rcv_data.buffer), goto fatal );
 		
 	} while (conn->cc_loop || (event != FDEVP_CNX_MSG_RECV));
 	
@@ -929,22 +936,11 @@
 /* The function that receives TLS data and re-builds a Diameter message -- it exits only on error or cancelation */
 int fd_tls_rcvthr_core(struct cnxctx * conn, gnutls_session_t session)
 {
-	struct timespec * rcv_on = &conn->cc_tls_para.recvon;
-	
-#ifndef DISABLE_SCTP
-	void * ptr = gnutls_transport_get_ptr(session);
-	if (ptr != conn) {
-		struct sctps_ctx * ctx = (struct sctps_ctx *) ptr;
-		rcv_on = &ctx->recvon;
-	}
-#endif /* DISABLE_SCTP */
-	
-	
 	/* No guarantee that GnuTLS preserves the message boundaries, so we re-build it as in TCP */
 	do {
 		uint8_t header[4];
-		uint8_t * newmsg;
-		size_t  length;
+		struct fd_cnx_rcvdata rcv_data;
+		struct fd_msg_pmdl *pmdl=NULL;
 		ssize_t ret = 0;
 		size_t	received = 0;
 
@@ -957,40 +953,39 @@
 			received += ret;
 		} while (received < sizeof(header));
 
-		length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
+		rcv_data.length = ((size_t)header[1] << 16) + ((size_t)header[2] << 8) + (size_t)header[3];
 
 		/* Check the received word is a valid beginning of a Diameter message */
 		if ((header[0] != DIAMETER_VERSION)	/* defined in <libfreeDiameter.h> */
-		   || (length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
+		   || (rcv_data.length > DIAMETER_MSG_SIZE_MAX)) { /* to avoid too big mallocs */
 			/* The message is suspect */
-			TRACE_DEBUG(INFO, "Received suspect header [ver: %d, size: %zd], assume disconnection", (int)header[0], length);
+			LOG_E( "Received suspect header [ver: %d, size: %zd] from '%s', assume disconnection", (int)header[0], rcv_data.length, conn->cc_remid);
 			fd_cnx_markerror(conn);
 			goto out;
 		}
 
 		/* Ok, now we can really receive the data */
-		CHECK_MALLOC(  newmsg = malloc( length + sizeof(struct timespec)) );
-		memcpy(newmsg, header, sizeof(header));
+		CHECK_MALLOC(  rcv_data.buffer = fd_cnx_alloc_msg_buffer( rcv_data.length, &pmdl ) );
+		memcpy(rcv_data.buffer, header, sizeof(header));
 
-		while (received < length) {
-			pthread_cleanup_push(free, newmsg); /* In case we are canceled, clean the partialy built buffer */
-			ret = fd_tls_recv_handle_error(conn, session, newmsg + received, length - received);
+		while (received < rcv_data.length) {
+			pthread_cleanup_push(free_rcvdata, &rcv_data); /* In case we are canceled, clean the partialy built buffer */
+			ret = fd_tls_recv_handle_error(conn, session, rcv_data.buffer + received, rcv_data.length - received);
 			pthread_cleanup_pop(0);
 
 			if (ret <= 0) {
-				free(newmsg);
+				free_rcvdata(&rcv_data);
 				goto out;
 			}
 			received += ret;
 		}
 		
-		/* The timestamp of the last TLS chunk received for this rebuilt message lives close to the session pointer, we piggyback it */
-		memcpy(newmsg + length, rcv_on, sizeof(struct timespec));
+		fd_hook_call(HOOK_DATA_RECEIVED, NULL, NULL, &rcv_data, pmdl);
 		
 		/* We have received a complete message, pass it to the daemon */
-		CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), 
+		CHECK_FCT_DO( ret = fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, rcv_data.length, rcv_data.buffer), 
 			{ 
-				free(newmsg); 
+				free_rcvdata(&rcv_data);
 				CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
 				return ret; 
 			} );
@@ -1776,7 +1771,7 @@
 #endif /* DISABLE_SCTP */
 	
 		default:
-			TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto);
+			TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto);
 			ASSERT(0);
 			return ENOTSUP;	/* or EINVAL... */
 	}
--- a/libfdcore/cnxctx.h	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/cnxctx.h	Fri May 10 18:49:19 2013 +0800
@@ -65,7 +65,6 @@
 		DiamId_t 			 cn;		/* If not NULL, remote certif will be checked to match this Common Name */
 		int				 mode; 		/* GNUTLS_CLIENT / GNUTLS_SERVER */
 		gnutls_session_t 		 session;	/* Session object (stream #0 in case of SCTP) */
-		struct timespec  		 recvon;	/* Timestamp of the last chunk of data received on this session -- before uncipher */
 	}		cc_tls_para;
 
 	/* If cc_proto == SCTP */
@@ -130,7 +129,6 @@
 		size_t   bufsz;
 		size_t   offset;
 	} 		 partial;	/* If the pull function did not read the full content of first message in raw, it stores it here for next read call. */
-	struct timespec  recvon;	/* Timestamp of the last chunk of data received on this stream -- before uncipher */
 	pthread_t	 thr;		/* Thread to decrypt raw data in this pair of streams */
 	gnutls_session_t session;	/* TLS context using this pair of streams -- except if strid == 0, in that case session is outside the array */
 };
--- a/libfdcore/config.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/config.c	Fri May 10 18:49:19 2013 +0800
@@ -80,68 +80,69 @@
 	return 0;
 }
 
-void fd_conf_dump()
+DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump)
 {
-	if (!TRACE_BOOL(INFO))
-		return;
+	FD_DUMP_HANDLE_OFFSET();
 	
-	fd_log_debug("-- Configuration :");
-	fd_log_debug("  Debug trace level ...... : %+d", fd_g_debug_lvl);
-	fd_log_debug("  Configuration file ..... : %s", fd_g_config->cnf_file);
-	fd_log_debug("  Diameter Identity ...... : %s (l:%Zi)", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len);
-	fd_log_debug("  Diameter Realm ......... : %s (l:%Zi)", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len);
-	fd_log_debug("  Tc Timer ............... : %u", fd_g_config->cnf_timer_tc);
-	fd_log_debug("  Tw Timer ............... : %u", fd_g_config->cnf_timer_tw);
-	fd_log_debug("  Local port ............. : %hu", fd_g_config->cnf_port);
-	fd_log_debug("  Local secure port ...... : %hu", fd_g_config->cnf_port_tls);
-	fd_log_debug("  Number of SCTP streams . : %hu", fd_g_config->cnf_sctp_str);
-	fd_log_debug("  Number of server threads : %hu", fd_g_config->cnf_dispthr);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{freeDiameter configuration}(@%p): \n", fd_g_config), return NULL);	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Default trace level .... : %+d\n", fd_g_debug_lvl), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Configuration file ..... : %s\n", fd_g_config->cnf_file), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Diameter Identity ...... : %s (l:%Zi)\n", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Diameter Realm ......... : %s (l:%Zi)\n", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Tc Timer ............... : %u\n", fd_g_config->cnf_timer_tc), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Tw Timer ............... : %u\n", fd_g_config->cnf_timer_tw), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local port ............. : %hu\n", fd_g_config->cnf_port), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local secure port ...... : %hu\n", fd_g_config->cnf_port_tls), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of server threads : %hu\n", fd_g_config->cnf_dispthr), return NULL);
 	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
-		fd_log_debug("  Local endpoints ........ : Default (use all available)");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local endpoints ........ : Default (use all available)\n"), return NULL);
 	} else {
-		fd_log_debug("  Local endpoints ........ : ");
-		fd_ep_dump( 29, &fd_g_config->cnf_endpoints );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local endpoints ........ : \n"), return NULL);
+		CHECK_MALLOC_DO( fd_ep_dump( FD_DUMP_STD_PARAMS, 29, &fd_g_config->cnf_endpoints ), return NULL);
 	}
 	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_apps)) {
-		fd_log_debug("  Local applications ..... : (none)");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local applications ..... : (none)\n"), return NULL);
 	} else {
 		struct fd_list * li = fd_g_config->cnf_apps.next;
-		fd_log_debug("  Local applications ..... : ");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local applications ..... : \n"), return NULL);
 		while (li != &fd_g_config->cnf_apps) {
 			struct fd_app * app = (struct fd_app *)li;
-			if (li != fd_g_config->cnf_apps.next) fd_log_debug("                             ");
-			fd_log_debug("App: %u\t%s%s\tVnd: %u", 
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "                             App: %u\t%s%s\tVnd: %u\n", 
 					app->appid,
 					app->flags.auth ? "Au" : "--",
 					app->flags.acct ? "Ac" : "--",
-					app->vndid);
+					app->vndid), return NULL);
 			li = li->next;
 		}
 	}
 	
-	fd_log_debug("  Flags : - IP ........... : %s", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled");
-	fd_log_debug("          - IPv6 ......... : %s", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled");
-	fd_log_debug("          - Relay app .... : %s", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled");
-	fd_log_debug("          - TCP .......... : %s", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Flags : - IP ........... : %s\n", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - IPv6 ......... : %s\n", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Relay app .... : %s\n", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - TCP .......... : %s\n", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled"), return NULL);
 	#ifdef DISABLE_SCTP
-	fd_log_debug("          - SCTP ......... : DISABLED (at compilation)");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - SCTP ......... : DISABLED (at compilation)\n"), return NULL);
 	#else /* DISABLE_SCTP */
-	fd_log_debug("          - SCTP ......... : %s", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - SCTP ......... : %s\n", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled"), return NULL);
 	#endif /* DISABLE_SCTP */
-	fd_log_debug("          - Pref. proto .. : %s", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP");
-	fd_log_debug("          - TLS method ... : %s", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Pref. proto .. : %s\n", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - TLS method ... : %s\n", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port"), return NULL);
 	
-	fd_log_debug("  TLS :   - Certificate .. : %s", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)");
-	fd_log_debug("          - Private key .. : %s", fd_g_config->cnf_sec_data.key_file ?: "(NONE)");
-	fd_log_debug("          - CA (trust) ... : %s (%d certs)", fd_g_config->cnf_sec_data.ca_file ?: "(none)", fd_g_config->cnf_sec_data.ca_file_nr);
-	fd_log_debug("          - CRL .......... : %s", fd_g_config->cnf_sec_data.crl_file ?: "(none)");
-	fd_log_debug("          - Priority ..... : %s", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')");
-	if (fd_g_config->cnf_sec_data.dh_file)
-		fd_log_debug("          - DH file ...... : %s", fd_g_config->cnf_sec_data.dh_file);
-	else
-		fd_log_debug("          - DH bits ...... : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  TLS :   - Certificate .. : %s\n", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Private key .. : %s\n", fd_g_config->cnf_sec_data.key_file ?: "(NONE)"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - CA (trust) ... : %s (%d certs)\n", fd_g_config->cnf_sec_data.ca_file ?: "(none)", fd_g_config->cnf_sec_data.ca_file_nr), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - CRL .......... : %s\n", fd_g_config->cnf_sec_data.crl_file ?: "(none)"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Priority ..... : %s\n", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')"), return NULL);
+	if (fd_g_config->cnf_sec_data.dh_file) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - DH file ...... : %s\n", fd_g_config->cnf_sec_data.dh_file), return NULL);
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - DH bits ...... : %d\n", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS), return NULL);
+	}
 	
-	fd_log_debug("  Origin-State-Id ........ : %u", fd_g_config->cnf_orstateid);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Origin-State-Id ........ : %u", fd_g_config->cnf_orstateid), return NULL);
+	
+	return *buf;
 }
 
 /* read contents of a file opened in "rb" mode and alloc this data into a gnutls_datum_t (must be freed afterwards) */
--- a/libfdcore/core.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/core.c	Fri May 10 18:49:19 2013 +0800
@@ -84,32 +84,6 @@
 		int code; size_t sz; void * data;
 		CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data),  break  );
 		switch (code) {
-			case FDEV_DUMP_DICT:
-				fd_dict_dump(fd_g_config->cnf_dict);
-				break;
-			
-			case FDEV_DUMP_EXT:
-				fd_ext_dump();
-				break;
-			
-			case FDEV_DUMP_SERV:
-				fd_servers_dump();
-				break;
-			
-			case FDEV_DUMP_QUEUES:
-				fd_fifo_dump(0, "Incoming messages", fd_g_incoming, fd_msg_dump_walk);
-				fd_fifo_dump(0, "Outgoing messages", fd_g_outgoing, fd_msg_dump_walk);
-				fd_fifo_dump(0, "Local messages",    fd_g_local,    fd_msg_dump_walk);
-				break;
-			
-			case FDEV_DUMP_CONFIG:
-				fd_conf_dump();
-				break;
-			
-			case FDEV_DUMP_PEERS:
-				fd_peer_dump_list(FULL);
-				break;
-			
 			case FDEV_TRIGGER:
 				{
 					int tv, *p;
@@ -181,7 +155,7 @@
 		return ret;
 	}
 	
-	TRACE_DEBUG(INFO, "libfdproto initialized.");
+	LOG_D("libfdproto initialized.");
 	
 	/* Name this thread */
 	fd_log_threadname("Main");
@@ -208,13 +182,11 @@
 	fd_g_config = &g_conf;
 	CHECK_FCT( fd_conf_init() );
 	
-	/* Initialize the message logging facility */
-	fd_msg_log_init(fd_g_config->cnf_dict);
-
 	/* Add definitions of the base protocol */
 	CHECK_FCT( fd_dict_base_protocol(fd_g_config->cnf_dict) );
 	
 	/* Initialize some modules */
+	CHECK_FCT( fd_hooks_init()  );
 	CHECK_FCT( fd_queues_init() );
 	CHECK_FCT( fd_msg_init()    );
 	CHECK_FCT( fd_sess_start()  );
@@ -227,6 +199,10 @@
 /* Parse the freeDiameter.conf configuration file, load the extensions */
 int fd_core_parseconf(const char * conffile)
 {
+	char * buf = NULL, *b;
+	size_t len = 0, offset=0;
+	
+	
 	TRACE_ENTRY("%p", conffile);
 	
 	/* Conf file */
@@ -242,11 +218,17 @@
 	CHECK_FCT(  fd_ext_load()  );
 	
 	/* Display configuration */
-	fd_conf_dump();
+	b = fd_conf_dump(&buf, &len, NULL);
+	LOG_N("%s\n", b ?: "Error during configuration dump...");
 	
 	/* Display registered triggers for FDEV_TRIGGER */
-	fd_event_trig_dump();
+	b = fd_event_trig_dump(&buf, &len, &offset);
+	if (!b || offset) {
+		LOG_N("%s\n", b ?: "Error during triggers dump...");
+	}
 	
+	free(buf);	
+		
 	return 0;
 }
 
@@ -306,7 +288,7 @@
 }
 
 
-/* Wait for the shutdown to be complete -- this must always be called after fd_core_shutdown to relaim some resources. */
+/* Wait for the shutdown to be complete -- this must always be called after fd_core_shutdown to reclaim some resources. */
 int fd_core_wait_shutdown_complete(void)
 {
 	int ret;
--- a/libfdcore/endpoints.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/endpoints.c	Fri May 10 18:49:19 2013 +0800
@@ -57,19 +57,6 @@
 		fd_list_init(list, NULL);
 	}
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		char buf[1024];
-		sSA_DUMP_NODE_SERV( buf, sizeof(buf), sa, NI_NUMERICHOST | NI_NUMERICSERV );
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Current list:");
-		fd_ep_dump( 4, list );
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Adding:");
-		fd_log_debug("    %s {%s%s%s%s%s}", buf,
-				(flags & EP_FL_CONF) 	? "C" : "-",
-				(flags & EP_FL_DISC)	    ? "D" : "-",
-				(flags & EP_FL_ADV)	    ? "A" : "-",
-				(flags & EP_FL_LL)	    ? "L" : "-",
-				(flags & EP_FL_PRIMARY)     ? "P" : "-");
-	}
 	ptr.sa = sa;
 	
 	/* Filter out a bunch of invalid addresses */
@@ -81,9 +68,7 @@
 				    /* the next one filters both EXPERIMENTAL, BADCLASS and MULTICAST. */
 				 || ((ntohl(ptr.sin->sin_addr.s_addr) & 0xe0000000) == 0xe0000000)
 				 || (ptr.sin->sin_addr.s_addr == INADDR_BROADCAST)) {
-					if (TRACE_BOOL(ANNOYING + 1)) {
-						TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Address was ignored, not added.");
-					}
+					LOG_A("  DEBUG:fd_ep_add_merge  Address was ignored, not added.");
 					return 0;
 				}
 			}
@@ -97,9 +82,7 @@
 				 || IN6_IS_ADDR_MULTICAST(&ptr.sin6->sin6_addr)
 				 || IN6_IS_ADDR_LINKLOCAL(&ptr.sin6->sin6_addr)
 				 || IN6_IS_ADDR_SITELOCAL(&ptr.sin6->sin6_addr)) {
-					if (TRACE_BOOL(ANNOYING + 1)) {
-						TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Address was ignored, not added.");
-					}
+					LOG_A("  DEBUG:fd_ep_add_merge  Address was ignored, not added.");
 					return 0;
 				}
 			}
@@ -107,9 +90,7 @@
 			break;
 
 		default:
-			if (TRACE_BOOL(ANNOYING + 1)) {
-				TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Address family was unknown, not added.");
-			}
+			LOG_A("  DEBUG:fd_ep_add_merge  Address family was unknown, not added.");
 			return 0;
 	}
 
@@ -174,10 +155,6 @@
 	/* Merge the flags */
 	ep->flags |= flags;
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  New list:");
-		fd_ep_dump( 4, list );
-	}
 	return 0;
 }
 
@@ -189,10 +166,6 @@
 	TRACE_ENTRY("%p %x", list, flags);
 	CHECK_PARAMS(list);
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter  Filter this list for flags %x:", flags);
-		fd_ep_dump( 4, list );
-	}
 	for (li = list->next; li != list; li = li->next) {
 		struct fd_endpoint * ep = (struct fd_endpoint *)li;
 		
@@ -203,10 +176,6 @@
 		}
 	}
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter  Resulting list:");
-		fd_ep_dump( 4, list );
-	}
 	return 0;
 }
 
@@ -218,10 +187,6 @@
 	TRACE_ENTRY("%p %d", list, af);
 	CHECK_PARAMS(list);
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_family  Filter this list for family %d:", af);
-		fd_ep_dump( 4, list );
-	}
 	for (li = list->next; li != list; li = li->next) {
 		struct fd_endpoint * ep = (struct fd_endpoint *)li;
 		
@@ -232,10 +197,6 @@
 		}
 	}
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_family  Resulting list:");
-		fd_ep_dump( 4, list );
-	}
 	return 0;
 }
 
@@ -252,12 +213,6 @@
 	li_out = list->next;
 	li_ex = exclude_list->next;
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_list  Filter this list ");
-		fd_ep_dump( 4, list );
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_list  Removing from list");
-		fd_ep_dump( 6, exclude_list );
-	}
 	/* Now browse both lists in parallel */
 	while ((li_out != list) && (li_ex != exclude_list)) {
 		int cmp;
@@ -303,10 +258,6 @@
 		free(li);
 	}
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_list  Resulting list:");
-		fd_ep_dump( 4, list );
-	}
 	return 0;
 
 }
@@ -333,26 +284,40 @@
 	return 0;
 }
 
-void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep )
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, struct fd_endpoint * ep )
 {
-	char buf[1024];
+	FD_DUMP_HANDLE_OFFSET();
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{ep}(@%p): ", ep), return NULL);
 	
-	sSA_DUMP_NODE_SERV( buf, sizeof(buf), &ep->sa, NI_NUMERICHOST | NI_NUMERICSERV );
-	fd_log_debug("%s%s {%s%s%s%s}%s", prefix ?: "", buf,
+	if (!ep) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
+		return *buf;
+	}
+	
+	CHECK_MALLOC_DO( fd_sa_dump_node_serv( FD_DUMP_STD_PARAMS, &ep->sa, NI_NUMERICHOST | NI_NUMERICSERV ), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {%s%s%s%s%s}",
 			(ep->flags & EP_FL_CONF) 	? "C" : "-",
 			(ep->flags & EP_FL_DISC) 	? "D" : "-",
 			(ep->flags & EP_FL_ADV) 	? "A" : "-",
 			(ep->flags & EP_FL_LL) 		? "L" : "-",
-			(ep->flags & EP_FL_PRIMARY) 	? "P" : "-");
+			(ep->flags & EP_FL_PRIMARY) 	? "P" : "-"), return NULL);
+	return *buf;
 }
 
-void fd_ep_dump( int indent, struct fd_list * eps )
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int indent, struct fd_list * eps  )
 {
 	struct fd_list * li;
-	for (li = eps->next; li != eps; li = li->next) {
-		struct fd_endpoint * ep = (struct fd_endpoint *)li;
-		fd_log_debug("%*s", indent, "");
-		fd_ep_dump_one( NULL, ep );
+	
+	FD_DUMP_HANDLE_OFFSET();
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{eps}(@%p):", indent, "", eps), return NULL);
+	if (eps) {
+		for (li = eps->next; li != eps; li = li->next) {
+			struct fd_endpoint * ep = (struct fd_endpoint *)li;
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*s", indent+1, ""), return NULL);
+			CHECK_MALLOC_DO( fd_ep_dump_one( FD_DUMP_STD_PARAMS, ep ), return NULL);
+		}
 	}
 }
 	
--- a/libfdcore/events.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/events.c	Fri May 10 18:49:19 2013 +0800
@@ -105,12 +105,6 @@
 	#define case_str( _val )\
 		case _val : return #_val
 		case_str(FDEV_TERMINATE);
-		case_str(FDEV_DUMP_DICT);
-		case_str(FDEV_DUMP_EXT);
-		case_str(FDEV_DUMP_SERV);
-		case_str(FDEV_DUMP_QUEUES);
-		case_str(FDEV_DUMP_CONFIG);
-		case_str(FDEV_DUMP_PEERS);
 		case_str(FDEV_TRIGGER);
 		
 		default:
@@ -167,20 +161,20 @@
 	return 0;
 }
 
-void fd_event_trig_dump()
+DECLARE_FD_DUMP_PROTOTYPE(fd_event_trig_dump)
 {
 	struct fd_list * li;
-	if (!TRACE_BOOL(FULL))
-		return;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_POSIX_DO( pthread_rwlock_rdlock(&trig_rwl),  );
 	
 	for (li = trig_list.next; li != &trig_list; li = li->next) {
 		struct trig_item *t = li->o;
-		fd_log_debug("  Trigger %d, module '%s': %p", t->trig_value, t->trig_module, t->cb);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{signal:%d}'%s'->%p ", t->trig_value, t->trig_module, t->cb), break);
 	}
 	
 	CHECK_POSIX_DO( pthread_rwlock_unlock(&trig_rwl),  );
+	return *buf;
 }
 
 static void *call_cb_detached(void * arg)
--- a/libfdcore/extensions.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/extensions.c	Fri May 10 18:49:19 2013 +0800
@@ -77,17 +77,17 @@
 }
 
 /* Dump the list */
-void fd_ext_dump(void)
+DECLARE_FD_DUMP_PROTOTYPE(fd_ext_dump)
 {
 	struct fd_list * li;
-	
-	fd_log_debug("Dumping extensions list :");
+	FD_DUMP_HANDLE_OFFSET();
 	
 	for (li = ext_list.next; li != &ext_list; li = li->next)
 	{
 		struct fd_ext_info * ext = (struct fd_ext_info *)li;
-		fd_log_debug(" - '%s'[%s] is %sloaded", ext->filename, ext->conffile?:"no conf", ext->handler ? "" : "not ");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{extension}(@%p): '%s'[%s], %sloaded%s", ext, ext->filename, ext->conffile?:"no conf", ext->handler ? "" : "not ", (li->next == &ext_list) ? "":"\n"), return NULL);
 	}
+	return *buf;
 }
 
 /* Check the dependencies. The object must have been dlopened already. */
--- a/libfdcore/fdcore-internal.h	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/fdcore-internal.h	Fri May 10 18:49:19 2013 +0800
@@ -85,7 +85,6 @@
 /* Configuration */
 int fd_conf_init();
 int fd_conf_deinit();
-void fd_conf_dump();
 int fd_conf_parse();
 int fddparse(struct fd_config * conf); /* yacc generated */
 int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out);
@@ -94,7 +93,6 @@
 /* Extensions */
 int fd_ext_add( char * filename, char * conffile );
 int fd_ext_load();
-void fd_ext_dump(void);
 int fd_ext_term(void);
 
 /* Messages */
@@ -217,13 +215,10 @@
 
 /* Events codespace for struct fd_peer->p_events */
 enum {
-	/* Dump all info about this peer in the debug log */
-	 FDEVP_DUMP_ALL = 1500
+	/* request to terminate this peer : disconnect, requeue all messages */
+	FDEVP_TERMINATE = 1500
 	
-	/* request to terminate this peer : disconnect, requeue all messages */
-	,FDEVP_TERMINATE
-	
-	/* A connection object has received a message. (data contains the buffer + struct timespec piggytailed -- unaligned) */
+	/* A connection object has received a message. (data contains the buffer + padding + struct fd_msg_pmdl) */
 	,FDEVP_CNX_MSG_RECV
 			 
 	/* A connection object has encountered an error (disconnected). */
@@ -249,13 +244,12 @@
 	
 };
 #define CHECK_PEVENT( _e ) \
-	(((int)(_e) >= FDEVP_DUMP_ALL) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
+	(((int)(_e) >= FDEVP_TERMINATE) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
 /* The following macro is actually called in p_psm.c -- another solution would be to declare it static inline */
 #define DECLARE_PEV_STR()				\
 const char * fd_pev_str(int event)			\
 {							\
 	switch (event) {				\
-		case_str(FDEVP_DUMP_ALL);		\
 		case_str(FDEVP_TERMINATE);		\
 		case_str(FDEVP_CNX_MSG_RECV);		\
 		case_str(FDEVP_CNX_ERROR);		\
@@ -277,11 +271,8 @@
 	int  		  validate;	/* The peer is new, it must be validated (by an extension) or error CEA to be sent */
 };
 
-
 /* Functions */
 int  fd_peer_fini();
-void fd_peer_dump_list(int details);
-void fd_peer_dump(struct fd_peer * peer, int details);
 int  fd_peer_alloc(struct fd_peer ** ptr);
 int  fd_peer_free(struct fd_peer ** ptr);
 int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx );
@@ -338,7 +329,6 @@
 
 
 /* Server sockets */
-void fd_servers_dump();
 int  fd_servers_start();
 int  fd_servers_stop();
 
@@ -371,4 +361,11 @@
 /* Flags for the fd_cnx_send function : */
 #define FD_CNX_ORDERED		(1 << 0)	/* All messages sent with this flag set will be delivered in the same order. No guarantee on other messages */
 
+/* Internal calls of the hook mechanism */
+void   fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl);
+void   fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl);
+int    fd_hooks_init(void);
+size_t fd_msg_pmdl_sizewithoverhead(size_t datalen);
+struct fd_msg_pmdl * fd_msg_pmdl_get_inbuf(uint8_t * buf, size_t datalen); 
+
 #endif /* _FDCORE_INTERNAL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfdcore/fifo_stats.c	Fri May 10 18:49:19 2013 +0800
@@ -0,0 +1,79 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, 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.								 *
+*********************************************************************************************************/
+
+#include "fdcore-internal.h"
+
+/* See include/freeDiameter/libfdcore.h for more information */
+int fd_stat_getstats(enum fd_stat_type stat, struct peer_hdr * peer, 
+			int * current_count, int * limit_count, int * highest_count, long long * total_count, 
+			struct timespec * total, struct timespec * blocking, struct timespec * last)
+{
+	struct fd_peer * p = (struct fd_peer *)peer;
+	TRACE_ENTRY( "%d %p %p %p %p %p %p %p %p", stat, peer, current_count, limit_count, highest_count, total_count, total, blocking, last);
+	
+	switch (stat) {
+		case STAT_G_LOCAL: {
+			CHECK_FCT( fd_fifo_getstats(fd_g_local, current_count, limit_count, highest_count, total_count, total, blocking, last) );
+		}
+		break;
+
+		case STAT_G_INCOMING: {
+			CHECK_FCT( fd_fifo_getstats(fd_g_incoming, current_count, limit_count, highest_count, total_count, total, blocking, last) );
+		}
+		break;
+
+		case STAT_G_OUTGOING: {
+			CHECK_FCT( fd_fifo_getstats(fd_g_outgoing, current_count, limit_count, highest_count, total_count, total, blocking, last) );
+		}
+		break;
+
+		case STAT_P_PSM: {
+			CHECK_PARAMS( CHECK_PEER( peer ) );
+			CHECK_FCT( fd_fifo_getstats(p->p_events, current_count, limit_count, highest_count, total_count, total, blocking, last) );
+		}
+		break;
+
+		case STAT_P_TOSEND: {
+			CHECK_PARAMS( CHECK_PEER( peer ) );
+			CHECK_FCT( fd_fifo_getstats(p->p_tosend, current_count, limit_count, highest_count, total_count, total, blocking, last) );
+		}
+		break;
+
+		default:
+			return EINVAL;
+	}
+	
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfdcore/hooks.c	Fri May 10 18:49:19 2013 +0800
@@ -0,0 +1,408 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, 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.								 *
+*********************************************************************************************************/
+
+#include "fdcore-internal.h"
+
+/* Structures for the fd_hook_data_hdl management */
+static struct fd_hook_data_hdl {
+	size_t	pmd_size;
+	void  (*pmd_init_cb)(struct fd_hook_permsgdata *);
+	void  (*pmd_fini_cb)(struct fd_hook_permsgdata *);
+} HDH_array[FD_HOOK_HANDLE_LIMIT];
+static int max_index = 0;
+static pthread_mutex_t HDH_lock = PTHREAD_MUTEX_INITIALIZER;
+
+/* The structure linked from the msg structure list */
+struct pmd_list_item {
+	struct fd_list	chain;		/* this list is ordered by hdl */
+	struct fd_hook_data_hdl * hdl; 
+	struct fd_hook_permsgdata { } pmd; /* this data belongs to the extension; we only know the size of it */
+};
+
+#define sizeof_pmd(hdl)	(((size_t)&((struct pmd_list_item *)0)->pmd) + hdl->pmd_size)
+
+/* Now a hook registered by an extension */
+struct fd_hook_hdl {
+	struct fd_list chain[HOOK_PEER_LAST+1];
+	void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata);
+	void  *regdata;
+	struct fd_hook_data_hdl *data_hdl;
+};
+
+/* Array of those hooks */
+struct {
+	struct fd_list sentinel;
+	pthread_rwlock_t rwlock;
+} HS_array[HOOK_PEER_LAST+1];
+
+/* Initialize the array of sentinels for the hooks */
+int fd_hooks_init(void)
+{
+	int i;
+	for (i=0; i <= HOOK_PEER_LAST; i++) {
+		fd_list_init(&HS_array[i].sentinel, NULL);
+		CHECK_POSIX( pthread_rwlock_init(&HS_array[i].rwlock, NULL) );
+	}
+	return 0;
+}
+
+/* Get a slot in the array */
+int fd_hook_data_register(
+	size_t permsgdata_size,
+	void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
+        void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
+        struct fd_hook_data_hdl **new_handle)
+{
+	int ret = ENOSPC, idx;
+	TRACE_ENTRY("%zd %p %p %p", permsgdata_size, permsgdata_init_cb, permsgdata_fini_cb, new_handle);
+	
+	CHECK_PARAMS( permsgdata_size && new_handle );
+	
+	CHECK_POSIX( pthread_mutex_lock(&HDH_lock) );
+	if (max_index < FD_HOOK_HANDLE_LIMIT) {
+		idx = max_index++;
+		ret = 0;
+	}
+	CHECK_POSIX( pthread_mutex_unlock(&HDH_lock) );
+	
+	if (ret == 0) {
+		HDH_array[idx].pmd_size = permsgdata_size;
+		HDH_array[idx].pmd_init_cb = permsgdata_init_cb;
+		HDH_array[idx].pmd_fini_cb = permsgdata_fini_cb;
+		*new_handle = &HDH_array[idx];
+	}
+	
+	return ret;
+}
+
+/* Register a new hook callback */
+int fd_hook_register (  uint32_t type_mask, 
+			void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata), 
+			void  *regdata, 
+			struct fd_hook_data_hdl *data_hdl,
+			struct fd_hook_hdl ** handler )
+{
+	struct fd_hook_hdl * newhdl = NULL;
+	int i;
+	
+	TRACE_ENTRY("%x %p %p %p %p", type_mask, fd_hook_cb, regdata, data_hdl, handler);
+	
+	CHECK_PARAMS( fd_hook_cb && handler );
+	
+	CHECK_MALLOC( newhdl = malloc(sizeof(struct fd_hook_hdl)) );
+	memset(newhdl, 0, sizeof(struct fd_hook_hdl));
+	
+	newhdl->fd_hook_cb = fd_hook_cb;
+	newhdl->regdata = regdata;
+	newhdl->data_hdl = data_hdl;
+	
+	for (i=0; i <= HOOK_PEER_LAST; i++) {
+		fd_list_init(&newhdl->chain[i], newhdl);
+		if (type_mask & (1<<i)) {
+			CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
+			fd_list_insert_before( &HS_array[i].sentinel, &newhdl->chain[i]);
+			CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
+		}
+	}
+	
+	*handler = newhdl;
+	return 0;
+}
+
+/* free this hook callback */
+int fd_hook_unregister( struct fd_hook_hdl * handler )
+{
+	int i;
+	TRACE_ENTRY("%p", handler);
+	CHECK_PARAMS( handler );
+	
+	for (i=0; i <= HOOK_PEER_LAST; i++) {
+		if ( ! FD_IS_LIST_EMPTY(&handler->chain[i])) {
+			CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
+			fd_list_unlink(&handler->chain[i]);
+			CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
+		}
+	}
+	
+	free(handler);
+	
+	return 0;
+}
+
+/* callback for the libfdproto to free the data associated with a message */
+static void pmdl_free(struct fd_msg_pmdl *pmdl)
+{
+	/* destroy all the items in the list */
+	while (!FD_IS_LIST_EMPTY(&pmdl->sentinel)) {
+		struct pmd_list_item * li = (struct pmd_list_item *)(pmdl->sentinel.next);
+		if (li->hdl->pmd_fini_cb) {
+			(*li->hdl->pmd_fini_cb)(&li->pmd);
+		}
+		fd_list_unlink(&li->chain);
+		free(li);
+	}
+	CHECK_POSIX_DO( pthread_mutex_destroy(&pmdl->lock), );
+	pmdl->sentinel.o = NULL;
+}
+
+/* Save the list of pmd into the message structure, as well as the callback to free this list */
+void   fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl)
+{
+	struct fd_msg_pmdl * in_msg;
+	
+	CHECK_PARAMS_DO( msg && pmdl, return );
+	in_msg = fd_msg_pmdl_get(msg);
+	ASSERT(in_msg && (in_msg->sentinel.o == NULL)); /* error / already initialized ??? */
+	in_msg->sentinel.o = pmdl_free;
+	/* Now move all items from the pmdl pointer into the initialized list */
+	CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
+	fd_list_move_end(&in_msg->sentinel, &pmdl->sentinel);
+	CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
+	pmdl_free(pmdl);
+	/* We're done */
+}
+
+/* Return the location of the permsgdata area corresponding to this handle, after eventually having created it. Return NULL in case of failure */
+static struct fd_hook_permsgdata * get_or_create_pmd(struct fd_msg_pmdl *pmdl, struct fd_hook_hdl * h) 
+{
+	struct fd_hook_permsgdata * ret = NULL;
+	struct fd_list * li;
+	
+	CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
+	
+	if (pmdl->sentinel.o == NULL) {
+		pmdl->sentinel.o = pmdl_free;
+	}
+	
+	/* Search in the list for an item with the same handle. The list is ordered by this handle */
+	for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) {
+		struct pmd_list_item * pli = (struct pmd_list_item *) li;
+		if (pli->hdl == h->data_hdl)
+			ret = &pli->pmd;
+		if (pli->hdl >= h->data_hdl)
+			break;
+	}
+	if (!ret) {
+		/* we need to create a new one and insert before li */
+		struct pmd_list_item * pli;
+		CHECK_MALLOC_DO( pli = malloc(sizeof_pmd(h->data_hdl)), );
+		if (pli) {
+			memset(pli, 0, sizeof_pmd(h->data_hdl));
+			fd_list_init(&pli->chain, pli);
+			pli->hdl = h->data_hdl;
+			ret = &pli->pmd;
+			if (h->data_hdl->pmd_init_cb) {
+				(*h->data_hdl->pmd_init_cb)(ret);
+			}
+			fd_list_insert_before(li, &pli->chain);
+		}
+	}
+	
+	CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
+	return ret;
+}
+
+struct fd_hook_permsgdata * fd_hook_get_request_pmd(struct fd_hook_data_hdl *data_hdl, struct msg * answer)
+{
+	struct msg * qry;
+	struct fd_msg_pmdl *pmdl;
+	struct fd_hook_permsgdata * ret = NULL;
+	struct fd_list * li;
+	
+	CHECK_FCT_DO( fd_msg_answ_getq(answer, &qry), return NULL );
+	if (!qry)
+		return NULL;
+	
+	pmdl = fd_msg_pmdl_get(qry);
+	if (!pmdl)
+		return NULL;
+	
+	CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
+	/* Search in the list for an item with the same handle. The list is ordered by this handle */
+	for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) {
+		struct pmd_list_item * pli = (struct pmd_list_item *) li;
+		if (pli->hdl == data_hdl)
+			ret = &pli->pmd;
+		if (pli->hdl >= data_hdl)
+			break;
+	}
+	CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
+	return ret;
+}
+
+/* The function that does the work of calling the extension's callbacks and also managing the permessagedata structures */
+void   fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl)
+{
+	struct fd_list * li;
+	ASSERT(type <= HOOK_PEER_LAST);
+	int call_default = 0;
+	
+	/* lock the list of hooks for this type */
+	CHECK_POSIX_DO( pthread_rwlock_rdlock(&HS_array[type].rwlock), );
+	
+	if (FD_IS_LIST_EMPTY(&HS_array[type].sentinel)) {
+		call_default = 1;
+	} else {
+		/* for each registered hook */
+		for (li = HS_array[type].sentinel.next; li != &HS_array[type].sentinel; li = li->next) {
+			struct fd_hook_hdl * h = (struct fd_hook_hdl *)li->o;
+			struct fd_hook_permsgdata * pmd = NULL;
+
+			/* do we need to handle pmd ? */
+			if (h->data_hdl && pmdl) {
+				pmd = get_or_create_pmd(pmdl, h);
+			}
+
+			/* Now, call this callback */
+			(*h->fd_hook_cb)(type, msg, &peer->p_hdr, other, pmd, h->regdata);
+		}
+	}
+	
+	/* done */
+	CHECK_POSIX_DO( pthread_rwlock_unlock(&HS_array[type].rwlock), );
+	
+	if (call_default) {
+		char * buf = NULL;
+		size_t len = 0;
+	
+		/* There was no registered handler, default behavior for this hook */
+		switch (type) {
+			case HOOK_DATA_RECEIVED: {
+				struct fd_cnx_rcvdata *rcv_data = other;
+				LOG_A("RCV: %zd bytes", rcv_data->length);
+				break;
+			}
+			
+			case HOOK_MESSAGE_RECEIVED: {
+				CHECK_MALLOC_DO(fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 1), break);
+				LOG_D("RCV from '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", buf);
+				break;
+			}
+			
+			case HOOK_MESSAGE_LOCAL: {
+				CHECK_MALLOC_DO(fd_msg_dump_full(&buf, &len, NULL, msg, NULL, 0, 1), break);
+				LOG_A("Handled to framework for sending: %s", buf);
+				break;
+			}
+			
+			case HOOK_MESSAGE_SENT: {
+				CHECK_MALLOC_DO(fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 1), break);
+				LOG_D("SENT to '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", buf);
+				break;
+			}
+			
+			case HOOK_MESSAGE_FAILOVER: {
+				CHECK_MALLOC_DO(fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 1), break);
+				LOG_D("Failing over message sent to '%s': %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", buf);
+				break;
+			}
+			
+			case HOOK_MESSAGE_PARSING_ERROR: {
+				if (msg) {
+					DiamId_t id = NULL;
+					size_t idlen;
+					if (!fd_msg_source_get( msg, &id, &idlen ))
+						id = (DiamId_t)"<error getting source>";
+					
+					if (!id)
+						id = (DiamId_t)"<local>";
+					
+					CHECK_MALLOC_DO(fd_msg_dump_treeview(&buf, &len, NULL, msg, NULL, 0, 1), break);
+					
+					LOG_E("Parsing error: '%s' for the following message received from '%s':\n%s", (char *)other, (char *)id, buf);
+				} else {
+					struct fd_cnx_rcvdata *rcv_data = other;
+					CHECK_MALLOC_DO(fd_dump_extend_hexdump(&buf, &len, NULL, rcv_data->buffer, rcv_data->length, 0, 0), break);
+					LOG_E("Parsing error: cannot parse %zdB buffer from '%s': %s",  rcv_data->length, peer ? peer->p_hdr.info.pi_diamid : "<unknown>", buf);
+				}
+				break;
+			}
+			
+			case HOOK_MESSAGE_ROUTING_ERROR: {
+				DiamId_t id = NULL;
+				size_t idlen;
+				if (!fd_msg_source_get( msg, &id, &idlen ))
+					id = (DiamId_t)"<error getting source>";
+
+				if (!id)
+					id = (DiamId_t)"<local>";
+
+				CHECK_MALLOC_DO(fd_msg_dump_treeview(&buf, &len, NULL, msg, NULL, 0, 1), break);
+
+				LOG_E("Routing error: '%s' for the following message:\n%s", (char *)other, buf);
+				break;
+			}
+			
+			case HOOK_MESSAGE_ROUTING_FORWARD: {
+				CHECK_MALLOC_DO(fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 1), break);
+				LOG_D("FORWARDING: %s", buf);
+				break;
+			}
+			
+			case HOOK_MESSAGE_ROUTING_LOCAL: {
+				CHECK_MALLOC_DO(fd_msg_dump_summary(&buf, &len, NULL, msg, NULL, 0, 1), break);
+				LOG_D("DISPATCHING: %s", buf);
+				break;
+			}
+			
+			case HOOK_MESSAGE_DROPPED: {
+				CHECK_MALLOC_DO(fd_msg_dump_treeview(&buf, &len, NULL, msg, NULL, 0, 1), break);
+				LOG_E("Message discarded ('%s'):\n%s", (char *)other, buf);
+				break;
+			}
+			
+			case HOOK_PEER_CONNECT_FAILED: {
+				if (msg) {
+					size_t offset = 0;
+					CHECK_MALLOC_DO(fd_dump_extend(&buf, &len, &offset, " CER/CEA dump:\n"), break);
+					CHECK_MALLOC_DO(fd_msg_dump_treeview(&buf, &len, &offset, msg, NULL, 0, 1), break);
+					LOG_N("Connection to '%s' failed: %s%s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", (char *)other, buf);
+				} else {
+					LOG_D("Connection to '%s' failed: %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", (char *)other);
+				}
+				break;
+			}
+			
+			case HOOK_PEER_CONNECT_SUCCESS: {
+				CHECK_MALLOC_DO(fd_msg_dump_treeview(&buf, &len, NULL, msg, NULL, 0, 1), break);
+				LOG_N("Connected to '%s', remote capabilities: %s", peer ? peer->p_hdr.info.pi_diamid : "<unknown>", buf);
+				break;
+			}
+			
+		}
+		
+		free(buf);
+	}
+}
--- a/libfdcore/messages.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/messages.c	Fri May 10 18:49:19 2013 +0800
@@ -345,7 +345,7 @@
 
 
 /* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */
-int fd_msg_parse_or_error( struct msg ** msg )
+int fd_msg_parse_or_error( struct msg ** msg, struct msg **error)
 {
 	int ret = 0;
 	struct msg * m;
@@ -354,8 +354,9 @@
 	
 	TRACE_ENTRY("%p", msg);
 	
-	CHECK_PARAMS(msg && *msg);
+	CHECK_PARAMS(msg && *msg && error);
 	m = *msg;
+	*error = NULL;
 	
 	/* Parse the message against our dictionary */
 	ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei);
@@ -363,8 +364,8 @@
 		&& (ret != ENOTSUP))	/* Command is not supported / Mandatory AVP is not supported */
 		return ret; /* 0 or another error */
 	
-	TRACE_DEBUG(INFO, "A message does not comply to the dictionary and/or rules (%s)", pei.pei_errcode);
-	fd_msg_dump_walk(FULL, m);
+	/* Log */
+	fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, m, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(m));
 	
 	CHECK_FCT( fd_msg_hdr(m, &hdr) );
 	
@@ -372,10 +373,13 @@
 	if (hdr->msg_flags & CMD_FLAG_REQUEST) {
 		
 		/* Create the error message */
-		CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) );
+		CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &m, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) );
 		
 		/* Set the error code */
-		CHECK_FCT( fd_msg_rescode_set(*msg, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) );
+		CHECK_FCT( fd_msg_rescode_set(m, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) );
+		
+		*msg = NULL;
+		*error = m;
 		
 	} else {
 		do { /* Rescue error messages */
@@ -408,15 +412,10 @@
 						
 					default: /* Other errors */
 						/* We let the application decide what to do with the message, we rescue it */
-						return 0;
+						*error = m;
 				}
 			}
 		} while (0);
-		
-		/* Just discard */
-		fd_msg_log( FD_MSG_LOG_DROPPED, m, "Answer not compliant to dictionary's ABNF (%s)", pei.pei_errcode  );
-		CHECK_FCT( fd_msg_free( m ) );
-		*msg = NULL;
 	}
 	
 	return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */
--- a/libfdcore/p_ce.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/p_ce.c	Fri May 10 18:49:19 2013 +0800
@@ -649,7 +649,7 @@
 	fd_cnx_destroy(*recv_cnx);
 	*recv_cnx = NULL;
 	if (*cer) {
-		fd_msg_log(FD_MSG_LOG_DROPPED, *cer, "An error occurred while rejecting a CER.");
+		//fd_msg_log(FD_MSG_LOG_DROPPED, *cer, "An error occurred while rejecting a CER.");
 		fd_msg_free(*cer);
 		*cer = NULL;
 	}
@@ -670,6 +670,8 @@
 			/* Close initiator connection */
 			fd_cnx_destroy(initiator);
 
+			LOG_D("%s: Election lost on outgoing connection, closing and answering CEA on incoming connection.", peer->p_hdr.info.pi_diamid);
+			
 			/* Process with the receiver side */
 			CHECK_FCT( fd_p_ce_process_receiver(peer) );
 
@@ -677,6 +679,8 @@
 			struct fd_pei pei;
 			memset(&pei, 0, sizeof(pei));
 			pei.pei_errcode = "ELECTION_LOST";
+			pei.pei_message = "Please answer my CER instead, you won the election.";
+			LOG_D("%s: Election lost on incoming connection, closing and waiting for CEA on outgoing connection.", peer->p_hdr.info.pi_diamid);
 
 			/* Answer an ELECTION LOST to the receiver side */
 			receiver_reject(&peer->p_receiver, &peer->p_cer, &pei);
@@ -719,7 +723,11 @@
 	/* If the state is not WAITCEA, just discard the message */
 	if (req || ((st = fd_peer_getstate(peer)) != STATE_WAITCEA)) {
 		if (*msg) {
-			fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Received CER/CEA while in '%s' state.", STATE_STR(st));
+			/* In such case, just discard the message */
+			char buf[128];
+			snprintf(buf, sizeof(buf), "Received while peer state machine was in state %s.", STATE_STR(st));
+			fd_hook_call(HOOK_MESSAGE_DROPPED, *msg, peer, buf, fd_msg_pmdl_get(*msg));
+
 			CHECK_FCT_DO( fd_msg_free(*msg), /* continue */);
 			*msg = NULL;
 		}
@@ -730,21 +738,28 @@
 	memset(&pei, 0, sizeof(pei));
 	
 	/* Save info from the CEA into the peer */
-	CHECK_FCT_DO( save_remote_CE_info(*msg, peer, &pei, &rc), goto cleanup );
-	
-	/* Dispose of the message, we don't need it anymore */
-	CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ );
-	*msg = NULL;
+	CHECK_FCT_DO( save_remote_CE_info(*msg, peer, &pei, &rc), 
+		{
+			fd_hook_call(HOOK_PEER_CONNECT_FAILED, *msg, peer, "An error occurred while processing incoming CEA.", NULL);
+			goto cleanup;
+		} );
 	
 	/* Check the Result-Code */
 	switch (rc) {
 		case ER_DIAMETER_SUCCESS:
+			/* Log success */
+			fd_hook_call(HOOK_PEER_CONNECT_SUCCESS, *msg, peer, NULL, NULL);
+			
+			/* Dispose of the message, we don't need it anymore */
+			CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ );
+			*msg = NULL;
+			
 			/* No problem, we can continue */
 			break;
 			
 		case ER_DIAMETER_TOO_BUSY:
 			/* Retry later */
-			TRACE_DEBUG(INFO, "Peer %s replied a CEA with Result-Code AVP DIAMETER_TOO_BUSY, will retry later.", peer->p_hdr.info.pi_diamid);
+			fd_hook_call(HOOK_PEER_CONNECT_FAILED, *msg, peer, "Remote peer is too busy", NULL);
 			fd_psm_cleanup(peer, 0);
 			fd_psm_next_timeout(peer, 0, 300);
 			return 0;
@@ -756,10 +771,11 @@
 		
 		default:
 			/* In any other case, we abort all attempts to connect to this peer */
-			TRACE_DEBUG(INFO, "Peer %s replied a CEA with Result-Code %d, aborting connection attempts.", peer->p_hdr.info.pi_diamid, rc);
+			fd_hook_call(HOOK_PEER_CONNECT_FAILED, *msg, peer, "CEA with unexpected error code", NULL);
 			return EINVAL;
 	}
 	
+	
 	/* Handshake if needed, start clear otherwise */
 	if ( ! fd_cnx_getTLS(peer->p_cnxctx) ) {
 		int todo = peer->p_hdr.info.config.pic_flags.sec & peer->p_hdr.info.runtime.pir_isi ;
@@ -777,7 +793,7 @@
 			CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
 				{
 					/* Handshake failed ...  */
-					fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection", peer->p_hdr.info.pi_diamid);
+					fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "TLS handshake failed after CER/CEA exchange", NULL);
 					goto cleanup;
 				} );
 
@@ -817,7 +833,11 @@
 	
 	TRACE_ENTRY("%p", peer);
 	
-	CHECK_FCT( set_peer_cnx(peer, &peer->p_receiver) );
+	CHECK_FCT_DO( set_peer_cnx(peer, &peer->p_receiver),
+		{
+			fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "Error saving the incoming connection in the peer structure", NULL);
+			return __ret__;
+		} );
 	msg = peer->p_cer;
 	peer->p_cer = NULL;
 	
@@ -927,6 +947,10 @@
 	CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, 0 ) );
 	CHECK_FCT( fd_msg_rescode_set(msg, "DIAMETER_SUCCESS", NULL, NULL, 0 ) );
 	CHECK_FCT( add_CE_info(msg, peer->p_cnxctx, isi & PI_SEC_TLS_OLD, isi & PI_SEC_NONE) );
+	
+	/* The connection is complete, but we may still need TLS handshake */
+	fd_hook_call(HOOK_PEER_CONNECT_SUCCESS, msg, peer, NULL, NULL);
+	
 	CHECK_FCT( fd_out_send(&msg, peer->p_cnxctx, peer, FD_CNX_ORDERED ) );
 	
 	/* Handshake if needed */
@@ -935,19 +959,25 @@
 		CHECK_FCT_DO( fd_cnx_handshake(peer->p_cnxctx, GNUTLS_SERVER, peer->p_hdr.info.config.pic_priority, NULL),
 			{
 				/* Handshake failed ...  */
-				fd_log_debug("TLS Handshake failed with peer '%s', resetting the connection", peer->p_hdr.info.pi_diamid);
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "TLS handshake failed after CER/CEA exchange", NULL);
 				goto cleanup;
 			} );
 		
 		/* Retrieve the credentials */
-		CHECK_FCT( fd_cnx_getcred(peer->p_cnxctx, &peer->p_hdr.info.runtime.pir_cert_list, &peer->p_hdr.info.runtime.pir_cert_list_size) );
+		CHECK_FCT_DO( fd_cnx_getcred(peer->p_cnxctx, &peer->p_hdr.info.runtime.pir_cert_list, &peer->p_hdr.info.runtime.pir_cert_list_size),
+			{
+				/* Error ...  */
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "Unable to retrieve remote credentials after TLS handshake", NULL);
+				goto cleanup;
+			} );
+		
 		
 		/* Call second validation callback if needed */
 		if (peer->p_cb2) {
 			TRACE_DEBUG(FULL, "Calling second validation callback for %s", peer->p_hdr.info.pi_diamid);
 			CHECK_FCT_DO( (*peer->p_cb2)( &peer->p_hdr.info ),
 				{
-					TRACE_DEBUG(INFO, "Validation callback rejected the peer %s after handshake", peer->p_hdr.info.pi_diamid);
+					fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "Validation callback rejected the peer after handshake", NULL);
 					CHECK_FCT( fd_psm_terminate( peer, "DO_NOT_WANT_TO_TALK_TO_YOU" ) );
 					return 0;
 				}  );
@@ -981,12 +1011,16 @@
 error_abort:
 	if (pei.pei_errcode) {
 		/* Send the error */
+		fd_hook_call(HOOK_PEER_CONNECT_FAILED, msg, peer, pei.pei_message ?: pei.pei_errcode, NULL);
 		receiver_reject(&peer->p_cnxctx, &msg, &pei);
+	} else {
+		char buf[1024];
+		snprintf(buf, sizeof(buf), "Unexpected error occurred while processing incoming connection from '%s'.", peer->p_hdr.info.pi_diamid);
+		fd_hook_call(HOOK_PEER_CONNECT_FAILED, msg, peer, buf, NULL);
 	}
 	
 cleanup:
 	if (msg) {
-		fd_msg_log(FD_MSG_LOG_DROPPED, msg, "An error occurred while processing a CER.");
 		fd_msg_free(msg);
 	}
 	fd_p_ce_clear_cnx(peer, NULL);
@@ -1026,6 +1060,7 @@
 			if (election_result(peer)) {
 				
 				/* Close initiator connection (was already set as principal) */
+				LOG_D("%s: Election lost on outgoing connection, closing and answering CEA on incoming connection.", peer->p_hdr.info.pi_diamid);
 				fd_p_ce_clear_cnx(peer, NULL);
 				
 				/* and go on with the receiver side */
@@ -1040,6 +1075,7 @@
 				/* Answer an ELECTION LOST to the receiver side and continue */
 				pei.pei_errcode = "ELECTION_LOST";
 				pei.pei_message = "Please answer my CER instead, you won the election.";
+				LOG_D("%s: Election lost on incoming connection, closing and waiting for CEA on outgoing connection.", peer->p_hdr.info.pi_diamid);
 				receiver_reject(cnx, msg, &pei);
 			}
 			break;
@@ -1047,6 +1083,7 @@
 		default:
 			pei.pei_errcode = "DIAMETER_UNABLE_TO_COMPLY"; /* INVALID COMMAND? in case of Capabilities-Updates? */
 			pei.pei_message = "Invalid state to receive a new connection attempt.";
+			LOG_E("%s: Rejecting new connection attempt while our state machine is in state '%s'", peer->p_hdr.info.pi_diamid, STATE_STR(cur_state));
 			receiver_reject(cnx, msg, &pei);
 	}
 				
--- a/libfdcore/p_cnx.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/p_cnx.c	Fri May 10 18:49:19 2013 +0800
@@ -235,7 +235,8 @@
 			}
 			if (FD_IS_LIST_EMPTY(&peer->p_connparams)) {
 				/* We encountered an error or we have looped over all the addresses of the peer. */
-				TRACE_DEBUG(INFO, "Unable to connect to the peer %s, aborting attempts for now.", peer->p_hdr.info.pi_diamid);
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "All connection attempts failed, will retry later", NULL);
+				
 				CHECK_FCT_DO( fatal_error = fd_event_send(peer->p_events, FDEVP_CNX_FAILED, 0, NULL), goto out );
 				return NULL;
 			}
@@ -278,12 +279,13 @@
 		CHECK_FCT_DO( fd_cnx_handshake(cnx, GNUTLS_CLIENT, peer->p_hdr.info.config.pic_priority, NULL),
 			{
 				/* Handshake failed ...  */
-				TRACE_DEBUG(INFO, "TLS Handshake failed with peer '%s', resetting the connection", peer->p_hdr.info.pi_diamid);
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "TLS Handshake failed", NULL);
 				fd_cnx_destroy(cnx);
 				empty_connection_list(peer);
 				fd_ep_filter(&peer->p_hdr.info.pi_endpoints, EP_FL_CONF);
 				goto out_pop;
 			} );
+		LOG_A("%s: TLS handshake successful.", peer->p_hdr.info.pi_diamid);
 	} else {
 		/* Prepare to receive the next message */
 		CHECK_FCT_DO( fatal_error = fd_cnx_start_clear(cnx, 0), goto out_pop );
--- a/libfdcore/p_out.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/p_out.c	Fri May 10 18:49:19 2013 +0800
@@ -36,7 +36,7 @@
 #include "fdcore-internal.h"
 
 /* Alloc a new hbh for requests, bufferize the message and send on the connection, save in sentreq if provided */
-static int do_send(struct msg ** msg, uint32_t flags, struct cnxctx * cnx, uint32_t * hbh, struct sr_list * srl)
+static int do_send(struct msg ** msg, uint32_t flags, struct cnxctx * cnx, uint32_t * hbh, struct fd_peer * peer)
 {
 	struct msg_hdr * hdr;
 	int msg_is_a_req;
@@ -44,17 +44,16 @@
 	size_t sz;
 	int ret;
 	uint32_t bkp_hbh = 0;
-	struct timespec senton;
-	struct msg * cpy_for_logs_only;
+	struct msg *cpy_for_logs_only;
 	
-	TRACE_ENTRY("%p %x %p %p %p", msg, flags, cnx, hbh, srl);
+	TRACE_ENTRY("%p %x %p %p %p", msg, flags, cnx, hbh, peer);
 	
 	/* Retrieve the message header */
 	CHECK_FCT( fd_msg_hdr(*msg, &hdr) );
 	
 	msg_is_a_req = (hdr->msg_flags & CMD_FLAG_REQUEST);
 	if (msg_is_a_req) {
-		CHECK_PARAMS(hbh && srl);
+		CHECK_PARAMS(hbh && peer);
 		/* Alloc the hop-by-hop id and increment the value for next message */
 		bkp_hbh = hdr->msg_hbhid;
 		hdr->msg_hbhid = *hbh;
@@ -69,34 +68,11 @@
 	
 	/* Save a request before sending so that there is no race condition with the answer */
 	if (msg_is_a_req) {
-		CHECK_FCT_DO( ret = fd_p_sr_store(srl, msg, &hdr->msg_hbhid, bkp_hbh), goto out );
+		CHECK_FCT_DO( ret = fd_p_sr_store(&peer->p_sr, msg, &hdr->msg_hbhid, bkp_hbh), goto out );
 	}
 	
-	CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &senton), /* ... */ );
-	CHECK_FCT_DO( fd_msg_ts_set_sent(cpy_for_logs_only, &senton), /* ... */ );
-	
 	/* Log the message */
-	fd_msg_log( FD_MSG_LOG_SENT, cpy_for_logs_only, "Sent to '%s'", fd_cnx_getid(cnx));
-	
-	{
-		struct timespec rcvon, delay;
-		
-		(void) fd_msg_ts_get_recv(cpy_for_logs_only, &rcvon);
-		if (rcvon.tv_sec != 0 || rcvon.tv_nsec != 0) {
-			TS_DIFFERENCE( &delay, &rcvon, &senton);
-			fd_msg_log( FD_MSG_LOG_TIMING, cpy_for_logs_only, "Forwarded in %ld.%6.6ld sec", (long)delay.tv_sec, delay.tv_nsec/1000);
-		} else { /* We log the answer time only for answers generated locally */
-			if (!msg_is_a_req) {
-				/* get the matching request */
-				struct msg * req;
-				struct timespec reqrcvon;
-				(void) fd_msg_answ_getq(cpy_for_logs_only, &req);
-				(void) fd_msg_ts_get_recv(req, &reqrcvon);
-				TS_DIFFERENCE( &delay, &reqrcvon, &senton);
-				fd_msg_log( FD_MSG_LOG_TIMING, cpy_for_logs_only, "Answered in %ld.%6.6ld sec", (long)delay.tv_sec, delay.tv_nsec/1000);
-			}
-		}
-	}
+	fd_hook_call(HOOK_MESSAGE_SENT, cpy_for_logs_only, peer, NULL, fd_msg_pmdl_get(cpy_for_logs_only));
 	
 	/* Send the message */
 	CHECK_FCT_DO( ret = fd_cnx_send(cnx, buf, sz, flags), );
@@ -121,7 +97,7 @@
 	struct msg *msg = arg;
 	CHECK_FCT_DO(fd_fifo_post(fd_g_outgoing, &msg),
 		{
-			fd_msg_log( FD_MSG_LOG_DROPPED, msg, "An error occurred while attempting to requeue this message during cancellation of the sending function");
+			//fd_msg_log( FD_MSG_LOG_DROPPED, msg, "An error occurred while attempting to requeue this message during cancellation of the sending function");
 			CHECK_FCT_DO(fd_msg_free(msg), /* What can we do more? */);
 		} );
 }
@@ -151,10 +127,10 @@
 		pthread_cleanup_push(cleanup_requeue, msg);
 		
 		/* Send the message, log any error */
-		CHECK_FCT_DO( ret = do_send(&msg, 0, peer->p_cnxctx, &peer->p_hbh, &peer->p_sr),
+		CHECK_FCT_DO( ret = do_send(&msg, 0, peer->p_cnxctx, &peer->p_hbh, peer),
 			{
 				if (msg) {
-					fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Internal error: Problem while sending (%s)", strerror(ret) );
+					//fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Internal error: Problem while sending (%s)", strerror(ret) );
 					fd_msg_free(msg);
 				}
 			} );
@@ -203,10 +179,10 @@
 			cnx = peer->p_cnxctx;
 
 		/* Do send the message */
-		CHECK_FCT_DO( ret = do_send(msg, flags, cnx, hbh, peer ? &peer->p_sr : NULL),
+		CHECK_FCT_DO( ret = do_send(msg, flags, cnx, hbh, peer),
 			{
 				if (msg) {
-					fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Internal error: Problem while sending (%s)", strerror(ret) );
+					//fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Internal error: Problem while sending (%s)", strerror(ret) );
 					fd_msg_free(*msg);
 					*msg = NULL;
 				}
--- a/libfdcore/p_psm.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/p_psm.c	Fri May 10 18:49:19 2013 +0800
@@ -240,7 +240,7 @@
 			
 			case FDEVP_CNX_INCOMING: {
 				struct cnx_incoming * evd = ev->data;
-				fd_msg_log( FD_MSG_LOG_DROPPED, evd->cer, "Message discarded while cleaning peer state machine queue." );
+				//fd_msg_log( FD_MSG_LOG_DROPPED, evd->cer, "Message discarded while cleaning peer state machine queue." );
 				CHECK_FCT_DO( fd_msg_free(evd->cer), /* continue */);
 				fd_cnx_destroy(evd->cnx);
 			}
@@ -453,12 +453,6 @@
 		goto psm_loop;
 	}
 
-	/* Handle the (easy) debug event now */
-	if (event == FDEVP_DUMP_ALL) {
-		fd_peer_dump(peer, ANNOYING);
-		goto psm_loop;
-	}
-
 	/* Requests to terminate the peer object */
 	if (event == FDEVP_TERMINATE) {
 		switch (cur_state) {
@@ -488,33 +482,32 @@
 	if (event == FDEVP_CNX_MSG_RECV) {
 		struct msg * msg = NULL;
 		struct msg_hdr * hdr;
-		struct timespec rcvon;
+		struct fd_cnx_rcvdata rcv_data;
+		struct fd_msg_pmdl * pmdl = NULL;
 		
-		/* Retrieve the piggytailed timestamp */
-		memcpy(&rcvon, ev_data+ev_sz, sizeof(struct timespec));
+		rcv_data.buffer = ev_data;
+		rcv_data.length = ev_sz;
+		pmdl = fd_msg_pmdl_get_inbuf(rcv_data.buffer, rcv_data.length);
 		
 		/* Parse the received buffer */
 		CHECK_FCT_DO( fd_msg_parse_buffer( (void *)&ev_data, ev_sz, &msg), 
 			{
-				fd_log_debug("Received invalid data from peer '%s', closing the connection", peer->p_hdr.info.pi_diamid);
+				fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, NULL, peer, &rcv_data, pmdl );
 				free(ev_data);
 				CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_reset );
 				goto psm_loop;
 			} );
 			
-		CHECK_FCT_DO( fd_msg_ts_set_recv(msg, &rcvon), /* ... */ );
-		
+		fd_hook_associate(msg, pmdl);
+	
 		/* If the current state does not allow receiving messages, just drop it */
 		if (cur_state == STATE_CLOSED) {
 			/* In such case, just discard the message */
-			fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Purged from peer '%s''s queue (CLOSED state).", peer->p_hdr.info.pi_diamid );
+			fd_hook_call(HOOK_MESSAGE_DROPPED, msg, peer, "Message purged from queue, peer in CLOSED state", fd_msg_pmdl_get(msg));
 			fd_msg_free(msg);
 			goto psm_loop;
 		}
 		
-		/* Log incoming message */
-		fd_msg_log( FD_MSG_LOG_RECEIVED, msg, "Received %zdb from '%s' (%s)", ev_sz, peer->p_hdr.info.pi_diamid, STATE_STR(cur_state) );
-	
 		/* Extract the header */
 		CHECK_FCT_DO( fd_msg_hdr(msg, &hdr), goto psm_end );
 		
@@ -524,7 +517,7 @@
 			/* Search matching request (same hbhid) */
 			CHECK_FCT_DO( fd_p_sr_fetch(&peer->p_sr, hdr->msg_hbhid, &req), goto psm_end );
 			if (req == NULL) {
-				fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Answer received with no corresponding sent request." );
+				fd_hook_call(HOOK_MESSAGE_DROPPED, msg, peer, "Answer received with no corresponding sent request.", fd_msg_pmdl_get(msg));
 				fd_msg_free(msg);
 				goto psm_loop;
 			}
@@ -532,13 +525,6 @@
 			/* Associate */
 			CHECK_FCT_DO( fd_msg_answ_associate( msg, req ), goto psm_end );
 			
-			/* Display the delay to receive the answer */
-			{
-				struct timespec reqsent, delay;
-				(void) fd_msg_ts_get_sent(req, &reqsent);
-				TS_DIFFERENCE( &delay, &reqsent, &rcvon );
-				fd_msg_log( FD_MSG_LOG_TIMING, msg, "Answer received in %ld.%6.6ld sec.", (long)delay.tv_sec, delay.tv_nsec / 1000 );
-			}
 		} else {
 			/* Mark the incoming request so that we know we have pending answers for this peer */
 			CHECK_POSIX_DO( pthread_mutex_lock(&peer->p_state_mtx), goto psm_end  );
@@ -546,6 +532,9 @@
 			CHECK_POSIX_DO( pthread_mutex_unlock(&peer->p_state_mtx), goto psm_end  );
 		}
 		
+		/* Log incoming message */
+		fd_hook_call(HOOK_MESSAGE_RECEIVED, msg, peer, NULL, fd_msg_pmdl_get(msg));
+		
 		if (cur_state == STATE_OPEN_NEW) {
 			/* OK, we have received something, so the connection is supposedly now in OPEN state at the remote site */
 			fd_psm_change_state(peer, STATE_OPEN );
@@ -583,30 +572,41 @@
 				case STATE_WAITCNXACK_ELEC:
 				case STATE_WAITCEA:
 				case STATE_CLOSED:
-				default:
+				default: {
 					/* In such case, just discard the message */
-					fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received from peer '%s' while connection was not in state %s.", peer->p_hdr.info.pi_diamid, STATE_STR(cur_state) );
+					char buf[128];
+					snprintf(buf, sizeof(buf), "Received while peer state machine was in state %s.", STATE_STR(cur_state));
+					fd_hook_call(HOOK_MESSAGE_DROPPED, msg, peer, buf, fd_msg_pmdl_get(msg));
 					fd_msg_free(msg);
+				}
 			}
 			goto psm_loop;
 		}
 		
 		/* Link-local message: They must be understood by our dictionary, otherwise we return an error */
 		{
-			int ret = fd_msg_parse_or_error( &msg );
+			struct msg * error = NULL;
+			int ret = fd_msg_parse_or_error( &msg, &error );
 			if (ret != EBADMSG) {
-				CHECK_FCT_DO( ret, goto psm_end );
+				CHECK_FCT_DO( ret, 
+					{ 
+						LOG_E("%s: An unexpected error occurred while parsing a link-local message", peer->p_hdr.info.pi_diamid); 
+						fd_msg_free(msg); 
+						goto psm_end; 
+					} );
 			} else {
-				if (msg) {
+				if (msg == NULL) {
 					/* Send the error back to the peer */
-					CHECK_FCT_DO( ret = fd_out_send(&msg, NULL, peer, FD_CNX_ORDERED),  );
-					if (msg) {
+					CHECK_FCT_DO( ret = fd_out_send(&error, NULL, peer, FD_CNX_ORDERED),  );
+					if (error) {
 						/* Only if an error occurred & the message was not saved / dumped */
-						fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Internal error: Problem while sending (%s)", strerror(ret) );
-						CHECK_FCT_DO( fd_msg_free(msg), goto psm_end);
+						LOG_E("%s: error sending a message", peer->p_hdr.info.pi_diamid); 
+						CHECK_FCT_DO( fd_msg_free(error), goto psm_end);
 					}
 				} else {
 					/* We received an invalid answer, let's disconnect */
+					LOG_E("%s: Received invalid answer to Base protocol message, disconnecting...", peer->p_hdr.info.pi_diamid);
+					CHECK_FCT_DO( fd_msg_free(msg), goto psm_end);
 					CHECK_FCT_DO( fd_event_send(peer->p_events, FDEVP_CNX_ERROR, 0, NULL), goto psm_reset );
 				}
 				goto psm_loop;
@@ -616,7 +616,12 @@
 		/* Handle the LL message and update the expiry timer appropriately */
 		switch (hdr->msg_code) {
 			case CC_CAPABILITIES_EXCHANGE:
-				CHECK_FCT_DO( fd_p_ce_msgrcv(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_reset );
+				CHECK_FCT_DO( fd_p_ce_msgrcv(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), 
+					{
+						if (msg)
+							CHECK_FCT_DO( fd_msg_free(msg), );
+						goto psm_reset;
+					} );
 				break;
 			
 			case CC_DISCONNECT_PEER:
@@ -651,7 +656,7 @@
 				
 				/* Cleanup the message if not done */
 				if (msg) {
-					fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received un-handled non-routable command from peer '%s'.", peer->p_hdr.info.pi_diamid );
+					//fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received un-handled non-routable command from peer '%s'.", peer->p_hdr.info.pi_diamid );
 					CHECK_FCT_DO( fd_msg_free(msg), /* continue */);
 					msg = NULL;
 				}
@@ -659,7 +664,7 @@
 		
 		/* At this point the message must have been fully handled already */
 		if (msg) {
-			fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Internal error ('%s'): unhandled message.", peer->p_hdr.info.pi_diamid );
+			//fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Internal error ('%s'): unhandled message.", peer->p_hdr.info.pi_diamid );
 			fd_msg_free(msg);
 		}
 		
@@ -685,6 +690,8 @@
 			default:
 				/* Mark the connection problem */
 				peer->p_flags.pf_cnx_pb = 1;
+			
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "The connection was broken", NULL);
 				
 				/* Destroy the connection, restart the timer to a new connection attempt */
 				fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
@@ -720,11 +727,12 @@
 		/* Get the new ones */
 		CHECK_FCT_DO( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
 		
-		/* We do not support local endpoints change currently, but it could be added here if needed (refresh fd_g_config->cnf_endpoints)*/
-		
-		if (TRACE_BOOL(ANNOYING)) {
-			TRACE_DEBUG(ANNOYING, "New remote endpoint(s):" );
-			fd_ep_dump(6, &peer->p_hdr.info.pi_endpoints);
+		/* We do not support local endpoints change currently, but it could be added here if needed (refresh fd_g_config->cnf_endpoints) */
+		{
+			char * buf = NULL;
+			size_t len = 0;
+			LOG_D("New remote endpoint(s): %s",  fd_ep_dump(&buf, &len, NULL, 6, &peer->p_hdr.info.pi_endpoints) ?: "error");
+			free(buf);
 		}
 		
 		/* Done */
@@ -745,7 +753,6 @@
 			params->cnx = NULL;
 		}
 		if (params->cer) {
-			fd_msg_log( FD_MSG_LOG_DROPPED, params->cer, "Internal error: this CER was not handled as expected." );
 			CHECK_FCT_DO( fd_msg_free(params->cer), );
 			params->cer = NULL;
 		}
@@ -766,6 +773,7 @@
 		switch (cur_state) {
 			case STATE_WAITCNXACK_ELEC:
 			case STATE_WAITCNXACK:
+				LOG_D("%s: Connection established", peer->p_hdr.info.pi_diamid);
 				fd_p_ce_handle_newcnx(peer, cnx);
 				break;
 				
@@ -794,6 +802,7 @@
 				break;
 				
 			case STATE_WAITCNXACK:
+				LOG_D("%s: Connection attempt failed", peer->p_hdr.info.pi_diamid);
 				/* Go back to CLOSE */
 				fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
 				goto psm_reset;
@@ -816,6 +825,7 @@
 				goto psm_loop;
 				
 			case STATE_CLOSED:
+				LOG_D("%s: Connecting...", peer->p_hdr.info.pi_diamid);
 				CHECK_FCT_DO( fd_psm_change_state(peer, STATE_WAITCNXACK), goto psm_end );
 				fd_psm_next_timeout(peer, 0, CNX_TIMEOUT);
 				CHECK_FCT_DO( fd_p_cnx_init(peer), goto psm_end );
@@ -824,9 +834,10 @@
 			case STATE_SUSPECT:
 				/* Mark the connection problem */
 				peer->p_flags.pf_cnx_pb = 1;
-			case STATE_CLOSING:
 			case STATE_WAITCNXACK:
 			case STATE_WAITCEA:
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, peer, "Timeout while waiting for remote peer", NULL);
+			case STATE_CLOSING:
 				/* Destroy the connection, restart the timer to a new connection attempt */
 				fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_tctimer ?: fd_g_config->cnf_timer_tc);
 				goto psm_reset;
@@ -862,6 +873,7 @@
 	goto psm_loop;
 	
 psm_end:
+	LOG_N("%s: Going to ZOMBIE state (no more activity)", peer->p_hdr.info.pi_diamid);
 	fd_psm_cleanup(peer, 1);
 	TRACE_DEBUG(INFO, "'%s'\t-> STATE_ZOMBIE (terminated)\t'%s'",
 			STATE_STR(fd_peer_getstate(peer)),
--- a/libfdcore/p_sr.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/p_sr.c	Fri May 10 18:49:19 2013 +0800
@@ -118,7 +118,7 @@
 	
 	/* If the callback did not dispose of the message, do it now */
 	if (ed->request) {
-		fd_msg_log(FD_MSG_LOG_DROPPED, ed->request, "Expiration period completed without an answer, and the expiry callback did not dispose of the message.");
+		//fd_msg_log(FD_MSG_LOG_DROPPED, ed->request, "Expiration period completed without an answer, and the expiry callback did not dispose of the message.");
 		CHECK_FCT_DO( fd_msg_free(ed->request), /* ignore */ );
 	}
 	
@@ -195,7 +195,7 @@
 		/* loop */
 	} while (1);
 error:	
-	; /* pthread_cleanup_pop sometimes expands as "} ..." and the label beofre this cause some compilers to complain... */
+	; /* pthread_cleanup_pop sometimes expands as "} ..." and the label before this cause some compilers to complain... */
 	pthread_cleanup_pop( 1 );
 	ASSERT(0); /* we have encountered a problem, maybe time to signal the framework to terminate? */
 	return NULL;
@@ -324,12 +324,12 @@
 			/* Requeue for sending to another peer */
 			CHECK_FCT_DO( ret = fd_fifo_post(fd_g_outgoing, &sr->req),
 				{
-					fd_msg_log( FD_MSG_LOG_DROPPED, sr->req, "Internal error: error while requeuing during failover: %s", strerror(ret) );
+					//fd_msg_log( FD_MSG_LOG_DROPPED, sr->req, "Internal error: error while requeuing during failover: %s", strerror(ret) );
 					CHECK_FCT_DO(fd_msg_free(sr->req), /* What can we do more? */)
 				});
 		} else {
 			/* Just free the request. */
-			fd_msg_log( FD_MSG_LOG_DROPPED, sr->req, "Sent & unanswered local message discarded during failover." );
+			//fd_msg_log( FD_MSG_LOG_DROPPED, sr->req, "Sent & unanswered local message discarded during failover." );
 			CHECK_FCT_DO(fd_msg_free(sr->req), /* Ignore */);
 		}
 		free(sr);
--- a/libfdcore/peers.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/peers.c	Fri May 10 18:49:19 2013 +0800
@@ -244,7 +244,7 @@
 		CHECK_FCT_DO(fd_fifo_post(fd_g_outgoing, &m), 
 			{
 				/* fallback: destroy the message */
-				fd_msg_log(FD_MSG_LOG_DROPPED, m, "Internal error: unable to requeue this message during failover process");
+				//fd_msg_log(FD_MSG_LOG_DROPPED, m, "Internal error: unable to requeue this message during failover process");
 				CHECK_FCT_DO(fd_msg_free(m), /* What can we do more? */)
 			} );
 	}
@@ -409,53 +409,61 @@
 }
 
 /* Dump info of one peer */
-void fd_peer_dump(struct fd_peer * peer, int details)
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump, struct peer_hdr * p, int details)
 {
-	char buf[1024];
-	if (peer->p_eyec != EYEC_PEER) {
-		fd_log_debug("  Invalid peer @ %p !", peer);
-		return;
-	}
-
-	snprintf(buf, sizeof(buf), ">  %s\t%s\t[%ldsr,%ldpa]", STATE_STR(fd_peer_getstate(peer)), peer->p_hdr.info.pi_diamid, peer->p_sr.cnt, peer->p_reqin_count);
-	if (details > INFO) {
-		snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>");
-		if (peer->p_hdr.info.runtime.pir_prodname)
-			snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev);
+	FD_DUMP_HANDLE_OFFSET();
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{peer}(@%p): ", p), return NULL);
+	
+	if (!CHECK_PEER(p)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
+	} else {
+		struct fd_peer * peer = (struct fd_peer *)p;
+		
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s [%s, cnt:%ldsr,%ldpa]", peer->p_hdr.info.pi_diamid, STATE_STR(fd_peer_getstate(peer)), peer->p_sr.cnt, peer->p_reqin_count), return NULL);
+		if (details > 0) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " rlm:%s", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>"), return NULL);
+			if (peer->p_hdr.info.runtime.pir_prodname) {
+				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " ['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev), return NULL);
+			}
+		}
+		if (details > 1) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " [from:%s] flags:%s%s%s%s%s%s%s lft:%ds", 
+				peer->p_dbgorig ?: "unset",
+				peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "-" :
+					(peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "4" : "6"),
+				peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "-" :
+					(peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "T" : "S"),
+				peer->p_hdr.info.config.pic_flags.alg ? "P" : "-",
+				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "N" :"-",
+				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "O" :"-",
+				peer->p_hdr.info.config.pic_flags.exp ? "E" : "-",
+				peer->p_hdr.info.config.pic_flags.persist ? "P" : "-",
+				peer->p_hdr.info.config.pic_lft), return NULL);
+		}
+	
 	}
-	fd_log_debug("%s", buf);
-	if (details > FULL) {
-		/* Dump all info */
-		fd_log_debug("\tEntry origin : %s", peer->p_dbgorig?: "not set");
-		fd_log_debug("\tConfig flags : %s%s%s - %s%s - %s%s", 
-				peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "." :
-					(peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "IP" : "IPv6"),
-				peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "." :
-					(peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "TCP" : "SCTP"),
-				peer->p_hdr.info.config.pic_flags.alg ? "PrefTCP" : ".",
-				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "NoTLSok" :".",
-				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "OldTLS" :".",
-				peer->p_hdr.info.config.pic_flags.exp ? "Expire" : ".",
-				peer->p_hdr.info.config.pic_flags.persist ? "Persist" : "."
-				);
-		fd_log_debug("\tLifetime : %d sec", peer->p_hdr.info.config.pic_lft);
-	}
+	
+	return *buf;
 }
 
 /* Dump the list of peers */
-void fd_peer_dump_list(int details)
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump_list, int details)
 {
 	struct fd_list * li;
+	FD_DUMP_HANDLE_OFFSET();
 	
-	fd_log_debug("Dumping list of peers :");
 	CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
 	
 	for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
-		struct fd_peer * np = (struct fd_peer *)li->o;
-		fd_peer_dump(np, details);
+		CHECK_MALLOC_DO( fd_peer_dump(FD_DUMP_STD_PARAMS, (struct peer_hdr *)li->o, details), break);
+		if (li->next != &fd_g_peers) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), break);
+		}
 	}
 	
 	CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
+	return *buf;
 }
 
 static struct dict_object *avp_oh_model = NULL;
@@ -482,9 +490,8 @@
 	CHECK_POSIX( pthread_mutex_lock(&cache_avp_lock) );
 	if (!avp_oh_model) {
 		avp_code_t code = AC_ORIGIN_HOST;
-		int ret;
-		CHECK_FCT_DO( ret = fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT),
-			{ CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) ); return ret; } );
+		CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_CODE, &code, &avp_oh_model, ENOENT),
+			{ LOG_E("Cannot find Origin-Host AVP definition in the dictionary!"); (void) pthread_mutex_unlock(&cache_avp_lock); return __ret__; } );
 	}
 	CHECK_POSIX( pthread_mutex_unlock(&cache_avp_lock) );
 	
@@ -495,10 +502,12 @@
 	
 	/* First, check if the Origin-Host value is valid */
 	if (!fd_os_is_valid_DiameterIdentity(avp_hdr->avp_value->os.data, avp_hdr->avp_value->os.len)) {
-		TRACE_DEBUG(INFO, "Received new CER with invalid Origin-Host");
 		CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, cer, MSGFL_ANSW_ERROR ) );
 		CHECK_FCT( fd_msg_rescode_set(*cer, "DIAMETER_INVALID_AVP_VALUE", 
 							"Your Origin-Host contains invalid characters.", avp_oh, 1 ) );
+		
+		fd_hook_call(HOOK_PEER_CONNECT_FAILED, *cer, NULL, "Received CER with invalid Origin-Host AVP", NULL);
+		
 		CHECK_FCT( fd_out_send(cer, *cnx, NULL, FD_CNX_ORDERED) );
 		return EINVAL;
 	}
@@ -537,6 +546,8 @@
 		peer->p_flags.pf_responder = 1;
 		peer->p_flags.pf_delete = 1;
 		
+		LOG_D("Created new peer object for incoming CER: %s", peer->p_hdr.info.pi_diamid);
+		
 #ifndef DISABLE_PEER_EXPIRY
 		/* Set this peer to expire on inactivity */
 		peer->p_hdr.info.config.pic_flags.exp 	= PI_EXP_INACTIVE;
@@ -582,6 +593,10 @@
 		/* Reset the "out" parameters, so that they are not cleanup on function return. */
 		*cer = NULL;
 		*cnx = NULL;
+	} else {
+		char buf[1024];
+		snprintf(buf, sizeof(buf), "An error occurred while processing new incoming CER: %s", strerror(ret));
+		fd_hook_call(HOOK_PEER_CONNECT_FAILED, *cer, NULL, buf, NULL);
 	}
 	
 	return ret;
--- a/libfdcore/queues.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/queues.c	Fri May 10 18:49:19 2013 +0800
@@ -73,7 +73,7 @@
 		CHECK_FCT(ret);
 		
 		/* We got one! */
-		fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Message lost because framework is terminating." );
+		//fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Message lost because framework is terminating." );
 		fd_msg_free(msg);
 	}
 	
--- a/libfdcore/routing_dispatch.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/routing_dispatch.c	Fri May 10 18:49:19 2013 +0800
@@ -392,7 +392,7 @@
 			CHECK_FCT( fd_peer_getbyid( id, idlen, 0, (void *)&peer ) );
 
 			if (!peer) {
-				fd_msg_log(FD_MSG_LOG_DROPPED, *pmsg, "Unable to send error '%s' to deleted peer '%s' in reply to this message.", error_code, id);
+				//fd_msg_log(FD_MSG_LOG_DROPPED, *pmsg, "Unable to send error '%s' to deleted peer '%s' in reply to this message.", error_code, id);
 				fd_msg_free(*pmsg);
 				*pmsg = NULL;
 				return 0;
@@ -431,7 +431,7 @@
 	enum disp_action action;
 	char * ec = NULL;
 	char * em = NULL;
-	struct msg *msgptr = msg;
+	struct msg *msgptr = msg, *error = NULL;
 
 	/* Read the message header */
 	CHECK_FCT( fd_msg_hdr(msg, &hdr) );
@@ -441,19 +441,27 @@
 	  (draft-asveren-dime-dupcons-00). This may conflict with path validation decisions, no clear answer yet */
 
 	/* At this point, we need to understand the message content, so parse it */
-	CHECK_FCT_DO( ret = fd_msg_parse_or_error( &msgptr ),
+	CHECK_FCT_DO( fd_msg_parse_or_error( &msgptr, &error ),
 		{
-			/* in case of error */
-			if ((ret == EBADMSG) && (msgptr != NULL)) {
-				/* msgptr now contains the answer message to send back */
-				CHECK_FCT( fd_fifo_post(fd_g_outgoing, &msgptr) );
+			int rescue = 0;
+			if (__ret__ != EBADMSG) {
+				fd_hook_call(HOOK_MESSAGE_DROPPED, msgptr, NULL, "Error while parsing received answer", fd_msg_pmdl_get(msgptr));
+				fd_msg_free(msgptr);
+			} else {
+				if (!msgptr) {
+					/* error now contains the answer message to send back */
+					CHECK_FCT( fd_fifo_post(fd_g_outgoing, &error) );
+				} else if (!error) {
+					/* We have received an invalid answer to our query */
+					fd_hook_call(HOOK_MESSAGE_DROPPED, msgptr, NULL, "Received answer failed the dictionary / rules parsing", fd_msg_pmdl_get(msgptr));
+					fd_msg_free(msgptr);
+				} else {
+					/* We will pass the invalid received error to the application */
+					rescue = 1;
+				}
 			}
-			if (msgptr) {	/* another error happen'd */
-				fd_msg_log( FD_MSG_LOG_DROPPED, msgptr,  "An unexpected error occurred while parsing the message (%s)", strerror(ret));
-				CHECK_FCT_DO( fd_msg_free(msgptr), /* continue */);
-			}
-			/* We're done with this one */
-			return 0;
+			if (!rescue)
+				return 0; /* We are done with this message, go to the next */
 		} );
 
 	/* First, if the original request was registered with a callback and we receive the answer, call it. */
@@ -510,7 +518,7 @@
 				}
 				
 				if (!is_req) {
-					fd_msg_log( FD_MSG_LOG_DROPPED, msgptr,  "Internal error: Answer received to locally issued request, but not handled by any handler.");
+					//fd_msg_log( FD_MSG_LOG_DROPPED, msgptr,  "Internal error: Answer received to locally issued request, but not handled by any handler.");
 					fd_msg_free(msgptr);
 					break;
 				}
@@ -755,7 +763,7 @@
 			TRACE_DEBUG(ANNOYING, "Calling next FWD callback on %p : %p", msgptr, rh->rt_fwd_cb);
 			CHECK_FCT_DO( ret = (*rh->rt_fwd_cb)(rh->cbdata, &msgptr),
 				{
-					fd_msg_log( FD_MSG_LOG_DROPPED, msgptr, "Internal error: a FWD routing callback returned an error (%s)", strerror(ret));
+					//fd_msg_log( FD_MSG_LOG_DROPPED, msgptr, "Internal error: a FWD routing callback returned an error (%s)", strerror(ret));
 					fd_msg_free(msgptr);
 					msgptr = NULL;
 				} );
@@ -814,7 +822,7 @@
 		/* Find the peer corresponding to this name */
 		CHECK_FCT( fd_peer_getbyid( qry_src, qry_src_len, 0, (void *) &peer ) );
 		if (fd_peer_getstate(peer) != STATE_OPEN) {
-			fd_msg_log( FD_MSG_LOG_DROPPED, msgptr, "Unable to forward answer to deleted / closed peer '%s'.", qry_src);
+			//fd_msg_log( FD_MSG_LOG_DROPPED, msgptr, "Unable to forward answer to deleted / closed peer '%s'.", qry_src);
 			fd_msg_free(msgptr);
 			return 0;
 		}
@@ -899,7 +907,7 @@
 			TRACE_DEBUG(ANNOYING, "Calling next OUT callback on %p : %p (prio %d)", msgptr, rh->rt_out_cb, rh->prio);
 			CHECK_FCT_DO( ret = (*rh->rt_out_cb)(rh->cbdata, msgptr, candidates),
 				{
-					fd_msg_log( FD_MSG_LOG_DROPPED, msgptr, "Internal error: an OUT routing callback returned an error (%s)", strerror(ret));
+					//fd_msg_log( FD_MSG_LOG_DROPPED, msgptr, "Internal error: an OUT routing callback returned an error (%s)", strerror(ret));
 					fd_msg_free(msgptr);
 					msgptr = NULL;
 					break;
@@ -947,7 +955,7 @@
 
 	/* If the message has not been sent, return an error */
 	if (msgptr) {
-		fd_msg_log( FD_MSG_LOG_NODELIVER, msgptr, "No suitable candidate to route the message to." );
+		//fd_msg_log( FD_MSG_LOG_NODELIVER, msgptr, "No suitable candidate to route the message to." );
 		return_error( &msgptr, "DIAMETER_UNABLE_TO_DELIVER", "No suitable candidate to route the message to", NULL);
 	}
 
--- a/libfdcore/sctp.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/sctp.c	Fri May 10 18:49:19 2013 +0800
@@ -1067,7 +1067,6 @@
 	size_t 			 bufsz = 0, datasize = 0;
 	size_t			 mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */
 	int 			 timedout = 0;
-	struct timespec 	 recv_on;
 	
 	TRACE_ENTRY("%p %p %p %p %p", conn, strid, buf, len, event);
 	CHECK_PARAMS( conn && buf && len && event );
@@ -1086,7 +1085,7 @@
 	
 	/* We will loop while all data is not received. */
 incomplete:
-	while (datasize + sizeof(struct timespec) >= bufsz ) {
+	while (datasize >= bufsz ) {
 		/* The buffer is full, enlarge it */
 		bufsz += mempagesz;
 		CHECK_MALLOC( data = realloc(data, bufsz ) );
@@ -1094,7 +1093,7 @@
 	/* the new data will be received following the preceding */
 	memset(&iov,  0, sizeof(iov));
 	iov.iov_base = data + datasize ;
-	iov.iov_len  = bufsz - sizeof(struct timespec) - datasize;
+	iov.iov_len  = bufsz - datasize;
 
 	/* Receive data from the socket */
 again:
@@ -1188,10 +1187,6 @@
 		return 0;
 	}
 	
-	/* Piggy-tail the timestamp of reception */
-	CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &recv_on), /* continue */ );
-	memcpy(data + datasize, &recv_on, sizeof(struct timespec));
-		
 	/* From this point, we have received a message */
 	*event = FDEVP_CNX_MSG_RECV;
 	*buf = data;
--- a/libfdcore/sctps.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/sctps.c	Fri May 10 18:49:19 2013 +0800
@@ -91,7 +91,6 @@
 			case FDEVP_CNX_MSG_RECV:
 				/* Demux this message to the appropriate fifo, another thread will pull, gnutls process, and send to target queue */
 				if (strid < conn->cc_sctp_para.pairs) {
-					/* Note, here the timespec is piggytailed to buf */
 					CHECK_FCT_DO(fd_event_send(conn->cc_sctps_data.array[strid].raw_recv, event, bufsz, buf), goto fatal );
 				} else {
 					TRACE_DEBUG(INFO, "Received packet (%zd bytes) on out-of-range stream #%d from %s, discarded.", bufsz, strid, conn->cc_remid);
@@ -195,9 +194,6 @@
 			/* Documentations says to return 0 on connection closed, but it does hang within gnutls_handshake */
 			return -1;
 		}
-		if (ev == FDEVP_CNX_MSG_RECV) {
-			memcpy(&ctx->recvon, ctx->partial.buf + ctx->partial.bufsz, sizeof(struct timespec)); /* retrieve piggy-tailed ts */
-		}
 	}
 		
 	pulled = ctx->partial.bufsz - ctx->partial.offset;
--- a/libfdcore/server.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/server.c	Fri May 10 18:49:19 2013 +0800
@@ -93,33 +93,38 @@
 
 
 /* Dump all servers information */
-void fd_servers_dump()
+DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump)
 {
 	struct fd_list * li, *cli;
 	
-	fd_log_debug("Dumping servers list :");
+	FD_DUMP_HANDLE_OFFSET();
+	
 	for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) {
 		struct server * s = (struct server *)li;
 		enum s_state st = get_status(s);
-		fd_log_debug("  Serv %p '%s': %s, %s, %s", 
-				s, fd_cnx_getid(s->conn), 
+		
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{server}(@%p)'%s': %s, %s, %s", s, fd_cnx_getid(s->conn), 
 				IPPROTO_NAME( s->proto ),
 				s->secur ? "Secur" : "NotSecur",
 				(st == NOT_CREATED) ? "Thread not created" :
 				((st == RUNNING) ? "Thread running" :
 				((st == TERMINATED) ? "Thread terminated" :
-							  "Thread status unknown")));
+							  "Thread status unknown"))), return NULL);
 		/* Dump the client list of this server */
 		CHECK_POSIX_DO( pthread_mutex_lock(&s->clients_mtx), );
 		for (cli = s->clients.next; cli != &s->clients; cli = cli->next) {
 			struct client * c = (struct client *)cli;
 			char bufts[128];
-			fd_log_debug("     Connected: '%s' (timeout: %s)",
-					fd_cnx_getid(c->conn),
-					fd_log_time(&c->ts, bufts, sizeof(bufts)));
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n  {client}(@%p)'%s': to:%s", c, fd_cnx_getid(c->conn), fd_log_time(&c->ts, bufts, sizeof(bufts))), break);
 		}
 		CHECK_POSIX_DO( pthread_mutex_unlock(&s->clients_mtx), );
+		
+		if (li->next != &FD_SERVERS) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+		}
 	}
+	
+	return *buf;
 }
 
 
@@ -128,10 +133,11 @@
 {
 	struct client * c = arg;
 	struct server * s = NULL;
-	uint8_t       * buf = NULL;
-	size_t 		bufsz;
+	struct fd_cnx_rcvdata rcv_data;
+	struct fd_msg_pmdl * pmdl = NULL;
 	struct msg    * msg = NULL;
 	struct msg_hdr *hdr = NULL;
+	struct fd_pei pei;
 	
 	TRACE_ENTRY("%p", c);
 	
@@ -146,9 +152,11 @@
 	if (s->secur) {
 		int ret = fd_cnx_handshake(c->conn, GNUTLS_SERVER, NULL, NULL);
 		if (ret != 0) {
-			if (TRACE_BOOL(INFO)) {
-				fd_log_debug("TLS handshake failed for client '%s', connection aborted.", fd_cnx_getid(c->conn));
-			}
+			char buf[1024];
+			snprintf(buf, sizeof(buf), "TLS handshake failed for client '%s', connection aborted.", fd_cnx_getid(c->conn));
+			
+			fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL);
+			
 			goto cleanup;
 		}
 	} else {
@@ -160,23 +168,65 @@
 	c->ts.tv_sec += INCNX_TIMEOUT;
 	
 	/* Receive the first Diameter message on the connection -- cleanup in case of timeout */
-	CHECK_FCT_DO( fd_cnx_receive(c->conn, &c->ts, &buf, &bufsz), goto cleanup );
+	CHECK_FCT_DO( fd_cnx_receive(c->conn, &c->ts, &rcv_data.buffer, &rcv_data.length), 
+		{
+			char buf[1024];
+			
+			switch (__ret__) {
+			case ETIMEDOUT:
+				snprintf(buf, sizeof(buf), "Client '%s' did not send CER within %ds, connection aborted.", fd_cnx_getid(c->conn), INCNX_TIMEOUT);
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL);
+				break;
+			
+			case ENOTCONN:
+				snprintf(buf, sizeof(buf), "Connection from '%s' in error before CER was received.", fd_cnx_getid(c->conn));
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL);
+				break;
+			
+			default:
+				snprintf(buf, sizeof(buf), "Connection from '%s': unspecified error, connection aborted.", fd_cnx_getid(c->conn));
+				fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL);
+			}
+			goto cleanup;
+		} );
 	
-	TRACE_DEBUG(FULL, "Received %zdb from new client '%s'", bufsz, fd_cnx_getid(c->conn));
+	TRACE_DEBUG(FULL, "Received %zdb from new client '%s'", rcv_data.length, fd_cnx_getid(c->conn));
+	
+	pmdl = fd_msg_pmdl_get_inbuf(rcv_data.buffer, rcv_data.length);
 	
 	/* Try parsing this message */
-	CHECK_FCT_DO( fd_msg_parse_buffer( &buf, bufsz, &msg ), /* Parsing failed */ goto cleanup );
+	CHECK_FCT_DO( fd_msg_parse_buffer( &rcv_data.buffer, rcv_data.length, &msg ), 
+		{ 	/* Parsing failed */ 
+			fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, NULL, NULL, &rcv_data, pmdl );
+			goto cleanup;
+		} );
 	
 	/* Log incoming message */
-	fd_msg_log( FD_MSG_LOG_RECEIVED, msg, "Received %zdb from new client '%s'", bufsz, fd_cnx_getid(c->conn) );
+	fd_hook_associate(msg, pmdl);
+	fd_hook_call(HOOK_MESSAGE_RECEIVED, msg, NULL, fd_cnx_getid(c->conn), fd_msg_pmdl_get(msg));
 	
 	/* We expect a CER, it must parse with our dictionary and rules */
-	CHECK_FCT_DO( fd_msg_parse_rules( msg, fd_g_config->cnf_dict, NULL ), /* Parsing failed -- trace details ? */ goto cleanup );
+	CHECK_FCT_DO( fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ), 
+		{ /* Parsing failed -- trace details */ 
+			char buf[1024];
+			
+			fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, msg, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(msg));
+			
+			snprintf(buf, sizeof(buf), "Error parsing CER from '%s', connection aborted.", fd_cnx_getid(c->conn));
+			fd_hook_call(HOOK_PEER_CONNECT_FAILED, NULL, NULL, buf, NULL);
+			
+			goto cleanup;
+		} );
 	
 	/* Now check we received a CER */
 	CHECK_FCT_DO( fd_msg_hdr ( msg, &hdr ), goto fatal_error );
 	CHECK_PARAMS_DO( (hdr->msg_appl == 0) && (hdr->msg_flags & CMD_FLAG_REQUEST) && (hdr->msg_code == CC_CAPABILITIES_EXCHANGE),
-		{ fd_log_debug("Connection '%s', expecting CER, received something else, closing...", fd_cnx_getid(c->conn)); goto cleanup; } );
+		{ /* Parsing failed -- trace details */ 
+			char buf[1024];
+			snprintf(buf, sizeof(buf), "Expected CER from '%s', received a different message, connection aborted.", fd_cnx_getid(c->conn));
+			fd_hook_call(HOOK_PEER_CONNECT_FAILED, msg, NULL, buf, NULL);
+			goto cleanup;
+		} );
 	
 	/* Finally, pass the information to the peers module which will handle it next */
 	pthread_cleanup_push((void *)fd_cnx_destroy, c->conn);
@@ -194,7 +244,6 @@
 	
 	/* Cleanup the parsed message if any */
 	if (msg) {
-		fd_msg_log( FD_MSG_LOG_DROPPED, msg, "Received invalid/unexpected message from connecting client '%s'", fd_cnx_getid(c->conn) );
 		CHECK_FCT_DO( fd_msg_free(msg), /* continue */);
 	}
 	
@@ -203,7 +252,7 @@
 		fd_cnx_destroy(c->conn);
 	
 	/* Cleanup the received buffer if any */
-	free(buf);
+	free(rcv_data.buffer);
 	
 	/* Detach the thread, cleanup the client structure */
 	pthread_detach(pthread_self());
@@ -231,11 +280,9 @@
 		struct client * c = NULL;
 		struct cnxctx * conn = NULL;
 		
-		/* Wait for a new client */
+		/* Wait for a new client or cancel */
 		CHECK_MALLOC_DO( conn = fd_cnx_serv_accept(s->conn), goto error );
 		
-		TRACE_DEBUG(FULL, "New connection accepted");
-		
 		/* Create a client structure */
 		CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto error );
 		memset(c, 0, sizeof(struct client));
@@ -255,8 +302,9 @@
 error:	
 	if (s)
 		set_status(s, TERMINATED);
-	/* Send error signal to the daemon */
-	TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating...");
+
+	/* Send error signal to the core */
+	LOG_F( "An error occurred in server module! Thread is terminating...");
 	CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
 
 	return NULL;
@@ -392,9 +440,14 @@
 			return EINVAL;
 		}
 	}
-	if (TRACE_BOOL(FULL)){
-		fd_log_debug("  Local server address(es) :");
-		fd_ep_dump( 5, &fd_g_config->cnf_endpoints );
+	
+	{
+		char * buf = NULL;
+		size_t len = 0, offset = 0;
+		CHECK_MALLOC_DO( fd_dump_extend( &buf, &len, &offset , "Local server address(es): "), );
+		CHECK_MALLOC_DO( fd_ep_dump(  &buf, &len, &offset, 5, &fd_g_config->cnf_endpoints ), );
+		LOG_N("%s", buf ?: "Error dumping addresses");
+		free(buf);
 	}
 	return 0;
 }
--- a/libfdcore/tcp.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdcore/tcp.c	Fri May 10 18:49:19 2013 +0800
@@ -123,6 +123,7 @@
 {
 	int ret = 0;
 	int s;
+	char * buf = NULL; size_t len = 0;
 	
 	TRACE_ENTRY("%p %p %d", sock, sa, salen);
 	CHECK_PARAMS( sock && (*sock <= 0) && sa && salen );
@@ -136,7 +137,8 @@
 	/* Cleanup if we are cancelled */
 	pthread_cleanup_push(fd_cleanup_socket, &s);
 	
-	TRACE_sSA(FD_LOG_DEBUG, FULL, "Attempting TCP connection with peer: ", sa, NI_NUMERICHOST | NI_NUMERICSERV, "..." );
+	LOG_D( "Attempting TCP connection to %s...", fd_sa_dump_node(&buf, &len, NULL, sa, NI_NUMERICHOST | NI_NUMERICSERV)?:"<error>" );
+	free(buf);
 	
 	/* Try connecting to the remote address */
 	ret = connect(s, sa, salen);
--- a/libfdproto/CMakeLists.txt	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/CMakeLists.txt	Fri May 10 18:49:19 2013 +0800
@@ -12,11 +12,11 @@
 	lists.c
 	log.c
 	messages.c
-	msg_log.c
 	ostr.c
 	portability.c
 	rt_data.c
 	sessions.c
+	utils.c
 	)
 
 # Save the list of files for testcases in the core's directory
--- a/libfdproto/dictionary.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/dictionary.c	Fri May 10 18:49:19 2013 +0800
@@ -147,13 +147,13 @@
 };
 
 /* Forward declarations of dump functions */
-static void dump_vendor_data 	  ( void * data );
-static void dump_application_data ( void * data );
-static void dump_type_data 	  ( void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_vendor_data, void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_application_data, void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_type_data, void * data );
   /* the dump function for enum has a different prototype since it need the datatype */
-static void dump_avp_data 	  ( void * data );
-static void dump_command_data 	  ( void * data );
-static void dump_rule_data 	  ( void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_data, void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_command_data, void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_rule_data, void * data );
 
 /* Forward declarations of search functions */
 static int search_vendor 	( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
@@ -172,7 +172,7 @@
 	int			parent;		/* 0: never; 1: may; 2: must */
 	enum dict_object_type	parenttype;	/* The type of the parent, when relevant */
 	int			eyecatcher;	/* A kind of signature for this object */
-	void 		      (*dump_data)(void * data );	/* The function to dump the data section */
+	DECLARE_FD_DUMP_PROTOTYPE( (*dump_data), void * data );	/* The function to dump the data section */
 	int 		      (*search_fct)(struct dictionary * dict, int criteria, const void * what, struct dict_object **result );;	/* The function to search an object of this type */
 	int			haslist[NB_LISTS_PER_OBJ];	/* Tell if this list is used */
 } dict_obj_info[] = { { 0, "(error)", 0, 0, 0, 0, NULL, NULL, {0, 0, 0} }
@@ -718,6 +718,21 @@
 		ret = ENOENT;							\
 }
 
+/* For searchs of type "xxx_OF_xxx": if the search object is sentinel list for the "what" object */
+#define SEARCH_sentinel( type_of_what, what_list_nr, sentinel_list_nr ) {			\
+	struct dict_object *__what = (struct dict_object *) what;				\
+	CHECK_PARAMS_DO( verify_object(__what) && 						\
+		(__what->type == (type_of_what)), 						\
+		   {  ret = EINVAL; goto end;  }  );						\
+	ret = 0;										\
+	if (result) {										\
+		/* this is similar to the "container_of" */					\
+		*result = (struct dict_object *)((char *)(__what->list[what_list_nr].head) - 	\
+		   		(size_t)&(((struct dict_object *)0)->list[sentinel_list_nr]));	\
+	}											\
+}
+
+
 static int search_vendor ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
 {
 	int ret = 0;
@@ -741,6 +756,11 @@
 			SEARCH_childs_parent( DICT_APPLICATION, &dict->dict_vendors );
 			break;
 		
+		case VENDOR_OF_AVP:
+			/* "what" should be an avp object */
+			SEARCH_sentinel( DICT_AVP, 0, 1 );
+			break;
+		
 		default:
 			/* Invalid criteria */
 			CHECK_PARAMS( criteria = 0 );
@@ -1149,29 +1169,29 @@
 /*******************************************************************************************************/
 /*******************************************************************************************************/
 /* The following functions are used to debug the module, and allow to print out the content of the dictionary */
-static void dump_vendor_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_vendor_data, void * data )
 {
 	struct dict_vendor_data * vendor = (struct dict_vendor_data *)data;
 	
-	fd_log_debug("data: %-6u \"%s\"", vendor->vendor_id, vendor->vendor_name);
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-6u \"%s\"", vendor->vendor_id, vendor->vendor_name);
 }
-static void dump_application_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_application_data, void * data )
 {
 	struct dict_application_data * appli = (struct dict_application_data *) data;
-	fd_log_debug("data: %-6u \"%s\"", appli->application_id, appli->application_name);
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-6u \"%s\"", appli->application_id, appli->application_name);
 }
-static void dump_type_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_type_data, void * data )
 {
 	struct dict_type_data * type = ( struct dict_type_data * ) data;
 	
-	fd_log_debug("data: %-12s \"%s\"", 
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-12s \"%s\"", 
 			type_base_name[type->type_base], 
 			type->type_name);
 }
-static void dump_enumval_data ( struct dict_enumval_data * enumval, enum dict_avp_basetype type )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_enumval_data, struct dict_enumval_data * enumval, enum dict_avp_basetype type )
 {
 	const int LEN_MAX = 20;
-	fd_log_debug("data: (%-12s) \"%s\" -> ", type_base_name[type], enumval->enum_name);
+	CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "data: (%-12s) \"%s\" -> ", type_base_name[type], enumval->enum_name), return NULL);
 	switch (type) {
 		case AVP_TYPE_OCTETSTRING:
 			{
@@ -1179,60 +1199,61 @@
 				if (enumval->enum_value.os.len < LEN_MAX)
 					n = enumval->enum_value.os.len;
 				for (i=0; i < n; i++)
-					fd_log_debug("0x%2hhX/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i]));
+					CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "0x%2hhX/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i])), return NULL);
 				if (n == LEN_MAX)
-					fd_log_debug("...");
+					CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "..."), return NULL);
 			}
 			break;
 		
 		case AVP_TYPE_INTEGER32:
-			fd_log_debug("%i", enumval->enum_value.i32);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%i", enumval->enum_value.i32), return NULL);
 			break;
 
 		case AVP_TYPE_INTEGER64:
-			fd_log_debug("%"PRId64, enumval->enum_value.i64);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%"PRId64, enumval->enum_value.i64), return NULL);
 			break;
 
 		case AVP_TYPE_UNSIGNED32:
-			fd_log_debug("%u", enumval->enum_value.u32);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%u", enumval->enum_value.u32), return NULL);
 			break;
 
 		case AVP_TYPE_UNSIGNED64:
-			fd_log_debug("%"PRIu64, enumval->enum_value.u64);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%"PRIu64, enumval->enum_value.u64), return NULL);
 			break;
 
 		case AVP_TYPE_FLOAT32:
-			fd_log_debug("%f", enumval->enum_value.f32);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%f", enumval->enum_value.f32), return NULL);
 			break;
 
 		case AVP_TYPE_FLOAT64:
-			fd_log_debug("%g", enumval->enum_value.f64);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%g", enumval->enum_value.f64), return NULL);
 			break;
 		
 		default:
-			fd_log_debug("??? (ERROR unknown type %d)", type);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "??? (ERROR unknown type %d)", type), return NULL);
 	}
+	return *buf;
 }
-static void dump_avp_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_data, void * data )
 {
 	struct dict_avp_data * avp = (struct dict_avp_data * ) data;
-	fd_log_debug("data: v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %-6u \"%s\"", 
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %-6u \"%s\"", 
 			DUMP_AVPFL_val(avp->avp_flag_val), 
 			DUMP_AVPFL_val(avp->avp_flag_mask), 
 			type_base_name[avp->avp_basetype], 
 			avp->avp_code, 
 			avp->avp_name );
 }
-static void dump_command_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_command_data, void * data )
 {
 	struct dict_cmd_data * cmd = (struct dict_cmd_data *) data;
-	fd_log_debug("data: v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %-6u \"%s\"", 
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %-6u \"%s\"", 
 			DUMP_CMDFL_val(cmd->cmd_flag_val), DUMP_CMDFL_val(cmd->cmd_flag_mask), cmd->cmd_code, cmd->cmd_name);
 }
-static void dump_rule_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_rule_data, void * data )
 {
 	struct dict_rule_data * rule = (struct dict_rule_data * )data;
-	fd_log_debug("data: pos:%d ord:%d m/M:%2d/%2d avp:\"%s\"", 
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: pos:%d ord:%d m/M:%2d/%2d avp:\"%s\"",
 			rule->rule_position, 
 			rule->rule_order, 
 			rule->rule_min, 
@@ -1240,158 +1261,168 @@
 			rule->rule_avp->data.avp.avp_name);
 }
 
-static void dump_object ( struct dict_object * obj, int parents, int depth, int indent );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_object, struct dict_object * obj, int parents, int depth, int indent );
 
-static void dump_list ( struct fd_list * sentinel, int parents, int depth, int indent )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_list, struct fd_list * sentinel, int parents, int depth, int indent )
 {
 	struct fd_list * li = sentinel;
 	/* We don't lock here, the caller must have taken the dictionary lock for reading already */
-	while (li->next != sentinel)
-	{
-		li = li->next;
-		dump_object( _O(li->o), parents, depth, indent );
+	if (FD_IS_LIST_EMPTY(sentinel)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*s{empty list}", indent, ""), return NULL);
+	} else {
+		while (li->next != sentinel)
+		{
+			li = li->next;
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+			CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, _O(li->o), parents, depth, indent ), return NULL);
+		}
 	}
 }
 
-static void dump_object ( struct dict_object * obj, int parents, int depth, int indent )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_object, struct dict_object * obj, int parents, int depth, int indent )
 {
-	if (obj == NULL)
-		return;
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{dictobj}(@%p): ", indent, "", obj), return NULL);
 	
-	if (parents)
-		dump_object (obj->parent, parents-1, 0, indent + 1 );
+	if (!verify_object(obj)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
+		return *buf;
+	}
 	
-	fd_log_debug("%*s@%p: %s%s (p:%-9p) ", 
-			indent,
-			"",
-			obj, 
-			verify_object(obj) ? "" : "INVALID ", 
-			_OBINFO(obj).name, 
-			obj->parent);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s p:%p ", 
+								_OBINFO(obj).name, 
+								obj->parent), return NULL);
 	
-	if (obj->type == DICT_ENUMVAL)
-		dump_enumval_data ( &obj->data.enumval, obj->parent->data.type.type_base );
-	else
-		_OBINFO(obj).dump_data(&obj->data);
+	if (obj->type == DICT_ENUMVAL) {
+		CHECK_MALLOC_DO( dump_enumval_data ( FD_DUMP_STD_PARAMS, &obj->data.enumval, obj->parent->data.type.type_base ), return NULL);
+	} else {
+		CHECK_MALLOC_DO( _OBINFO(obj).dump_data(FD_DUMP_STD_PARAMS, &obj->data), return NULL);
+	}
+	
+	if (parents) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*sparent:", indent + 1, ""), return NULL);
+		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, obj->parent, parents-1, 0, 0 ), return NULL);
+	}
 	
 	if (depth) {
 		int i;
 		for (i=0; i<NB_LISTS_PER_OBJ; i++) {
 			if ((obj->list[i].o == NULL) && (obj->list[i].next != &obj->list[i])) {
-				fd_log_debug("%*s>%p: list[%d]:", indent, "", obj, i);
-				dump_list(&obj->list[i], parents, depth - 1, indent + 2);
+				CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &obj->list[i], 0, depth - 1, indent + 2), return NULL);
+				break; /* we get duplicate information sorted by another criteria otherwise, which is not very useful */
 			}
 		}
 	}
+	
+	return *buf;
 }
 
-void fd_dict_dump_object(struct dict_object * obj)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_object, struct dict_object * obj)
 {
-	fd_log_debug("Dictionary object %p dump:", obj);
-	dump_object( obj, 1, 2, 2 );
+	FD_DUMP_HANDLE_OFFSET();
+	
+	CHECK_MALLOC_DO( dump_object(FD_DUMP_STD_PARAMS, obj, 1, 2, 0), return NULL);
+	
+	return *buf;
 }
 
-void fd_dict_dump(struct dictionary * dict)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump, struct dictionary * dict)
 {
 	int i;
 	struct fd_list * li;
 	
-	CHECK_PARAMS_DO(dict && (dict->dict_eyec == DICT_EYECATCHER), return);
+	FD_DUMP_HANDLE_OFFSET();
+		
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{dictionary}(@%p): ", dict), return NULL);
+	
+	if ((dict == NULL) || (dict->dict_eyec != DICT_EYECATCHER)) {
+		return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL");
+	}
 	
 	CHECK_POSIX_DO(  pthread_rwlock_rdlock( &dict->dict_lock ), /* ignore */  );
 	
-	fd_log_debug("######################################################");
-	fd_log_debug("###### Dumping vendors, AVPs and related rules #######");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : VENDORS / AVP / RULES}\n", dict), goto error);
+	CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, &dict->dict_vendors, 0, 3, 3 ), goto error);
+	for (li = dict->dict_vendors.list[0].next; li != &dict->dict_vendors.list[0]; li = li->next) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, li->o, 0, 3, 3 ), goto error);
+	}
 	
-	dump_object( &dict->dict_vendors, 0, 3, 0 );
-	for (li = dict->dict_vendors.list[0].next; li != &dict->dict_vendors.list[0]; li = li->next)
-		dump_object( li->o, 0, 3, 0 );
-	
-	fd_log_debug("######          Dumping applications           #######");
-
-	dump_object( &dict->dict_applications, 0, 1, 0 );
-	for (li = dict->dict_applications.list[0].next; li != &dict->dict_applications.list[0]; li = li->next)
-		dump_object( li->o, 0, 1, 0 );
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : APPLICATIONS}\n", dict), goto error);
+	CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, &dict->dict_applications, 0, 1, 3 ), goto error);
+	for (li = dict->dict_applications.list[0].next; li != &dict->dict_applications.list[0]; li = li->next) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, li->o, 0, 1, 3 ), goto error);
+	}
 	
-	fd_log_debug("######             Dumping types               #######");
-
-	dump_list( &dict->dict_types, 0, 2, 0 );
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : TYPES / ENUMVAL}", dict), goto error);
+	CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &dict->dict_types, 0, 2, 3 ), goto error);
 	
-	fd_log_debug("######      Dumping commands per name          #######");
-
-	dump_list( &dict->dict_cmd_name, 0, 2, 0 );
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : COMMANDS / RULES}", dict), goto error);
+	CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &dict->dict_cmd_code, 0, 0, 3 ), goto error);
 	
-	fd_log_debug("######   Dumping commands per code and flags   #######");
-
-	dump_list( &dict->dict_cmd_code, 0, 0, 0 );
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : statistics}", dict), goto error);
+	for (i=1; i<=DICT_TYPE_MAX; i++)
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n   %5d: %s",  dict->dict_count[i], dict_obj_info[i].name), goto error);
 	
-	fd_log_debug("######             Statistics                  #######");
-
-	for (i=1; i<=DICT_TYPE_MAX; i++)
-		fd_log_debug(" %5d objects of type %s", dict->dict_count[i], dict_obj_info[i].name);
-	
-	fd_log_debug("######################################################");
-	
+	CHECK_POSIX_DO(  pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */  );
+	return *buf;
+error:	
 	/* Free the rwlock */
 	CHECK_POSIX_DO(  pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */  );
+	return NULL;
 }
 
 /**************************** Dump AVP values ********************************/
 
 /* Default dump functions */
-static int dump_val_os(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_os, union avp_value * value)
 {
 	int i;
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "<") );
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<"), return NULL);
 	for (i = 0; i < value->os.len; i++) {
 		if (i == 1024) { /* Dump only up to 1024 bytes of the buffer */
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, "[...] (len=%zd)", value->os.len) );
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "[...] (len=%zd)", value->os.len), return NULL);
 			break;
 		}
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "%s%02.2X", (i==0 ? "" : " "), value->os.data[i]) );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s%02hhX", (i==0 ? "" : " "), value->os.data[i]), return NULL);
 	}
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, ">") );
-	return 0;
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ">"), return NULL);
+	return *buf;
 }
 
-static int dump_val_i32(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_i32, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%i (0x%x)", value->i32, value->i32) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%i (0x%x)", value->i32, value->i32);
 }
 
-static int dump_val_i64(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_i64, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%lli (0x%llx)", value->i64, value->i64) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%" PRId64 " (0x%" PRIx64 ")", value->i64, value->i64);
 }
 
-static int dump_val_u32(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_u32, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%u (0x%x)", value->u32, value->u32) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%u (0x%x)", value->u32, value->u32);
 }
 
-static int dump_val_u64(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_u64, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%llu (0x%llx)", value->u64, value->u64) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%" PRIu64 " (0x%" PRIx64 ")", value->u64, value->u64);
 }
 
-static int dump_val_f32(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_f32, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%f", value->f32) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%f", value->f32);
 }
 
-static int dump_val_f64(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_f64, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%g", value->f64) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%g", value->f64);
 }
 
 /* Get the dump function for basic dict_avp_basetype */
-static int (*get_default_dump_val_cb(enum dict_avp_basetype datatype))(union avp_value *, char **, size_t *, size_t *)
+static DECLARE_FD_DUMP_PROTOTYPE((*get_default_dump_val_cb(enum dict_avp_basetype datatype)), union avp_value *)
 {
 	switch (datatype) {
 		case AVP_TYPE_OCTETSTRING:
@@ -1425,63 +1456,61 @@
 #define INOBJHDR 	"%*s   "
 #define INOBJHDRVAL 	indent<0 ? 1 : indent, indent<0 ? "-" : "|"
 
+typedef DECLARE_FD_DUMP_PROTOTYPE((*dump_val_cb_t), union avp_value *);
+
 /* Formatter for the AVP value dump line */
-static int dump_avp_val(union avp_value *avp_value, 
-			int (*def_dump_val_cb)(union avp_value *, char **, size_t *, size_t *), 
-			char * (*dump_val_cb)(union avp_value *), 
+static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_val, union avp_value *avp_value, 
+			dump_val_cb_t def_dump_val_cb, 
+			dump_val_cb_t dump_val_cb, 
 			enum dict_avp_basetype datatype, 
 			char * type_name, 
 			char * const_name, 
 			int indent, 
-			char **outstr, 
-			size_t *offset, 
-			size_t *outlen,
 		        int header)
 {
 	if (header) {
 		/* Header for all AVP values dumps: */
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "value ", INOBJHDRVAL) );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, INOBJHDR "value ", INOBJHDRVAL), return NULL);
 	
 		/* If the type is provided, write it */
 		if (type_name) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, "t: '%s' ", type_name) );
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "t: '%s' ", type_name), return NULL);
 		}
 	
 		/* Always give the base datatype anyway */
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "(%s) ", type_base_name[datatype]) );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(%s) ", type_base_name[datatype]), return NULL);
 
 		/* Now, the value */
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "v: ") );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "v: "), return NULL);
 	}
 	if (const_name) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "'%s' (", const_name) );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s' (", const_name), return NULL);
 	}
 	if (dump_val_cb) {
-		char * str;
-		CHECK_MALLOC_DO( str = (*dump_val_cb)(avp_value), dump_add_str(outstr, offset, outlen, "(dump failed)") );
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "%s", str) );
-		free(str);
+		CHECK_MALLOC_DO( (*dump_val_cb)( FD_DUMP_STD_PARAMS, avp_value), fd_dump_extend( FD_DUMP_STD_PARAMS, "(dump failed)"));
 	} else {
-		CHECK_FCT( (*def_dump_val_cb)(avp_value, outstr, offset, outlen) );
+		CHECK_MALLOC_DO( (*def_dump_val_cb)( FD_DUMP_STD_PARAMS, avp_value), return NULL);
 	}
 	if (const_name) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, ")") );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ")"), return NULL);
 	}
 	
 	/* Done! */
-	return 0;
+	return *buf;
 }
 
 /* Dump the value of an AVP of known type into the returned str */
-int fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, char **outstr, size_t *offset, size_t *outlen, int header)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_avp_value, union avp_value *avp_value, struct dict_object * model, int indent, int header)
 {
-	char * (*dump_val_cb)(union avp_value *avp_value) = NULL;
+	DECLARE_FD_DUMP_PROTOTYPE((*dump_val_cb), union avp_value *avp_value) = NULL;
 	struct dict_object * type = NULL;
 	char * type_name = NULL;
 	char * const_name = NULL;
 	
+	FD_DUMP_HANDLE_OFFSET();
+	
 	/* Check the parameters are correct */
-	CHECK_PARAMS( avp_value && verify_object(model) && (model->type == DICT_AVP) );
+	CHECK_PARAMS_DO( avp_value && verify_object(model) && (model->type == DICT_AVP), return NULL );
 	
 	/* Get the type definition of this AVP */
 	type = model->parent;
@@ -1501,14 +1530,14 @@
 		memcpy(&request.search.enum_value, avp_value, sizeof(union avp_value));
 		/* bypass checks */
 		if ((search_enumval( type->dico, ENUMVAL_BY_STRUCT, &request, &enumval ) == 0) && (enumval)) {
-			/* We found a cosntant, get its name */
+			/* We found a constant, get its name */
 			const_name = enumval->data.enumval.enum_name;
 		}
 	}
 	
 	/* And finally, dump the value */
-	CHECK_FCT( dump_avp_val(avp_value, get_default_dump_val_cb(model->data.avp.avp_basetype), dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent, outstr, offset, outlen, header) );
-	return 0;
+	CHECK_MALLOC_DO( dump_avp_val(FD_DUMP_STD_PARAMS, avp_value, get_default_dump_val_cb(model->data.avp.avp_basetype), dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent, header), return NULL );
+	return *buf;
 }
 
 /*******************************************************************************************************/
@@ -1573,51 +1602,51 @@
 	/* Check the "parent" parameter */
 	switch (dict_obj_info[type].parent) {
 		case 0:	/* parent is forbidden */
-			CHECK_PARAMS( parent == NULL );
+			CHECK_PARAMS_DO( parent == NULL, goto error_param );
 		
 		case 1:	/* parent is optional */
 			if (parent == NULL)
 				break;
 		
 		case 2: /* parent is mandatory */
-			CHECK_PARAMS(  verify_object(parent)  );
+			CHECK_PARAMS_DO(  verify_object(parent), goto error_param  );
 			
 			if (type == DICT_RULE ) { /* Special case : grouped AVP or Command parents are allowed */
-				CHECK_PARAMS( (parent->type == DICT_COMMAND ) 
-						|| ( (parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED ) ) );
+				CHECK_PARAMS_DO( (parent->type == DICT_COMMAND ) 
+						|| ( (parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED ) ), goto error_param );
 			} else {
-				CHECK_PARAMS( parent->type == dict_obj_info[type].parenttype );
+				CHECK_PARAMS_DO( parent->type == dict_obj_info[type].parenttype, goto error_param );
 			}
 	}
 	
 	/* For AVP object, we must also check that the "vendor" referenced exists */
 	if (type == DICT_AVP) {
 		CHECK_FCT_DO(  fd_dict_search( dict, DICT_VENDOR, VENDOR_BY_ID, &(((struct dict_avp_data *)data)->avp_vendor), (void*)&vendor, ENOENT ),
-			{ TRACE_DEBUG(INFO, "Unable to find vendor '%d' referenced in the AVP data", ((struct dict_avp_data *)data)->avp_vendor); return EINVAL; }  );
+			{ TRACE_DEBUG(INFO, "Unable to find vendor '%d' referenced in the AVP data", ((struct dict_avp_data *)data)->avp_vendor); goto error_param; }  );
 		
 		/* Also check if a parent is provided, that the type are the same */
 		if (parent) {
-			CHECK_PARAMS(  parent->data.type.type_base == ((struct dict_avp_data *)data)->avp_basetype  );
+			CHECK_PARAMS_DO(  parent->data.type.type_base == ((struct dict_avp_data *)data)->avp_basetype, goto error_param  );
 		}
 	}
 	
 	/* For RULE object, we must also check that the "avp" referenced exists */
 	if (type == DICT_RULE) {
-		CHECK_PARAMS(  verify_object(((struct dict_rule_data *)data)->rule_avp)  );
-		CHECK_PARAMS(  ((struct dict_rule_data *)data)->rule_avp->type == DICT_AVP  );
+		CHECK_PARAMS_DO(  verify_object(((struct dict_rule_data *)data)->rule_avp), goto error_param  );
+		CHECK_PARAMS_DO(  ((struct dict_rule_data *)data)->rule_avp->type == DICT_AVP, goto error_param  );
 	}
 	
 	/* For COMMAND object, check that the 'R' flag is fixed */
 	if (type == DICT_COMMAND) {
-		CHECK_PARAMS( ((struct dict_cmd_data *)data)->cmd_flag_mask & CMD_FLAG_REQUEST   );
+		CHECK_PARAMS_DO( ((struct dict_cmd_data *)data)->cmd_flag_mask & CMD_FLAG_REQUEST, goto error_param   );
 	}
 	
 	/* We have to check that the new values are not equal to the sentinels */
 	if (type == DICT_VENDOR) {
-		CHECK_PARAMS( ((struct dict_vendor_data *)data)->vendor_id != 0   );
+		CHECK_PARAMS_DO( ((struct dict_vendor_data *)data)->vendor_id != 0, goto error_param   );
 	}
 	if (type == DICT_APPLICATION) {
-		CHECK_PARAMS( ((struct dict_application_data *)data)->application_id != 0   );
+		CHECK_PARAMS_DO( ((struct dict_application_data *)data)->application_id != 0, goto error_param   );
 	}
 	
 	/* Parameters are valid, create the new object */
@@ -1717,6 +1746,10 @@
 	
 	return 0;
 	
+error_param:
+	ret = EINVAL;
+	goto all_errors;
+
 error_unlock:
 	CHECK_POSIX_DO(  pthread_rwlock_unlock(&dict->dict_lock),  /* continue */  );
 	if (ret == EEXIST) {
@@ -1727,7 +1760,7 @@
 				/* if we are here, it means the two vendors id are identical */
 				if (fd_os_cmp(locref->data.vendor.vendor_name, locref->datastr_len, 
 						new->data.vendor.vendor_name, new->datastr_len)) {
-					TRACE_DEBUG(FULL, "Conflicting vendor name");
+					TRACE_DEBUG(INFO, "Conflicting vendor name: %s", new->data.vendor.vendor_name);
 					break;
 				}
 				/* Otherwise (same name), we consider the function succeeded, since the (same) object is in the dictionary */
@@ -1865,23 +1898,26 @@
 				ret = 0;
 				break;
 		}
-		if (ret) {
-			TRACE_DEBUG(INFO, "An existing object with different non-key data was found: EEXIST");
-			if (TRACE_BOOL(INFO)) {
-				fd_log_debug("New object to insert:");
-				dump_object(new, 0, 0, 3);
-				fd_log_debug("Object already in dictionary:");			
-				dump_object(locref, 0, 0 , 3);
-			}
-		} else {
+		if (!ret) {
 			TRACE_DEBUG(FULL, "An existing object with the same data was found, ignoring the error...");
 		}
 		if (ref)
 			*ref = locref;
-	} else {
-		CHECK_FCT_DO( ret, ); /* log the error */ 
 	}
-
+all_errors:
+	if (ret != 0) {
+		char * buf = NULL;
+		size_t len = 0;
+		
+		CHECK_MALLOC( dict_obj_info[CHECK_TYPE(type) ? type : 0].dump_data(&buf, &len, NULL, data) );
+		TRACE_DEBUG(INFO, "An error occurred while adding the following data in the dictionary: %s", buf);
+		
+		if (ret == EEXIST) {
+			CHECK_MALLOC( dump_object(&buf, &len, NULL, locref, 0, 0, 0) );
+			TRACE_DEBUG(INFO, "Conflicting entry in the dictionary: %s", buf);
+		}
+		free(buf);
+	}
 error_free:
 	free(new);
 	return ret;
--- a/libfdproto/dictionary_functions.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/dictionary_functions.c	Fri May 10 18:49:19 2013 +0800
@@ -152,10 +152,8 @@
 }
 
 /* Dump the content of an Address AVP */
-char * fd_dictfct_Address_dump(union avp_value * avp_value)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Address_dump, union avp_value * avp_value)
 {
-	char * ret;
-	#define STR_LEN	1024
 	union {
 		sSA	sa;
 		sSS	ss;
@@ -164,14 +162,14 @@
 	} s;
 	uint16_t fam;
 	
-	memset(&s, 0, sizeof(s));
+	FD_DUMP_HANDLE_OFFSET();
 	
-	CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
+	memset(&s, 0, sizeof(s));
 	
 	/* The first two octets represent the address family, http://www.iana.org/assignments/address-family-numbers/ */
 	if (avp_value->os.len < 2) {
-		snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
-		return ret;
+		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid length: %zd]", avp_value->os.len), return NULL);
+		return *buf;
 	}
 	
 	/* Following octets are the address in network byte order already */
@@ -181,8 +179,8 @@
 			/* IP */
 			s.sa.sa_family = AF_INET;
 			if (avp_value->os.len != 6) {
-				snprintf(ret, STR_LEN, "[invalid IP length: %zd]", avp_value->os.len);
-				return ret;
+				CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid IP length: %zd]", avp_value->os.len), return NULL);
+				return *buf;
 			}
 			memcpy(&s.sin.sin_addr.s_addr, avp_value->os.data + 2, 4);
 			break;
@@ -190,23 +188,17 @@
 			/* IP6 */
 			s.sa.sa_family = AF_INET6;
 			if (avp_value->os.len != 18) {
-				snprintf(ret, STR_LEN, "[invalid IP6 length: %zd]", avp_value->os.len);
-				return ret;
+				CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid IP6 length: %zd]", avp_value->os.len), return NULL);
+				return *buf;
 			}
 			memcpy(&s.sin6.sin6_addr.s6_addr, avp_value->os.data + 2, 16);
 			break;
 		default:
-			snprintf(ret, STR_LEN, "[unsupported family: 0x%hx]", fam);
-			return ret;
+			CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[unsupported family: 0x%hx]", fam), return NULL);
+			return *buf;
 	}
 	
-	{
-		int rc = getnameinfo(&s.sa, sSAlen(&s.sa), ret, STR_LEN, NULL, 0, NI_NUMERICHOST);
-		if (rc)
-			snprintf(ret, STR_LEN, "%s", (char *)gai_strerror(rc));
-	}
-	
-	return ret;
+	return fd_sa_dump_node(FD_DUMP_STD_PARAMS, &s.sa, NI_NUMERICHOST);
 }
 
 
@@ -215,42 +207,24 @@
 /*    UTF8String  AVP  type    */
 /*******************************/
 
-/* Dump the AVP in a natural human-readable format */
-char * fd_dictfct_UTF8String_dump(union avp_value * avp_value)
+/* Dump the AVP in a natural human-readable format. This dumps the complete length of the AVP, it is up to the caller to truncate if needed */
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_UTF8String_dump, union avp_value * avp_value)
 {
-#define TRUNC_LEN	1024 /* avoid very long strings */
-	char * ret;
-	CHECK_MALLOC_DO( ret = malloc(TRUNC_LEN+2+3+1), return NULL );
-	*ret = '"';
-	strncpy(ret+1, (char *)avp_value->os.data, TRUNC_LEN);
-	/* be sure to have a nul-terminated string */
-	ret[TRUNC_LEN+1] = '\0';
-	if (ret[1] != '\0') {
-		/* We sanitize the returned string to avoid UTF8 boundary problem.
-		We do this whether the string is trucated at TRUNC_LEN or not, to avoid potential problem
-		with malformed AVP */
-
-		char * end = strchr(ret, '\0');
-		while (end > ret) {
-			end--;
-			char b = *end;
-			/* after the position pointed by end, we have only \0s */
-			if ((b & 0x80) == 0) {
-				break; /* this is a single byte char, no problem */
-			} else {
-				/* this byte is start or cont. of multibyte sequence, as we do not know the next byte we need to delete it. */
-				*end = '\0';
-				if (b & 0x40)
-					break; /* This was a start byte, we can stop the loop */
-			}
-		}
-		if (strlen((char *)avp_value->os.data) > strlen(ret+1))
-			strcat(end, "...");
-		strcat(end, "\"");
-	} else {
-		*ret = '\0';
+	size_t l;
+	FD_DUMP_HANDLE_OFFSET();
+	
+	l = avp_value->os.len;
+	/* Just in case the string ends in invalid UTF-8 chars, we shorten it */
+	while ((l > 0) && (avp_value->os.data[l - 1] & 0x80)) {
+		/* this byte is start or cont. of multibyte sequence, as we do not know the next byte we need to delete it. */
+		l--;
+		if (avp_value->os.data[l] & 0x40)
+			break; /* This was a start byte, we can stop the loop */
 	}
-	return ret;
+	
+	CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "\"%.*s\"", (int)l, (char *)avp_value->os.data), return NULL);
+	
+	return *buf;
 }
 
 
@@ -325,22 +299,24 @@
 	return diameter_string_to_time_t((const char *)avp_value->os.data, avp_value->os.len, interpreted);
 }
 
-char * fd_dictfct_Time_dump(union avp_value * avp_value)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump, union avp_value * avp_value)
 {
-	char * ret;
 	time_t val;
 	struct tm conv;
-	CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
+		
+	FD_DUMP_HANDLE_OFFSET();
+	
 	if (avp_value->os.len != 4) {
-		snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
-		return ret;
+		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid length: %zd]", avp_value->os.len), return NULL);
+		return *buf;
 	}
+
 	if (diameter_string_to_time_t((char *)avp_value->os.data, avp_value->os.len, &val) != 0) {
-		snprintf(ret, STR_LEN, "[time conversion error]");
-		return ret;
+		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[time conversion error]"), return NULL);
+		return *buf;
 	}
-	gmtime_r(&val, &conv);
-	snprintf(ret, STR_LEN, "%d%02d%02dT%02d%02d%02d+00", conv.tm_year+1900, conv.tm_mon+1, conv.tm_mday, conv.tm_hour, conv.tm_min, conv.tm_sec);
-	return ret;
+	
+	CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "%d%02d%02dT%02d%02d%02d+00", conv.tm_year+1900, conv.tm_mon+1, conv.tm_mday, conv.tm_hour, conv.tm_min, conv.tm_sec), return NULL);
+	return *buf;
 }
 
--- a/libfdproto/dispatch.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/dispatch.c	Fri May 10 18:49:19 2013 +0800
@@ -96,7 +96,7 @@
 		/* We have a match, the cb must be called. */
 		CHECK_FCT_DO( (r = (*hdl->cb)(msg, avp, sess, hdl->opaque, action)),
 			{
-				fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Internal error: a DISPATCH callback returned an error (%s)", strerror(r));
+				//fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Internal error: a DISPATCH callback returned an error (%s)", strerror(r));
 				fd_msg_free(*msg);
 				*msg = NULL;
 			}
--- a/libfdproto/fdproto-internal.h	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/fdproto-internal.h	Fri May 10 18:49:19 2013 +0800
@@ -47,19 +47,12 @@
 int fd_sess_init(void);
 void fd_sess_fini(void);
 
-/* Where debug messages are sent */
-extern FILE * fd_g_debug_fstr;
-
-/* Special message dump function */
-void fd_msg_dump_fstr_one ( struct msg * msg, FILE * fstr );
-void fd_msg_dump_fstr ( struct msg * msg, FILE * fstr );
-
 /* Iterator on the rules of a parent object */
 int fd_dict_iterate_rules ( struct dict_object *parent, void * data, int (*cb)(void *, struct dict_rule_data *) );
 
 /* Dispatch / messages / dictionary API */
 int fd_dict_disp_cb(enum dict_object_type type, struct dict_object *obj, struct fd_list ** cb_list);
-int fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, char **outstr, size_t *offset, size_t *outlen, int header);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_avp_value, union avp_value *avp_value, struct dict_object * model, int indent, int header);
 int fd_disp_call_cb_int( struct fd_list * cb_list, struct msg ** msg, struct avp *avp, struct session *sess, enum disp_action *action, 
 			struct dict_object * obj_app, struct dict_object * obj_cmd, struct dict_object * obj_avp, struct dict_object * obj_enu);
 extern pthread_rwlock_t fd_disp_lock;
@@ -68,40 +61,4 @@
 int fd_sess_reclaim_msg ( struct session ** session );
 
 
-/* For dump routines into string buffers */
-#include <stdarg.h>
-static __inline__ int dump_init_str(char **outstr, size_t *offset, size_t *outlen) 
-{
-	*outlen = 1<<12;
-	CHECK_MALLOC( *outstr = malloc(*outlen) );
-	*offset = 0;
-	(*outstr)[0] = 0;
-	return 0;
-}
-static __inline__ int dump_add_str(char **outstr, size_t *offset, size_t *outlen, char * fmt, ...) 
-{
-	va_list argp;
-	int len;
-	va_start(argp, fmt);
-	len = vsnprintf(*outstr + *offset, *outlen - *offset, fmt, argp);
-	va_end(argp);
-	if ((len + *offset) >= *outlen) {
-		char * newstr;
-		/* buffer was too short, extend */
-		size_t newsize = ((len + *offset) + (1<<12)) & ~((1<<12) - 1); /* next multiple of 4k */
-		CHECK_MALLOC( newstr = realloc(*outstr, newsize) );
-		
-		/* redo */
-		*outstr = newstr;
-		*outlen = newsize;
-		va_start(argp, fmt);
-		len = vsnprintf(*outstr + *offset, *outlen - *offset, fmt, argp);
-		va_end(argp);
-	}
-	*offset += len;
-	return 0;
-}
-
-
-
 #endif /* _LIBFDPROTO_INTERNAL_H */
--- a/libfdproto/fifo.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/fifo.c	Fri May 10 18:49:19 2013 +0800
@@ -69,6 +69,17 @@
 	void		(*l_cb)(struct fifo *, void **);
 	int 		highest;/* The highest count value for which h_cb has been called */
 	int		highest_ever; /* The max count value this queue has reached (for tweaking) */
+	
+	long long	total_items;   /* Cumulated number of items that went through this fifo (excluding current count), always increasing. */
+	struct timespec total_time;    /* Cumulated time all items spent in this queue, including blocking time (always growing, use deltas for monitoring) */
+	struct timespec blocking_time; /* Cumulated time threads trying to post new items were blocked (queue full). */
+	struct timespec last_time;     /* For the last element retrieved from the queue, how long it take between posting (including blocking) and poping */
+	
+};
+
+struct fifo_item {
+	struct fd_list   item;
+	struct timespec  posted_on;
 };
 
 /* The eye catcher value */
@@ -107,39 +118,45 @@
 }
 
 /* Dump the content of a queue */
-void fd_fifo_dump(int level, char * name, struct fifo * queue, void (*dump_item)(int level, void * item))
+DECLARE_FD_DUMP_PROTOTYPE(fd_fifo_dump, char * name, struct fifo * queue, fd_fifo_dump_item_cb dump_item)
 {
-	TRACE_ENTRY("%i %p %p %p", level, name, queue, dump_item);
-	
-	if (!TRACE_BOOL(level))
-		return;
+	FD_DUMP_HANDLE_OFFSET();
 	
-	fd_log_debug("Dumping queue '%s' (%p):", name ?: "?", queue);
+	if (name) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(@%p): ", name, queue), return NULL);	
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{fifo}(@%p): ", queue), return NULL);
+	}
+	
 	if (!CHECK_FIFO( queue )) {
-		fd_log_debug("  Queue invalid!");
-		if (queue)
-			fd_log_debug("  (%x != %x)", queue->eyec, FIFO_EYEC);
-		return;
+		return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL");
 	}
 	
 	CHECK_POSIX_DO(  pthread_mutex_lock( &queue->mtx ), /* continue */  );
-	fd_log_debug("   %d elements in queue / %d threads waiting", queue->count, queue->thrs);
-	fd_log_debug("   %d elements max / %d threads waiting to push", queue->max, queue->thrs_push);
-	fd_log_debug("   thresholds: %d / %d (h:%d), cb: %p,%p (%p), highest: %d",
-			queue->high, queue->low, queue->highest, 
-			queue->h_cb, queue->l_cb, queue->data,
-			queue->highest_ever);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "items:%d,%d,%d threads:%d,%d stats:%lld/%ld.%06ld,%ld.%06ld,%ld.%06ld thresholds:%d,%d,%d,%p,%p,%p", 
+						queue->count, queue->highest_ever, queue->max,
+						queue->thrs, queue->thrs_push,
+						queue->total_items,(long)queue->total_time.tv_sec,(long)(queue->total_time.tv_nsec/1000),(long)queue->blocking_time.tv_sec,(long)(queue->blocking_time.tv_nsec/1000),(long)queue->last_time.tv_sec,(long)(queue->last_time.tv_nsec/1000),
+						queue->high, queue->low, queue->highest, queue->h_cb, queue->l_cb, queue->data), 
+			 goto error);
 	
 	if (dump_item) {
 		struct fd_list * li;
 		int i = 0;
 		for (li = queue->list.next; li != &queue->list; li = li->next) {
-			fd_log_debug("  [%i] item %p in fifo %p:", i++, li->o, queue);
-			(*dump_item)(level, li->o);
+			struct fifo_item * fi = (struct fifo_item *)li;
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n [#%i](@%p)@%ld.%06ld: ", 
+						i++, fi->item.o, (long)fi->posted_on.tv_sec,(long)(fi->posted_on.tv_nsec/1000)), 
+					 goto error);
+			CHECK_MALLOC_DO( (*dump_item)(FD_DUMP_STD_PARAMS, fi->item.o), goto error);
 		}
 	}
 	CHECK_POSIX_DO(  pthread_mutex_unlock( &queue->mtx ), /* continue */  );
 	
+	return *buf;
+error:
+	CHECK_POSIX_DO(  pthread_mutex_unlock( &queue->mtx ), /* continue */  );
+	return NULL;
 }
 
 /* Delete a queue. It must be empty. */ 
@@ -242,6 +259,22 @@
 	old->count = 0;
 	old->eyec = FIFO_EYEC;
 	
+	/* Merge the stats in the new queue */
+	new->total_items += old->total_items;
+	old->total_items = 0;
+	
+	new->total_time.tv_nsec += old->total_time.tv_nsec;
+	new->total_time.tv_sec += old->total_time.tv_sec + (new->total_time.tv_nsec / 1000000000);
+	new->total_time.tv_nsec %= 1000000000;
+	old->total_time.tv_nsec = 0;
+	old->total_time.tv_sec = 0;
+	
+	new->blocking_time.tv_nsec += old->blocking_time.tv_nsec;
+	new->blocking_time.tv_sec += old->blocking_time.tv_sec + (new->blocking_time.tv_nsec / 1000000000);
+	new->blocking_time.tv_nsec %= 1000000000;
+	old->blocking_time.tv_nsec = 0;
+	old->blocking_time.tv_sec = 0;
+	
 	/* Unlock, we're done */
 	CHECK_POSIX(  pthread_mutex_unlock( &new->mtx )  );
 	CHECK_POSIX(  pthread_mutex_unlock( &old->mtx )  );
@@ -249,19 +282,38 @@
 	return 0;
 }
 
-/* Get the length of the queue */
-int fd_fifo_length ( struct fifo * queue, int * length )
+/* Get the information on the queue */
+int fd_fifo_getstats( struct fifo * queue, int * current_count, int * limit_count, int * highest_count, long long * total_count, 
+				           struct timespec * total, struct timespec * blocking, struct timespec * last)
 {
-	TRACE_ENTRY( "%p %p", queue, length );
+	TRACE_ENTRY( "%p %p %p %p %p %p %p %p", queue, current_count, limit_count, highest_count, total_count, total, blocking, last);
 	
 	/* Check the parameters */
-	CHECK_PARAMS( CHECK_FIFO( queue ) && length );
+	CHECK_PARAMS( CHECK_FIFO( queue ) );
 	
 	/* lock the queue */
 	CHECK_POSIX(  pthread_mutex_lock( &queue->mtx )  );
 	
-	/* Retrieve the count */
-	*length = queue->count;
+	if (current_count)
+		*current_count = queue->count;
+	
+	if (limit_count)
+		*limit_count = queue->max;
+	
+	if (highest_count)
+		*highest_count = queue->highest_ever;
+	
+	if (total_count)
+		*total_count = queue->total_items;
+	
+	if (total)
+		memcpy(total, &queue->total_time, sizeof(struct timespec));
+	
+	if (blocking)
+		memcpy(blocking, &queue->blocking_time, sizeof(struct timespec));
+	
+	if (last)
+		memcpy(last, &queue->last_time, sizeof(struct timespec));
 	
 	/* Unlock */
 	CHECK_POSIX(  pthread_mutex_unlock( &queue->mtx )  );
@@ -270,8 +322,9 @@
 	return 0;
 }
 
+
 /* alternate version with no error checking */
-int fd_fifo_length_noerr ( struct fifo * queue )
+int fd_fifo_length ( struct fifo * queue )
 {
 	if ( !CHECK_FIFO( queue ) )
 		return 0;
@@ -325,14 +378,18 @@
 /* Post a new item in the queue */
 int fd_fifo_post_int ( struct fifo * queue, void ** item )
 {
-	struct fd_list * new;
+	struct fifo_item * new;
 	int call_cb = 0;
+	struct timespec posted_on, queued_on;
 	
 	TRACE_ENTRY( "%p %p", queue, item );
 	
 	/* Check the parameters */
 	CHECK_PARAMS( CHECK_FIFO( queue ) && item && *item );
 	
+	/* Get the timing of this call */
+	CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &posted_on)  );
+	
 	/* lock the queue */
 	CHECK_POSIX(  pthread_mutex_lock( &queue->mtx )  );
 	
@@ -352,15 +409,16 @@
 	}
 	
 	/* Create a new list item */
-	CHECK_MALLOC_DO(  new = malloc (sizeof (struct fd_list)) , {
+	CHECK_MALLOC_DO(  new = malloc (sizeof (struct fifo_item)) , {
 			pthread_mutex_unlock( &queue->mtx );
+			return ENOMEM;
 		} );
 	
-	fd_list_init(new, *item);
+	fd_list_init(&new->item, *item);
 	*item = NULL;
 	
 	/* Add the new item at the end */
-	fd_list_insert_before( &queue->list, new);
+	fd_list_insert_before( &queue->list, &new->item);
 	queue->count++;
 	if (queue->highest_ever < queue->count)
 		queue->highest_ever = queue->count;
@@ -369,6 +427,20 @@
 		queue->highest = queue->count;
 	}
 	
+	/* store timing */
+	memcpy(&new->posted_on, &posted_on, sizeof(struct timespec));
+	
+	/* update queue timing info "blocking time" */
+	{
+		long long blocked_ns;
+		CHECK_SYS(  clock_gettime(CLOCK_REALTIME, &queued_on)  );
+		blocked_ns = (queued_on.tv_sec - posted_on.tv_sec) * 1000000000;
+		blocked_ns += (queued_on.tv_nsec - posted_on.tv_nsec);
+		blocked_ns += queue->blocking_time.tv_nsec;
+		queue->blocking_time.tv_sec += blocked_ns / 1000000000;
+		queue->blocking_time.tv_nsec = blocked_ns % 1000000000;
+	}
+	
 	/* Signal if threads are asleep */
 	if (queue->thrs > 0) {
 		CHECK_POSIX(  pthread_cond_signal(&queue->cond_pull)  );
@@ -393,14 +465,32 @@
 static void * mq_pop(struct fifo * queue)
 {
 	void * ret = NULL;
-	struct fd_list * li;
+	struct fifo_item * fi;
+	struct timespec now;
 	
 	ASSERT( ! FD_IS_LIST_EMPTY(&queue->list) );
 	
-	fd_list_unlink(li = queue->list.next);
+	fi = (struct fifo_item *)(queue->list.next);
+	ret = fi->item.o;
+	fd_list_unlink(&fi->item);
 	queue->count--;
-	ret = li->o;
-	free(li);
+	queue->total_items++;
+	
+	/* Update the timings */
+	CHECK_SYS_DO(  clock_gettime(CLOCK_REALTIME, &now), goto skip_timing  );
+	{
+		long long elapsed = (now.tv_sec - fi->posted_on.tv_sec) * 1000000000;
+		elapsed += now.tv_nsec - fi->posted_on.tv_nsec;
+		
+		queue->last_time.tv_sec = elapsed / 1000000000;
+		queue->last_time.tv_nsec = elapsed % 1000000000;
+		
+		elapsed += queue->total_time.tv_nsec;
+		queue->total_time.tv_sec += elapsed / 1000000000;
+		queue->total_time.tv_nsec = elapsed % 1000000000;
+	}
+skip_timing:	
+	free(fi);
 	
 	if (queue->thrs_push) {
 		CHECK_POSIX_DO( pthread_cond_signal( &queue->cond_push ), );
@@ -508,7 +598,7 @@
 		TRACE_DEBUG(FULL, "The queue is being destroyed -> EPIPE");
 		return EPIPE;
 	}
-		
+	
 	if (queue->count > 0) {
 		/* There are items in the queue, so pick the first one */
 		*item = mq_pop(queue);
--- a/libfdproto/init.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/init.c	Fri May 10 18:49:19 2013 +0800
@@ -57,9 +57,6 @@
 		return ret;
 	}
 	
-	/* Set the debug stream */
-	fd_g_debug_fstr = stdout;
-	
 	/* Initialize the modules that need it */
 	fd_msg_eteid_init();
 	CHECK_FCT( fd_sess_init() );
--- a/libfdproto/log.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/log.c	Fri May 10 18:49:19 2013 +0800
@@ -37,11 +37,9 @@
 
 #include <stdarg.h>
 
-FILE * fd_g_debug_fstr;
-
 pthread_mutex_t fd_log_lock = PTHREAD_MUTEX_INITIALIZER;
 pthread_key_t	fd_log_thname;
-int fd_g_debug_lvl = INFO;
+int fd_g_debug_lvl = FD_LOG_NOTICE;
 
 static void fd_internal_logger( int, const char *, va_list );
 static int use_colors = 0; /* 0: not init, 1: yes, 2: no */
@@ -87,16 +85,16 @@
 }
 
 
-static void fd_internal_logger( int loglevel, const char *format, va_list ap )
+static void fd_internal_logger( int printlevel, const char *format, va_list ap )
 {
     char buf[25];
-    FILE *fstr = fd_g_debug_fstr ?: stdout;
-    int local_use_color = 0;
 
-    /* logging has been decided by macros outside already */
+    /* Do we need to trace this ? */
+    if (printlevel < fd_g_debug_lvl)
+    	return;
 
     /* add timestamp */
-    fprintf(fstr, "%s  ", fd_log_time(NULL, buf, sizeof(buf)));
+    printf("%s  ", fd_log_time(NULL, buf, sizeof(buf)));
     
     /* Use colors on stdout ? */
     if (!use_colors) {
@@ -106,22 +104,20 @@
 		use_colors = 2;
     }
     
-    /* now, this time log, do we use colors? */
-    if ((fstr == stdout) && (use_colors == 1))
-	    local_use_color = 1;
+    switch(printlevel) {
+	    case FD_LOG_ANNOYING:  printf("%s	A   ", (use_colors == 1) ? "\e[0;37m" : ""); break;
+	    case FD_LOG_DEBUG:     printf("%s DBG   ", (use_colors == 1) ? "\e[0;37m" : ""); break;
+	    case FD_LOG_NOTICE:    printf("%sNOTI   ", (use_colors == 1) ? "\e[1;37m" : ""); break;
+	    case FD_LOG_ERROR:     printf("%sERROR  ", (use_colors == 1) ? "\e[0;31m" : ""); break;
+	    case FD_LOG_FATAL:     printf("%sFATAL! ", (use_colors == 1) ? "\e[0;31m" : ""); break;
+	    default:               printf("%s ???   ", (use_colors == 1) ? "\e[0;31m" : "");
+    }
+    vprintf(format, ap);
+    if (use_colors == 1)
+	     printf("\e[00m");
+    printf("\n");
     
-    switch(loglevel) {
-	    case FD_LOG_DEBUG:  fprintf(fstr, "%s DBG   ", local_use_color ? "\e[0;37m" : ""); break;
-	    case FD_LOG_NOTICE: fprintf(fstr, "%sNOTI   ", local_use_color ? "\e[1;37m" : ""); break;
-	    case FD_LOG_ERROR:  fprintf(fstr, "%sERROR  ", local_use_color ? "\e[0;31m" : ""); break;
-	    default:            fprintf(fstr, "%s ???   ", local_use_color ? "\e[0;31m" : "");
-    }
-    vfprintf(fstr, format, ap);
-    if (local_use_color)
-	     fprintf(fstr, "\e[00m");
-    fprintf(fstr, "\n");
-    
-    fflush(fstr);
+    fflush(stdout);
 }
 
 /* Log a debug message */
@@ -142,14 +138,16 @@
 	(void)pthread_mutex_unlock(&fd_log_lock);
 }
 
-/* Log debug message to file. */
-void fd_log_debug_fstr( FILE * fstr, const char * format, ... )
+/* Log a debug message */
+void fd_log_va ( int loglevel, const char * format, va_list args )
 {
-	va_list ap;
+	(void)pthread_mutex_lock(&fd_log_lock);
 	
-	va_start(ap, format);
-	vfprintf(fstr, format, ap);
-	va_end(ap);
+	pthread_cleanup_push(fd_cleanup_mutex_silent, &fd_log_lock);
+	fd_logger(loglevel, format, args);
+	pthread_cleanup_pop(0);
+	
+	(void)pthread_mutex_unlock(&fd_log_lock);
 }
 
 /* Function to set the thread's friendly name */
@@ -207,3 +205,115 @@
 
 	return buf;
 }
+
+
+static size_t sys_mempagesz = 0;
+
+static size_t get_mempagesz(void) {
+	if (!sys_mempagesz) {
+		sys_mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */
+		if (sys_mempagesz <= 0)
+			sys_mempagesz = 1024; /* default size if above call failed */
+	}
+	return sys_mempagesz;
+}
+
+
+/* Helper function for fd_*_dump. Prints the format string from 'offset' into '*buf', extends if needed. The location of buf can be updated by this function. */
+char * fd_dump_extend(char ** buf, size_t *len, size_t *offset, const char * format, ... )
+{
+	va_list ap;
+	int to_write;
+	size_t o = 0;
+	size_t mempagesz = get_mempagesz();
+	
+	/* we do not TRACE_ENTRY this one on purpose */
+	
+	CHECK_PARAMS_DO(buf && len, return NULL);
+	
+	if (*buf == NULL) {
+		CHECK_MALLOC_DO(*buf = malloc(mempagesz), return NULL);
+		*len = mempagesz;
+	}
+	
+	if (offset)
+		o = *offset;
+	
+	va_start(ap, format);
+	to_write = vsnprintf(*buf + o, *len - o, format, ap);
+	va_end(ap);
+	
+	if (to_write + o >= *len) {
+		/* There was no room in the buffer, we extend and redo */
+		size_t new_len = (((to_write + o) / mempagesz) + 1) * mempagesz;
+		CHECK_MALLOC_DO(*buf = realloc(*buf, new_len), return NULL);
+		*len = new_len;
+		
+		va_start(ap, format);
+		to_write = vsnprintf(*buf + o, *len - o, format, ap);
+		va_end(ap);
+	}
+	
+	if (offset)
+		*offset += to_write;
+	
+	return *buf;
+}
+
+char * fd_dump_extend_hexdump(char ** buf, size_t *len, size_t *offset, uint8_t *data, size_t datalen, size_t trunc, size_t wrap )
+{
+	int truncated = 0;
+	size_t towrite = 0;
+	size_t o = 0;
+	int i;
+	char * p;
+	size_t mempagesz = get_mempagesz();
+#define TRUNK_MARK "[...]"
+
+	CHECK_PARAMS_DO(buf && len && data, return NULL);
+	
+	if (trunc && (datalen > trunc)) {
+		datalen = trunc;
+		truncated = 1;
+	}
+	
+	towrite = datalen * 2;
+	
+	if (wrap)
+		towrite += datalen / wrap; /* add 1 '\n' every wrap byte */
+	
+	if (truncated)
+		towrite += CONSTSTRLEN(TRUNK_MARK);
+	
+	
+	if (offset)
+		o = *offset;
+	
+	if (*buf == NULL) {
+		/* Directly allocate the size we need */
+		*len = (((towrite + o) / mempagesz) + 1 ) * mempagesz;
+		CHECK_MALLOC_DO(*buf = malloc(*len), return NULL);
+	} else if ((towrite + o) >= *len) {
+		/* There is no room in the buffer, we extend and redo */
+		size_t new_len = (((towrite + o) / mempagesz) + 1) * mempagesz;
+		CHECK_MALLOC_DO(*buf = realloc(*buf, new_len), return NULL);
+		*len = new_len;
+	}
+	
+	p = *buf + o;
+	for (i = 0; i < datalen; i++) {
+		sprintf(p, "%02hhX", data[i]);
+		p+=2;
+		if ((wrap) && ((i+1) % wrap == 0)) {
+			*p++='\n'; *p ='\0'; /* we want to ensure the buffer is always 0-terminated */
+		}
+	}
+	
+	if (truncated)
+		memcpy(p, TRUNK_MARK, CONSTSTRLEN(TRUNK_MARK));
+		
+	if (offset)
+		*offset += towrite;
+	
+	return *buf;
+}
--- a/libfdproto/messages.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/messages.c	Fri May 10 18:49:19 2013 +0800
@@ -88,6 +88,10 @@
 	struct msg_avp_chain	 avp_chain;		/* Chaining information of this AVP */
 	int			 avp_eyec;		/* Must be equal to MSG_AVP_EYEC */
 	struct dict_object	*avp_model;		/* If not NULL, pointer to the dictionary object of this avp */
+	struct {
+		avp_code_t	 mnf_code;		
+		vendor_id_t	 mnf_vendor;		
+	}  			 avp_model_not_found;	/* When model resolution has failed, store a copy of the data here to avoid searching again */
 	struct avp_hdr		 avp_public;		/* AVP data that can be managed by other modules */
 	
 	uint8_t			*avp_source;		/* If the message was parsed from a buffer, pointer to the AVP data start in the buffer. */
@@ -112,6 +116,10 @@
 	struct msg_avp_chain	 msg_chain;		/* List of the AVPs in the message */
 	int			 msg_eyec;		/* Must be equal to MSG_MSG_EYEC */
 	struct dict_object	*msg_model;		/* If not NULL, pointer to the dictionary object of this message */
+	struct {
+		command_code_t	 mnf_code;
+		uint8_t		 mnf_flags;		
+	}  			 msg_model_not_found;	/* When model resolution has failed, store a copy of the data here to avoid searching again */
 	struct msg_hdr		 msg_public;		/* Message data that can be managed by extensions. */
 	
 	uint8_t			*msg_rawbuffer;		/* data buffer that was received, saved during fd_msg_parse_buffer and freed in fd_msg_parse_dict */
@@ -128,9 +136,7 @@
 		}		 msg_cb;		/* Callback to be called when an answer is received, or timeout expires, if not NULL */
 	DiamId_t		 msg_src_id;		/* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */
 	size_t			 msg_src_id_len;	/* cached length of this string */
-	struct timespec		 msg_ts_rcv;		/* Timestamp when this message was received from the network */
-	struct timespec		 msg_ts_sent;		/* Timestamp when this message was sent to the network */
-	
+	struct fd_msg_pmdl	 msg_pmdl;		/* list of permessagedata structures. */
 };
 
 /* Macro to compute the message header size */
@@ -195,6 +201,9 @@
 	memset(msg, 0, sizeof(struct msg));
 	init_chain( &msg->msg_chain, MSG_MSG);
 	msg->msg_eyec = MSG_MSG_EYEC;
+	
+	fd_list_init(&msg->msg_pmdl.sentinel, NULL);
+	CHECK_POSIX_DO( pthread_mutex_init(&msg->msg_pmdl.lock, NULL), );
 }
 
 
@@ -348,13 +357,15 @@
 	
 	/* Add the Session-Id AVP if session is known */
 	if (sess && dict) {
-		struct dict_object * sess_id_avp;
+		static struct dict_object * sess_id_avp = NULL;
 		os0_t sid;
 		size_t sidlen;
 		struct avp * avp;
 		union avp_value val;
 		
-		CHECK_FCT( fd_dict_search( dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &sess_id_avp, ENOENT) );
+		if (!sess_id_avp) {
+			CHECK_FCT( fd_dict_search( dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &sess_id_avp, ENOENT) );
+		}
 		CHECK_FCT( fd_sess_getsid ( sess, &sid, &sidlen ) );
 		CHECK_FCT( fd_msg_avp_new ( sess_id_avp, 0, &avp ) );
 		val.os.data = sid;
@@ -665,6 +676,10 @@
 		CHECK_FCT_DO( fd_sess_reclaim_msg ( &_M(obj)->msg_sess ), /* continue */);
 	}
 	
+	if ((obj->type == MSG_MSG) && (_M(obj)->msg_pmdl.sentinel.o != NULL)) {
+		((void (*)(struct fd_msg_pmdl *))_M(obj)->msg_pmdl.sentinel.o)(&_M(obj)->msg_pmdl);
+	}
+	
 	/* free the object */
 	free(obj);
 	
@@ -712,385 +727,441 @@
 /***************************************************************************************************************/
 /* Debug functions: dumping */
 
-/* indent inside an object */
-#define INOBJHDR 	"%*s   "
-#define INOBJHDRVAL 	indent<0 ? 1 : indent, indent<0 ? "-" : "|"
+/* messages and AVP formatters */
+typedef DECLARE_FD_DUMP_PROTOTYPE( (*msg_dump_formatter_msg), struct msg * msg );
+typedef DECLARE_FD_DUMP_PROTOTYPE( (*msg_dump_formatter_avp), struct avp * avp, int level, int first, int last );
 
-/* Write some debug data in a buffer */
-
-/* Dump a msg_t object */
-static int obj_dump_msg (struct msg * msg, int indent, char **outstr, size_t *offset, size_t *outlen )
+/* Core function to process the dumping */
+static DECLARE_FD_DUMP_PROTOTYPE( msg_dump_process, msg_dump_formatter_msg msg_format, msg_dump_formatter_avp avp_format, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
 {
-	int ret = 0;
-	char buftime[256];
-	size_t tsoffset = 0;
-	struct tm tm;
-	
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%*sMSG: %p|", INOBJHDRVAL, msg) );
-	
-	if (!CHECK_MSG(msg)) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "INVALID!", INOBJHDRVAL) );
-		return 0;
-	}
-	
-	if ((msg->msg_ts_rcv.tv_sec != 0) || (msg->msg_ts_rcv.tv_nsec != 0)) {
-		tsoffset += strftime(buftime + tsoffset, sizeof(buftime) - tsoffset, "%D,%T", localtime_r( &msg->msg_ts_rcv.tv_sec , &tm ));
-		tsoffset += snprintf(buftime + tsoffset, sizeof(buftime) - tsoffset, ".%6.6ld", msg->msg_ts_rcv.tv_nsec / 1000);
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "Received: %s|", INOBJHDRVAL, buftime) );
-	}
-	if ((msg->msg_ts_sent.tv_sec != 0) || (msg->msg_ts_sent.tv_nsec != 0)) {
-		tsoffset += strftime(buftime + tsoffset, sizeof(buftime) - tsoffset, "%D,%T", localtime_r( &msg->msg_ts_sent.tv_sec , &tm ));
-		tsoffset += snprintf(buftime + tsoffset, sizeof(buftime) - tsoffset, ".%6.6ld", msg->msg_ts_sent.tv_nsec / 1000);
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "Sent    : %s|", INOBJHDRVAL, buftime) );
+	FD_DUMP_HANDLE_OFFSET();
+		
+	if (force_parsing) {
+		(void) fd_msg_parse_dict(obj, dict, NULL);
 	}
 	
-	if (!msg->msg_model) {
-		
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "(no model)|", INOBJHDRVAL) );
-		
-	} else {
-		
-		enum dict_object_type dicttype;
-		struct dict_cmd_data  dictdata;
-		ret = fd_dict_gettype(msg->msg_model, &dicttype);
-		if (ret || (dicttype != DICT_COMMAND)) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "(invalid model: %d %d)|", INOBJHDRVAL, ret, dicttype) );
-			goto public;
-		}
-		ret = fd_dict_getval(msg->msg_model, &dictdata);
-		if (ret != 0) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "(error getting model data: %s)|", INOBJHDRVAL, strerror(ret)) );
-			goto public;
-		}
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "model : v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %u \"%s\"|", INOBJHDRVAL, 
-			DUMP_CMDFL_val(dictdata.cmd_flag_val), DUMP_CMDFL_val(dictdata.cmd_flag_mask), dictdata.cmd_code, dictdata.cmd_name) );
-	}
-public:	
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "public: V:%d L:%d fl:" DUMP_CMDFL_str " CC:%u A:%d hi:%x ei:%x|", INOBJHDRVAL, 
-		msg->msg_public.msg_version,
-		msg->msg_public.msg_length,
-		DUMP_CMDFL_val(msg->msg_public.msg_flags),
-		msg->msg_public.msg_code,
-		msg->msg_public.msg_appl,
-		msg->msg_public.msg_hbhid,
-		msg->msg_public.msg_eteid
-		) );
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "intern: rwb:%p rt:%d cb:%p,%p(%p) qry:%p asso:%d sess:%p src:%s(%zd)|", 
-			INOBJHDRVAL, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.anscb, msg->msg_cb.expirecb, msg->msg_cb.data, msg->msg_query, msg->msg_associated, msg->msg_sess, msg->msg_src_id?:"(nil)", msg->msg_src_id_len) );
-	return 0;
-}
-
-/* Dump an avp object */
-static int obj_dump_avp ( struct avp * avp, int indent, char **outstr, size_t *offset, size_t *outlen )
-{
-	int ret = 0;
-	
-	if (!CHECK_AVP(avp)) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "INVALID!", INOBJHDRVAL) );
-		return 0;
-	}
-	
-	if (!avp->avp_model) {
-		
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "(no model resolved)|", INOBJHDRVAL) );
-		
-	} else {
-		
-		enum dict_object_type dicttype;
-		struct dict_avp_data dictdata;
-		ret = fd_dict_gettype(avp->avp_model, &dicttype);
-		if (ret || (dicttype != DICT_AVP)) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "(invalid model: %d %d)|", INOBJHDRVAL, ret, dicttype) );
-			goto public;
-		}
-		ret = fd_dict_getval(avp->avp_model, &dictdata);
-		if (ret != 0) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "(error getting model data: %s)|", INOBJHDRVAL, strerror(ret)) );
-			goto public;
-		}
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "model : v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %u \"%s\"|", INOBJHDRVAL, 
-			DUMP_AVPFL_val(dictdata.avp_flag_val), 
-			DUMP_AVPFL_val(dictdata.avp_flag_mask), 
-			type_base_name[dictdata.avp_basetype], 
-			dictdata.avp_code, 
-			dictdata.avp_name ) );
-	}
-public:	
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "public: C:%u fl:" DUMP_AVPFL_str " L:%d V:%u  data:@%p|", INOBJHDRVAL, 
-		avp->avp_public.avp_code,
-		DUMP_AVPFL_val(avp->avp_public.avp_flags),
-		avp->avp_public.avp_len,
-		avp->avp_public.avp_vendor,
-		avp->avp_public.avp_value
-		) );
-	/* Dump the value if set */
-	if (avp->avp_public.avp_value) {
-		if (!avp->avp_model) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "(data set but no model: ERROR)|", INOBJHDRVAL) );
-		} else {
-			CHECK_FCT( fd_dict_dump_avp_value(avp->avp_public.avp_value, avp->avp_model, indent, outstr, offset, outlen, 1) );
-		}
-	}
-
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "intern: src:%p mf:%d raw:%p(%d)|", INOBJHDRVAL, avp->avp_source, avp->avp_mustfreeos, avp->avp_rawdata, avp->avp_rawlen) );
-	return 0;
-}
-
-/* Dump a single object content into out string, realloc if needed */
-static int msg_dump_intern ( int level, msg_or_avp * obj, int indent, char **outstr, size_t *offset, size_t *outlen )
-{
-	/* Log only if we are at least at level */
-	if ( ! TRACE_BOOL(level) )
-		return 0;
-	
-	/* Check the object */
-	if (!VALIDATE_OBJ(obj)) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, ">>> invalid object (%p)!.", obj) );
-		return 0;
-	}
-	
-	/* Dump the object */
 	switch (_C(obj)->type) {
 		case MSG_AVP:
-			CHECK_FCT( obj_dump_avp ( _A(obj), indent, outstr, offset, outlen ));
+			CHECK_MALLOC_DO( (*avp_format)(FD_DUMP_STD_PARAMS, (struct avp *)obj, 0, 1, 1), return NULL);
 			break;
-		
+
 		case MSG_MSG:
-			CHECK_FCT( obj_dump_msg ( _M(obj), indent, outstr, offset, outlen ) );
+			CHECK_MALLOC_DO( (*msg_format)(FD_DUMP_STD_PARAMS, (struct msg *)obj), return NULL);
 			break;
-		
+
 		default:
 			ASSERT(0);
 	}
-	return 0;
+		
+	if (recurse) {
+		struct avp * avp = NULL;
+		int first = 1;
+		CHECK_FCT_DO(  fd_msg_browse ( obj, MSG_BRW_FIRST_CHILD, &avp, NULL ), avp = NULL );
+		while (avp) {
+			struct avp * nextavp = NULL;
+			CHECK_FCT_DO(  fd_msg_browse ( avp, MSG_BRW_NEXT, &nextavp, NULL ), nextavp = NULL  );
+			CHECK_MALLOC_DO( (*avp_format)(FD_DUMP_STD_PARAMS, avp, 1, first, nextavp ? 0 : 1), return NULL);
+			avp = nextavp;
+			first = 0;
+		};
+	}
+	
+	return *buf;
 }
 
-/* Dump a message to a specified file stream */
-void fd_msg_dump_fstr ( struct msg * msg, FILE * fstr )
+/*
+ * Tree View message dump
+ */
+static DECLARE_FD_DUMP_PROTOTYPE( msg_format_treeview, struct msg * msg )
 {
-	msg_or_avp * ref = msg;
-	int indent = 2;
-	char *outstr;
-	size_t offset, outlen;
-	CHECK_FCT_DO( dump_init_str(&outstr, &offset, &outlen), { fd_log_debug_fstr(fstr, "Error initializing string for dumping %p", msg); return; } );
-	do {
-		CHECK_FCT_DO(  msg_dump_intern ( NONE, ref, indent, &outstr, &offset, &outlen ),
-				fd_log_debug_fstr(fstr, "Error while dumping %p", ref) );
-		
-		/* Now find the next object */
-		CHECK_FCT_DO(  fd_msg_browse ( ref, MSG_BRW_WALK, &ref, &indent ), break  );
+	if (!CHECK_MSG(msg)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{message}(@%p): INVALID", msg), return NULL);
+		return *buf;
+	}
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{message}(@%p): ", msg), return NULL);
+	if (!msg->msg_model) {
+		if (msg->msg_model_not_found.mnf_code) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not found in dictionary)\n"), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not searched in dictionary)\n"), return NULL);
+		}
+	} else {
+		enum dict_object_type dicttype;
+		struct dict_cmd_data  dictdata;
+		if (fd_dict_gettype(msg->msg_model, &dicttype) || (dicttype != DICT_COMMAND)) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(invalid model information)\n"), return NULL);
+		} else if (fd_dict_getval(msg->msg_model, &dictdata)) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(error getting model information)\n"), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'\n", dictdata.cmd_name), return NULL);
+		}
+	}
 		
-		/* dump next object */
-	} while (ref);
-	
-	/* now really output this in one shot, so it is not interrupted */
-	fd_log_debug_fstr(fstr, "%s", outstr);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Version: 0x%02hhX\n", msg->msg_public.msg_version), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Length: %d\n", msg->msg_public.msg_length), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Flags: 0x%02hhX (" DUMP_CMDFL_str ")\n", msg->msg_public.msg_flags, DUMP_CMDFL_val(msg->msg_public.msg_flags)), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Command Code: %u\n", msg->msg_public.msg_code), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  ApplicationId: %d\n", msg->msg_public.msg_appl), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Hop-by-Hop Identifier: 0x%8X\n", msg->msg_public.msg_hbhid), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  End-to-End Identifier: 0x%8X\n", msg->msg_public.msg_eteid), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "   {debug data}: src:%s(%zd) rwb:%p rt:%d cb:%p,%p(%p) qry:%p asso:%d sess:%p", msg->msg_src_id?:"(nil)", msg->msg_src_id_len, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.anscb, msg->msg_cb.expirecb, msg->msg_cb.data, msg->msg_query, msg->msg_associated, msg->msg_sess), return NULL);
 	
-	free(outstr);
-}
-void fd_msg_dump_fstr_one ( struct msg * msg, FILE * fstr ) /* just the header */
-{
-	char *outstr;
-	size_t offset, outlen;
-	CHECK_FCT_DO( dump_init_str(&outstr, &offset, &outlen), { fd_log_debug_fstr(fstr, "Error initializing string for dumping %p", msg); return; } );
-	CHECK_FCT_DO(  msg_dump_intern ( NONE, msg, 2, &outstr, &offset, &outlen ),
-				fd_log_debug_fstr(fstr, "Error while dumping %p", msg) );
-	/* now really output this in one shot, so it is not interrupted */
-	fd_log_debug_fstr(fstr, "%s", outstr);
-	
-	free(outstr);
+	return *buf;
 }
 
-/* Completely dump a msg_t object */
-static int full_obj_dump_msg (struct msg * msg, struct dictionary *dict, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE( avp_format_treeview, struct avp * avp, int level, int first, int last )
 {
-	int ret = 0;
-	int success = 0;
-	struct dict_cmd_data dictdata;
-	char buf[20];
-
-	if (!CHECK_MSG(msg)) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "INVALID MESSAGE") );
-		return 0;
+	char * name;
+	struct dict_avp_data  dictdata;
+	struct dict_avp_data *dictinfo = NULL;
+	struct dict_vendor_data  vendordata;
+	struct dict_vendor_data *vendorinfo = NULL;
+	
+	if (level) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+	}
+	
+	if (!CHECK_AVP(avp)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{avp}(@%p): INVALID", avp), return NULL);
+		return *buf;
+	}
+	
+	if (!level) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{avp}(@%p): ", avp), return NULL);
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*sAVP: ", level * 3, ""), return NULL);
 	}
 	
-	if (!msg->msg_model) {
-		fd_msg_parse_dict(msg, dict, NULL);
-	}
-	if (!msg->msg_model) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "(no model) ") );
+	if (!avp->avp_model) {
+		if (avp->avp_model_not_found.mnf_code) {
+			name = "(not found in dictionary)";
+		} else {
+			name = "(not searched in dictionary)";
+		}
 	} else {
 		enum dict_object_type dicttype;
-		ret = fd_dict_gettype(msg->msg_model, &dicttype);
-		if (ret || (dicttype != DICT_COMMAND)) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, "(invalid model: %d %d) ", ret, dicttype) );
+		if (fd_dict_gettype(avp->avp_model, &dicttype) || (dicttype != DICT_AVP)) {
+			name = "(invalid model information)";
+		} else if (fd_dict_getval(avp->avp_model, &dictdata)) {
+			name = "(error getting model information)";
 		} else {
-			ret = fd_dict_getval(msg->msg_model, &dictdata);
-			if (ret != 0) {
-				CHECK_FCT( dump_add_str(outstr, offset, outlen, "(error getting model data: %s) ", strerror(ret)) );
-			} else {
-				success = 1;
+			name = dictdata.avp_name;
+			dictinfo = &dictdata;
+			if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+				struct dictionary * dict;
+				struct dict_object * vendor;
+				if ((!fd_dict_getdict(avp->avp_model, &dict))
+				&& (!fd_dict_search(dict, DICT_VENDOR, VENDOR_OF_AVP, avp->avp_model, &vendor, ENOENT))
+				&& (!fd_dict_getval(vendor, &vendordata))) {
+					vendorinfo = &vendordata;
+				}
 			}
 		}
 	}
-
-	if (msg->msg_public.msg_appl) {
-		snprintf(buf, sizeof(buf), "%u/", msg->msg_public.msg_appl);
+	
+	if (dictinfo) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%u)", name, avp->avp_public.avp_code), return NULL);
 	} else {
-		buf[0] = '\0';
-	}
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%s(%s%u)[" DUMP_CMDFL_str "], Length=%u, Hop-By-Hop-Id=0x%08x, End-to-End=0x%08x",
-				success ? dictdata.cmd_name :  "unknown", buf, msg->msg_public.msg_code, DUMP_CMDFL_val(msg->msg_public.msg_flags),
-				msg->msg_public.msg_length, msg->msg_public.msg_hbhid, msg->msg_public.msg_eteid));
-
-	return 0;
-}
-
-/* Dump an avp object completely */
-static int full_obj_dump_avp ( struct avp * avp, char **outstr, size_t *offset, size_t *outlen, int first )
-{
-	int success = 0;
-	struct dict_avp_data dictdata;
-	char buf[20];
-
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, first ? ((*outstr)[*offset-1] == '=' ? "{ " : ", { ") : ", ") );
-
-	if (!CHECK_AVP(avp)) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "INVALID AVP") );
-		return 0;
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%u%s", avp->avp_public.avp_code, name), return NULL);
 	}
 	
-	if (avp->avp_model) {
-		enum dict_object_type dicttype;
-		int ret;
-		ret = fd_dict_gettype(avp->avp_model, &dicttype);
-		if (ret || (dicttype != DICT_AVP)) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, "(invalid model: %d %d) ", ret, dicttype) );
-		} else { 
-			ret = fd_dict_getval(avp->avp_model, &dictdata);
-			if (ret != 0) {
-				CHECK_FCT( dump_add_str(outstr, offset, outlen, "(error getting model data: %s) ", strerror(ret)) );
-			} else {
-				success = 1;
-			}
+	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+		if (vendorinfo) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " vend='%s'(%u)", vendorinfo->vendor_name, avp->avp_public.avp_vendor), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " vend=%u", avp->avp_public.avp_vendor), return NULL);
+		}
+	}
+
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " l=%d f=" DUMP_AVPFL_str " val=", avp->avp_public.avp_len, DUMP_AVPFL_val(avp->avp_public.avp_flags)), return NULL);
+	
+	if (dictinfo && (dictinfo->avp_basetype == AVP_TYPE_GROUPED)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(grouped)"), return NULL);
+		if (level) {
+			struct avp * inavp = NULL;
+			int first = 1;
+			CHECK_FCT_DO(  fd_msg_browse ( avp, MSG_BRW_FIRST_CHILD, &inavp, NULL ), inavp = NULL );
+			while (inavp) {
+				struct avp * nextavp = NULL;
+				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+				CHECK_FCT_DO(  fd_msg_browse ( inavp, MSG_BRW_NEXT, &nextavp, NULL ), inavp = NULL  );
+				CHECK_MALLOC_DO( avp_format_treeview(FD_DUMP_STD_PARAMS, inavp, level + 1, first, nextavp ? 0 : 1), return NULL);
+				inavp = nextavp;
+				first = 0;
+			};
+		}
+	} else {
+		if (avp->avp_public.avp_value) {
+			CHECK_MALLOC_DO( fd_dict_dump_avp_value(FD_DUMP_STD_PARAMS, avp->avp_public.avp_value, avp->avp_model, 0, 0), return NULL);
+		} else if (avp->avp_rawdata) {
+			CHECK_MALLOC_DO( fd_dump_extend_hexdump(FD_DUMP_STD_PARAMS, avp->avp_rawdata, avp->avp_rawlen, 0, 0), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not set)"), return NULL);
 		}
 	}
 
-	if (avp->avp_public.avp_vendor) {
-		snprintf(buf, sizeof(buf), "%u/", avp->avp_public.avp_vendor);
-	} else {
-		buf[0] = '\0';
+	return *buf;
+}
+
+/* multi-line human-readable dump similar to wireshark output */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_treeview, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
+{
+	return msg_dump_process(FD_DUMP_STD_PARAMS, msg_format_treeview, avp_format_treeview, obj, dict, force_parsing, recurse);
+}
+
+
+/*
+ * One-line dumper for compact but complete traces
+ */
+static DECLARE_FD_DUMP_PROTOTYPE( msg_format_full, struct msg * msg )
+{
+	int success = 0;
+	struct dict_cmd_data dictdata;
+	
+	if (!CHECK_MSG(msg)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID MESSAGE", msg), return NULL);
+		return *buf;
 	}
-	/* \todo add full vendorname? */
-	CHECK_FCT(dump_add_str(outstr, offset, outlen, "%s(%s%u)[" DUMP_AVPFL_str "]=", success ? dictdata.avp_name : "unknown", buf, avp->avp_public.avp_code, DUMP_AVPFL_val(avp->avp_public.avp_flags)));
-
-	/* Dump the value if set */
-	if (avp->avp_public.avp_value) {
-		if (!avp->avp_model) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, "(unknown data type)") );
+	
+	if (!msg->msg_model) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(no model) "), return NULL);
+	} else {
+		enum dict_object_type dicttype=0;
+		if (fd_dict_gettype(msg->msg_model, &dicttype) || (dicttype != DICT_COMMAND)) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(invalid model %d) ", dicttype), return NULL);
+		} else if (fd_dict_getval(msg->msg_model, &dictdata)) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(error getting model data) "), return NULL);
 		} else {
-			CHECK_FCT( fd_dict_dump_avp_value(avp->avp_public.avp_value, avp->avp_model, 1, outstr, offset, outlen, 0) );
+			success = 1;
 		}
 	}
-
-	return 0;
+	if (msg->msg_public.msg_appl) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, 
+				   "%s(%u/%u)[" DUMP_CMDFL_str "], Length=%u, Hop-By-Hop-Id=0x%08x, End-to-End=0x%08x",
+					success ? dictdata.cmd_name :  "unknown",  msg->msg_public.msg_appl, msg->msg_public.msg_code, DUMP_CMDFL_val(msg->msg_public.msg_flags),
+					msg->msg_public.msg_length, msg->msg_public.msg_hbhid, msg->msg_public.msg_eteid), return NULL);
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, 
+				   "%s(%u)[" DUMP_CMDFL_str "], Length=%u, Hop-By-Hop-Id=0x%08x, End-to-End=0x%08x",
+					success ? dictdata.cmd_name :  "unknown", msg->msg_public.msg_code, DUMP_CMDFL_val(msg->msg_public.msg_flags),
+					msg->msg_public.msg_length, msg->msg_public.msg_hbhid, msg->msg_public.msg_eteid), return NULL);
+	}
+	return *buf;
 }
 
-/* Dump full message */
-void fd_msg_dump_full ( int level, struct dictionary *dict, const char *prefix, msg_or_avp *obj )
+static DECLARE_FD_DUMP_PROTOTYPE( avp_format_full, struct avp * avp, int level, int first, int last )
 {
-	msg_or_avp * ref = obj;
-	char *outstr;
-	int indent = 1;
-	int first = 1;
-	int previous;
-	size_t offset, outlen;
-	CHECK_FCT_DO( dump_init_str(&outstr, &offset, &outlen), 
-		      { fd_log_error("Error initializing string for dumping %p", obj); return; } );
-	CHECK_FCT_DO( dump_add_str(&outstr, &offset, &outlen, "%s: ", prefix),
-		      { fd_log_error("Error while dumping %p", ref); return; });
+	int success = 0;
+	struct dict_avp_data  dictdata;
+	struct dict_vendor_data  vendordata;
+	struct dict_vendor_data *vendorinfo = NULL;
+	
+	
+	if (level) {
+		if ((first) && ((*buf)[*offset - 1] == '=')) {
+			/* We are first AVP of a grouped AVP */
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{ "), return NULL);
+		} else {
+			/* We follow another AVP, or a message header */
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ", { "), return NULL);
+		}
+	}
+	
+	if (!CHECK_AVP(avp)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID AVP"), return NULL);
+		goto end;
+	}
+	
 
-	do {
-		/* Check the object */
-		if (!VALIDATE_OBJ(ref)) {
-			CHECK_FCT_DO( dump_add_str(&outstr, &offset, &outlen, ">>> invalid object (%p)", ref),
-				      { fd_log_error("Error in error handling dumping %p", ref); break; });
+	if (avp->avp_model) {
+		enum dict_object_type dicttype;
+		if (fd_dict_gettype(avp->avp_model, &dicttype) || (dicttype != DICT_AVP)) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(invalid model: %d) ", dicttype), return NULL);
+		} else if (fd_dict_getval(avp->avp_model, &dictdata)) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(error getting model data) "), return NULL);
+		} else {
+			success = 1;
 		}
-		/* Dump the object */
-		switch (_C(ref)->type) {
-		case MSG_AVP:
-			CHECK_FCT_DO( full_obj_dump_avp ( _A(ref), &outstr, &offset, &outlen, first ),
-				      { fd_log_error("Error in error handling dumping %p", ref); });
-			break;
-		case MSG_MSG:
-			CHECK_FCT_DO( full_obj_dump_msg ( _M(obj), dict, &outstr, &offset, &outlen ),
-				      { fd_log_error("Error in error handling dumping %p", ref); });
-			break;
-		default:
-			ASSERT(0);
-		}
+	}
+	
+	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s(%u/%u)[" DUMP_AVPFL_str "]=", 
+					success ? dictdata.avp_name : "unknown", avp->avp_public.avp_vendor, avp->avp_public.avp_code, DUMP_AVPFL_val(avp->avp_public.avp_flags)), return NULL);
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s(%u)[" DUMP_AVPFL_str "]=", 
+					success ? dictdata.avp_name : "unknown", avp->avp_public.avp_code, DUMP_AVPFL_val(avp->avp_public.avp_flags)), return NULL);
+	}
 
-		first = 0;
-		previous = indent;
-		/* Now find the next object */
-		CHECK_FCT_DO( fd_msg_browse ( ref, MSG_BRW_WALK, &ref, &indent ), break  );
-		if (previous < indent) {
-			first = 1;
-		} else while (previous-- > indent) {
-			CHECK_FCT_DO( dump_add_str(&outstr, &offset, &outlen, " }"),
-				      { fd_log_error("Error while dumping %p", ref); return; });
+		
+	if (success && (dictdata.avp_basetype == AVP_TYPE_GROUPED)) {
+		if (level) {
+			struct avp * inavp = NULL;
+			int first = 1;
+			CHECK_FCT_DO(  fd_msg_browse ( avp, MSG_BRW_FIRST_CHILD, &inavp, NULL ), inavp = NULL );
+			while (inavp) {
+				struct avp * nextavp = NULL;
+				CHECK_FCT_DO(  fd_msg_browse ( inavp, MSG_BRW_NEXT, &nextavp, NULL ), inavp = NULL  );
+				CHECK_MALLOC_DO( avp_format_full(FD_DUMP_STD_PARAMS, inavp, level + 1, first, nextavp ? 0 : 1), return NULL);
+				inavp = nextavp;
+				first = 0;
+			};
 		}
-		/* dump next object */
-	} while (ref);
-
-	fd_log(level, "%s", outstr);
-	free(outstr);
+	} else {
+		if (avp->avp_public.avp_value) {
+			CHECK_MALLOC_DO( fd_dict_dump_avp_value(FD_DUMP_STD_PARAMS, avp->avp_public.avp_value, avp->avp_model, 0, 0), return NULL);
+		} else if (avp->avp_rawdata) {
+			CHECK_MALLOC_DO( fd_dump_extend_hexdump(FD_DUMP_STD_PARAMS, avp->avp_rawdata, avp->avp_rawlen, 0, 0), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not set)"), return NULL);
+		}
+	}
+	
+end:
+	if (level) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " }"), return NULL);
+	}
+	
+	return *buf;
 }
 
-/* Dump a message content -- for debug mostly */
-void fd_msg_dump_walk ( int level, msg_or_avp *obj )
+/* one-line dump with all the contents of the message */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_full, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
 {
-	msg_or_avp * ref = obj;
-	int indent = 1;
-	char *outstr;
-	size_t offset, outlen;
-	CHECK_FCT_DO( dump_init_str(&outstr, &offset, &outlen), 
-			{ fd_log_debug_fstr(fd_g_debug_fstr, "Error initializing string for dumping %p", obj); return; } );
-
-	do {
-		CHECK_FCT_DO(  msg_dump_intern ( level, ref, indent, &outstr, &offset, &outlen ),
-				fd_log_debug_fstr(fd_g_debug_fstr, "Error while dumping %p", ref) );
-		
-		/* Now find the next object */
-		CHECK_FCT_DO(  fd_msg_browse ( ref, MSG_BRW_WALK, &ref, &indent ), break  );
-		
-		/* dump next object */
-	} while (ref);
-	
-	/* now really output this in one shot, so it is not interrupted */
-	TRACE_DEBUG(level, "------ Dumping object %p (w)-------", obj);
-	TRACE_DEBUG(level, "%s", outstr);
-	TRACE_DEBUG(level, "------ /end of object %p -------", obj);
-	
-	free(outstr);
-}
-
-/* Dump a single object content -- for debug mostly */
-void fd_msg_dump_one ( int level, msg_or_avp * obj )
-{
-	char *outstr;
-	size_t offset, outlen;
-	CHECK_FCT_DO( dump_init_str(&outstr, &offset, &outlen), 
-			{ fd_log_debug_fstr(fd_g_debug_fstr, "Error initializing string for dumping %p", obj); return; } );
-	CHECK_FCT_DO(  msg_dump_intern ( level, obj, 1, &outstr, &offset, &outlen ),
-			fd_log_debug_fstr(fd_g_debug_fstr, "Error while dumping %p", obj) );
-	TRACE_DEBUG(level, "------ Dumping object %p (s)-------", obj);
-	TRACE_DEBUG(level, "%s", outstr);
-	TRACE_DEBUG(level, "------ /end of object %p -------", obj);
-	free(outstr);
+	return msg_dump_process(FD_DUMP_STD_PARAMS, msg_format_full, avp_format_full, obj, dict, force_parsing, recurse);
 }
 
 
+
+/*
+ * One-line dumper for compact but complete traces
+ */
+static DECLARE_FD_DUMP_PROTOTYPE( msg_format_summary, struct msg * msg )
+{
+	if (!CHECK_MSG(msg)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{message}(@%p): INVALID", msg), return NULL);
+		return *buf;
+	}
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{message}(@%p): ", msg), return NULL);
+	if (!msg->msg_model) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(no model)"), return NULL);
+	} else {
+		enum dict_object_type dicttype;
+		struct dict_cmd_data  dictdata;
+		if (fd_dict_gettype(msg->msg_model, &dicttype) || (dicttype != DICT_COMMAND) || (fd_dict_getval(msg->msg_model, &dictdata))) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(model error)"), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'", dictdata.cmd_name), return NULL);
+		}
+	}
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%u/%u f:" DUMP_CMDFL_str " src:'%s' len:%d", 
+				msg->msg_public.msg_appl, msg->msg_public.msg_code, DUMP_CMDFL_val(msg->msg_public.msg_flags), msg->msg_src_id?:"(nil)", msg->msg_public.msg_length), return NULL);
+
+	return *buf;
+}
+
+static DECLARE_FD_DUMP_PROTOTYPE( avp_format_summary, struct avp * avp, int level, int first, int last )
+{
+	char * name;
+	struct dict_avp_data  dictdata;
+	struct dict_avp_data *dictinfo = NULL;
+	struct dict_vendor_data  vendordata;
+	struct dict_vendor_data *vendorinfo = NULL;
+	
+	if (level) {
+		if (first) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {"), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "+"), return NULL);
+		}
+	}
+	
+	if (!CHECK_AVP(avp)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID"), return NULL);
+		goto end;
+	}
+	
+	if (!level) {
+		/* We have been called to explicitely dump this AVP, so we parse its name if available */
+		if (!avp->avp_model) {
+			name = "(no model)";
+		} else {
+			enum dict_object_type dicttype;
+			if (fd_dict_gettype(avp->avp_model, &dicttype) || (dicttype != DICT_AVP) || (fd_dict_getval(avp->avp_model, &dictdata))) {
+				name = "(model error)";
+			} else {
+				name = dictdata.avp_name;
+				dictinfo = &dictdata;
+				if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+					struct dictionary * dict;
+					struct dict_object * vendor;
+					if ((!fd_dict_getdict(avp->avp_model, &dict))
+					&& (!fd_dict_search(dict, DICT_VENDOR, VENDOR_OF_AVP, avp->avp_model, &vendor, ENOENT))
+					&& (!fd_dict_getval(vendor, &vendordata))) {
+						vendorinfo = &vendordata;
+					}
+				}
+			}
+		}
+
+		if (dictinfo) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%u)", name, avp->avp_public.avp_code), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%u%s", avp->avp_public.avp_code, name), return NULL);
+		}
+
+		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+			if (vendorinfo) {
+				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " V='%s'(%u)", vendorinfo->vendor_name, avp->avp_public.avp_vendor), return NULL);
+			} else {
+				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " V=%u", avp->avp_public.avp_vendor), return NULL);
+			}
+		}
+
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " L=%d F=" DUMP_AVPFL_str " V=", avp->avp_public.avp_len, DUMP_AVPFL_val(avp->avp_public.avp_flags)), return NULL);
+
+		if ((!dictinfo) || (dictinfo->avp_basetype != AVP_TYPE_GROUPED)) {
+			if (avp->avp_public.avp_value) {
+				CHECK_MALLOC_DO( fd_dict_dump_avp_value(FD_DUMP_STD_PARAMS, avp->avp_public.avp_value, avp->avp_model, 0, 0), return NULL);
+			} else if (avp->avp_rawdata) {
+				CHECK_MALLOC_DO( fd_dump_extend_hexdump(FD_DUMP_STD_PARAMS, avp->avp_rawdata, avp->avp_rawlen, 0, 0), return NULL);
+			} else {
+				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not set)"), return NULL);
+			}
+		}
+	} else {
+		/* For embedded AVPs, we only display (vendor,) code & length */
+		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "V=%u,", avp->avp_public.avp_vendor), return NULL);
+		}
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "C=%u,L=%d", avp->avp_public.avp_code, avp->avp_public.avp_len), return NULL);
+	}
+	
+end:
+	if ((level) && (last)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "}"), return NULL);
+	}
+	
+	return *buf;
+}
+
+/* This one only prints a short display, does not go into the complete tree */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_summary, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
+{
+	return msg_dump_process(FD_DUMP_STD_PARAMS, msg_format_summary, avp_format_summary, obj, dict, force_parsing, recurse);
+}
+
+#ifndef OLD_CODE_TO_BE_REPLACED
+void fd_msg_dump_walk ( int level, msg_or_avp *obj )
+{
+	LOG_D("fd_msg_dump_walk %d, %p is deprecated", level, obj);
+}
+void fd_msg_dump_one ( int level, msg_or_avp * obj )
+{
+	LOG_D("fd_msg_dump_one %d, %p is deprecated", level, obj);
+}
+#endif
 /***************************************************************************************************************/
 /* Simple meta-data management */
 
@@ -1186,8 +1257,8 @@
 	if (! (msg->msg_public.msg_flags & CMD_FLAG_REQUEST ))
 		return anscb ? EINVAL : 0; /* we associate with requests only */
 	
-	CHECK_PARAMS( (anscb == NULL)    || (msg->msg_cb.anscb == NULL) ); /* We are not overwritting a cb */
-	CHECK_PARAMS( (expirecb == NULL) || (msg->msg_cb.expirecb == NULL) ); /* We are not overwritting a cb */
+	CHECK_PARAMS( (anscb == NULL)    || (msg->msg_cb.anscb == NULL) ); /* We are not overwriting a cb */
+	CHECK_PARAMS( (expirecb == NULL) || (msg->msg_cb.expirecb == NULL) ); /* We are not overwriting a cb */
 	
 	/* Associate callback and data with the message, if any */
 	msg->msg_cb.anscb = anscb;
@@ -1363,54 +1434,6 @@
 	return 0;
 }
 
-int fd_msg_ts_set_recv( struct msg * msg, struct timespec * ts )
-{
-	TRACE_ENTRY("%p %p", msg, ts);
-	
-	/* Check we received valid parameters */
-	CHECK_PARAMS( CHECK_MSG(msg) );
-	CHECK_PARAMS( ts );
-	
-	memcpy(&msg->msg_ts_rcv, ts, sizeof(struct timespec));
-	return 0;
-}
-
-int fd_msg_ts_get_recv( struct msg * msg, struct timespec * ts )
-{
-	TRACE_ENTRY("%p %p", msg, ts);
-	
-	/* Check we received valid parameters */
-	CHECK_PARAMS( CHECK_MSG(msg) );
-	CHECK_PARAMS( ts );
-	
-	memcpy(ts, &msg->msg_ts_rcv, sizeof(struct timespec));
-	return 0;
-}
-
-int fd_msg_ts_set_sent( struct msg * msg, struct timespec * ts )
-{
-	TRACE_ENTRY("%p %p", msg, ts);
-	
-	/* Check we received valid parameters */
-	CHECK_PARAMS( CHECK_MSG(msg) );
-	CHECK_PARAMS( ts );
-	
-	memcpy(&msg->msg_ts_sent, ts, sizeof(struct timespec));
-	return 0;
-}
-
-int fd_msg_ts_get_sent( struct msg * msg, struct timespec * ts )
-{
-	TRACE_ENTRY("%p %p", msg, ts);
-	
-	/* Check we received valid parameters */
-	CHECK_PARAMS( CHECK_MSG(msg) );
-	CHECK_PARAMS( ts );
-	
-	memcpy(ts, &msg->msg_ts_sent, sizeof(struct timespec));
-	return 0;
-}
-
 /* Associate a session with a message, use only when the session was just created */
 int fd_msg_sess_set(struct msg * msg, struct session * session)
 {
@@ -1481,6 +1504,13 @@
 	return 0;
 }
 
+/* Retrieve the location of the pmd list for the message; return NULL if failed */
+struct fd_msg_pmdl * fd_msg_pmdl_get(struct msg * msg)
+{
+	CHECK_PARAMS_DO( CHECK_MSG(msg), return NULL );
+	return &msg->msg_pmdl;
+}
+
 
 /******************* End-to-end counter *********************/
 static uint32_t fd_eteid;
@@ -1924,23 +1954,20 @@
 	
 	CHECK_PARAMS(  buffer &&  *buffer  &&  msg  &&  (buflen >= GETMSGHDRSZ())  );
 	buf = *buffer;
-	*buffer = NULL;
 	
 	if ( buf[0] != DIAMETER_VERSION) {
 		TRACE_DEBUG(INFO, "Invalid version in message: %d (supported: %d)", buf[0], DIAMETER_VERSION);
-		free(buf);
 		return EBADMSG;
 	}
 	
 	msglen = ntohl(*(uint32_t *)buf) & 0x00ffffff;
 	if ( buflen < msglen ) {  
 		TRACE_DEBUG(INFO, "Truncated message (%zd / %d)", buflen, msglen );
-		free(buf);
 		return EBADMSG; 
 	}
 	
 	/* Create a new object */
-	CHECK_MALLOC_DO( new = malloc (sizeof(struct msg)),  { free(buf); return ENOMEM; }  );
+	CHECK_MALLOC( new = malloc (sizeof(struct msg)) );
 	
 	/* Initialize the fields */
 	init_msg(new);
@@ -1956,11 +1983,12 @@
 	new->msg_public.msg_hbhid = ntohl(*(uint32_t *)(buf+12));
 	new->msg_public.msg_eteid = ntohl(*(uint32_t *)(buf+16));
 	
-	new->msg_rawbuffer = buf;
-	
 	/* Parse the AVP list */
 	CHECK_FCT_DO( ret = parsebuf_list(buf + GETMSGHDRSZ(), buflen - GETMSGHDRSZ(), &new->msg_chain.children), { destroy_tree(_C(new)); return ret; }  );
 	
+	/* Parsing successful */
+	new->msg_rawbuffer = buf;
+	*buffer = NULL;
 	*msg = new;
 	return 0;
 }
@@ -2003,16 +2031,26 @@
 		}
 	}
 	
-	/* Now try and resolve the model from the avp code and vendor */
-	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
-		struct dict_avp_request_ex avpreq;
-		memset(&avpreq, 0, sizeof(avpreq));
-		avpreq.avp_vendor.vendor_id = avp->avp_public.avp_vendor;
-		avpreq.avp_data.avp_code = avp->avp_public.avp_code;
-		CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_STRUCT, &avpreq, &avp->avp_model, 0));
-	} else {
-		/* no vendor */
-		CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE, &avp->avp_public.avp_code, &avp->avp_model, 0));
+	/* Check if we already searched for this model without success */
+	if ((avp->avp_model_not_found.mnf_code != avp->avp_public.avp_code)
+	||  (avp->avp_model_not_found.mnf_vendor != avp->avp_public.avp_vendor)) {
+	
+		/* Now try and resolve the model from the avp code and vendor */
+		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+			struct dict_avp_request_ex avpreq;
+			memset(&avpreq, 0, sizeof(avpreq));
+			avpreq.avp_vendor.vendor_id = avp->avp_public.avp_vendor;
+			avpreq.avp_data.avp_code = avp->avp_public.avp_code;
+			CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_STRUCT, &avpreq, &avp->avp_model, 0));
+		} else {
+			/* no vendor */
+			CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE, &avp->avp_public.avp_code, &avp->avp_model, 0));
+		}
+		
+		if (!avp->avp_model) {
+			avp->avp_model_not_found.mnf_code = avp->avp_public.avp_code;
+			avp->avp_model_not_found.mnf_vendor = avp->avp_public.avp_vendor;
+		}
 	}
 	
 	/* First handle the case where we have not found this AVP in the dictionary */
@@ -2177,19 +2215,44 @@
 	
 	CHECK_PARAMS(  CHECK_MSG(msg)  );
 	
+	/* First, check if we already have a model. */
+	if (msg->msg_model != NULL) {
+		/* Check if this model is still valid for the message data */
+		enum dict_object_type 	 dicttype;
+		struct dict_cmd_data     data;
+		ASSERT(((fd_dict_gettype(msg->msg_model, &dicttype) == 0) && (dicttype == DICT_COMMAND)));
+		(void)fd_dict_getval( msg->msg_model, &data);
+		if ((data.cmd_code != msg->msg_public.msg_code) 
+		||  ((data.cmd_flag_val & data.cmd_flag_mask) != (msg->msg_public.msg_flags && data.cmd_flag_mask))) {
+			msg->msg_model = NULL;
+		} else {
+			goto chain;
+		}
+	}
+	
+	/* Check if we already searched for this model without success */
+	if ((msg->msg_model_not_found.mnf_code == msg->msg_public.msg_code) 
+	&& (msg->msg_model_not_found.mnf_flags == msg->msg_public.msg_flags)) {
+		goto no_model;
+	} else {
+		msg->msg_model_not_found.mnf_code = 0;
+	}
+	
 	/* Look for the model from the header */
 	CHECK_FCT_DO( ret = fd_dict_search ( dict, DICT_COMMAND, 
 			(msg->msg_public.msg_flags & CMD_FLAG_REQUEST) ? CMD_BY_CODE_R : CMD_BY_CODE_A,
 			&msg->msg_public.msg_code,
 			&msg->msg_model, ENOTSUP),
 		{
-			if ((ret == ENOTSUP) && (error_info)) {
-				error_info->pei_errcode = "DIAMETER_COMMAND_UNSUPPORTED";
-				error_info->pei_protoerr = 1;
+			if (ret == ENOTSUP) {
+				/* update the model not found info */
+				msg->msg_model_not_found.mnf_code = msg->msg_public.msg_code;
+				msg->msg_model_not_found.mnf_flags = msg->msg_public.msg_flags;
+				goto no_model;
 			}
 			return ret;
 		} );
-	
+chain:	
 	if (!only_hdr) {
 		/* Then process the children */
 		ret = parsedict_do_chain(dict, &msg->msg_chain.children, 1, error_info);
@@ -2202,6 +2265,12 @@
 	}
 	
 	return ret;
+no_model:
+	if (error_info) {
+		error_info->pei_errcode = "DIAMETER_COMMAND_UNSUPPORTED";
+		error_info->pei_protoerr = 1;
+	}
+	return ENOTSUP;
 }
 
 int fd_msg_parse_dict ( msg_or_avp * object, struct dictionary * dict, struct fd_pei *error_info )
@@ -2351,7 +2420,7 @@
 			min = 1;
 	}
 	if (count < min) {
-		TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is < the rule min (%d) for '%s'.", count, min, avp_name);
+		fd_log_error("Conflicting rule: the number of occurences (%d) is < the rule min (%d) for '%s'.", count, min, avp_name);
 		if (pr_data->pei) {
 			pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
 			pr_data->pei->pei_avp = empty_avp(rule->rule_avp);
@@ -2361,7 +2430,7 @@
 	
 	/* Check the "max" value */
 	if ((rule->rule_max != -1) && (count > rule->rule_max)) {
-		TRACE_DEBUG(INFO, "Conflicting rule: the number of occurences (%d) is > the rule max (%d) for '%s'.", count, rule->rule_max, avp_name);
+		fd_log_error("Conflicting rule: the number of occurences (%d) is > the rule max (%d) for '%s'.", count, rule->rule_max, avp_name);
 		if (pr_data->pei) {
 			if (rule->rule_max == 0)
 				pr_data->pei->pei_errcode = "DIAMETER_AVP_NOT_ALLOWED";
@@ -2382,7 +2451,7 @@
 		case RULE_FIXED_HEAD:
 			/* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *after* its fixed position */
 			if (first > rule->rule_order) {
-				TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_HEAD AVP appears first in (%d) position, the rule requires (%d) for '%s'.", first, rule->rule_order, avp_name);
+				fd_log_error("Conflicting rule: the FIXED_HEAD AVP appears first in (%d) position, the rule requires (%d) for '%s'.", first, rule->rule_order, avp_name);
 				if (pr_data->pei) {
 					pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
 					pr_data->pei->pei_message = "AVP was not in its fixed position";
@@ -2395,7 +2464,7 @@
 		case RULE_FIXED_TAIL:
 			/* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *before* its fixed position */
 			if (last > rule->rule_order) {	/* We have a ">" here because we count in reverse order (i.e. from the end) */
-				TRACE_DEBUG(INFO, "Conflicting rule: the FIXED_TAIL AVP appears last in (%d) position, the rule requires (%d) for '%s'.", last, rule->rule_order, avp_name);
+				fd_log_error("Conflicting rule: the FIXED_TAIL AVP appears last in (%d) position, the rule requires (%d) for '%s'.", last, rule->rule_order, avp_name);
 				if (pr_data->pei) {
 					pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
 					pr_data->pei->pei_message = "AVP was not in its fixed position";
@@ -2638,7 +2707,7 @@
 				*error_code = "DIAMETER_APPLICATION_UNSUPPORTED";
 			*action = DISP_ACT_ERROR;
 		} else {
-			fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Internal error: Received this answer to a local query with an unsupported application %d", (*msg)->msg_public.msg_appl);
+			//fd_msg_log( FD_MSG_LOG_DROPPED, *msg, "Internal error: Received this answer to a local query with an unsupported application %d", (*msg)->msg_public.msg_appl);
 			fd_msg_free(*msg);
 			*msg = NULL;
 		}
--- a/libfdproto/msg_log.c	Fri May 10 09:50:09 2013 +0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*********************************************************************************************************
-* Software License Agreement (BSD License)                                                               *
-* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
-*													 *
-* Copyright (c) 2013, 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.								 *
-*********************************************************************************************************/
-
-/* messages logging facility */
-#include "fdproto-internal.h"
-#include <stdarg.h>
-
-/* Configuration of this module */
-static struct {
-	struct {
-		enum fd_msg_log_method 	meth;
-		const char * 		metharg;
-	} causes[FD_MSG_LOG_MAX + 1];
-	pthread_mutex_t lock;
-	int		init;
-	struct dictionary *dict;	
-} ml_conf = { .lock = PTHREAD_MUTEX_INITIALIZER, .init = 0 };
-
-
-/* Initialize the module, with a dictionary to use to better parse the messages */
-void fd_msg_log_init(struct dictionary *dict) 
-{
-	memset(&ml_conf.causes, 0, sizeof(ml_conf.causes));
-	ml_conf.init = 1;
-	ml_conf.dict = dict;
-}
-
-/* Set a configuration property */
-int fd_msg_log_config(enum fd_msg_log_cause cause, enum fd_msg_log_method method, const char * arg)
-{
-	/* Check the parameters are valid */
-	TRACE_ENTRY("%d %d %p", cause, method, arg);
-	CHECK_PARAMS( (cause >= 0) && (cause <= FD_MSG_LOG_MAX) );
-	CHECK_PARAMS( (method >= FD_MSG_LOGTO_NONE) && (method <= FD_MSG_LOGTO_DIR) );
-	CHECK_PARAMS( (method == FD_MSG_LOGTO_NONE) || (method == FD_MSG_LOGTO_DEBUGONLY) || (arg != NULL) );
-	
-	/* Lock the configuration */
-	CHECK_POSIX( pthread_mutex_lock(&ml_conf.lock) );
-	if (!ml_conf.init) {
-		ASSERT(0);
-	}
-	
-	/* Now set the parameter */
-	ml_conf.causes[cause].meth = method;
-	ml_conf.causes[cause].metharg = arg;
-	
-	if (method) {
-		TRACE_DEBUG(INFO, "Logging %s messages set to %s '%s'", 
-			(cause == FD_MSG_LOG_DROPPED) ? "DROPPED" :
-				(cause == FD_MSG_LOG_RECEIVED) ? "RECEIVED" :
-					(cause == FD_MSG_LOG_SENT) ? "SENT" :
-					(cause == FD_MSG_LOG_NODELIVER) ? "NODELIVER" :
-					(cause == FD_MSG_LOG_TIMING) ? "TIMING" :
-						"???",
-			(method == FD_MSG_LOGTO_NONE) ? "none" :
-				(method == FD_MSG_LOGTO_DEBUGONLY) ? "debug" :
-				(method == FD_MSG_LOGTO_FILE) ? "file" :
-				(method == FD_MSG_LOGTO_DIR) ? "directory" :
-					"???",
-			arg);
-	}
-	
-	CHECK_POSIX( pthread_mutex_unlock(&ml_conf.lock) );
-	
-	/* Done */
-	return 0;
-}
-
-/* Do not log anything within this one, since log lock is held */
-static void fd_cleanup_mutex_silent( void * mutex )
-{
-	(void)pthread_mutex_unlock((pthread_mutex_t *)mutex);
-}
-
-/* Really log the message */
-void fd_msg_log( enum fd_msg_log_cause cause, struct msg * msg, const char * prefix_format, ... )
-{
-	va_list ap;
-	enum fd_msg_log_method 	meth;
-	const char * 		metharg;
-	FILE * fstr;
-	
-	char buftime[256];
-	size_t offset = 0;
-	struct timespec ts;
-	struct tm tm;
-	
-	TRACE_ENTRY("%d %p %p", cause, msg, prefix_format);
-	CHECK_PARAMS_DO( (cause >= 0) && (cause <= FD_MSG_LOG_MAX),
-	{
-		TRACE_DEBUG(INFO, "Invalid cause received (%d)! Message was:", cause);
-		fd_msg_dump_walk(INFO, msg);
-	} );
-	
-	/* First retrieve the config for this message */
-	CHECK_POSIX_DO( pthread_mutex_lock(&ml_conf.lock), );
-	if (!ml_conf.init) {
-		ASSERT(0);
-	}
-	meth    = ml_conf.causes[cause].meth;
-	metharg = ml_conf.causes[cause].metharg;
-	CHECK_POSIX_DO( pthread_mutex_unlock(&ml_conf.lock), );
-	
-	/* Return now when loging is not requested */
-	if ((meth == FD_MSG_LOGTO_NONE) 
-	 || ((meth == FD_MSG_LOGTO_DEBUGONLY) && (fd_g_debug_lvl < INFO))) {
-		return;
-	}
-	
-	/* Get current time */
-	CHECK_SYS_DO( clock_gettime(CLOCK_REALTIME, &ts), /* continue */);
-	offset += strftime(buftime + offset, sizeof(buftime) - offset, "%D,%T", localtime_r( &ts.tv_sec , &tm ));
-	offset += snprintf(buftime + offset, sizeof(buftime) - offset, ".%6.6ld", ts.tv_nsec / 1000);
-	
-
-	/* Okay, now we will create the file descriptor */
-	switch (meth) {
-		case FD_MSG_LOGTO_DEBUGONLY:
-			fstr = fd_g_debug_fstr;
-			break;
-			
-		case FD_MSG_LOGTO_FILE:
-			TODO("Log to arg file");
-			TODO("Log a note to debug stream");
-			TRACE_DEBUG(INFO, "%s", metharg);
-			break;
-		case FD_MSG_LOGTO_DIR:
-			TODO("Log to arg directory in a new file");
-			TODO("Log a note to debug stream");
-			break;
-		default:
-			break;
-	}
-	
-	/* For file methods, let's parse the message so it looks better */
-	if (((meth != FD_MSG_LOGTO_DEBUGONLY) || (fd_g_debug_lvl > FULL)) && ml_conf.dict) {
-		CHECK_FCT_DO( fd_msg_parse_dict( msg, ml_conf.dict, NULL ), );
-	}
-	
-	/* Then dump the prefix message to this stream, & to debug stream */
-	(void)pthread_mutex_lock(&fd_log_lock);
-	pthread_cleanup_push(fd_cleanup_mutex_silent, &fd_log_lock);
-	fprintf( fstr, "\n");
-	va_start(ap, prefix_format);
-	vfprintf( fstr, prefix_format, ap);
-	va_end(ap);
-	fflush(fstr);
-	pthread_cleanup_pop(0);
-	(void)pthread_mutex_unlock(&fd_log_lock);
-	
-	fd_log_debug_fstr(fstr, " Logged: %s", buftime);
-	
-	/* And now the message itself */
-	if ((meth == FD_MSG_LOGTO_DEBUGONLY) && (fd_g_debug_lvl <= INFO)) {
-		/* dump only the header */
-		fd_msg_dump_fstr_one(msg, fstr);
-	} else {
-		/* dump the full content */
-		fd_msg_dump_fstr(msg, fstr);
-	}
-	
-	/* And finally close the stream if needed */
-	switch (meth) {
-		case FD_MSG_LOGTO_FILE:
-			TODO("close?");
-			break;
-		case FD_MSG_LOGTO_DIR:
-			TODO("close?");
-			break;
-		default:
-			break;
-	}
-}
-
--- a/libfdproto/ostr.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/ostr.c	Fri May 10 18:49:19 2013 +0800
@@ -185,20 +185,21 @@
  if *inoutsz is != 0 on entry, *id may not be \0-terminated.
  memory has the following meaning: 0: *id can be realloc'd. 1: *id must be malloc'd on output (was static)
 */
-#if defined(DIAMID_IDNA_IGNORE) || defined(DIAMID_IDNA_REJECT)
-GCC_DIAG_OFF("-Wunused-but-set-variable")
-#endif
 int fd_os_validate_DiameterIdentity(char ** id, size_t * inoutsz, int memory)
 {
+#if !defined(DIAMID_IDNA_IGNORE) && !defined(DIAMID_IDNA_REJECT)
 	int gotsize = 0;
+#endif /* defined(DIAMID_IDNA_IGNORE) || defined(DIAMID_IDNA_REJECT) */
 	
 	TRACE_ENTRY("%p %p", id, inoutsz);
 	CHECK_PARAMS( id && *id && inoutsz );
 	
 	if (!*inoutsz)
 		*inoutsz = strlen(*id);
+#if !defined(DIAMID_IDNA_IGNORE) && !defined(DIAMID_IDNA_REJECT)
 	else
 		gotsize = 1;
+#endif /* defined(DIAMID_IDNA_IGNORE) || defined(DIAMID_IDNA_REJECT) */
 	
 #ifndef DIAMID_IDNA_IGNORE
 	
@@ -248,9 +249,6 @@
 	}
 	return 0;
 }
-#if defined(DIAMID_IDNA_IGNORE) || defined(DIAMID_IDNA_REJECT)
-GCC_DIAG_ON("-Wunused-but-set-variable")
-#endif
 
 /* Analyze a DiameterURI and return its components. 
   Return EINVAL if the URI is not valid. 
--- a/libfdproto/rt_data.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/rt_data.c	Fri May 10 18:49:19 2013 +0800
@@ -248,6 +248,21 @@
 	return 0;
 }
 
+/* Only retrieve the number of times this message has been processed by the routing-out mechanism (i.e. number of times it was failed over) */
+int  fd_rtd_get_nb_attempts(struct rt_data * rtd, int * sendingattemtps)
+{
+	struct fd_list * li;
+	int match = 0;
+	
+	TRACE_ENTRY("%p %p", rtd, sendingattemtps);
+	CHECK_PARAMS( rtd && sendingattemtps );
+	
+	*sendingattemtps = rtd->extracted;
+	
+	/* Done! */
+	return 0;
+}
+
 /* Extract the list of valid candidates, and initialize their scores */
 void fd_rtd_candidate_extract(struct rt_data * rtd, struct fd_list ** candidates, int ini_score)
 {
--- a/libfdproto/sessions.c	Fri May 10 09:50:09 2013 +0800
+++ b/libfdproto/sessions.c	Fri May 10 18:49:19 2013 +0800
@@ -68,7 +68,8 @@
 struct session_handler {
 	int		  eyec;	/* An eye catcher also used to ensure the object is valid, must be SH_EYEC */
 	int		  id;	/* A unique integer to identify this handler */
-	void 		(*cleanup)(session_state *, os0_t, void *); /* The cleanup function to be called for cleaning a state */
+	void 		(*cleanup)(struct sess_state *, os0_t, void *); /* The cleanup function to be called for cleaning a state */
+	session_state_dump state_dump; /* dumper function */
 	void             *opaque; /* a value that is passed as is to the cleanup callback */
 };
 
@@ -79,7 +80,7 @@
 /* Data structures linked from the sessions, containing the applications states */
 struct state {
 	int			 eyec;	/* Must be SD_EYEC */
-	session_state		*state;	/* The state registered by the application, never NULL (or the whole object is deleted) */
+	struct sess_state	*state;	/* The state registered by the application, never NULL (or the whole object is deleted) */
 	struct fd_list		 chain;	/* Chaining in the list of session's states ordered by hdl->id */
 	union {
 		struct session_handler	*hdl;	/* The handler for which this state was registered */
@@ -272,7 +273,7 @@
 }
 
 /* Create a new handler */
-int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state *, os0_t, void *), void * opaque )
+int fd_sess_handler_create ( struct session_handler ** handler, void (*cleanup)(struct sess_state *, os0_t, void *), session_state_dump dumper, void * opaque )
 {
 	struct session_handler *new;
 	
@@ -289,6 +290,7 @@
 	
 	new->eyec = SH_EYEC;
 	new->cleanup = cleanup;
+	new->state_dump = dumper;
 	new->opaque = opaque;
 	
 	*handler = new;
@@ -717,7 +719,7 @@
 }
 
 /* Save a state information with a session */
-int fd_sess_state_store_internal ( struct session_handler * handler, struct session * session, session_state ** state )
+int fd_sess_state_store ( struct session_handler * handler, struct session * session, struct sess_state ** state )
 {
 	struct state *new;
 	struct fd_list * li;
@@ -770,7 +772,7 @@
 }
 
 /* Get the data back */
-int fd_sess_state_retrieve_internal ( struct session_handler * handler, struct session * session, session_state ** state )
+int fd_sess_state_retrieve ( struct session_handler * handler, struct session * session, struct sess_state ** state )
 {
 	struct fd_list * li;
 	struct state * st = NULL;
@@ -872,49 +874,60 @@
 
 
 /* Dump functions */
-void fd_sess_dump(int level, struct session * session)
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump, struct session * session, int with_states)
 {
-	struct fd_list * li;
-	char buf[30];
-	struct tm tm;
+	FD_DUMP_HANDLE_OFFSET();
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{session}(@%p): ", session), return NULL);
 	
-	if (!TRACE_BOOL(level))
-		return;
-	
-	fd_log_debug("\t  %*s -- Session @%p --", level, "", session);
 	if (!VALIDATE_SI(session)) {
-		fd_log_debug("\t  %*s  Invalid session object", level, "");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
 	} else {
+		char timebuf[30];
+		struct tm tm;
+
+		strftime(timebuf, sizeof(timebuf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm ));
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%zd) h:%x m:%d d:%d to:%s.%06ld",
+							session->sid, session->sidlen, session->hash, session->msg_cnt, session->is_destroyed,
+							timebuf, session->timeout.tv_nsec/1000), 
+				 return NULL);
 		
-		fd_log_debug("\t  %*s  sid '%s'(%zd), hash %x, msg %d, destroyed %d", level, "", session->sid, session->sidlen, session->hash, session->msg_cnt, session->is_destroyed);
-
-		strftime(buf, sizeof(buf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm ));
-		fd_log_debug("\t  %*s  timeout %s.%09ld", level, "", buf, session->timeout.tv_nsec);
-
-		CHECK_POSIX_DO( pthread_mutex_lock(&session->stlock), /* ignore */ );
-		pthread_cleanup_push( fd_cleanup_mutex, &session->stlock );
-		for (li = session->states.next; li != &session->states; li = li->next) {
-			struct state * st = (struct state *)(li->o);
-			fd_log_debug("\t  %*s    handler %d registered data %p", level, "", st->hdl->id, st->state);
+		if (with_states) {
+			struct fd_list * li;
+			CHECK_POSIX_DO( pthread_mutex_lock(&session->stlock), /* ignore */ );
+			pthread_cleanup_push( fd_cleanup_mutex, &session->stlock );
+			
+			for (li = session->states.next; li != &session->states; li = li->next) {
+				struct state * st = (struct state *)(li->o);
+				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n  {state i:%d}(@%p): ", st->hdl->id, st), return NULL);
+				if (st->hdl->state_dump) {
+					CHECK_MALLOC_DO( (*st->hdl->state_dump)( FD_DUMP_STD_PARAMS, st->state), 
+							fd_dump_extend( FD_DUMP_STD_PARAMS, "[dumper error]"));
+				} else {
+					CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<%p>", st->state), return NULL);
+				}
+			}
+			
+			pthread_cleanup_pop(0);
+			CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ );
 		}
-		pthread_cleanup_pop(0);
-		CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ );
 	}
-	fd_log_debug("\t  %*s -- end of session @%p --", level, "", session);
+	
+	return *buf;
 }
 
-void fd_sess_dump_hdl(int level, struct session_handler * handler)
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump_hdl, struct session_handler * handler)
 {
-	if (!TRACE_BOOL(level))
-		return;
+	FD_DUMP_HANDLE_OFFSET();
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{sesshdl}(@%p): ", handler), return NULL);
 	
-	fd_log_debug("\t  %*s -- Handler @%p --", level, "", handler);
 	if (!VALIDATE_SH(handler)) {
-		fd_log_debug("\t  %*s  Invalid session handler object", level, "");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
 	} else {
-		fd_log_debug("\t  %*s  id %d, cleanup %p, opaque %p", level, "", handler->id, handler->cleanup, handler->opaque);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "i:%d cl:%p d:%p o:%p", handler->id, handler->cleanup, handler->state_dump, handler->opaque), return NULL);
 	}
-	fd_log_debug("\t  %*s -- end of handler @%p --", level, "", handler);
+	return *buf;
 }	
 
 int fd_sess_getcount(uint32_t *cnt)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libfdproto/utils.c	Fri May 10 18:49:19 2013 +0800
@@ -0,0 +1,92 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, 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.								 *
+*********************************************************************************************************/
+
+#include "fdproto-internal.h"
+
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node, sSA * sa, int flags)
+{
+	char addrbuf[INET6_ADDRSTRLEN];
+	FD_DUMP_HANDLE_OFFSET();
+	
+	if (sa) {
+		int rc = getnameinfo(sa, sSAlen( sa ), addrbuf, sizeof(addrbuf), NULL, 0, flags);
+		if (rc) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s", gai_strerror(rc)), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s", &addrbuf[0]), return NULL);
+		}
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(NULL / ANY)"), return NULL);
+	}
+	
+	return *buf;
+}
+
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node_serv, sSA * sa, int flags) 
+{
+	char addrbuf[INET6_ADDRSTRLEN];
+	char servbuf[32];
+	FD_DUMP_HANDLE_OFFSET();
+	
+	if (sa) {
+		int rc = getnameinfo(sa, sSAlen( sa ), addrbuf, sizeof(addrbuf), servbuf, sizeof(servbuf), flags);
+		if (rc) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s", gai_strerror(rc)), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s(s)", &addrbuf[0], &servbuf[0]), return NULL);
+		}
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(NULL / ANY)"), return NULL);
+	}
+	return *buf;
+}
+
+void fd_sa_sdump_numeric(char * buf /* must be at least sSA_DUMP_STRLEN */, sSA * sa)
+{
+	char addrbuf[INET6_ADDRSTRLEN];
+	char servbuf[32];
+	
+	if (sa) {
+		int rc = getnameinfo(sa, sSAlen( sa ), addrbuf, sizeof(addrbuf), servbuf, sizeof(servbuf), NI_NUMERICHOST | NI_NUMERICSERV);
+		if (rc) {
+			snprintf(buf, sSA_DUMP_STRLEN, "%s", gai_strerror(rc));
+		} else {
+			snprintf(buf, sSA_DUMP_STRLEN, "%s(%s)", addrbuf, servbuf);
+		}
+	} else {
+		snprintf(buf, sSA_DUMP_STRLEN, "(NULL / ANY)");
+	}
+	
+}
--- a/tests/CMakeLists.txt	Fri May 10 09:50:09 2013 +0800
+++ b/tests/CMakeLists.txt	Fri May 10 18:49:19 2013 +0800
@@ -25,6 +25,7 @@
 	testpeers
 	testdict
 	testmesg
+	testmesg_stress
 	testsess
 	testdisp
 	testcnx
--- a/tests/testcnx.c	Fri May 10 09:50:09 2013 +0800
+++ b/tests/testcnx.c	Fri May 10 18:49:19 2013 +0800
@@ -714,7 +714,7 @@
 		#if 0
 		/* For debug: dump the object */
 		fd_log_debug("Dumping CER");
-		fd_msg_dump_walk(0, cer);
+		fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, cer, fd_g_config->cnf_dict, 0, 1));
 		#endif
 		
 		CHECK( 0, fd_msg_bufferize( cer, &cer_buf, &cer_sz ) );
--- a/tests/testdict.c	Fri May 10 09:50:09 2013 +0800
+++ b/tests/testdict.c	Fri May 10 18:49:19 2013 +0800
@@ -191,7 +191,7 @@
 		
 		CHECK(1, obj ? 1 : 0 );
 #if 1
-		fd_dict_dump_object(obj);
+		fd_log_debug("%s", fd_dict_dump_object(FD_DUMP_TEST_PARAMS, obj));
 #endif
 		CHECK( 0, fd_dict_delete(obj) );
 		cntbkp = count;
@@ -203,6 +203,8 @@
 		
 	}
 	
+	LOG_D( "Dictionary at the end of %s: %s", __FILE__, fd_dict_dump(FD_DUMP_TEST_PARAMS, fd_g_config->cnf_dict) ?: "error");
+	
 	/* That's all for the tests yet */
 	PASSTEST();
 } 
--- a/tests/testdisp.c	Fri May 10 09:50:09 2013 +0800
+++ b/tests/testdisp.c	Fri May 10 18:49:19 2013 +0800
@@ -698,7 +698,7 @@
 		CHECK( 0, app->flags.acct );
 		
 		#if 0
-		fd_conf_dump();
+		fd_log_debug("%s", fd_conf_dump(FD_DUMP_TEST_PARAMS));
 		#endif
 	}
 	
--- a/tests/testfifo.c	Fri May 10 09:50:09 2013 +0800
+++ b/tests/testfifo.c	Fri May 10 18:49:19 2013 +0800
@@ -216,15 +216,15 @@
 	/* Basic operation */
 	{
 		struct fifo * queue = NULL;
-		int count;
 		struct msg * msg  = NULL;
+		int max;
+		long long count;
 		
 		/* Create the queue */
 		CHECK( 0, fd_fifo_new(&queue, 0) );
 		
 		/* Check the count is 0 */
-		CHECK( 0, fd_fifo_length(queue, &count) );
-		CHECK( 0, count);
+		CHECK( 0, fd_fifo_length(queue) );
 		
 		/* Now enqueue */
 		msg = msg1;
@@ -235,33 +235,28 @@
 		CHECK( 0, fd_fifo_post(queue, &msg) );
 		
 		/* Check the count is 3 */
-		CHECK( 0, fd_fifo_length(queue, &count) );
-		CHECK( 3, count);
+		CHECK( 3, fd_fifo_length(queue) );
 		
 		/* Retrieve the first message using fd_fifo_get */
 		CHECK( 0, fd_fifo_get(queue, &msg) );
 		CHECK( msg1, msg);
-		CHECK( 0, fd_fifo_length(queue, &count) );
-		CHECK( 2, count);
+		CHECK( 2, fd_fifo_length(queue) );
 		
 		/* Retrieve the second message using fd_fifo_timedget */
 		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
 		ts.tv_sec += 1; /* Set the timeout to 1 second */
 		CHECK( 0, fd_fifo_timedget(queue, &msg, &ts) );
 		CHECK( msg2, msg);
-		CHECK( 0, fd_fifo_length(queue, &count) );
-		CHECK( 1, count);
+		CHECK( 1, fd_fifo_length(queue) );
 		
 		/* Retrieve the third message using meq_tryget */
 		CHECK( 0, fd_fifo_tryget(queue, &msg) );
 		CHECK( msg3, msg);
-		CHECK( 0, fd_fifo_length(queue, &count) );
-		CHECK( 0, count);
+		CHECK( 0, fd_fifo_length(queue) );
 		
 		/* Check that another meq_tryget does not block */
 		CHECK( EWOULDBLOCK, fd_fifo_tryget(queue, &msg) );
-		CHECK( 0, fd_fifo_length(queue, &count) );
-		CHECK( 0, count);
+		CHECK( 0, fd_fifo_length(queue) );
 		
 		/* Check the timedget actually timesout */
 		CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
@@ -271,8 +266,18 @@
 			ts.tv_sec += 1;
 		}
 		CHECK( ETIMEDOUT, fd_fifo_timedget(queue, &msg, &ts) );
-		CHECK( 0, fd_fifo_length(queue, &count) );
-		CHECK( 0, count);
+		CHECK( 0, fd_fifo_length(queue) );
+		
+		/* Post & get another message */
+		msg = msg1;
+		CHECK( 0, fd_fifo_post(queue, &msg) );
+		CHECK( 0, fd_fifo_timedget(queue, &msg, &ts) );
+		CHECK( msg1, msg);		
+		
+		/* Check some statistics */
+		CHECK( 0, fd_fifo_getstats(queue, NULL, NULL, &max, &count, NULL, NULL, NULL) );
+		CHECK( 3, max );
+		CHECK( 4, count );	
 		
 		/* We're done for basic tests */
 		CHECK( 0, fd_fifo_del(&queue) );
@@ -289,7 +294,6 @@
 		struct msg   		*msgs[NBR_MSG * NBR_THREADS * 2], *msg;
 		pthread_t  		 thr [NBR_THREADS * 2];
 		struct dict_object	*dwr_model = NULL;
-		int 			 count;
 		int			 i;
 		int			 nbr_threads;
 #ifdef _POSIX_THREAD_THREADS_MAX
@@ -360,8 +364,7 @@
 		}
 		
 		/* Check the count of the queue is back to 0 */
-		CHECK( 0, fd_fifo_length(queue, &count) );
-		CHECK( 0, count);
+		CHECK( 0, fd_fifo_length(queue) );
 		
 		/* Destroy this queue and the messages */
 		CHECK( 0, fd_fifo_del(&queue) );
@@ -555,8 +558,6 @@
 		
 		CHECK( 14, iter );
 		
-		/* fd_fifo_dump(0, "test", queue, NULL); */
-		
 		for (; i < td.nbr; i++) {
 			CHECK( 0, fd_fifo_tryget(queue, &item) );
 			CHECK( i, *item);
--- a/tests/testmesg.c	Fri May 10 09:50:09 2013 +0800
+++ b/tests/testmesg.c	Fri May 10 18:49:19 2013 +0800
@@ -60,8 +60,8 @@
 		
 		#if 0
 		/* For debug: dump the object */
-		fd_log_debug("Dumping Accounting-Request empty message");
-		fd_msg_dump_walk( 0, acr );
+		fd_log_debug("Dumping Accounting-Request empty message:");
+		fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, acr, fd_g_config->cnf_dict, 0, 1));
 		#endif
 	}
 	
@@ -78,9 +78,9 @@
 		#if 0
 		/* For debug: dump the object */
 		fd_log_debug("Dumping Proxy-Info AVP");
-		fd_msg_dump_walk(0, pi);
+		fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, pi, fd_g_config->cnf_dict, 0, 1));
 		fd_log_debug("Dumping dictionary model");
-		fd_dict_dump_object(pi_model);
+		fd_log_debug("%s", fd_dict_dump_object(FD_DUMP_TEST_PARAMS, pi_model));
 		#endif
 		
 	}
@@ -106,7 +106,7 @@
 		#if 0
 		/* For debug: dump the object */
 		fd_log_debug("Dumping Accounting-Request with Proxy-Info AVP at the end");
-		fd_msg_dump_walk(0, acr);
+		fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, acr, fd_g_config->cnf_dict, 0, 1));
 		#endif
 	}
 	
@@ -305,12 +305,12 @@
 				< grouped >
 						*/
 			#if 0
-			fd_dict_dump_object ( gavp );
+			fd_log_debug("%s", fd_dict_dump_object(FD_DUMP_TEST_PARAMS, gavp));
 			#endif
 		}
 		#if 0
 		{
-			fd_dict_dump_object ( vendor );
+			fd_log_debug("%s", fd_dict_dump_object(FD_DUMP_TEST_PARAMS, vendor));
 		}
 		#endif
 	}
@@ -364,7 +364,7 @@
 			CHECK( 0, fd_msg_update_length ( avpi ) );
 			#if 0
 			fd_log_debug("AVP no vendor, value 3.1415:");
-			fd_msg_dump_one(0, avpi);
+			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
 			#endif
 			CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
 			CHECK( 12, avpdata->avp_len );
@@ -381,7 +381,7 @@
 			CHECK( 0, fd_msg_update_length ( avpi ) );
 			#if 0
 			fd_log_debug("AVP vendor, value 0x123456789abcdeL:");
-			fd_msg_dump_one(0, avpi);
+			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
 			#endif
 			CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
 			CHECK( 20, avpdata->avp_len );
@@ -407,7 +407,7 @@
 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
 				#if 0
 				fd_log_debug("AVP enum i32, value 2 (from const):");
-				fd_msg_dump_one(0, avpi);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
 				#endif
 			}
 			
@@ -428,7 +428,7 @@
 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
 				#if 0
 				fd_log_debug("AVP enum i32, value -5 (from const):");
-				fd_msg_dump_one(0, avpi);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
 				#endif
 				/* Check the size is correct ( 12 for header + 4 for value ) */
 				CHECK( 0, fd_msg_update_length ( avpi ) );
@@ -443,7 +443,7 @@
 			CHECK( 0, fd_msg_update_length ( avpi ) );
 			#if 0
 			fd_log_debug("AVP vendor enum i32, value -10 (not const):");
-			fd_msg_dump_one(0, avpi);
+			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
 			#endif
 			
 			/* Add an octetstring AVP */
@@ -458,7 +458,7 @@
 				CHECK( 0, fd_msg_update_length ( avpi ) );
 				#if 0
 				fd_log_debug("AVP octet string, 'This\\0 is a b...'");
-				fd_msg_dump_one(0, avpi);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
 				#endif
 				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
 				CHECK( 101, avpdata->avp_len );
@@ -487,7 +487,7 @@
 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
 				#if 0
 				fd_log_debug("AVP Enumuerated OctetString (from const):");
-				fd_msg_dump_one(0, avpi);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
 				#endif
 				/* Check the size is correct ( 12 for header + 5 for value ) */
 				CHECK( 0, fd_msg_update_length ( avpi ) );
@@ -512,7 +512,7 @@
 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
 				#if 0
 				fd_log_debug("AVP Enumuerated OctetString (from const):");
-				fd_msg_dump_one(0, avpi);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
 				#endif
 				/* Check the size is correct ( 12 for header + 3 for value ) */
 				CHECK( 0, fd_msg_update_length ( avpi ) );
@@ -534,7 +534,7 @@
 				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
 				#if 0
 				fd_log_debug("AVP octet string, '1234678'");
-				fd_msg_dump_one(0, avpch);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpch, fd_g_config->cnf_dict, 0, 0));
 				#endif
 				CHECK( 0, fd_msg_update_length ( avpch ) );
 				CHECK( 0, fd_msg_avp_hdr ( avpch, &avpdata ) );
@@ -547,7 +547,7 @@
 				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
 				#if 0
 				fd_log_debug("AVP octet string, '12346789'");
-				fd_msg_dump_one(0, avpch);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpch, fd_g_config->cnf_dict, 0, 0));
 				#endif
 			  }
 			
@@ -579,7 +579,7 @@
 			 */
 			CHECK( 0, fd_msg_update_length ( msg ) );
 			#if 0
-			fd_msg_dump_walk(0, msg);
+			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
 			#endif
 			CHECK( 344, msgdata->msg_length );
 			
@@ -659,7 +659,7 @@
 			CPYBUF();
 			CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
 			#if 0
-			fd_msg_dump_walk(0, msg);
+			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
 			#endif
 			
 			/* reinit the msg */
@@ -732,7 +732,7 @@
 				CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
 				
 				#if 0
-				fd_msg_dump_walk(0, msg);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
 				#endif
 				
 				/* reset */
@@ -756,6 +756,7 @@
 			
 			{
 				unsigned char * buftmp = NULL;
+				struct msg * error;
 				/* Check the parse or error works as expected */
 				CPYBUF();
 				
@@ -764,11 +765,13 @@
 				/* Check that we cannot support this message now */
 				CHECK( 0, fd_msg_init() );
 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
-				CHECK( EBADMSG, fd_msg_parse_or_error( &msg ) );
+				CHECK( EBADMSG, fd_msg_parse_or_error( &msg, &error ) );
+				CHECK( NULL, msg );
+				msg = error;
 				
 				CHECK( 0, fd_msg_bufferize( msg, &buftmp, NULL ) );				
 				
-				fd_msg_dump_walk(0, msg);
+				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
 				
 				TODO("Check the Failed-AVP is as expected");
 				
@@ -782,7 +785,7 @@
 			CHECK( 0, fd_msg_parse_buffer( &buf, 344, &msg) );
 			CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
 			#if 0
-			fd_msg_dump_walk(0, msg);
+			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
 			#endif
 		}
 		
@@ -1335,14 +1338,14 @@
 			
 			/* Okay, now delete the message and parse the buffer, then check we obtain the same values back */
 			#if 0
-			fd_msg_dump_walk(0, msg);
+			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
 			#endif
 			CHECK( 0, fd_msg_free( msg ) );
 			
 			CHECK( 0, fd_msg_parse_buffer( &buf, 148, &msg) );
 			CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
 			#if 0
-			fd_msg_dump_walk(0, msg);
+			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
 			#endif
 			
 			CHECK( 0, fd_msg_browse ( msg, MSG_BRW_FIRST_CHILD, &avp, NULL) );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/testmesg_stress.c	Fri May 10 18:49:19 2013 +0800
@@ -0,0 +1,544 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
+*													 *
+* Copyright (c) 2013, 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.								 *
+*********************************************************************************************************/
+
+#include "tests.h"
+
+/* The number of times each operation is repeated to measure the average operation time */
+#define DEFAULT_NUMBER_OF_SAMPLES	100000
+
+static void display_result(int nr, struct timespec * start, struct timespec * end, char * fct, char * type, char *op)
+{
+	long double dur = (long double)end->tv_sec + (long double)end->tv_nsec/1000000000;
+	dur -= (long double)start->tv_sec + (long double)start->tv_nsec/1000000000;
+	long double thrp = (long double)nr / dur;
+	printf("%-19s: %d %-8s %-7s in %.6LFs (%.1LFmsg/s)\n", fct, nr, type, op, dur, thrp);
+}
+
+
+
+/* Main test routine */
+int main(int argc, char *argv[])
+{
+	struct msg * acr = NULL;
+	struct avp * pi = NULL, *avp1, *avp2;
+	unsigned char * buf = NULL;
+	
+	test_parameter = DEFAULT_NUMBER_OF_SAMPLES;
+	
+	/* First, initialize the daemon modules */
+	INIT_FD();
+	
+	{
+		struct dict_object * acr_model = NULL;
+
+		/* Now find the ACR dictionary object */
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) );
+
+		/* Create the instance, using the templates */
+		CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) );
+	}
+	
+	/* Now let's create some additional Dictionary objects for the test */
+	{
+		/* The constant values used here are totally arbitrary chosen */
+		struct dict_object * vendor;
+		{
+			struct dict_vendor_data vendor_data = { 73565, "Vendor test" };
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_VENDOR, &vendor_data , NULL, &vendor ) );
+		}
+		
+		{
+			struct dict_application_data app_data = { 73566, "Application test" };
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app_data , vendor, NULL ) );
+		}
+		
+		{
+			struct dict_avp_data avp_data = { 73567, 0, "AVP Test - no vendor - f32", 0, 0, AVP_TYPE_FLOAT32 };
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		
+		{
+			struct dict_avp_data avp_data = { 139103, 0, "AVP Test - no vendor - f64", 0, 0, AVP_TYPE_FLOAT64 };
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
+		}
+		
+		{ 
+			struct dict_object  * type = NULL;
+			struct dict_type_data type_data = { AVP_TYPE_INTEGER64, "Int64 test" };
+			struct dict_avp_data  avp_data = { 73568, 73565, "AVP Test - i64", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER64 };
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
+		}
+		
+		{
+			struct dict_object     * type = NULL;
+			struct dict_type_data    type_data = { AVP_TYPE_INTEGER32, "Enum32 test" };
+			struct dict_enumval_data val1 = { "i32 const test (val 1)", { .i32 = 1 } };
+			struct dict_enumval_data val2 = { "i32 const test (val 2)", { .i32 = 2 } };
+			struct dict_enumval_data val3 = { "i32 const test (val -5)",{ .i32 = -5 } };
+			struct dict_avp_data     avp_data = { 73569, 73565, "AVP Test - enumi32", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER32 };
+			
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val3 , type, NULL ) );
+		}
+			
+		{ 
+			struct dict_object  * type = NULL;
+			struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS test" };
+			struct dict_avp_data  avp_data = { 73570, 73565, "AVP Test - os", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
+		}
+		
+		{
+			struct dict_object     * type = NULL;
+			struct dict_type_data    type_data = { AVP_TYPE_OCTETSTRING, "OS enum test" };
+			struct dict_enumval_data val1 = { "os const test (Test)", { .os = { (unsigned char *)"Test", 4 } } };
+			struct dict_enumval_data val2 = { "os const test (waaad)", { .os = { (unsigned char *)"waaad", 5 } } };
+			struct dict_enumval_data val3 = { "os const test (waa)", { .os = { (unsigned char *)"waaad", 3 } } };
+			struct dict_avp_data     avp_data = { 73571, 73565, "AVP Test - enumos", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
+			
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val3 , type, NULL ) );
+		}
+		
+		{
+			struct dict_object * gavp = NULL;
+			struct dict_avp_data avp_data = { 73572, 73565, "AVP Test - grouped", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED };
+			
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, &gavp ) );
+			
+			/* Macro to search AVP and create a rule */		
+			#define ADD_RULE( _parent, _vendor, _avpname, _pos, _min, _max, _ord ) {		\
+				struct dict_object * _avp = NULL;						\
+				struct dict_avp_request _req = { (_vendor), 0, (_avpname) };			\
+				struct dict_rule_data _data;							\
+				CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\
+				_data.rule_avp = _avp;								\
+				_data.rule_position = (_pos);							\
+				_data.rule_order = (_ord);							\
+				_data.rule_min = (_min);							\
+				_data.rule_max = (_max);							\
+				CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &_data , (_parent), NULL ) );	\
+			}
+			
+			ADD_RULE(gavp, 73565, "AVP Test - os", RULE_OPTIONAL,   -1, -1,  0);
+			
+		}
+			
+		{
+			struct dict_object  * application = NULL;
+			struct dict_object  * command = NULL;
+			struct dict_cmd_data  cmd_data = { 73573, "Test-Command-Request", CMD_FLAG_REQUEST, CMD_FLAG_REQUEST };
+			
+			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd_data , application, &command ) );
+			ADD_RULE(command, 0,     "AVP Test - no vendor - f32", 	RULE_FIXED_HEAD, -1,  1,  1);
+			ADD_RULE(command, 73565, "AVP Test - i64",		RULE_REQUIRED,   -1, -1,  0);
+			ADD_RULE(command, 73565, "AVP Test - enumi32", 		RULE_OPTIONAL,   -1, -1,  0);
+			ADD_RULE(command, 73565, "AVP Test - os", 		RULE_OPTIONAL,   -1, -1,  0);
+			ADD_RULE(command, 73565, "AVP Test - enumos", 		RULE_OPTIONAL,   -1, -1,  0);
+			ADD_RULE(command, 73565, "AVP Test - grouped", 		RULE_OPTIONAL,   -1, -1,  0);
+		}
+		
+		{
+			struct dict_object  * application = NULL;
+			struct dict_object  * command = NULL;
+			struct dict_cmd_data  cmd_data = { 73573, "Test-Command-Answer", CMD_FLAG_REQUEST, 0 };
+			
+			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) );
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd_data , application, &command ) );
+		}
+		
+		{
+			struct dict_object  * gavp = NULL;
+			struct dict_avp_data  avp_data = { 73574, 73565, "AVP Test - rules", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED };
+			
+			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, &gavp ) );
+			
+			ADD_RULE(gavp,     0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD,   0, 1, 1);
+			ADD_RULE(gavp, 73565, "AVP Test - i64", 	    RULE_FIXED_HEAD,  -1, 1, 2);
+			ADD_RULE(gavp, 73565, "AVP Test - enumi32", 	    RULE_FIXED_HEAD,  -1, 1, 3);
+			ADD_RULE(gavp, 73565, "AVP Test - os", 	    	    RULE_REQUIRED,     2, 3, 0);
+			ADD_RULE(gavp, 73565, "AVP Test - enumos",     	    RULE_OPTIONAL,     0, 1, 0);
+			ADD_RULE(gavp, 73565, "AVP Test - grouped",         RULE_FIXED_TAIL,  -1, 1, 1);
+			/* ABNF : 
+				< no vendor - f32 >
+				< i64 >
+				< enumi32 >
+			    2*3 { os }
+			     *1 [ enumos ]
+				< grouped >
+						*/
+		}
+	}
+	
+	/* Now create some values and check the length is correctly handled */
+	{
+		struct dict_object * cmd_model = NULL;
+		struct msg         * msg = NULL;
+		struct dict_object * avp_model = NULL;
+		struct avp         * avp = NULL;
+		union avp_value      value;
+		
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) );
+		
+		/* Check the sizes are handled properly */
+		{
+			struct avp * avpi = NULL;
+			struct avp * avpch = NULL;
+			struct avp_hdr * avpdata = NULL;
+			struct msg_hdr * msgdata = NULL;
+			#define ADD_AVP( _parent, _position, _avpi, _avpvendor, _avpname) {			\
+				struct dict_object * _avp = NULL;						\
+				struct dict_avp_request _req = { (_avpvendor), 0, (_avpname) };			\
+				CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\
+				CHECK( 0, fd_msg_avp_new ( _avp, 0, &_avpi ) );					\
+				CHECK( 0, fd_msg_avp_add ( (_parent), (_position), _avpi ) );			\
+			}
+			/* Create a message with many AVP inside */
+			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
+			CHECK( 0, fd_msg_hdr ( msg, &msgdata ) );
+			
+			/* Avp no vendor, float32 => size = 12 */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,     "AVP Test - no vendor - f32" );
+			value.f32 = 3.1415;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+			
+			/* Add a vendor AVP, integer64 => size = 20 */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - i64" );
+			value.i64 = 0x123456789abcdeLL;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+			
+			/* Add an AVP with an enum value */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
+			{
+				struct dict_object * type_model = NULL;
+				struct dict_object * value_model = NULL;
+				struct dict_enumval_request request;
+				
+				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
+				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
+				memset(&request, 0, sizeof(request));
+				request.type_obj = type_model;
+				request.search.enum_name = "i32 const test (val 2)";
+				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
+				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
+			}
+			
+			/* Add an AVP with an enum value, negative */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
+			{
+				struct dict_object  * type_model = NULL;
+				struct dict_object  * value_model = NULL;
+				struct dict_enumval_request request;
+				
+				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
+				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
+				memset(&request, 0, sizeof(request));
+				request.type_obj = type_model;
+				request.search.enum_name = "i32 const test (val -5)";
+				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
+				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
+			}
+			
+			/* Now add a value which is not a constant into an enumerated AVP */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
+			value.i32 = -10;
+			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+			
+			/* Add an octetstring AVP */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - os" );
+			{
+				unsigned char buf[90];
+				memcpy(&buf, "This\0 is a buffer of dat\a. It is not a string so we can have any c\0ntr\0l character here...\0\0", 89);
+				value.os.data = buf;
+				value.os.len = 89;
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
+				memset(&buf, 0, sizeof(buf)); /* Test that the OS value is really copied */
+			}
+
+			/* Add an octetstring from an enumerated constant */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumos" );
+			{
+				struct dict_object  * type_model = NULL;
+				struct dict_object  * value_model = NULL;
+				struct dict_enumval_request request;
+				
+				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
+				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
+				memset(&request, 0, sizeof(request));
+				request.type_obj = type_model;
+				request.search.enum_name = "os const test (waaad)";
+				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
+				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
+			}
+				
+			/* Add an octetstring from an enumerated constant */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumos" );
+			{
+				struct dict_object  * type_model = NULL;
+				struct dict_object  * value_model = NULL;
+				struct dict_enumval_request request;
+				
+				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
+				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
+				memset(&request, 0, sizeof(request));
+				request.type_obj = type_model;
+				request.search.enum_name = "os const test (waa)";
+				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
+				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
+				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
+			}
+				
+			/* Now test the grouped AVPs */	
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - grouped" );
+			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
+			  {
+				value.os.data = (unsigned char *)"12345678";
+				value.os.len = 8;
+				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
+			  }
+			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
+			  {
+				value.os.data = (unsigned char *)"123456789";
+				value.os.len = 9;
+				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
+			  }
+			
+			/* Add another similar grouped AVP, to have lot of padding */
+			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - grouped" );
+			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
+			  {
+				value.os.data = (unsigned char *)"1";
+				value.os.len = 1;
+				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
+			  }
+			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
+			  {
+				value.os.data = (unsigned char *)"1234567";
+				value.os.len = 7;
+				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
+			  }
+			
+			/* Set the application to the test application: 73566 */
+			msgdata->msg_appl = 73566;
+			
+			/* Set the hop-by-hop ID to a random value: 0x4b44b41d */
+			msgdata->msg_hbhid = 0x4b44b41d;
+			/* Set the end-to-end ID to a random value: 0xe2ee2e1d */
+			msgdata->msg_eteid = 0xe2ee2e1d;
+		}
+		
+		CHECK( 0, fd_msg_bufferize( msg, &buf, NULL ) );
+		
+		LOG_D( "Test message: %s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, NULL, 0, 1));
+		
+		/* Now free the message, we keep only the buffer. */
+		CHECK( 0, fd_msg_free( msg ) );
+		
+	}
+	
+	/* We have our "buf" now, length is 344 -- cf. testmesg.c. */
+	
+	/* Test the throughput of the different functions function */
+	{
+		struct stress_struct {
+			struct msg * m;
+			uint8_t * b;
+		} * stress_array;
+		int i;
+		struct timespec start, end;
+		
+		struct msg * msg;
+		
+		
+		/* Create the copies of the message buffer */
+		stress_array = calloc(test_parameter, sizeof(struct stress_struct));
+		CHECK( stress_array ? 1 : 0, 1);
+		
+		for (i=0; i < test_parameter; i++) {
+			stress_array[i].b = malloc(344);
+			if (!stress_array[i].b)
+				break;
+			memcpy(stress_array[i].b, buf, 344);
+		}
+		CHECK( test_parameter, i ); /* if false, a malloc failed */
+		
+	/* fd_msg_parse_buffer */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
+		
+		/* Test the msg_parse_buffer function */
+		for (i=0; i < test_parameter; i++) {
+			if (0 != fd_msg_parse_buffer( &stress_array[i].b, 344, &stress_array[i].m) )
+				break;
+		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
+		display_result(test_parameter, &start, &end, "fd_msg_parse_buffer", "buffers", "parsed");
+		
+	/* fd_msg_parse_dict */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
+		
+		/* Test the fd_msg_parse_dict function */
+		for (i=0; i < test_parameter; i++) {
+			if (0 != fd_msg_parse_dict( stress_array[i].m, fd_g_config->cnf_dict, NULL ) )
+				break;
+		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
+		display_result(test_parameter, &start, &end, "fd_msg_parse_dict", "messages", "parsed");
+		
+		
+	/* fd_msg_parse_rules */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
+		
+		/* Test the fd_msg_parse_rules function */
+		for (i=0; i < test_parameter; i++) {
+			if (0 != fd_msg_parse_rules( stress_array[i].m, fd_g_config->cnf_dict, NULL ) )
+				break;
+		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
+		display_result(test_parameter, &start, &end, "fd_msg_parse_rules", "messages", "parsed");
+		
+		
+	/* fd_msg_new_answer_from_req (0) */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
+		
+		/* Test the fd_msg_new_answer_from_req function */
+		for (i=0; i < test_parameter; i++) {
+			if (0 != fd_msg_new_answer_from_req( fd_g_config->cnf_dict, &stress_array[i].m, 0 ) )
+				break;
+		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
+		display_result(test_parameter, &start, &end, "new_answer(normal)", "messages", "created");
+		
+		/* unlink answers and go back to request messages */
+		for (i=0; i < test_parameter; i++) {
+			struct msg * ans = stress_array[i].m;
+			if (0 != fd_msg_answ_getq( ans, &stress_array[i].m ) )
+				break;
+			if (0 != fd_msg_answ_detach( ans ) )
+				break;
+			fd_msg_free( ans );
+		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
+		
+		
+	/* fd_msg_new_answer_from_req (MSGFL_ANSW_ERROR) */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
+		
+		/* Test the fd_msg_new_answer_from_req function */
+		for (i=0; i < test_parameter; i++) {
+			if ( 0 != fd_msg_new_answer_from_req( fd_g_config->cnf_dict, &stress_array[i].m, MSGFL_ANSW_ERROR ) )
+				break;
+		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
+		display_result(test_parameter, &start, &end, "new_answer(error)", "messages", "created");
+		
+		/* unlink answers and go back to request messages */
+		for (i=0; i < test_parameter; i++) {
+			struct msg * ans = stress_array[i].m;
+			if (0 != fd_msg_answ_getq( ans, &stress_array[i].m ) )
+				break;
+			if (0 != fd_msg_answ_detach( ans ) )
+				break;
+			fd_msg_free( ans );
+		}
+		
+		
+	/* fd_msg_bufferize */
+		
+
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
+		
+		/* Test the fd_msg_bufferize function */
+		for (i=0; i < test_parameter; i++) {
+			size_t len = 0;
+			if (0 != fd_msg_bufferize( stress_array[i].m, &stress_array[i].b, &len ) )
+				break;
+		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
+		display_result(test_parameter, &start, &end, "fd_msg_bufferize", "buffers", "created");
+		
+		
+	/* fd_msg_free */
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &start) );
+		
+		/* Free those messages */
+		for (i=0; i < test_parameter; i++) {
+			fd_msg_free( stress_array[i].m );
+		}
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
+		display_result(test_parameter, &start, &end, "fd_msg_free", "messages", "freed");
+		
+		
+		for (i=0; i < test_parameter; i++) {
+			free(stress_array[i].b);
+		}
+		free(stress_array);
+	}
+		
+	
+	/* That's all for the tests yet */
+	PASSTEST();
+} 
+	
--- a/tests/testpeers.c	Fri May 10 09:50:09 2013 +0800
+++ b/tests/testpeers.c	Fri May 10 18:49:19 2013 +0800
@@ -56,7 +56,7 @@
 			CHECK( 0, fd_peer_add(&inf, __FILE__, NULL, NULL));
 		}
 	}
-	fd_peer_dump_list(0);
+	fd_log_debug("%s", fd_peer_dump_list(FD_DUMP_TEST_PARAMS, 0));
 	/* Check we are able to find again any of these */
 	{
 		int i;
--- a/tests/tests.h	Fri May 10 09:50:09 2013 +0800
+++ b/tests/tests.h	Fri May 10 18:49:19 2013 +0800
@@ -67,31 +67,36 @@
 
 /* Define the macro to fail a test with a message */
 #define FAILTEST( message... ){				\
-	TRACE_ERROR(message);				\
-	TRACE_ERROR("FAILED: %s ", __STRIPPED_FILE__);	\
+	LOG_F(message);					\
+	LOG_F("FAILED: %s ", __STRIPPED_FILE__);	\
+	free(tbuf);					\
 	exit(FAIL);					\
 }
 
 /* Define the macro to pass a test */
 #define PASSTEST( ){					\
-	TRACE_NOTICE("PASS: %s", __STRIPPED_FILE__);	\
+	LOG_N("PASS: %s", __STRIPPED_FILE__);		\
 	(void)fd_core_shutdown();			\
 	(void)fd_core_wait_shutdown_complete();		\
 	(void)fd_thr_term(&signal_thr);			\
+	free(tbuf);					\
 	exit(PASS);					\
 }
 
-static int test_verbo = 0;
 static struct fd_config conf;
 extern struct fd_config * fd_g_config;
 
+/* for dumps */
+static char * tbuf = NULL; size_t tbuflen = 0;
+#define FD_DUMP_TEST_PARAMS &tbuf, &tbuflen, NULL
+
+
 /* Define the standard check routines */
 #define CHECK( _val, _assert ){				\
-	if (test_verbo > 0) {				\
-		TRACE_NOTICE("CHECK( %s == %s )",	\
+	LOG_D("CHECK( %s == %s )",			\
 				#_assert,		\
 				#_val);			\
-	}{						\
+	{						\
 	__typeof__ (_val) __ret = (_assert);		\
 	if (__ret != (_val)) {				\
 		FAILTEST( "%s:%d: CHECK FAILED : %s == %lx != %lx",	\
@@ -135,18 +140,19 @@
 }
 static int gnutls_debug = 0;
 
+static int test_parameter = 0;
 
 static inline void parse_cmdline(int argc, char * argv[]) {
 	int c;
 	int no_timeout = 0;
-	while ((c = getopt (argc, argv, "dqnf:F:g:")) != -1) {
+	while ((c = getopt (argc, argv, "dqnf:F:g:p:")) != -1) {
 		switch (c) {
 			case 'd':	/* Increase verbosity of debug messages.  */
-				test_verbo++;
+				fd_g_debug_lvl--;
 				break;
 				
 			case 'q':	/* Decrease verbosity.  */
-				test_verbo--;
+				fd_g_debug_lvl++;
 				break;
 			
 			case 'n':	/* Disable the timeout of the test.  */
@@ -173,11 +179,14 @@
 				gnutls_debug = (int)atoi(optarg);
 				break;
 				
+			case 'p':	/* Set a debug level and function for GNU TLS calls.  */
+				test_parameter = (int)atoi(optarg);
+				break;
+				
 			default:	/* bug: option not considered.  */
 				return;
 		}
 	}
-	fd_g_debug_lvl = (test_verbo > 0) ? (test_verbo - 1) : 0;
 	if (!no_timeout) {
 		alarm(TEST_TIMEOUT);
 	}
@@ -196,6 +205,8 @@
 	
 	CHECK( 0, fd_libproto_init() );
 	
+	CHECK( 0, fd_hooks_init() );	
+	
 	fd_log_threadname(fname);
 	
 	/* Parse the command line */
@@ -215,9 +226,6 @@
 	/* Initialize the config */
 	CHECK( 0, fd_conf_init() );
 
-	/* Initialize the message logging facility */
-	fd_msg_log_init(fd_g_config->cnf_dict);
-
 	/* Add definitions of the base protocol */
 	CHECK( 0, fd_dict_base_protocol(fd_g_config->cnf_dict) );
 	
--- a/tests/testsess.c	Fri May 10 09:50:09 2013 +0800
+++ b/tests/testsess.c	Fri May 10 18:49:19 2013 +0800
@@ -42,14 +42,14 @@
 #define TEST_SID	(os0_t)TEST_SID_IN
 
 #define TEST_EYEC	0x7e57e1ec
-struct mystate {
+struct sess_state {
 	int	eyec;	/* TEST_EYEC */
 	os0_t   sid; 	/* the session with which the data was registered */
 	int  *  freed;	/* location where to write the freed status */
 	void *  opaque; /* if opaque was provided, this is the value we expect */
 };
 
-static void mycleanup( struct mystate * data, os0_t sid, void * opaque )
+static void mycleanup( struct sess_state * data, os0_t sid, void * opaque )
 {
 	/* sanity */
 	CHECK( 1, sid ? 1 : 0 );
@@ -66,12 +66,12 @@
 	free(data);
 }
 
-static __inline__ struct mystate * new_state(os0_t sid, int *freed) 
+static __inline__ struct sess_state * new_state(os0_t sid, int *freed) 
 {
-	struct mystate *new;
-	new = malloc(sizeof(struct mystate));
+	struct sess_state *new;
+	new = malloc(sizeof(struct sess_state));
 	CHECK( 1, new ? 1 : 0 );
-	memset(new, 0, sizeof(struct mystate));
+	memset(new, 0, sizeof(struct sess_state));
 	new->eyec = TEST_EYEC;
 	new->sid = os0dup(sid, strlen((char *)sid));
 	CHECK( 1, new->sid ? 1 : 0 );
@@ -105,14 +105,14 @@
 	/* Test functions related to handlers (simple situation) */
 	{
 		void * testptr = NULL;
-		CHECK( 0, fd_sess_handler_create ( &hdl1, mycleanup, NULL ) );
-		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup, NULL ) );
+		CHECK( 0, fd_sess_handler_create ( &hdl1, mycleanup, NULL, NULL ) );
+		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup, NULL, NULL ) );
 		CHECK( 0, fd_sess_handler_destroy( &hdl2, &testptr ) );
 		CHECK( 1, testptr == NULL ? 1 : 0 );
-		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup, g_opaque ) );
+		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup, NULL, g_opaque ) );
 		#if 0
-		fd_sess_dump_hdl(0, hdl1);
-		fd_sess_dump_hdl(0, hdl2);
+		fd_log_debug("%s\n", fd_sess_dump_hdl(FD_DUMP_TEST_PARAMS, hdl1));
+		fd_log_debug("%s\n", fd_sess_dump_hdl(FD_DUMP_TEST_PARAMS, hdl2));
 		#endif
 	}
 	
@@ -122,8 +122,8 @@
 		CHECK( 0, fd_sess_new( &sess1, TEST_DIAM_ID, CONSTSTRLEN(TEST_DIAM_ID), NULL, 0 ) );
 		CHECK( 0, fd_sess_new( &sess2, TEST_DIAM_ID, CONSTSTRLEN(TEST_DIAM_ID), NULL, 0 ) );
 		#if 0
-		fd_sess_dump(0, sess1);
-		fd_sess_dump(0, sess2);
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess1, 1));
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess2, 1));
 		#endif
 		
 		/* Check both string start with the diameter Id, but are different */
@@ -140,8 +140,8 @@
 		CHECK( 0, fd_sess_new( &sess1, TEST_DIAM_ID, 0, TEST_OPT, 0 ) );
 		CHECK( 0, fd_sess_new( &sess2, TEST_DIAM_ID, CONSTSTRLEN(TEST_DIAM_ID), TEST_OPT, CONSTSTRLEN(TEST_OPT_IN) - 1 ) );
 		#if 0
-		fd_sess_dump(0, sess1);
-		fd_sess_dump(0, sess2);
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess1, 1));
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess2, 1));
 		#endif
 		
 		CHECK( 0, fd_sess_getsid(sess1, &str1, &str1len) );
@@ -164,8 +164,8 @@
 		CHECK( sess3, sess1 );
 		CHECK( 0, fd_sess_new( &sess2, NULL, 0, TEST_SID, CONSTSTRLEN(TEST_SID_IN) - 1 ) );
 		#if 0
-		fd_sess_dump(0, sess1);
-		fd_sess_dump(0, sess2);
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess1, 1));
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess2, 1));
 		#endif
 		CHECK( 0, fd_sess_getsid(sess1, &str1, &str1len) );
 		CHECK( 0, fd_sess_getsid(sess2, &str2, &str2len) );
@@ -210,7 +210,7 @@
 	
 	/* Test fd_sess_reclaim */
 	{
-		struct mystate *tms;
+		struct sess_state *tms;
 		
 		CHECK( 0, fd_sess_fromsid( TEST_SID, CONSTSTRLEN(TEST_SID_IN), &sess1, &new ) );
 		CHECK( 1, new ? 1 : 0 );
@@ -270,7 +270,7 @@
 	
 	/* Test states operations */
 	{
-		struct mystate * ms[6], *tms;
+		struct sess_state * ms[6], *tms;
 		int freed[6];
 		struct timespec timeout;
 		void * testptr = NULL;
@@ -294,7 +294,7 @@
 		CHECK( 1, ms[1] ? 1 : 0 );
 		
 		#if 0
-		fd_sess_dump(0, sess1);
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess1, 1));
 		#endif
 		
 		CHECK( 0, fd_sess_state_retrieve( hdl1, sess1, &ms[0] ) );
@@ -331,9 +331,9 @@
 		CHECK( 0, fd_sess_state_store ( hdl2, sess3, &ms[5] ) );
 		
 		#if 0
-		fd_sess_dump(0, sess1);
-		fd_sess_dump(0, sess2);
-		fd_sess_dump(0, sess3);
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess1, 1));
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess2, 1));
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess3, 1));
 		#endif
 		
 		/* Destroy session 3 */
@@ -356,8 +356,8 @@
 		CHECK( 1, testptr == g_opaque ? 1 : 0 );
 		
 		#if 1
-		fd_sess_dump(0, sess1);
-		fd_sess_dump(0, sess2);
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess1, 1));
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess2, 1));
 		#endif
 		
 		/* Create again session 3, check that no data is associated to it */
@@ -372,8 +372,8 @@
 		CHECK( 0, clock_gettime(CLOCK_REALTIME, &timeout) );
 		CHECK( 0, fd_sess_settimeout( sess2, &timeout) );
 		#if 1
-		fd_sess_dump(0, sess1);
-		fd_sess_dump(0, sess2);
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess1, 1));
+		fd_log_debug("%s\n", fd_sess_dump(FD_DUMP_TEST_PARAMS, sess2, 1));
 		#endif
 		timeout.tv_sec = 0;
 		timeout.tv_nsec= 50000000; /* 50 ms */
"Welcome to our mercurial repository"