1 /*********************************************************************************************************
2 * Software License Agreement (BSD License)                                                               *
3 * Author: Sebastien Decugis <sdecugis@freediameter.net>							 *
4 *													 *
5 * Copyright (c) 2020, WIDE Project and NICT								 *
6 * All rights reserved.											 *
7 * 													 *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are  *
9 * permitted provided that the following conditions are met:						 *
10 * 													 *
11 * * Redistributions of source code must retain the above 						 *
12 *   copyright notice, this list of conditions and the 							 *
13 *   following disclaimer.										 *
14 *    													 *
15 * * Redistributions in binary form must reproduce the above 						 *
16 *   copyright notice, this list of conditions and the 							 *
17 *   following disclaimer in the documentation and/or other						 *
18 *   materials provided with the distribution.								 *
19 * 													 *
20 * * Neither the name of the WIDE Project or NICT nor the 						 *
21 *   names of its contributors may be used to endorse or 						 *
22 *   promote products derived from this software without 						 *
23 *   specific prior written permission of WIDE Project and 						 *
24 *   NICT.												 *
25 * 													 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
34 *********************************************************************************************************/
35 
36 #include "tests.h"
37 
38 /* Main test routine */
main(int argc,char * argv[])39 int main(int argc, char *argv[])
40 {
41 	struct msg * acr = NULL;
42 	struct avp * pi = NULL, *avp1, *avp2;
43 	unsigned char * buf = NULL;
44 
45 	/* First, initialize the daemon modules */
46 	INIT_FD();
47 
48 	/* Create the message object from model */
49 	{
50 		struct dict_object * acr_model = NULL;
51 
52 		/* Now find the ACR dictionary object */
53 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) );
54 
55 		/* Create the instance, using the templates */
56 		CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) );
57 
58 		/* Check there is no child */
59 		CHECK( ENOENT, fd_msg_browse ( acr, MSG_BRW_FIRST_CHILD, NULL, NULL) );
60 
61 		#if 0
62 		/* For debug: dump the object */
63 		fd_log_debug("Dumping Accounting-Request empty message:");
64 		fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, acr, fd_g_config->cnf_dict, 0, 1));
65 		#endif
66 	}
67 
68 	/* Create the Proxy-Info AVP from model */
69 	{
70 		struct dict_object * pi_model = NULL;
71 
72 		/* Now find the ACR dictionary object */
73 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &pi_model, ENOENT ) );
74 
75 		/* Create the instance, using the templates */
76 		CHECK( 0, fd_msg_avp_new ( pi_model, 0, &pi ) );
77 
78 		#if 0
79 		/* For debug: dump the object */
80 		fd_log_debug("Dumping Proxy-Info AVP");
81 		fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, pi, fd_g_config->cnf_dict, 0, 1));
82 		fd_log_debug("Dumping dictionary model");
83 		fd_log_debug("%s", fd_dict_dump_object(FD_DUMP_TEST_PARAMS, pi_model));
84 		#endif
85 
86 	}
87 
88 	/* Get a reference to the current last AVP in the message */
89 	{
90 		int diff = 0;
91 
92 		CHECK( 0, fd_msg_avp_new ( NULL, 0, &avp1 ) );
93 		CHECK( 0, fd_msg_avp_add ( acr, MSG_BRW_LAST_CHILD, avp1) );
94 
95 		CHECK( 0, fd_msg_browse ( acr, MSG_BRW_LAST_CHILD, &avp2, &diff) );
96 		CHECK( 1, diff );
97 		CHECK( avp1, avp2 );
98 
99 		/* Check that we cannot add this AVP to another object since it is already linked */
100 		CHECK( EINVAL, fd_msg_avp_add( pi, MSG_BRW_LAST_CHILD, avp1) );
101 	}
102 
103 	/* Now add the Proxy-Info AVP at the end of the message */
104 	{
105 		CHECK( 0, fd_msg_avp_add( acr, MSG_BRW_LAST_CHILD, pi) );
106 		#if 0
107 		/* For debug: dump the object */
108 		fd_log_debug("Dumping Accounting-Request with Proxy-Info AVP at the end");
109 		fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, acr, fd_g_config->cnf_dict, 0, 1));
110 		#endif
111 	}
112 
113 	/* Check the last child is now the proxy-Info */
114 	{
115 		CHECK( 0, fd_msg_browse ( acr, MSG_BRW_LAST_CHILD, &avp2, NULL) );
116 		CHECK( pi, avp2 );
117 	}
118 
119 	/* Check that the avp before the proxy-info is the previous last one */
120 	{
121 		int diff = 0;
122 		CHECK( 0, fd_msg_browse ( pi, MSG_BRW_PREV, &avp2, &diff) );
123 		CHECK( avp1, avp2 );
124 		CHECK( 0, diff);
125 	}
126 
127 	/* Check that there are no AVP after the proxy-info */
128 	CHECK( ENOENT, fd_msg_browse ( pi, MSG_BRW_NEXT, NULL, NULL) );
129 
130 	/* Test the fd_msg_free function unlinks the object properly */
131 	{
132 		struct dict_object * rr_model = NULL;
133 
134 		/* Now find the dictionary object */
135 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &rr_model, ENOENT ) );
136 
137 		/* Create the instance, using the templates */
138 		CHECK( 0, fd_msg_avp_new ( rr_model, 0, &avp1 ) );
139 
140 		/* Add the AVP at the end of the message */
141 		CHECK( 0, fd_msg_avp_add( pi, MSG_BRW_NEXT, avp1) );
142 
143 		/* Check the last AVP of the message is now this one */
144 		CHECK( 0, fd_msg_browse ( acr, MSG_BRW_LAST_CHILD, &avp2, NULL) );
145 		CHECK( avp1, avp2 );
146 
147 		/* Now delete it */
148 		CHECK( 0, fd_msg_free( avp1 ) );
149 
150 		/* Check the last AVP of the message is back to pi */
151 		CHECK( 0, fd_msg_browse ( acr, MSG_BRW_LAST_CHILD, &avp2, NULL) );
152 		CHECK( pi, avp2 );
153 
154 		/* Delete the whole message */
155 		CHECK( 0, fd_msg_free( acr ) );
156 	}
157 
158 	/* Recreate the message object */
159 	{
160 		struct dict_object * acr_model = NULL;
161 
162 		/* Now find the ACR dictionary object */
163 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) );
164 
165 		/* Create the instance, using the templates */
166 		CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) );
167 
168 /* TODO: Do we need this recreated? acr is not used again . */
169 	}
170 
171 	/* Now let's create some additional Dictionary objects for the test */
172 	{
173 		/* The constant values used here are totally arbitrary chosen */
174 		struct dict_object * vendor;
175 		{
176 			struct dict_vendor_data vendor_data = { 73565, "Vendor test" };
177 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_VENDOR, &vendor_data , NULL, &vendor ) );
178 		}
179 
180 		{
181 			struct dict_application_data app_data = { 73566, "Application test" };
182 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app_data , vendor, NULL ) );
183 		}
184 
185 		{
186 			struct dict_avp_data avp_data = { 73567, 0, "AVP Test - no vendor - f32", 0, 0, AVP_TYPE_FLOAT32 };
187 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
188 		}
189 
190 		{
191 			struct dict_avp_data avp_data = { 139103, 0, "AVP Test - no vendor - f64", 0, 0, AVP_TYPE_FLOAT64 };
192 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
193 		}
194 
195 		{
196 			struct dict_object  * type = NULL;
197 			struct dict_type_data type_data = { AVP_TYPE_INTEGER64, "Int64 test" };
198 			struct dict_avp_data  avp_data = { 73568, 73565, "AVP Test - i64", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER64 };
199 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
200 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
201 		}
202 
203 		{
204 			struct dict_object     * type = NULL;
205 			struct dict_type_data    type_data = { AVP_TYPE_INTEGER32, "Enum32 test" };
206 			struct dict_enumval_data val1 = { "i32 const test (val 1)", { .i32 = 1 } };
207 			struct dict_enumval_data val2 = { "i32 const test (val 2)", { .i32 = 2 } };
208 			struct dict_enumval_data val3 = { "i32 const test (val -5)",{ .i32 = -5 } };
209 			struct dict_avp_data     avp_data = { 73569, 73565, "AVP Test - enumi32", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER32 };
210 
211 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
212 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
213 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
214 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
215 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val3 , type, NULL ) );
216 		}
217 
218 		{
219 			struct dict_object  * type = NULL;
220 			struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS test" };
221 			struct dict_avp_data  avp_data = { 73570, 73565, "AVP Test - os", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
222 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
223 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
224 		}
225 
226 		{
227 			struct dict_object     * type = NULL;
228 			struct dict_type_data    type_data = { AVP_TYPE_OCTETSTRING, "OS enum test" };
229 			struct dict_enumval_data val1 = { "os const test (Test)", { .os = { (unsigned char *)"Test", 4 } } };
230 			struct dict_enumval_data val2 = { "os const test (waaad)", { .os = { (unsigned char *)"waaad", 5 } } };
231 			struct dict_enumval_data val3 = { "os const test (waa)", { .os = { (unsigned char *)"waaad", 3 } } };
232 			struct dict_avp_data     avp_data = { 73571, 73565, "AVP Test - enumos", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
233 
234 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
235 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
236 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
237 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
238 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val3 , type, NULL ) );
239 		}
240 
241 		{
242 			struct dict_object * gavp = NULL;
243 			struct dict_avp_data avp_data = { 73572, 73565, "AVP Test - grouped", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED };
244 
245 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, &gavp ) );
246 
247 			/* Macro to search AVP and create a rule */
248 			#define ADD_RULE( _parent, _vendor, _avpname, _pos, _min, _max, _ord ) {		\
249 				struct dict_object * _avp = NULL;						\
250 				struct dict_avp_request _req = { (_vendor), 0, (_avpname) };			\
251 				struct dict_rule_data _data;							\
252 				CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\
253 				_data.rule_avp = _avp;								\
254 				_data.rule_position = (_pos);							\
255 				_data.rule_order = (_ord);							\
256 				_data.rule_min = (_min);							\
257 				_data.rule_max = (_max);							\
258 				CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &_data , (_parent), NULL ) );	\
259 			}
260 
261 			ADD_RULE(gavp, 73565, "AVP Test - os", RULE_OPTIONAL,   -1, -1,  0);
262 
263 		}
264 
265 		{
266 			struct dict_object  * application = NULL;
267 			struct dict_object  * command = NULL;
268 			struct dict_cmd_data  cmd_data = { 73573, "Test-Command-Request", CMD_FLAG_REQUEST, CMD_FLAG_REQUEST };
269 
270 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) );
271 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd_data , application, &command ) );
272 			ADD_RULE(command, 0,     "AVP Test - no vendor - f32", 	RULE_FIXED_HEAD, -1,  1,  1);
273 			ADD_RULE(command, 73565, "AVP Test - i64",		RULE_REQUIRED,   -1, -1,  0);
274 			ADD_RULE(command, 73565, "AVP Test - enumi32", 		RULE_OPTIONAL,   -1, -1,  0);
275 			ADD_RULE(command, 73565, "AVP Test - os", 		RULE_OPTIONAL,   -1, -1,  0);
276 			ADD_RULE(command, 73565, "AVP Test - enumos", 		RULE_OPTIONAL,   -1, -1,  0);
277 			ADD_RULE(command, 73565, "AVP Test - grouped", 		RULE_OPTIONAL,   -1, -1,  0);
278 		}
279 
280 		{
281 			struct dict_object  * application = NULL;
282 			struct dict_object  * command = NULL;
283 			struct dict_cmd_data  cmd_data = { 73573, "Test-Command-Answer", CMD_FLAG_REQUEST, 0 };
284 
285 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) );
286 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd_data , application, &command ) );
287 			ADD_RULE(command, 0, "Session-Id",			RULE_FIXED_HEAD, 1, 1, 1);
288 			ADD_RULE(command, 0, "Result-Code",			RULE_OPTIONAL,   0, 1, 0);
289 			ADD_RULE(command, 0, "Experimental-Result",		RULE_OPTIONAL,   0, 1, 0);
290 			ADD_RULE(command, 0, "Origin-Host",			RULE_REQUIRED,   1, 1, 0);
291 			ADD_RULE(command, 0, "Origin-Realm",			RULE_REQUIRED,   1, 1, 0);
292 		}
293 
294 		{
295 			struct dict_object  * gavp = NULL;
296 			struct dict_avp_data  avp_data = { 73574, 73565, "AVP Test - rules", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED };
297 
298 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, &gavp ) );
299 
300 			ADD_RULE(gavp,     0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD,   0, 1, 1);
301 			ADD_RULE(gavp, 73565, "AVP Test - i64", 	    RULE_FIXED_HEAD,  -1, 1, 2);
302 			ADD_RULE(gavp, 73565, "AVP Test - enumi32", 	    RULE_FIXED_HEAD,  -1, 1, 3);
303 			ADD_RULE(gavp, 73565, "AVP Test - os", 	    	    RULE_REQUIRED,     2, 3, 0);
304 			ADD_RULE(gavp, 73565, "AVP Test - enumos",     	    RULE_OPTIONAL,     0, 1, 0);
305 			ADD_RULE(gavp, 73565, "AVP Test - grouped",         RULE_FIXED_TAIL,  -1, 1, 1);
306 			/* ABNF :
307 				< no vendor - f32 >
308 				< i64 >
309 				< enumi32 >
310 			    2*3 { os }
311 			     *1 [ enumos ]
312 				< grouped >
313 						*/
314 			#if 0
315 			fd_log_debug("%s", fd_dict_dump_object(FD_DUMP_TEST_PARAMS, gavp));
316 			#endif
317 		}
318 
319 		{
320 			struct dict_object  * type = NULL;
321 			struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS test2", NULL, NULL, NULL, fd_dictfct_CharInOS_check, "@." };
322 			struct dict_avp_data  avp_data = { 73575, 73565, "AVP Test - os2", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING };
323 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
324 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
325 		}
326 
327 		{
328 			struct dict_object     * type = NULL;
329 			struct dict_type_data    type_data = { AVP_TYPE_UNSIGNED32, "Enumerated(73565/Experimental-Result-Code)" };
330 			struct dict_avp_data     avp_data = { 73576, 73565, "Experimental-Result-Code", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_UNSIGNED32 };
331 			struct dict_enumval_data val1 = { "DIAMETER_TEST_RESULT_1000", { .u32 = 1000 } };
332 			struct dict_enumval_data val2 = { "DIAMETER_TEST_RESULT_5000", { .u32 = 5000 } };
333 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) );
334 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) );
335 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) );
336 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) );
337 		}
338 
339 		#if 0
340 		{
341 			fd_log_debug("%s", fd_dict_dump_object(FD_DUMP_TEST_PARAMS, vendor));
342 		}
343 		#endif
344 	}
345 
346 	/* Now create some values and check the length is correctly handled */
347 	{
348 		struct dict_object * cmd_model = NULL;
349 		struct msg         * msg = NULL;
350 		struct dict_object * avp_model = NULL;
351 		struct avp         * avp = NULL;
352 		union avp_value      value;
353 
354 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) );
355 
356 		/* Check an error is trigged if the AVP has no value set */
357 		{
358 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP,     AVP_BY_NAME,     "AVP Test - no vendor - f32", &avp_model, ENOENT ) );
359 
360 			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
361 			CHECK( 0, fd_msg_avp_new ( avp_model, 0, &avp ) );
362 
363 			CHECK( 0, fd_msg_avp_add ( msg, MSG_BRW_FIRST_CHILD, avp ) );
364 
365 			CHECK( EINVAL, fd_msg_update_length ( avp ) );
366 			CHECK( EINVAL, fd_msg_update_length ( msg ) );
367 
368 			CHECK( 0, fd_msg_free( msg ) );
369 		}
370 
371 		/* Check the sizes are handled properly */
372 		{
373 			struct avp * avpi = NULL;
374 			struct avp * avpch = NULL;
375 			struct avp_hdr * avpdata = NULL;
376 			struct msg_hdr * msgdata = NULL;
377 			#define ADD_AVP( _parent, _position, _avpi, _avpvendor, _avpname) {			\
378 				struct dict_object * _avp = NULL;						\
379 				struct dict_avp_request _req = { (_avpvendor), 0, (_avpname) };			\
380 				CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\
381 				CHECK( 0, fd_msg_avp_new ( _avp, 0, &_avpi ) );					\
382 				CHECK( 0, fd_msg_avp_add ( (_parent), (_position), _avpi ) );			\
383 			}
384 			/* Create a message with many AVP inside */
385 			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
386 			CHECK( 0, fd_msg_hdr ( msg, &msgdata ) );
387 
388 			/* Avp no vendor, float32 => size = 12 */
389 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,     "AVP Test - no vendor - f32" );
390 			value.f32 = 3.1415;
391 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
392 			CHECK( 0, fd_msg_update_length ( avpi ) );
393 			#if 0
394 			fd_log_debug("AVP no vendor, value 3.1415:");
395 			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
396 			#endif
397 			CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
398 			CHECK( 12, avpdata->avp_len );
399 
400 			/* Check what happens when we delete the value */
401 			CHECK( 0, fd_msg_avp_setvalue ( avpi, NULL ) );
402 			CHECK( EINVAL, fd_msg_update_length ( avpi ) );
403 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
404 
405 			/* Add a vendor AVP, integer64 => size = 20 */
406 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - i64" );
407 			value.i64 = 0x123456789abcdeLL;
408 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
409 			CHECK( 0, fd_msg_update_length ( avpi ) );
410 			#if 0
411 			fd_log_debug("AVP vendor, value 0x123456789abcdeL:");
412 			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
413 			#endif
414 			CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
415 			CHECK( 20, avpdata->avp_len );
416 
417 			/* Check the size of the message is 20 (header) + 12 + 20 = 52 */
418 			CHECK( 0, fd_msg_update_length ( msg ) );
419 			CHECK( 52, msgdata->msg_length );
420 
421 			/* Add an AVP with an enum value */
422 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
423 			{
424 				struct dict_object * type_model = NULL;
425 				struct dict_object * value_model = NULL;
426 				struct dict_enumval_request request;
427 
428 				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
429 				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
430 				memset(&request, 0, sizeof(request));
431 				request.type_obj = type_model;
432 				request.search.enum_name = "i32 const test (val 2)";
433 				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
434 				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
435 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
436 				#if 0
437 				fd_log_debug("AVP enum i32, value 2 (from const):");
438 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
439 				#endif
440 			}
441 
442 			/* Add an AVP with an enum value, negative */
443 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
444 			{
445 				struct dict_object  * type_model = NULL;
446 				struct dict_object  * value_model = NULL;
447 				struct dict_enumval_request request;
448 
449 				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
450 				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
451 				memset(&request, 0, sizeof(request));
452 				request.type_obj = type_model;
453 				request.search.enum_name = "i32 const test (val -5)";
454 				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
455 				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
456 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
457 				#if 0
458 				fd_log_debug("AVP enum i32, value -5 (from const):");
459 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
460 				#endif
461 				/* Check the size is correct ( 12 for header + 4 for value ) */
462 				CHECK( 0, fd_msg_update_length ( avpi ) );
463 				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
464 				CHECK( 16, avpdata->avp_len );
465 			}
466 
467 			/* Now add a value which is not a constant into an enumerated AVP */
468 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumi32" );
469 			value.i32 = -10;
470 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
471 			CHECK( 0, fd_msg_update_length ( avpi ) );
472 			#if 0
473 			fd_log_debug("AVP vendor enum i32, value -10 (not const):");
474 			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
475 			#endif
476 
477 			/* Add an octetstring AVP */
478 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - os" );
479 			{
480 				unsigned char buf[90];
481 				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);
482 				value.os.data = buf;
483 				value.os.len = 89;
484 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
485 				memset(&buf, 0, sizeof(buf)); /* Test that the OS value is really copied */
486 				CHECK( 0, fd_msg_update_length ( avpi ) );
487 				#if 0
488 				fd_log_debug("AVP octet string, 'This\\0 is a b...'");
489 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
490 				#endif
491 				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
492 				CHECK( 101, avpdata->avp_len );
493 				CHECK( 'T', avpdata->avp_value->os.data[0] );
494 				CHECK( 'i', avpdata->avp_value->os.data[6] );
495 			}
496 
497 			/* Check the size of the message is 20 (header) + 12 + 20 + 16 * 3 + 101 + 3 (padding) = 204 */
498 			CHECK( 0, fd_msg_update_length ( msg ) );
499 			CHECK( 204, msgdata->msg_length );
500 
501 			/* Add an octetstring from an enumerated constant */
502 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumos" );
503 			{
504 				struct dict_object  * type_model = NULL;
505 				struct dict_object  * value_model = NULL;
506 				struct dict_enumval_request request;
507 
508 				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
509 				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
510 				memset(&request, 0, sizeof(request));
511 				request.type_obj = type_model;
512 				request.search.enum_name = "os const test (waaad)";
513 				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
514 				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
515 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
516 				#if 0
517 				fd_log_debug("AVP Enumuerated OctetString (from const):");
518 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
519 				#endif
520 				/* Check the size is correct ( 12 for header + 5 for value ) */
521 				CHECK( 0, fd_msg_update_length ( avpi ) );
522 				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
523 				CHECK( 17, avpdata->avp_len );
524 			}
525 
526 			/* Add an octetstring from an enumerated constant */
527 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - enumos" );
528 			{
529 				struct dict_object  * type_model = NULL;
530 				struct dict_object  * value_model = NULL;
531 				struct dict_enumval_request request;
532 
533 				CHECK( 0, fd_msg_model ( avpi, &avp_model ) );
534 				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) );
535 				memset(&request, 0, sizeof(request));
536 				request.type_obj = type_model;
537 				request.search.enum_name = "os const test (waa)";
538 				CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) );
539 				CHECK( 0, fd_dict_getval ( value_model, &request.search ) );
540 				CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) );
541 				#if 0
542 				fd_log_debug("AVP Enumuerated OctetString (from const):");
543 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpi, fd_g_config->cnf_dict, 0, 0));
544 				#endif
545 				/* Check the size is correct ( 12 for header + 3 for value ) */
546 				CHECK( 0, fd_msg_update_length ( avpi ) );
547 				CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
548 				CHECK( 15, avpdata->avp_len );
549 			}
550 
551 
552 			/* Check the size of the message is 20 (header) + 12 + 20 + 16 * 3 + (101 + 3) + (17 + 3) + (15 + 1) = 240 */
553 			CHECK( 0, fd_msg_update_length ( msg ) );
554 			CHECK( 240, msgdata->msg_length );
555 
556 			/* Now test the grouped AVPs */
557 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - grouped" );
558 			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
559 			  {
560 				value.os.data = (unsigned char *)"12345678";
561 				value.os.len = 8;
562 				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
563 				#if 0
564 				fd_log_debug("AVP octet string, '1234678'");
565 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpch, fd_g_config->cnf_dict, 0, 0));
566 				#endif
567 				CHECK( 0, fd_msg_update_length ( avpch ) );
568 				CHECK( 0, fd_msg_avp_hdr ( avpch, &avpdata ) );
569 				CHECK( 20, avpdata->avp_len );
570 			  }
571 			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
572 			  {
573 				value.os.data = (unsigned char *)"123456789";
574 				value.os.len = 9;
575 				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
576 				#if 0
577 				fd_log_debug("AVP octet string, '12346789'");
578 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, avpch, fd_g_config->cnf_dict, 0, 0));
579 				#endif
580 			  }
581 
582 			/* Check the size is updated recursively: (gavp hdr: 12) + (avp1: 20) + (avp2: 21 + 3) = 56 */
583 			CHECK( 0, fd_msg_update_length ( avpi ) );
584 			CHECK( 0, fd_msg_avp_hdr ( avpi, &avpdata ) );
585 			CHECK( 56, avpdata->avp_len );
586 
587 			/* Add another similar grouped AVP, to have lot of padding */
588 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 73565, "AVP Test - grouped" );
589 			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
590 			  {
591 				value.os.data = (unsigned char *)"1";
592 				value.os.len = 1;
593 				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
594 			  }
595 			  ADD_AVP( avpi, MSG_BRW_LAST_CHILD, avpch, 73565, "AVP Test - os" );
596 			  {
597 				value.os.data = (unsigned char *)"1234567";
598 				value.os.len = 7;
599 				CHECK( 0, fd_msg_avp_setvalue ( avpch, &value ) );
600 			  }
601 
602 			/* Now check the global size of the message, if padding is correctly handled */
603 			/* size = 20 (header) + 12 + 20 + 16 * 3 + (101 + 3) + (17 + 3) + (15 + 1)
604 			 *        + ( 12 + ( 20 + 21) + 3 )         # padding for the grouped AVP = 3
605 			 *        + ( 12 + ( (13 + 3) + 19 ) + 1 )  # and 1 for this one
606 			 * size = 240 + 56 + 48 = 344
607 			 */
608 			CHECK( 0, fd_msg_update_length ( msg ) );
609 			#if 0
610 			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
611 			#endif
612 			CHECK( 344, msgdata->msg_length );
613 
614 			/* Set the application to the test application: 73566 */
615 			msgdata->msg_appl = 73566;
616 
617 			/* Set the hop-by-hop ID to a random value: 0x4b44b41d */
618 			msgdata->msg_hbhid = 0x4b44b41d;
619 			/* Set the end-to-end ID to a random value: 0xe2ee2e1d */
620 			msgdata->msg_eteid = 0xe2ee2e1d;
621 		}
622 
623 		/* Test the msg_bufferize function */
624 		{
625 
626 			CHECK( 0, fd_msg_bufferize( msg, &buf, NULL ) );
627 
628 			/* Test the first bytes */
629 			CHECK( 0x01, buf[0] ); /* Version */
630 			CHECK( 0x00, buf[1] ); /* Length: 344 = 0x000158 */
631 			CHECK( 0x01, buf[2] );
632 			CHECK( 0x58, buf[3] );
633 			CHECK( 0x80, buf[4] ); /* flags: only "R" is set. */
634 			CHECK( 0x01, buf[5] ); /* Command code: 73573 = 0x011F65 */
635 			CHECK( 0x1F, buf[6] );
636 			CHECK( 0x65, buf[7] );
637 			CHECK( 0x00, buf[8] ); /* App ID: 73566 = 0x00011F5E */
638 			CHECK( 0x01, buf[9] );
639 			CHECK( 0x1F, buf[10] );
640 			CHECK( 0x5E, buf[11] );
641 			CHECK( 0x4b, buf[12] ); /* hop-by-hop id: 0x4b44b41d */
642 			CHECK( 0x44, buf[13] );
643 			CHECK( 0xb4, buf[14] );
644 			CHECK( 0x1d, buf[15] );
645 			CHECK( 0xe2, buf[16] ); /* end-to-end id: 0xe2ee2e1d */
646 			CHECK( 0xee, buf[17] );
647 			CHECK( 0x2e, buf[18] );
648 			CHECK( 0x1d, buf[19] );
649 
650 			CHECK( 0x00, buf[20] ); /* First AVP (AVP Test - no vendor - f32) begin: code 73567 = 0x00011F5F */
651 			CHECK( 0x01, buf[21] );
652 			CHECK( 0x1F, buf[22] );
653 			CHECK( 0x5F, buf[23] );
654 			CHECK( 0x00, buf[24] ); /* flags: 0 */
655 			CHECK( 0x00, buf[25] ); /* length: 12 = 0x00000c */
656 			CHECK( 0x00, buf[26] );
657 			CHECK( 0x0C, buf[27] );
658 			CHECK( 0x40, buf[28] ); /* Value: 3.1415:  sign = '+' => most significant bit = 0 */
659 			CHECK( 0x49, buf[29] ); /* 2 <= 3.1415 < 4 => exponent = 1 => biaised (on 8 bits) = (decimal) 128 = (binary) 100 0000 0 */
660 			CHECK( 0x0e, buf[30] ); /* significand = (decimal) 1.57075 = (binary) 1.100 1001 0000 1110 0101 0110 */
661 			CHECK( 0x56, buf[31] ); /* total => 0100 0000 0100 1001 0000 1110 0101 0110 = (hexa) 40 49 0e 56*/
662 
663 			/* The other AVPs will be tested by successful parsing... */
664 		}
665 
666 		/* Now free the message, we keep only the buffer. */
667 		CHECK( 0, fd_msg_free( msg ) );
668 
669 	}
670 
671 	/* Test the parsing of buffers and messages */
672 	{
673 		unsigned char * buf_cpy = NULL;
674 		struct msg * msg;
675 
676 		#define CPYBUF() {			\
677 			buf_cpy = malloc(344);		\
678 			CHECK( buf_cpy ? 1 : 0, 1);	\
679 			memcpy(buf_cpy, buf, 344);	\
680 		}
681 
682 		/* Test the msg_parse_buffer function */
683 		{
684 			CPYBUF();
685 			CHECK( EBADMSG, fd_msg_parse_buffer( &buf_cpy, 340, &msg) );
686 
687 			CPYBUF();
688 			CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
689 			#if 0
690 			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
691 			#endif
692 
693 			/* reinit the msg */
694 			CHECK( 0, fd_msg_free ( msg ) );
695 
696 		}
697 
698 		/* Test the fd_msg_search_avp function */
699 		{
700 			struct dict_object * avp_model;
701 			struct avp 	   * found;
702 			struct avp 	   * grouped = NULL;
703 			struct avp_hdr     * avpdata = NULL;
704 
705 			/* Now find the Test f32 AVP dictionary object */
706 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) );
707 
708 			CPYBUF();
709 			CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
710 			CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
711 #if 0
712 			LOG_D("msg: %s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
713 #endif
714 
715 			/* Search this AVP instance in the msg */
716 			CHECK( 0, fd_msg_search_avp( msg, avp_model, &found ) );
717 
718 			/* Check the AVP value is 3.1415 */
719 			CHECK( 0, fd_msg_avp_hdr ( found, &avpdata ) );
720 			CHECK( 3.1415F, avpdata->avp_value->f32 );
721 
722 			/* Search for the first grouped message */
723 			{
724 			struct dict_avp_request grouped_req = { 73565, 0, "AVP Test - grouped"};
725 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &grouped_req, &avp_model, ENOENT ) );
726 			}
727 			CHECK( 0, fd_msg_search_avp( msg, avp_model, &grouped ) );
728 #if 0
729 			LOG_D("grouped: %s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, grouped, fd_g_config->cnf_dict, 0, 1));
730 #endif
731 
732 			/* Find the first item in the grouped */
733 			{
734 			struct dict_avp_request avp_req = { 73565, 0, "AVP Test - os"};
735 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &avp_req, &avp_model, ENOENT ) );
736 			}
737 
738 			CHECK( 0, fd_msg_search_avp( grouped, avp_model, &found ) );
739 
740 			/* Check the AVP value is "1" */
741 			CHECK( 0, fd_msg_avp_hdr ( found, &avpdata ) );
742 			CHECK( 8, avpdata->avp_value->os.len );
743 			CHECK( 0, memcmp(avpdata->avp_value->os.data, "12345678", 8));
744 
745 			/* reinit the msg */
746 			CHECK( 0, fd_msg_free ( msg ) );
747 
748 		}
749 
750 		/* Test the msg_parse_dict function */
751 		{
752 			/* Test with an unknown command code */
753 			{
754 				CPYBUF();
755 
756 				/* Change the command-code */
757 				buf_cpy[5] = 0x11;
758 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
759 				CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
760 
761 				/* reset */
762 				CHECK( 0, fd_msg_free ( msg ) );
763 			}
764 
765 			/* Test with an unknown Mandatory AVP */
766 			{
767 				CPYBUF();
768 
769 				buf_cpy[20] = 0x11;	/* New AVP code = 0x11011F5F, undefined */
770 				buf_cpy[24] = 0x40; 	/* Add the 'M' flag */
771 
772 				/* Check that we cannot support this message now */
773 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
774 				CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
775 
776 				/* reset */
777 				CHECK( 0, fd_msg_free ( msg ) );
778 			}
779 
780 			/* Test with an unknown optional AVP */
781 			{
782 				CPYBUF();
783 
784 				buf_cpy[20] = 0x11;	/* New AVP code = 0x11011F5F, undefined */
785 
786 				/* Check that we can support this message now */
787 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
788 				CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
789 
790 				#if 0
791 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
792 				#endif
793 
794 				/* reset */
795 				CHECK( 0, fd_msg_free ( msg ) );
796 			}
797 
798 			/* Test with an invalid AVP (definition mismatch with the dictionary) */
799 			{
800 				CPYBUF();
801 
802 				buf_cpy[21] = 0x02;	/* New AVP code = 0x00021F5F, f64 type in the dictionary */
803 
804 
805 				/* Check that we cannot support this message now */
806 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
807 				CHECK( EBADMSG, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
808 
809 				/* reset */
810 				CHECK( 0, fd_msg_free ( msg ) );
811 			}
812 
813 			/* Test with a type verifier */
814 			{
815 				struct fd_pei error_info;
816 				CPYBUF();
817 				buf_cpy[103] = 0x67;	/* Replaced AVP code = 0x00011F67, OS test2 type in the dictionary */
818 
819 				/* Check that we cannot support this message now */
820 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
821 				CHECK( EBADMSG, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
822 
823 				/* reset */
824 				CHECK( 0, fd_msg_free ( msg ) );
825 
826 				CPYBUF();
827 				buf_cpy[103] = 0x67;	/* Replaced AVP code = 0x00011F67, OS test2 type in the dictionary */
828 
829 				/* Check error reporting works */
830 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
831 				CHECK( EBADMSG, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, &error_info ) );
832 
833 				#if 1
834 				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));
835 				#endif
836 
837 				/* reset */
838 				CHECK( 0, fd_msg_free ( msg ) );
839 
840 				CPYBUF();
841 				buf_cpy[103] = 0x67;	/* Replaced AVP code = 0x00011F67, OS test2 type in the dictionary */
842 				buf_cpy[130] = '@';
843 				buf_cpy[140] = '.';     /* now we comply to the constraints */
844 
845 				/* Check that we cannot support this message now */
846 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
847 				CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
848 
849 				/* reset */
850 				CHECK( 0, fd_msg_free ( msg ) );
851 
852 
853 			}
854 
855 			{
856 				unsigned char * buftmp = NULL;
857 				struct msg * error;
858 				/* Check the parse or error works as expected */
859 				CPYBUF();
860 
861 				buf_cpy[21] = 0x02;	/* New AVP code = 0x00021F5F, f64 type in the dictionary */
862 
863 				/* Check that we cannot support this message now */
864 				CHECK( 0, fd_msg_init() );
865 				CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) );
866 				CHECK( EBADMSG, fd_msg_parse_or_error( &msg, &error ) );
867 				CHECK( NULL, msg );
868 				msg = error;
869 
870 				CHECK( 0, fd_msg_bufferize( msg, &buftmp, NULL ) );
871 
872 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
873 
874 				TODO("Check the Failed-AVP is as expected");
875 
876 
877 				/* reset */
878 				CHECK( 0, fd_msg_free ( msg ) );
879 				free(buftmp);
880 			}
881 
882 
883 			CHECK( 0, fd_msg_parse_buffer( &buf, 344, &msg) );
884 			CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
885 			#if 0
886 			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
887 			#endif
888 		}
889 
890 		/* Now test the msg_parse_rule function */
891 		{
892 			struct fd_pei pei;
893 
894 			CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ) );
895 
896 			/* Use the "AVP Test - rules" AVP to test the rules */
897 			{
898 				struct avp * tavp = NULL;
899 				struct avp * tempavp = NULL;
900 				struct avp * childavp = NULL;
901 
902 				ADD_AVP( msg, MSG_BRW_LAST_CHILD, tavp, 73565, "AVP Test - rules" );
903 
904 				/* Create a conforming message first */
905 				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp,     0, "AVP Test - no vendor - f32" );
906 				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - i64" );
907 				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - enumi32" );
908 				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - os" );
909 				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - os" );
910 				ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - grouped" );
911 
912 				/* Check the message is still conform */
913 				CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ) );
914 
915 				/* The first avp is optional in fixed position, so remove it and check the message is still OK */
916 				CHECK( 0, fd_msg_browse ( tavp, MSG_BRW_FIRST_CHILD, &childavp, NULL) );
917 				CHECK( 0, fd_msg_free ( childavp ) );
918 				CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ) );
919 				ADD_AVP( tavp, MSG_BRW_FIRST_CHILD, childavp,     0, "AVP Test - no vendor - f32" );
920 
921 
922 				/* Now break some rules and check it is detected */
923 				#define CHECK_CONFLICT( _msg, _error, _conflictavp_name, _conflictavp_vnd )		{	\
924 					struct fd_pei _pei;									\
925 					CHECK( EBADMSG,  fd_msg_parse_rules( _msg, fd_g_config->cnf_dict, &_pei ) );		\
926 					if (_error) {										\
927 						CHECK( 0, strcmp( _error, _pei.pei_errcode ) );					\
928 					}											\
929 					if ((_conflictavp_name) == NULL) {							\
930 						CHECK( NULL, _pei.pei_avp);							\
931 					} else {										\
932 						struct dict_avp_request _req = { (_conflictavp_vnd), 0, (_conflictavp_name) };	\
933 						struct dict_object *    _avp;							\
934 						struct dict_object * _conflict;							\
935 						CHECK( 1, (_pei.pei_avp) ? 1 : 0 );						\
936 						CHECK( 0, fd_msg_model( _pei.pei_avp, &_conflict ) );				\
937 						CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));	\
938 						CHECK( _avp, _conflict );							\
939 					}											\
940 				}
941 
942 			/* ABNF :
943 				< no vendor - f32 >
944 				< i64 >
945 				< enumi32 >
946 			    2*3 { os }
947 			     *1 [ enumos ]
948 				< grouped >
949 						*/
950 				{
951 					/* Test the FIXED_HEAD rules positions: add another AVP before the third */
952 					CHECK( 0, fd_msg_browse ( tavp, MSG_BRW_FIRST_CHILD, &tempavp, NULL) ); /* tempavp is the novendor avp */
953 					CHECK( 0, fd_msg_browse ( tempavp, MSG_BRW_NEXT, &tempavp, NULL) );     /* tempavp is the i64 avp */
954 					ADD_AVP( tempavp, MSG_BRW_NEXT, childavp, 73565, "AVP Test - os" );
955 
956 					CHECK_CONFLICT( msg, "DIAMETER_MISSING_AVP", "AVP Test - enumi32", 73565 );
957 
958 					/* Now remove this AVP */
959 					CHECK( 0, fd_msg_free ( childavp ) );
960 				}
961 				{
962 					/* Remove the third AVP, same rule must conflict */
963 					CHECK( 0, fd_msg_browse ( tempavp, MSG_BRW_NEXT, &childavp, NULL) );     /* childavp is the enumi32 avp */
964 					CHECK( 0, fd_msg_free ( childavp ) );
965 
966 					CHECK_CONFLICT( msg, "DIAMETER_MISSING_AVP", "AVP Test - enumi32", 73565 );
967 
968 					/* Add the AVP back */
969 					ADD_AVP( tempavp, MSG_BRW_NEXT, childavp, 73565, "AVP Test - enumi32" );
970 				}
971 
972 				{
973 					/* Test the minimum value in the REQUIRED rule: delete one of the os AVPs */
974 					CHECK( 0, fd_msg_browse ( childavp, MSG_BRW_NEXT, &tempavp, NULL) );     /* tempavp is the os avp */
975 					CHECK( 0, fd_msg_free ( tempavp ) );
976 
977 					CHECK_CONFLICT( msg, "DIAMETER_MISSING_AVP", "AVP Test - os", 73565 ); /* The rule requires at least 2 AVP, we have only 1 */
978 
979 					/* Now add this AVP */
980 					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" );
981 				}
982 				{
983 					/* Test the maximum value in the REQUIRED rule: add more of the os AVPs */
984 					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" );
985 					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" );
986 
987 					CHECK_CONFLICT( msg, "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES", "AVP Test - os", 73565 ); /* The rule requires at most 3 AVP, we have 4 */
988 
989 					/* Now delete these AVP */
990 					CHECK( 0, fd_msg_free ( tempavp ) );
991 					CHECK( 0, fd_msg_browse ( childavp, MSG_BRW_NEXT, &tempavp, NULL) );
992 					CHECK( 0, fd_msg_free ( tempavp ) );
993 				}
994 
995 				{
996 					/* Test the maximum value in the OPTIONAL rule: add 2 enumos AVPs */
997 					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" );
998 
999 					/* The message is still conform */
1000 					CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ) );
1001 
1002 					/* Now break the rule */
1003 					ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" );
1004 
1005 					CHECK_CONFLICT( msg, "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES", "AVP Test - enumos", 73565 );
1006 
1007 					/* Now delete this AVP */
1008 					CHECK( 0, fd_msg_free ( tempavp ) );
1009 				}
1010 
1011 				{
1012 					/* Test the RULE_FIXED_TAIL rules positions: add another AVP at the end */
1013 					ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - os" );
1014 
1015 					CHECK_CONFLICT( msg, "DIAMETER_MISSING_AVP", "AVP Test - grouped", 73565 );
1016 
1017 					/* Now remove this AVP */
1018 					CHECK( 0, fd_msg_free ( childavp ) );
1019 				}
1020 			}
1021 		}
1022 
1023 		/* Test the fd_msg_new_answer_from_req function */
1024 		{
1025 			struct dict_object * cmd_model = NULL;
1026 			struct msg         * msg = NULL;
1027 			struct avp * pi1, *pi2, *avp;
1028 			char * host1="host1", * host2="host2";
1029 			union avp_value      value;
1030 			struct msg_hdr * msgdata = NULL;
1031 
1032 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) );
1033 
1034 			/* Test default behavior without flags */
1035 			{
1036 				/* Create a message with some AVPs inside */
1037 				CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
1038 				CHECK( 0, fd_msg_hdr ( msg, &msgdata ) );
1039 
1040 				/* Add a session id */
1041 				CHECK( 0, fd_msg_new_session( msg, (os0_t)"testmsg", strlen("testmsg") ) );
1042 
1043 				/* Create two instances of Proxy-Info */
1044 				ADD_AVP( msg, MSG_BRW_LAST_CHILD, pi1, 0, "Proxy-Info");
1045 				ADD_AVP( msg, MSG_BRW_LAST_CHILD, pi2, 0, "Proxy-Info");
1046 
1047 				ADD_AVP( pi1, MSG_BRW_LAST_CHILD, avp, 0, "Proxy-State");
1048 				value.os.data = (os0_t)"ps_pi1";
1049 				value.os.len = strlen((char *)value.os.data);
1050 				CHECK( 0, fd_msg_avp_setvalue ( avp, &value ) );
1051 
1052 				ADD_AVP( pi2, MSG_BRW_LAST_CHILD, avp, 0, "Proxy-State");
1053 				value.os.data = (os0_t)"pi2_state";
1054 				value.os.len = strlen((char *)value.os.data);
1055 				CHECK( 0, fd_msg_avp_setvalue ( avp, &value ) );
1056 
1057 				ADD_AVP( pi1, MSG_BRW_FIRST_CHILD, avp, 0, "Proxy-Host");
1058 				value.os.data = (os0_t)host1;
1059 				value.os.len = strlen(host1);
1060 				CHECK( 0, fd_msg_avp_setvalue ( avp, &value ) );
1061 
1062 				ADD_AVP( pi2, MSG_BRW_LAST_CHILD, avp, 0, "Proxy-Host");
1063 				value.os.data = (os0_t)host2;
1064 				value.os.len = strlen(host2);
1065 				CHECK( 0, fd_msg_avp_setvalue ( avp, &value ) );
1066 
1067 				ADD_AVP( pi2, MSG_BRW_LAST_CHILD, avp, 73565, "AVP Test - i64");
1068 				value.i64 = 0x123456789abcdeLL;
1069 				CHECK( 0, fd_msg_avp_setvalue ( avp, &value ) );
1070 
1071 
1072 				/* Now call the fd_msg_new_answer_from_req function */
1073 				CHECK( 0, fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &msg, 0 ) );
1074 
1075 				/* Check there is a Session-Id AVP */
1076 				{
1077 					struct session * sess;
1078 					int new;
1079 					CHECK( 0, fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, &new) );
1080 					CHECK( 1, sess == NULL ? 0 : 1 );
1081 					CHECK( 0, new ? 1 : 0 );
1082 				}
1083 
1084 				/* Check there are two Proxy-Info with the two hosts */
1085 				{
1086 					int got_h1 = 0, got_h2=0;
1087 					CHECK( 0, fd_msg_browse ( msg, MSG_BRW_FIRST_CHILD, &avp, NULL) );
1088 					while(avp) {
1089 						struct avp_hdr * avpdata = NULL;
1090 						CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1091 						if (avpdata->avp_code == AC_PROXY_INFO) {
1092 							struct avp * iavp;
1093 							CHECK( 0, fd_msg_browse ( avp, MSG_BRW_FIRST_CHILD, &iavp, NULL) );
1094 							while(iavp) {
1095 								struct avp_hdr * iavpdata = NULL;
1096 								CHECK( 0, fd_msg_avp_hdr ( iavp, &iavpdata ) );
1097 								if (iavpdata->avp_code == AC_PROXY_HOST) {
1098 									if (!memcmp(host1, iavpdata->avp_value->os.data, strlen(host1)))
1099 										got_h1++;
1100 									if (!memcmp(host2, iavpdata->avp_value->os.data, strlen(host2)))
1101 										got_h2++;
1102 								}
1103 								CHECK( 0, fd_msg_browse ( iavp, MSG_BRW_NEXT, &iavp, NULL) );
1104 							}
1105 						}
1106 
1107 						CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1108 					}
1109 
1110 					CHECK(1, got_h1);
1111 					CHECK(1, got_h2);
1112 				}
1113 
1114 				/* Now test the behavior of fd_msg_rescode_set with a grouped AVP */
1115 				CHECK( 0, fd_msg_rescode_set(msg, "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES", NULL, pi1, 1) );
1116 
1117 				fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
1118 
1119 				TODO("Check the Failed-AVP is as expected");
1120 
1121 				CHECK( 0, fd_msg_free( msg ) );
1122 			}
1123 
1124 		}
1125 	}
1126 
1127 	/* Test the msg_avp_value_interpret and msg_avp_value_encode functions. use the Address type and Host-IP-Address AVPs */
1128 	{
1129 		struct dict_object * cer_model = NULL;
1130 		struct msg * cer = NULL;
1131 
1132 		struct dict_object * hia_model = NULL;
1133 		struct avp *avp4, *avp6;
1134 		#define TEST_IP4 "192.168.100.101"
1135 		char buf4[INET_ADDRSTRLEN];
1136 		#define	TEST_IP6 "1111:2222:3333:4444:1234:5678:9abc:def0"
1137 		char buf6[INET6_ADDRSTRLEN];
1138 
1139 		struct sockaddr_storage ss;
1140 		struct sockaddr_in  sin,  *psin;
1141 		struct sockaddr_in6 sin6, *psin6;
1142 
1143 		/* Find the CER dictionary object */
1144 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) );
1145 
1146 		/* Now find the Host-IP-Address dictionary object */
1147 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &hia_model, ENOENT ) );
1148 
1149 		/* Create the msg instance */
1150 		CHECK( 0, fd_msg_new ( cer_model, 0, &cer ) );
1151 
1152 		/* Create the avp instances */
1153 		CHECK( 0, fd_msg_avp_new ( hia_model, 0, &avp4 ) );
1154 		CHECK( 0, fd_msg_avp_new ( hia_model, 0, &avp6 ) );
1155 
1156 		/* Set the value of the IP avp */
1157 		sin.sin_family = AF_INET;
1158 		CHECK( 1, inet_pton( AF_INET, TEST_IP4, &sin.sin_addr.s_addr ) );
1159 		CHECK( 0, fd_msg_avp_value_encode ( &sin, avp4 ) );
1160 
1161 		/* Set the value of the IP6 avp */
1162 		sin6.sin6_family = AF_INET6;
1163 		CHECK( 1, inet_pton( AF_INET6, TEST_IP6, &sin6.sin6_addr.s6_addr ) );
1164 		CHECK( 0, fd_msg_avp_value_encode ( &sin6, avp6 ) );
1165 
1166 		/* Add these AVPs in the message */
1167 		CHECK( 0, fd_msg_avp_add( cer, MSG_BRW_LAST_CHILD, avp4) );
1168 		CHECK( 0, fd_msg_avp_add( cer, MSG_BRW_LAST_CHILD, avp6) );
1169 
1170 		/* Create the buffer for this message */
1171 		CHECK( 0, fd_msg_bufferize( cer, &buf, NULL ) );
1172 
1173 		/* Now free the message, we keep only the buffer. */
1174 		CHECK( 0, fd_msg_free( cer ) );
1175 
1176 		/* Check the content of the buffer is correct (skip command header) */
1177 		CHECK( 0x00, buf[20] ); /* First AVP (IP4) begins: code 257 = 0x00000101 */
1178 		CHECK( 0x00, buf[21] );
1179 		CHECK( 0x01, buf[22] );
1180 		CHECK( 0x01, buf[23] );
1181 		CHECK( 0x40, buf[24] ); /* flags: M */
1182 		CHECK( 0x00, buf[25] ); /* length: 8+6 = 0x00000e */
1183 		CHECK( 0x00, buf[26] );
1184 		CHECK( 0x0E, buf[27] );
1185 		CHECK( 0x00, buf[28] ); /* Value: AddressType 1 */
1186 		CHECK( 0x01, buf[29] );
1187 		CHECK(  192, buf[30] ); /* 192.168.100.101 */
1188 		CHECK(  168, buf[31] );
1189 		CHECK(  100, buf[32] );
1190 		CHECK(  101, buf[33] );
1191 
1192 		CHECK( 0x00, buf[34] ); /* Padding */
1193 		CHECK( 0x00, buf[35] );
1194 
1195 		CHECK( 0x00, buf[36] ); /* Second AVP (IP6) begins: code 257 = 0x00000101 */
1196 		CHECK( 0x00, buf[37] );
1197 		CHECK( 0x01, buf[38] );
1198 		CHECK( 0x01, buf[39] );
1199 		CHECK( 0x40, buf[40] ); /* flags: M */
1200 		CHECK( 0x00, buf[41] ); /* length: 8+18 = 0x00001a */
1201 		CHECK( 0x00, buf[42] );
1202 		CHECK( 0x1A, buf[43] );
1203 		CHECK( 0x00, buf[44] ); /* Value: AddressType 2 */
1204 		CHECK( 0x02, buf[45] );
1205 		CHECK( 0x11, buf[46] ); /* 1111:2222:3333:4444:1234:5678:9abc:def0 */
1206 		CHECK( 0x11, buf[47] );
1207 		CHECK( 0x22, buf[48] );
1208 		CHECK( 0x22, buf[49] );
1209 		CHECK( 0x33, buf[50] );
1210 		CHECK( 0x33, buf[51] );
1211 		CHECK( 0x44, buf[52] );
1212 		CHECK( 0x44, buf[53] );
1213 		CHECK( 0x12, buf[54] );
1214 		CHECK( 0x34, buf[55] );
1215 		CHECK( 0x56, buf[56] );
1216 		CHECK( 0x78, buf[57] );
1217 		CHECK( 0x9a, buf[58] );
1218 		CHECK( 0xbc, buf[59] );
1219 		CHECK( 0xde, buf[60] );
1220 		CHECK( 0xf0, buf[61] );
1221 
1222 		/* Ok, now let's recreate the message */
1223 		CHECK( 0, fd_msg_parse_buffer( &buf, 64, &cer) );
1224 		CHECK( 0, fd_msg_parse_dict( cer, fd_g_config->cnf_dict, NULL ) );
1225 
1226 		/* Get the pointers to the first and last AVP */
1227 		CHECK( 0, fd_msg_browse( cer, MSG_BRW_FIRST_CHILD, &avp4, NULL) );
1228 		CHECK( 0, fd_msg_browse( cer, MSG_BRW_LAST_CHILD,  &avp6, NULL) );
1229 
1230 		/* Try and interpret the data in the AVPs */
1231 		CHECK( 0, fd_msg_avp_value_interpret ( avp4, &ss ) );
1232 		psin = (struct sockaddr_in *)&ss;
1233 		CHECK( AF_INET, psin->sin_family );
1234 		CHECK( 0, (inet_ntop( AF_INET, &psin->sin_addr.s_addr, buf4, sizeof(buf4) ) == NULL) ? errno : 0 );
1235 		CHECK( 0, strcmp( buf4, TEST_IP4 ) );
1236 
1237 		CHECK( 0, fd_msg_avp_value_interpret ( avp6, &ss ) );
1238 		psin6 = (struct sockaddr_in6 *)&ss;
1239 		CHECK( AF_INET6, psin6->sin6_family );
1240 		CHECK( 0, (inet_ntop( AF_INET6, &psin6->sin6_addr.s6_addr, buf6, sizeof(buf6) ) == NULL) ? errno : 0 );
1241 		CHECK( 0, strcasecmp( buf6, TEST_IP6 ) );
1242 
1243 		/* Ok, it's done */
1244 		CHECK( 0, fd_msg_free( cer ) );
1245 	}
1246 
1247 	/* Check proper encoding / decoding for all basic types of AVP */
1248 	{
1249 		{
1250 			struct dict_avp_data avp_data = { 91001, 0, "AVP Test 2 - os", 0, 0, AVP_TYPE_OCTETSTRING };
1251 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
1252 		}
1253 		{
1254 			struct dict_avp_data avp_data = { 91002, 0, "AVP Test 2 - i32", 0, 0, AVP_TYPE_INTEGER32 };
1255 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
1256 		}
1257 		{
1258 			struct dict_avp_data avp_data = { 91003, 0, "AVP Test 2 - i64", 0, 0, AVP_TYPE_INTEGER64 };
1259 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
1260 		}
1261 		{
1262 			struct dict_avp_data avp_data = { 91004, 0, "AVP Test 2 - u32", 0, 0, AVP_TYPE_UNSIGNED32 };
1263 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
1264 		}
1265 		{
1266 			struct dict_avp_data avp_data = { 91005, 0, "AVP Test 2 - u64", 0, 0, AVP_TYPE_UNSIGNED64 };
1267 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
1268 		}
1269 		{
1270 			struct dict_avp_data avp_data = { 91006, 0, "AVP Test 2 - f32", 0, 0, AVP_TYPE_FLOAT32 };
1271 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
1272 		}
1273 		{
1274 			struct dict_avp_data avp_data = { 91007, 0, "AVP Test 2 - f64", 0, 0, AVP_TYPE_FLOAT64 };
1275 			CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) );
1276 		}
1277 
1278 		{
1279 			struct dict_object * cmd_model = NULL;
1280 			struct msg         * msg = NULL;
1281 			struct avp         * avp = NULL;
1282 			union avp_value      value;
1283 			struct avp         * avpi = NULL;
1284 			struct avp_hdr     * avpdata = NULL;
1285 			struct msg_hdr     * msgdata = NULL;
1286 
1287 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) );
1288 
1289 			/* Create a message */
1290 			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
1291 			CHECK( 0, fd_msg_hdr ( msg, &msgdata ) );
1292 
1293 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0, 	"AVP Test 2 - os" );
1294 			value.os.data = (unsigned char *) "waaad";
1295 			value.os.len = 6;
1296 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1297 
1298 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - i32" );
1299 			value.i32 = 0x123456;
1300 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1301 
1302 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - i32" );
1303 			value.i32 = -0x123456;
1304 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1305 
1306 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - i64" );
1307 			value.i64 = 0x11223344556677LL;
1308 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1309 
1310 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - i64" );
1311 			value.i64 = -0x11223344556677LL;
1312 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1313 
1314 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - u32" );
1315 			value.u32 = 0xFEDCBA98;
1316 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1317 
1318 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - u64" );
1319 			value.u64 = 0x123456789abcdef0LL;
1320 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1321 
1322 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - f32" );
1323 			value.f32 = 2097153.0F;
1324 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1325 
1326 			ADD_AVP( msg, MSG_BRW_LAST_CHILD, avpi, 0,	"AVP Test 2 - f64" );
1327 			value.f64 = -1099511627777LL;
1328 			CHECK( 0, fd_msg_avp_setvalue ( avpi, &value ) );
1329 
1330 			/* Ok now bufferize */
1331 			CHECK( 0, fd_msg_bufferize( msg, &buf, NULL ) );
1332 
1333 			/* Test the first bytes */
1334 			CHECK( 0x01, buf[0] ); /* Version */
1335 			CHECK( 0x00, buf[1] ); /* Length: 148 = 0x000094 */
1336 			CHECK( 0x00, buf[2] );
1337 			CHECK( 0x94, buf[3] );
1338 			CHECK( 0x80, buf[4] ); /* flags: only "R" is set. */
1339 			CHECK( 0x01, buf[5] ); /* Command code: 73573 = 0x011F65 */
1340 			CHECK( 0x1F, buf[6] );
1341 			CHECK( 0x65, buf[7] );
1342 			CHECK( 0x00, buf[8] ); /* App ID */
1343 			CHECK( 0x01, buf[9] );
1344 			CHECK( 0x1F, buf[10] );
1345 			CHECK( 0x5E, buf[11] );
1346 			CHECK( 0x00, buf[12] ); /* hop-by-hop id */
1347 			CHECK( 0x00, buf[13] );
1348 			CHECK( 0x00, buf[14] );
1349 			CHECK( 0x00, buf[15] );
1350 			CHECK( 0x00, buf[16] ); /* end-to-end id */
1351 			CHECK( 0x00, buf[17] );
1352 			CHECK( 0x00, buf[18] );
1353 			CHECK( 0x00, buf[19] );
1354 
1355 			CHECK( 0x00, buf[20] ); /* First AVP (AVP Test 2 - os) begin: code 91001 = 0x00016379 */
1356 			CHECK( 0x01, buf[21] );
1357 			CHECK( 0x63, buf[22] );
1358 			CHECK( 0x79, buf[23] );
1359 			CHECK( 0x00, buf[24] ); /* flags: 0 */
1360 			CHECK( 0x00, buf[25] ); /* length: 14 = 0x00000e */
1361 			CHECK( 0x00, buf[26] );
1362 			CHECK( 0x0e, buf[27] );
1363 
1364 			CHECK( 0x77, buf[28] ); /* "waaad\0" + padding */
1365 			CHECK( 0x61, buf[29] );
1366 			CHECK( 0x61, buf[30] );
1367 			CHECK( 0x61, buf[31] );
1368 			CHECK( 0x64, buf[32] );
1369 			CHECK( 0x00, buf[33] );
1370 			CHECK( 0x00, buf[34] );
1371 			CHECK( 0x00, buf[35] );
1372 
1373 			/* 36 ~ 43 : 2nd AVP header (size at last octet) */
1374 			CHECK( 0x0c, buf[43] );
1375 			CHECK( 0x00, buf[44] ); /* 0x123456 stored in integer32 in network byte order */
1376 			CHECK( 0x12, buf[45] );
1377 			CHECK( 0x34, buf[46] );
1378 			CHECK( 0x56, buf[47] );
1379 
1380 			/* 48 ~ 55 : next AVP header */
1381 			CHECK( 0xff, buf[56] ); /* -0x123456 stored in integer32 in network byte order. */
1382 			CHECK( 0xed, buf[57] ); /* We assume that two's complement is the correct representation, although it's not clearly specified. */
1383 			CHECK( 0xcb, buf[58] ); /* 00 12 34 56 inversed => FF ED CB A9 */
1384 			CHECK( 0xaa, buf[59] ); /* then "+1" => FF ED CB AA */
1385 
1386 			/* 60 ~ 67 : next header */
1387 			CHECK( 0x10, buf[67] ); /* (the size) */
1388 			CHECK( 0x00, buf[68] ); /* 0x11223344556677 in network byte order */
1389 			CHECK( 0x11, buf[69] );
1390 			CHECK( 0x22, buf[70] );
1391 			CHECK( 0x33, buf[71] );
1392 			CHECK( 0x44, buf[72] );
1393 			CHECK( 0x55, buf[73] );
1394 			CHECK( 0x66, buf[74] );
1395 			CHECK( 0x77, buf[75] );
1396 
1397 			/* 76 ~ 83 : next header */
1398 			CHECK( 0xFF, buf[84] ); /*  - 0x11223344556677 (in two's complement) */
1399 			CHECK( 0xEE, buf[85] ); /* gives FF EE DD CC BB AA 99 89 */
1400 			CHECK( 0xDD, buf[86] );
1401 			CHECK( 0xCC, buf[87] );
1402 			CHECK( 0xBB, buf[88] );
1403 			CHECK( 0xAA, buf[89] );
1404 			CHECK( 0x99, buf[90] );
1405 			CHECK( 0x89, buf[91] );
1406 
1407 			/* 92 ~ 99 : next header */
1408 			CHECK( 0x0c, buf[99] ); /* (the size) */
1409 			CHECK( 0xFE, buf[100]); /* 0xFEDCBA98 in network byte order */
1410 			CHECK( 0xDC, buf[101]);
1411 			CHECK( 0xBA, buf[102]);
1412 			CHECK( 0x98, buf[103]);
1413 
1414 			/* 104 ~ 111 : next header */
1415 			CHECK( 0x10, buf[111] ); /* (the size) */
1416 			CHECK( 0x12, buf[112]); /* 0x123456789abcdef0LL in network byte order */
1417 			CHECK( 0x34, buf[113]);
1418 			CHECK( 0x56, buf[114]);
1419 			CHECK( 0x78, buf[115]);
1420 			CHECK( 0x9a, buf[116]);
1421 			CHECK( 0xbc, buf[117]);
1422 			CHECK( 0xde, buf[118]);
1423 			CHECK( 0xf0, buf[119]);
1424 
1425 			/* 120 ~ 127 : next header */
1426 			CHECK( 0x0c, buf[127] ); /* (the size) */
1427 			CHECK( 0x4a, buf[128]); /* http://en.wikipedia.org/wiki/IEEE_754-1985 to get descvription of the format */
1428 			CHECK( 0x00, buf[129]); /* v = 2097153 = 2^21 + 2 ^ 0; sign : "+", 2^21 <= v < 2^22 => exponent = 21; biaised on 8 bits => 21 + 127 => 100 1010 0 */
1429 			CHECK( 0x00, buf[130]); /* v = (+1) * (1 ^ 21) * ( 1 + 2^-21 ) => significand 000 0000 0000 0000 0000 0100 */
1430 			CHECK( 0x04, buf[131]); /* result: 4a 00 00 04 */
1431 
1432 			/* 132 ~ 139 : next header */
1433 			CHECK( 0x10, buf[139] ); /* (the size) */
1434 			CHECK( 0xc2, buf[140]); /* -1099511627777L ( 2^40 + 1 ) in network byte order */
1435 			CHECK( 0x70, buf[141]); /* sign: - => most significant bit = 1 */
1436 			CHECK( 0x00, buf[142]); /* 2^40 <= v < 2^41 => biaised exponent on 11 bits: 1023 + 40: 100 0010  0111 */
1437 			CHECK( 0x00, buf[143]); /* significand: 1 + 2^-40 => 0000  0000 0000  0000 0000  0000 0000  0000 0000  0001 0000  0000 0000 */
1438 			CHECK( 0x00, buf[144]); /* result: c2 70 00 00 00 00 10 00 */
1439 			CHECK( 0x00, buf[145]);
1440 			CHECK( 0x10, buf[146]);
1441 			CHECK( 0x00, buf[147]);
1442 
1443 
1444 
1445 			/* Okay, now delete the message and parse the buffer, then check we obtain the same values back */
1446 			#if 0
1447 			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
1448 			#endif
1449 			CHECK( 0, fd_msg_free( msg ) );
1450 
1451 			CHECK( 0, fd_msg_parse_buffer( &buf, 148, &msg) );
1452 			CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict, NULL ) );
1453 			#if 0
1454 			fd_log_debug("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
1455 			#endif
1456 
1457 			CHECK( 0, fd_msg_browse ( msg, MSG_BRW_FIRST_CHILD, &avp, NULL) );
1458 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1459 			CHECK( 6, avpdata->avp_value->os.len );
1460 			CHECK( 'w', (char)(avpdata->avp_value->os.data[0]) );
1461 			CHECK( 'a', (char)(avpdata->avp_value->os.data[1]) );
1462 			CHECK( 'd', (char)(avpdata->avp_value->os.data[4]) );
1463 			CHECK( '\0', (char)(avpdata->avp_value->os.data[5]) );
1464 
1465 			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1466 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1467 			CHECK( 0x123456, avpdata->avp_value->i32 );
1468 
1469 			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1470 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1471 			CHECK( -0x123456, avpdata->avp_value->i32 );
1472 
1473 			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1474 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1475 			CHECK( 0x11223344556677LL, avpdata->avp_value->i64 );
1476 
1477 			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1478 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1479 			CHECK( -0x11223344556677LL, avpdata->avp_value->i64 );
1480 
1481 			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1482 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1483 			CHECK( 0xFEDCBA98, avpdata->avp_value->u32 );
1484 
1485 			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1486 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1487 			CHECK( 0x123456789abcdef0LL, avpdata->avp_value->u64 );
1488 
1489 			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1490 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1491 			CHECK( 2097153.0F, avpdata->avp_value->f32 );
1492 
1493 			CHECK( 0, fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL) );
1494 			CHECK( 0, fd_msg_avp_hdr ( avp, &avpdata ) );
1495 			CHECK( -1099511627777LL, avpdata->avp_value->f64 );
1496 
1497 			CHECK( 0, fd_msg_free( msg ) );
1498 		}
1499 	}
1500 
1501 	/* Test the fd_msg_add_result function for Result-Code */
1502 	{
1503 		struct msg		* msg = NULL;
1504 		struct dict_object	* avp_model = NULL;
1505 		struct avp		* rc = NULL;
1506 		struct avp_hdr		* avpdata = NULL;
1507 
1508 		{
1509 			struct dict_object * cmd_model = NULL;
1510 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Answer", &cmd_model, ENOENT ) );
1511 
1512 			/* Create a message */
1513 			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
1514 
1515 			/* Add a session id */
1516 			CHECK( 0, fd_msg_new_session( msg, (os0_t)"testmsg", strlen("testmsg") ) );
1517 
1518 			/* Find the DICT_TYPE Enumerated(Result-Code) */
1519 			struct dict_object * restype = NULL;
1520 			CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_BY_NAME, "Enumerated(Result-Code)", &restype, ENOENT ) );
1521 
1522 			/* Now test the behavior of fd_msg_add_result for Result-Code AVP */
1523 			CHECK( 0, fd_msg_add_result(msg, 0, restype, "DIAMETER_SUCCESS", NULL, NULL, 1) );
1524 
1525 			LOG_D("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
1526 		}
1527 
1528 		/* Ensure Result-Code is present */
1529 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &avp_model, ENOENT ) );
1530 		CHECK( 0, fd_msg_search_avp( msg, avp_model, &rc ) );
1531 
1532 		/* Check the Result-Code AVP value is DIAMETER_SUCCESS */
1533 		CHECK( 0, fd_msg_avp_hdr ( rc, &avpdata ) );
1534 		CHECK( ER_DIAMETER_SUCCESS, avpdata->avp_value->u32 );
1535 
1536 		/* Ensure Experimental-Result is missing */
1537 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &avp_model, ENOENT ) );
1538 		CHECK( ENOENT, fd_msg_search_avp( msg, avp_model, NULL ) );
1539 
1540 		/* Free msg */
1541 		CHECK( 0, fd_msg_free( msg ) );
1542 	}
1543 
1544 	/* Test the fd_msg_add_result function for Experimental-Result */
1545 	{
1546 		struct msg		* msg = NULL;
1547 		struct dict_object	* avp_model = NULL;
1548 		struct avp		* er = NULL;
1549 		struct avp		* erc = NULL;
1550 		struct avp_hdr		* avpdata = NULL;
1551 
1552 		{
1553 			struct dict_object * cmd_model = NULL;
1554 			CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Answer", &cmd_model, ENOENT ) );
1555 
1556 			/* Create a message */
1557 			CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) );
1558 
1559 			/* Add a session id */
1560 			CHECK( 0, fd_msg_new_session( msg, (os0_t)"testmsg", strlen("testmsg") ) );
1561 
1562 			/* Find the DICT_TYPE Enumerated(73565/Experimental-Result-Code) */
1563 			struct dict_object * restype = NULL;
1564 			CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_BY_NAME, "Enumerated(73565/Experimental-Result-Code)", &restype, ENOENT ) );
1565 
1566 			/* Now test the behavior of fd_msg_add_result for Experimental-Result AVP */
1567 			CHECK( 0, fd_msg_add_result(msg, 73565, restype, "DIAMETER_TEST_RESULT_5000", NULL, NULL, 1) );
1568 
1569 			LOG_D("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1));
1570 		}
1571 
1572 		/* Ensure Result-Code is missing */
1573 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &avp_model, ENOENT ) );
1574 		CHECK( ENOENT, fd_msg_search_avp( msg, avp_model, NULL ) );
1575 
1576 		/* Ensure Experimental-Result is present */
1577 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &avp_model, ENOENT ) );
1578 		CHECK( 0, fd_msg_search_avp( msg, avp_model, &er ) );
1579 
1580 		/* Ensure Experimental-Result-Code is present */
1581 		CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result-Code", &avp_model, ENOENT ) );
1582 		CHECK( 0, fd_msg_search_avp( er, avp_model, &erc ) );
1583 
1584 		/* Check the Experimental-Result-Code AVP value is 5000 */
1585 		CHECK( 0, fd_msg_avp_hdr ( erc, &avpdata ) );
1586 		CHECK( 5000, avpdata->avp_value->u32 );
1587 
1588 		/* Free msg */
1589 		CHECK( 0, fd_msg_free( msg ) );
1590 	}
1591 
1592 	/* Check IPv4 -> IPv6 and IPv6->IPv4 mapping */
1593 	{
1594 		struct in_addr i4;
1595 		memset(&i4, 0xff, sizeof(i4));
1596 		CHECK( 1, inet_pton( AF_INET, TEST_IP4, &i4 ) );
1597 
1598 		#define TEST_IP6MAP "::ffff:" TEST_IP4
1599 
1600 		struct in6_addr i6;
1601 		memset(&i6, 0xff, sizeof(i6));
1602 		IN6_ADDR_V4MAP(&i6.s6_addr, i4.s_addr);
1603 		char buf6[INET6_ADDRSTRLEN];
1604 		CHECK( 0, (inet_ntop( AF_INET6, &i6, buf6, sizeof(buf6) ) == NULL) ? errno : 0 );
1605 		LOG_D("buf6='%s'", buf6);
1606 		CHECK( 0, strcasecmp( buf6, TEST_IP6MAP ) );
1607 
1608 		struct in_addr o4;
1609 		o4.s_addr = IN6_ADDR_V4UNMAP(&i6);
1610 		char buf4[INET_ADDRSTRLEN];
1611 		CHECK( 0, (inet_ntop( AF_INET, &o4.s_addr, buf4, sizeof(buf4) ) == NULL) ? errno : 0 );
1612 		CHECK( 0, strcmp( buf4, TEST_IP4 ) );
1613 	}
1614 
1615 	/* That's all for the tests yet */
1616 	PASSTEST();
1617 }
1618 
1619