Index: include/freeDiameter/libfdcore.h
===================================================================
--- include/freeDiameter/libfdcore.h	(revision 1397)
+++ include/freeDiameter/libfdcore.h	(revision 1425)
@@ -553,4 +553,28 @@
 
 /*
+ * FUNCTION:	fd_msg_add_result
+ *
+ * PARAMETERS:
+ *  msg		: A msg object -- it must be an answer.
+ *  vendor	: Vendor. If 0, add Result-Code else add Experimental-Result.
+ *  restype	: DICT_TYPE containing rescode (ex: from TYPE_BY_NAME "Enumerated(Result-Code)").
+ *  rescode	: The name of the returned error code (ex: "DIAMETER_INVALID_AVP").
+ *  errormsg	: (optional) human-readable error message to put in Error-Message AVP.
+ *  optavp	: (optional) If provided, the content will be put inside a Failed-AVP.
+ *  type_id	: 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host.
+ *
+ * DESCRIPTION:
+ *  This function adds a Result-Code AVP (if vendor is 0) or Experimental-Result AVP (vendor is not 0)
+ *  to a message, and optionally
+ *  - sets the 'E' error flag in the header,
+ *  - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs.
+ *
+ * RETURN VALUE:
+ *  0		: Operation complete.
+ *  !0		: an error occurred.
+ */
+int fd_msg_add_result( struct msg * msg, vendor_id_t vendor, struct dict_object * restype, char * rescode, char * errormsg, struct avp * optavp, int type_id );
+
+/*
  * FUNCTION:	fd_msg_rescode_set
  *
@@ -562,12 +586,13 @@
  *  type_id	: 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host.
  *
- * DESCRIPTION: 
- *   This function adds a Result-Code AVP to a message, and optionally
+ * DESCRIPTION:
+ *  This function adds a Result-Code AVP to a message, and optionally
  *  - sets the 'E' error flag in the header,
  *  - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs.
- *
- * RETURN VALUE:
- *  0      	: Operation complete.
- *  !0      	: an error occurred.
+ *  Uses fd_msg_add_result with vendor 0 and restype for Enumerated(Result-Code).
+ *
+ * RETURN VALUE:
+ *  0		: Operation complete.
+ *  !0		: an error occurred.
  */
 int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id );
Index: libfdcore/messages.c
===================================================================
--- libfdcore/messages.c	(revision 1383)
+++ libfdcore/messages.c	(revision 1425)
@@ -43,4 +43,7 @@
 static struct dict_object * dict_avp_FAVP= NULL; /* Failed-AVP */
 static struct dict_object * dict_avp_RC  = NULL; /* Result-Code */
+static struct dict_object * dict_avp_ER  = NULL; /* Experimental-Result */
+static struct dict_object * dict_avp_VI  = NULL; /* Vendor-Id */
+static struct dict_object * dict_avp_ERC = NULL; /* Experimental-Result-Code */
 struct dict_object * fd_dict_avp_OSI = NULL; /* Origin-State-Id */
 struct dict_object * fd_dict_cmd_CER = NULL; /* Capabilities-Exchange-Request */
@@ -64,4 +67,7 @@
 	CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT)  );
 	CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP",      	&dict_avp_FAVP, ENOENT)  );
+	CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &dict_avp_ER, ENOENT)  );
+	CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id",		&dict_avp_VI, ENOENT)  );
+	CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result-Code", &dict_avp_ERC, ENOENT)  );
 
 	CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", 	&fd_dict_avp_DC , ENOENT)  );
@@ -167,28 +173,24 @@
 
 
-/* Add Result-Code and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */
-int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id )
+/* Add Result-Code or Experimental-Result, and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */
+int fd_msg_add_result( struct msg * msg, vendor_id_t vendor, struct dict_object * restype, char * rescode, char * errormsg, struct avp * optavp, int type_id )
 {
 	union avp_value val;
-	struct avp * avp_RC  = NULL;
-	struct avp * avp_EM  = NULL;
-	struct avp * avp_ERH = NULL;
-	struct avp * avp_FAVP= NULL;
 	uint32_t rc_val = 0;
 	int set_e_bit=0;
 	int std_err_msg=0;
 
-	TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id);
-
-	CHECK_PARAMS(  msg && rescode  );
+	TRACE_ENTRY("%p %d %p %s %p %p %d", msg, vendor, restype, rescode, errormsg, optavp, type_id);
+
+	CHECK_PARAMS(  msg && restype && rescode  );
 
 	/* Find the enum value corresponding to the rescode string, this will give the class of error */
 	{
 		struct dict_object * enum_obj = NULL;
+
+		/* Search in the restype */
 		struct dict_enumval_request req;
 		memset(&req, 0, sizeof(struct dict_enumval_request));
-
-		/* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */
-		CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT  )  );
+		req.type_obj = restype;
 
 		/* Now search for the value given as parameter */
