Index: include/freeDiameter/libfdproto.h
===================================================================
--- include/freeDiameter/libfdproto.h	(revision 1295)
+++ include/freeDiameter/libfdproto.h	(revision 1300)
@@ -1259,4 +1259,26 @@
 typedef int (*dict_avpdata_encode) (void * data, union avp_value * val);
 
+/*
+ * CALLBACK:	dict_avpdata_check
+ *
+ * PARAMETERS:
+ *   val	: Pointer to the AVP value that was received and needs to be sanity checked.
+ *   data      : a parameter stored in the type structure (to enable more generic check functions)
+ *   error_msg: upon erroneous value, a string describing the error can be returned here (it will be strcpy by caller). This description will be returned in the error message, if any. 
+ *
+ * DESCRIPTION: 
+ *   This callback can be provided with a derived type in order to improve the operation of the
+ *  fd_msg_parse_dict function. When this callback is present, the value of the AVP that has
+ * been parsed is passed to this function for finer granularity check. For example for some 
+ * speccific AVP, the format of an OCTETSTRING value can be further checked, or the
+ * interger value can be verified.
+ *
+ * RETURN VALUE:
+ *  0      	: The value is valid.
+ *  !0          : An error occurred, the error code is returned. It is advised to return EINVAL on incorrect val
+ */
+typedef int (*dict_avpdata_check) (void * data, union avp_value * val, char ** error_msg);
+
+
 
 /* Type to hold data associated to a derived AVP data type */
@@ -1267,4 +1289,6 @@
 	dict_avpdata_encode	 type_encode;	/* cb to convert formatted data into an AVP value (or NULL) */
 	DECLARE_FD_DUMP_PROTOTYPE((*type_dump), union avp_value * val); /* cb called by fd_msg_dump_* for this type of data (if != NULL). Returned string must be freed.  */
+	dict_avpdata_check       type_check;
+	void  *                          type_check_param;
 };
 
@@ -1293,4 +1317,7 @@
 DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump, union avp_value * avp_value);
 
+
+/* For string AVP, the following type_check function provides simple basic check for specific characters presence, e.g. use "@." for trivial email address check */
+int fd_dictfct_CharInOS_check(void * data, union avp_value * val, char ** error_msg);
 
 
Index: libfdproto/dictionary_functions.c
===================================================================
--- libfdproto/dictionary_functions.c	(revision 1284)
+++ libfdproto/dictionary_functions.c	(revision 1300)
@@ -359,2 +359,29 @@
 }
 
+/* Check that a given AVP value contains all the characters from data in the same order */
+static char error_message[80];
+int fd_dictfct_CharInOS_check(void * data, union avp_value * val, char ** error_msg)
+{
+	char * inChar = data;
+	char * inData = (char *)val->os.data;
+	int i = 0;
+	CHECK_PARAMS(data);
+	while (*inChar != '\0') {
+		while (i < val->os.len) {
+			if (*inChar == inData[i++]) {
+				inChar++;
+				break;
+			}
+		}
+		if (i >= val->os.len)
+			break;
+	}
+	if (*inChar == '\0')
+		return 0;
+	
+	if (error_msg) {
+		snprintf(error_message, sizeof(error_message), "Could not find '%c' in AVP", *inChar);
+		*error_msg = error_message;
+	}
+	return EBADMSG;
+}
Index: libfdproto/messages.c
===================================================================
--- libfdproto/messages.c	(revision 1298)
+++ libfdproto/messages.c	(revision 1300)
@@ -2037,4 +2037,6 @@
 {
 	struct dict_avp_data dictdata;
+	struct dict_type_data derivedtypedata;
+	struct dict_object * avp_derived_type = NULL;
 	uint8_t * source;
 	
@@ -2217,4 +2219,31 @@
 			break;
 	
+	}
+	
+	/* Is there a derived type check function ? */
+	CHECK_FCT ( fd_dict_search ( dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &avp_derived_type, 0) );
+	if (avp_derived_type) {
+		CHECK_FCT(  fd_dict_getval(avp_derived_type, &derivedtypedata)  );
+		if (derivedtypedata.type_check != NULL) {
+			char * err;
+			int ret = (*derivedtypedata.type_check)( derivedtypedata.type_check_param, &avp->avp_storage, &err );
+
+			if (ret != 0) {
+				TRACE_DEBUG(INFO, "The AVP failed to pass the dictionary validation");
+				if (error_info) {				
+						error_info->pei_errcode = "DIAMETER_INVALID_AVP_VALUE";
+						error_info->pei_avp = avp;
+						strncpy(error_message, err, sizeof(error_message));
+						error_info->pei_message = error_message;
+				} else {
+					char * buf = NULL;
+					size_t buflen;
+					CHECK_MALLOC(fd_msg_dump_treeview(&buf, &buflen, NULL, avp, NULL, 0, 0));
+					LOG_E("Invalid AVP: %s", buf);
+					free(buf);
+				}
+				return ret; /* should we just return EBADMSG? */
+			}
+		}
 	}
 	
Index: tests/testmesg.c
===================================================================
--- tests/testmesg.c	(revision 1281)
+++ tests/testmesg.c	(revision 1300)
@@ -309,4 +309,13 @@
 			#endif
 		}
+
+		{ 
+			struct dict_object  * type = NULL;
+			struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS test2", NULL, NULL, NULL, fd_dictfct_CharInOS_check, "@." };
+			struct dict_avp_data  avp_data = { 73575, 73565, "AVP Test - os2", 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 ) );
+		}
+		
 		#if 0
 		{
@@ -753,4 +762,46 @@
 				/* reset */
 				CHECK( 0, fd_msg_free ( msg ) );
+			}
+			
+			/* Test with a type verifier */
+			{
+				struct fd_pei error_info;
+				CPYBUF();
+				buf_cpy[103] = 0x67;	/* Replaced AVP code = 0x00011F67, OS test2 type in the dictionary */
+				
+				/* Check that we cannot support this message now */
+				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
+				CHECK( EBADMSG, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
+				
+				/* reset */
+				CHECK( 0, fd_msg_free ( msg ) );
+
+				CPYBUF();
+				buf_cpy[103] = 0x67;	/* Replaced AVP code = 0x00011F67, OS test2 type in the dictionary */
+				
+				/* Check error reporting works */
+				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
+				CHECK( EBADMSG, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, &error_info ) );
+				
+				#if 1
+				fd_log_debug("Error reported: %s\n in AVP: %s", error_info.pei_message, fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, error_info.pei_avp, fd_g_config->cnf_dict, 0, 1));
+				#endif
+				
+				/* reset */
+				CHECK( 0, fd_msg_free ( msg ) );
+				
+				CPYBUF();
+				buf_cpy[103] = 0x67;	/* Replaced AVP code = 0x00011F67, OS test2 type in the dictionary */
+				buf_cpy[130] = '@';
+				buf_cpy[140] = '.';     /* now we comply to the constraints */
+				
+				/* Check that we cannot support this message now */
+				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
+				CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
+				
+				/* reset */
+				CHECK( 0, fd_msg_free ( msg ) );
+				
+				
 			}
 			
@@ -1399,5 +1450,4 @@
 	}
 	
-
 	/* That's all for the tests yet */
 	PASSTEST();