@@ -208,18 +210,56 @@
 	}
 
-	/* Create the Result-Code AVP */
-	CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) );
-
-	/* Set its value */
-	memset(&val, 0, sizeof(val));
-	val.u32  = rc_val;
-	CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) );
-
-	/* Add it to the message */
-	CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) );
+	if (vendor == 0) {
+		/* Vendor 0; create the Result-Code AVP */
+		struct avp * avp_RC  = NULL;
+		CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) );
+
+		/* Set its value */
+		memset(&val, 0, sizeof(val));
+		val.u32  = rc_val;
+		CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) );
+
+		/* Add it to the message */
+		CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) );
+	} else {
+		/* Vendor !0; create the Experimental-Result AVP */
+		struct avp * avp_ER  = NULL;
+		CHECK_FCT( fd_msg_avp_new( dict_avp_ER, 0, &avp_ER ) );
+
+		/* Create the Vendor-Id AVP and add to Experimental-Result */
+		{
+			struct avp * avp_VI  = NULL;
+			CHECK_FCT( fd_msg_avp_new( dict_avp_VI, 0, &avp_VI ) );
+
+			/* Set Vendor-Id value to vendor */
+			memset(&val, 0, sizeof(val));
+			val.u32  = vendor;
+			CHECK_FCT( fd_msg_avp_setvalue( avp_VI, &val ) );
+
+			/* Add it to Experimental-Result */
+			CHECK_FCT( fd_msg_avp_add( avp_ER, MSG_BRW_LAST_CHILD, avp_VI ) );
+		}
+
+		/* Create the Experimental-Result-Code AVP and add to Experimental-Result */
+		{
+			struct avp * avp_ERC  = NULL;
+			CHECK_FCT( fd_msg_avp_new( dict_avp_ERC, 0, &avp_ERC ) );
+
+			/* Set Experimental-Result-Code value to rc_val */
+			memset(&val, 0, sizeof(val));
+			val.u32  = rc_val;
+			CHECK_FCT( fd_msg_avp_setvalue( avp_ERC, &val ) );
+
+			/* Add it to Experimental-Result */
+			CHECK_FCT( fd_msg_avp_add( avp_ER, MSG_BRW_LAST_CHILD, avp_ERC ) );
+		}
+
+		/* Add it to the message */
+		CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ER ) );
+	}
 
 	if (type_id == 2) {
 		/* Add the Error-Reporting-Host AVP */
-
+		struct avp * avp_ERH = NULL;
 		CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) );
 
@@ -232,9 +272,9 @@
 		/* Add it to the message */
 		CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) );
-
-	}
-
-	/* Now add the optavp in a FailedAVP if provided */
+	}
+
+	/* Now add the optavp in a Failed-AVP if provided */
 	if (optavp) {
+		struct avp * avp_FAVP= NULL;
 		struct avp * optavp_cpy = NULL;
 		struct avp_hdr *opt_hdr, *optcpy_hdr;
@@ -310,5 +350,5 @@
 	if (std_err_msg || errormsg) {
 		/* Add the Error-Message AVP */
-
+		struct avp * avp_EM  = NULL;
 		CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) );
 
@@ -330,4 +370,11 @@
 
 	return 0;
+}
+
+int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id )
+{
+	struct dict_object * restype = NULL;
+	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &restype, ENOENT ) );
+	return fd_msg_add_result(msg, 0, restype, rescode, errormsg, optavp, type_id);
 }
 
Index: tests/testmesg.c
===================================================================
--- tests/testmesg.c	(revision 1423)
+++ tests/testmesg.c	(revision 1425)
@@ -283,4 +283,9 @@
 			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, "Session-Id",			RULE_FIXED_HEAD, 1, 1, 1);
+			ADD_RULE(command, 0, "Result-Code",			RULE_OPTIONAL,   0, 1, 0);
+			ADD_RULE(command, 0, "Experimental-Result",		RULE_OPTIONAL,   0, 1, 0);
+			ADD_RULE(command, 0, "Origin-Host",			RULE_REQUIRED,   1, 1, 0);
+			ADD_RULE(command, 0, "Origin-Realm",			RULE_REQUIRED,   1, 1, 0);
 		}
 		
@@ -317,5 +322,17 @@
 			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_UNSIGNED32, "Enumerated(73565/Experimental-Result-Code)" };
+			struct dict_avp_data     avp_data = { 73576, 73565, "Experimental-Result-Code", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_UNSIGNED32 };
+			struct dict_enumval_data val1 = { "DIAMETER_TEST_RESULT_1000", { .u32 = 1000 } };
+			struct dict_enumval_data val2 = { "DIAMETER_TEST_RESULT_5000", { .u32 = 5000 } };
+			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 ) );
+		}
+
 		#if 0
 		{
@@ -1478,4 +1495,95 @@
 	}
 
+	/* Test the fd_msg_add_result function for Result-Code */
+	{
+		struct msg		* msg = NULL;
+		struct dict_object	* avp_model = NULL;
+		struct avp		* rc = NULL;
+		struct avp_hdr		* avpdata = NULL;
+
+		{
+			struct dict_object * cmd_model = NULL;
+			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Answer", &cmd_model, ENOENT ) );
+
+			/* Create a message */
+			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
+
+			/* Add a session id */
+			CHECK( 0, fd_msg_new_session( msg, (os0_t)"tm2", strlen("tm2") ) );
+
+			/* Find the DICT_TYPE Enumerated(Result-Code) */
+			struct dict_object * restype = NULL;
+			CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_BY_NAME, "Enumerated(Result-Code)", &restype, ENOENT ) );
+
+			/* Now test the behavior of fd_msg_add_result for Result-Code AVP */
+			CHECK( 0, fd_msg_add_result(msg, 0, restype, "DIAMETER_SUCCESS", NULL, NULL, 1) );
+
+			LOG_D("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
+		}
+
+		/* Ensure Result-Code is present */
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &avp_model, ENOENT ) );
+		CHECK( 0, fd_msg_search_avp( msg, avp_model, &rc ) );
+
+		/* Check the Result-Code AVP value is DIAMETER_SUCCESS */
+		CHECK( 0, fd_msg_avp_hdr ( rc, &avpdata ) );
+		CHECK( ER_DIAMETER_SUCCESS, avpdata->avp_value->u32 );
+
+		/* Ensure Experimental-Result is missing */
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &avp_model, ENOENT ) );
+		CHECK( ENOENT, fd_msg_search_avp( msg, avp_model, NULL ) );
+
+		/* Free msg */
+		CHECK( 0, fd_msg_free( msg ) );
+	}
+
+	/* Test the fd_msg_add_result function for Experimental-Result */
+	{
+		struct msg		* msg = NULL;
+		struct dict_object	* avp_model = NULL;
+		struct avp		* er = NULL;
+		struct avp		* erc = NULL;
+		struct avp_hdr		* avpdata = NULL;
+
+		{
+			struct dict_object * cmd_model = NULL;
+			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Answer", &cmd_model, ENOENT ) );
+
+			/* Create a message */
+			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
+
+			/* Add a session id */
+			CHECK( 0, fd_msg_new_session( msg, (os0_t)"tm2", strlen("tm2") ) );
+
+			/* Find the DICT_TYPE Enumerated(73565/Experimental-Result-Code) */
+			struct dict_object * restype = NULL;
+			CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_BY_NAME, "Enumerated(73565/Experimental-Result-Code)", &restype, ENOENT ) );
+
+			/* Now test the behavior of fd_msg_add_result for Experimental-Result AVP */
+			CHECK( 0, fd_msg_add_result(msg, 73565, restype, "DIAMETER_TEST_RESULT_5000", NULL, NULL, 1) );
+
+			LOG_D("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
+		}
+
+		/* Ensure Result-Code is missing */
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &avp_model, ENOENT ) );
+		CHECK( ENOENT, fd_msg_search_avp( msg, avp_model, NULL ) );
+
+		/* Ensure Experimental-Result is present */
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &avp_model, ENOENT ) );
+		CHECK( 0, fd_msg_search_avp( msg, avp_model, &er ) );
+
+		/* Ensure Experimental-Result-Code is present */
+		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result-Code", &avp_model, ENOENT ) );
+		CHECK( 0, fd_msg_search_avp( er, avp_model, &erc ) );
+
+		/* Check the Experimental-Result-Code AVP value is 5000 */
+		CHECK( 0, fd_msg_avp_hdr ( erc, &avpdata ) );
+		CHECK( 5000, avpdata->avp_value->u32 );
+
+		/* Free msg */
+		CHECK( 0, fd_msg_free( msg ) );
+	}
+
 	/* Check IPv4 -> IPv6 and IPv6->IPv4 mapping */
 	{
