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 /* Messages module.
37  *
38  * This module allows to manipulate the msg and avp structures that represents a Diameter message in memory.
39  */
40 
41 #include "fdproto-internal.h"
42 
43 #include <sys/param.h>
44 
45 /* Type of object */
46 enum msg_objtype {
47 	MSG_MSG = 1,
48 	MSG_AVP
49 };
50 
51 /* Chaining of elements as a free hierarchy */
52 struct msg_avp_chain {
53 	struct fd_list		chaining;	/* Chaining information at this level. */
54 	struct fd_list		children;	/* sentinel for the children of this object */
55 	enum msg_objtype 	type;		/* Type of this object, _MSG_MSG or _MSG_AVP */
56 };
57 
58 /* Return the chain information from an AVP or MSG. Since it's the first field, we just cast */
59 #define _C(_x) ((struct msg_avp_chain *)(_x))
60 
61 /* Some details about chaining:
62  *
63  *  A message is made of a header ( msg ) and 0 or more AVPs ( avp ).
64  * The structure is a kind of tree, where some AVPs (grouped AVPs) can contain other AVPs.
65  * Example:
66  * msg
67  *  |-avp
68  *  |-gavp
69  *  |   |-avp
70  *  |   |-avp
71  *  |   \-avp
72  *  |-avp
73  *  \-avp
74  *
75  * Each item (msg or avp) structure begins with a msg_avp_chain structure.
76  * The element at the top of the hierarchy (msg in our example) has all the fields of its "chaining" equal to the same value.
77  *
78  * All elements at the same level are linked by their "chaining" list.
79  * The "children" list is the sentinel for the lists of children of this element.
80  */
81 
82 /* The following definitions are used to recognize objects in memory. */
83 #define MSG_MSG_EYEC	(0x11355463)
84 #define MSG_AVP_EYEC	(0x11355467)
85 
86 /* The following structure represents an AVP instance. */
87 struct avp {
88 	struct msg_avp_chain	 avp_chain;		/* Chaining information of this AVP */
89 	int			 avp_eyec;		/* Must be equal to MSG_AVP_EYEC */
90 	struct dict_object	*avp_model;		/* If not NULL, pointer to the dictionary object of this avp */
91 	struct {
92 		avp_code_t	 mnf_code;
93 		vendor_id_t	 mnf_vendor;
94 	}  			 avp_model_not_found;	/* When model resolution has failed, store a copy of the data here to avoid searching again */
95 	struct avp_hdr		 avp_public;		/* AVP data that can be managed by other modules */
96 
97 	uint8_t			*avp_source;		/* If the message was parsed from a buffer, pointer to the AVP data start in the buffer. */
98 	uint8_t			*avp_rawdata;		/* when the data can not be interpreted, the raw data is copied here. The header is not part of it. */
99 	size_t			 avp_rawlen;		/* The length of the raw buffer. */
100 	union avp_value		 avp_storage;		/* To avoid many alloc/free, store the integer values here and set avp_public.avp_data to &storage */
101 	int			 avp_mustfreeos;	/* 1 if an octetstring is malloc'd in avp_storage and must be freed. */
102 };
103 
104 /* Macro to compute the AVP header size */
105 #define AVPHDRSZ_NOVEND	8
106 #define AVPHDRSZ_VENDOR	12
107 #define GETAVPHDRSZ( _flag ) ((_flag & AVP_FLAG_VENDOR) ? AVPHDRSZ_VENDOR : AVPHDRSZ_NOVEND)
108 
109 /* Macro to cast a msg_avp_t */
110 #define _A(_x) ((struct avp *)(_x))
111 /* Check the type and eyecatcher */
112 #define CHECK_AVP(_x) ((_x) && (_C(_x)->type == MSG_AVP) && (_A(_x)->avp_eyec == MSG_AVP_EYEC))
113 
114 /* The following structure represents an instance of a message (command and children AVPs). */
115 struct msg {
116 	struct msg_avp_chain	 msg_chain;		/* List of the AVPs in the message */
117 	int			 msg_eyec;		/* Must be equal to MSG_MSG_EYEC */
118 	struct dict_object	*msg_model;		/* If not NULL, pointer to the dictionary object of this message */
119 	struct {
120 		command_code_t	 mnf_code;
121 		uint8_t		 mnf_flags;
122 	}  			 msg_model_not_found;	/* When model resolution has failed, store a copy of the data here to avoid searching again */
123 	struct msg_hdr		 msg_public;		/* Message data that can be managed by extensions. */
124 
125 	uint8_t			*msg_rawbuffer;		/* data buffer that was received, saved during fd_msg_parse_buffer and freed in fd_msg_parse_dict */
126 	int			 msg_routable;		/* Is this a routable message? (0: undef, 1: routable, 2: non routable) */
127 	struct msg		*msg_query;		/* the associated query if the message is a received answer */
128 	int			 msg_associated;	/* and the counter part information in the query, to avoid double free */
129 	struct rt_data		*msg_rtdata;		/* Routing list for the query */
130 	struct session		*msg_sess;		/* Cached message session if any */
131 	struct {
132 			void (*anscb)(void *, struct msg **);
133 			void (*expirecb)(void *, DiamId_t, size_t, struct msg **);
134 			void * data;
135 			struct timespec timeout;
136 		}		 msg_cb;		/* Callback to be called when an answer is received, or timeout expires, if not NULL */
137 	DiamId_t		 msg_src_id;		/* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */
138 	size_t			 msg_src_id_len;	/* cached length of this string */
139 	struct fd_msg_pmdl	 msg_pmdl;		/* list of permessagedata structures. */
140 };
141 
142 /* Macro to compute the message header size */
143 #define GETMSGHDRSZ() 	20
144 
145 /* Macro to cast a msg_avp_t */
146 #define _M(_x) ((struct msg *)(_x))
147 /* Check the type and eyecatcher */
148 #define CHECK_MSG(_x) ((_x) && (_C(_x)->type == MSG_MSG) && (_M(_x)->msg_eyec == MSG_MSG_EYEC))
149 
150 #define VALIDATE_OBJ(_x) ( (CHECK_MSG(_x)) || (CHECK_AVP(_x)) )
151 
152 
153 /* Macro to validate a MSGFL_ value */
154 #define CHECK_AVPFL(_fl) ( ((_fl) & (- (AVPFL_MAX << 1) )) == 0 )
155 #define CHECK_MSGFL(_fl) ( ((_fl) & (- (MSGFL_MAX << 1) )) == 0 )
156 
157 
158 /* initial sizes of AVP from their types, in bytes. */
159 static int avp_value_sizes[] = {
160 	 0,	/* AVP_TYPE_GROUPED: size is dynamic */
161 	 0,	/* AVP_TYPE_OCTETSTRING: size is dynamic */
162 	 4,	/* AVP_TYPE_INTEGER32: size is 32 bits */
163 	 8,	/* AVP_TYPE_INTEGER64: size is 64 bits */
164 	 4,	/* AVP_TYPE_UNSIGNED32: size is 32 bits */
165 	 8,	/* AVP_TYPE_UNSIGNED64: size is 64 bits */
166 	 4,	/* AVP_TYPE_FLOAT32: size is 32 bits */
167 	 8	/* AVP_TYPE_FLOAT64: size is 64 bits */
168 };
169 #define CHECK_BASETYPE( _type ) ( ((_type) <= AVP_TYPE_MAX) && ((_type) >= 0) )
170 #define GETINITIALSIZE( _type, _vend ) (avp_value_sizes[ CHECK_BASETYPE(_type) ? (_type) : 0] + GETAVPHDRSZ(_vend))
171 
172 /* Forward declaration */
173 static int parsedict_do_msg(struct dictionary * dict, struct msg * msg, int only_hdr, struct fd_pei *error_info);
174 
175 /***************************************************************************************************************/
176 /* Creating objects */
177 
178 /* Initialize a msg_avp_chain structure */
init_chain(struct msg_avp_chain * chain,int type)179 static void init_chain(struct msg_avp_chain * chain, int type)
180 {
181 	fd_list_init( &chain->chaining, (void *)chain);
182 	fd_list_init( &chain->children, (void *)chain);
183 	chain->type = type;
184 }
185 
186 /* Initialize a new AVP object */
init_avp(struct avp * avp)187 static void init_avp ( struct avp * avp )
188 {
189 	TRACE_ENTRY("%p", avp);
190 
191 	memset(avp, 0, sizeof(struct avp));
192 	init_chain( &avp->avp_chain, MSG_AVP);
193 	avp->avp_eyec = MSG_AVP_EYEC;
194 }
195 
196 /* Initialize a new MSG object */
init_msg(struct msg * msg)197 static void init_msg ( struct msg * msg )
198 {
199 	TRACE_ENTRY("%p", msg);
200 
201 	memset(msg, 0, sizeof(struct msg));
202 	init_chain( &msg->msg_chain, MSG_MSG);
203 	msg->msg_eyec = MSG_MSG_EYEC;
204 
205 	fd_list_init(&msg->msg_pmdl.sentinel, NULL);
206 	CHECK_POSIX_DO( pthread_mutex_init(&msg->msg_pmdl.lock, NULL), );
207 }
208 
209 
210 /* Create a new AVP instance */
fd_msg_avp_new(struct dict_object * model,int flags,struct avp ** avp)211 int fd_msg_avp_new ( struct dict_object * model, int flags, struct avp ** avp )
212 {
213 	struct avp *new = NULL;
214 
215 	TRACE_ENTRY("%p %x %p", model, flags, avp);
216 
217 	/* Check the parameters */
218 	CHECK_PARAMS(  avp && CHECK_AVPFL(flags)  );
219 
220 	if (model) {
221 		enum dict_object_type 	 dicttype;
222 		CHECK_PARAMS( (fd_dict_gettype(model, &dicttype) == 0) && (dicttype == DICT_AVP) );
223 	}
224 
225 	/* Create a new object */
226 	CHECK_MALLOC(  new = malloc (sizeof(struct avp))  );
227 
228 	/* Initialize the fields */
229 	init_avp(new);
230 
231 	if (model) {
232 		struct dict_avp_data dictdata;
233 
234 		CHECK_FCT_DO(  fd_dict_getval(model, &dictdata), { free(new); return __ret__; }  );
235 
236 		new->avp_model = model;
237 		new->avp_public.avp_code    = dictdata.avp_code;
238 		new->avp_public.avp_flags   = dictdata.avp_flag_val;
239 		new->avp_public.avp_len = GETINITIALSIZE(dictdata.avp_basetype, dictdata.avp_flag_val );
240 		new->avp_public.avp_vendor  = dictdata.avp_vendor;
241 	}
242 
243 	if (flags & AVPFL_SET_BLANK_VALUE) {
244 		new->avp_public.avp_value = &new->avp_storage;
245 	}
246 
247 	if (flags & AVPFL_SET_RAWDATA_FROM_AVP) {
248 		new->avp_rawlen = (*avp)->avp_public.avp_len - GETAVPHDRSZ( (*avp)->avp_public.avp_flags );
249 		if (new->avp_rawlen) {
250 			CHECK_MALLOC_DO(  new->avp_rawdata = malloc(new->avp_rawlen), { free(new); return __ret__; }  );
251 			memset(new->avp_rawdata, 0x00, new->avp_rawlen);
252 		}
253 	}
254 
255 	/* The new object is ready, return */
256 	*avp = new;
257 	return 0;
258 }
259 
260 /* Create a new message instance */
fd_msg_new(struct dict_object * model,int flags,struct msg ** msg)261 int fd_msg_new ( struct dict_object * model, int flags, struct msg ** msg )
262 {
263 	struct msg * new = NULL;
264 
265 	TRACE_ENTRY("%p %x %p", model, flags, msg);
266 
267 	/* Check the parameters */
268 	CHECK_PARAMS(  msg && CHECK_MSGFL(flags)  );
269 
270 	if (model) {
271 		enum dict_object_type 	 dicttype;
272 		CHECK_PARAMS( (fd_dict_gettype(model, &dicttype) == 0) && (dicttype == DICT_COMMAND) );
273 	}
274 
275 	/* Create a new object */
276 	CHECK_MALLOC(  new = malloc (sizeof(struct msg))  );
277 
278 	/* Initialize the fields */
279 	init_msg(new);
280 	new->msg_public.msg_version	= DIAMETER_VERSION;
281 	new->msg_public.msg_length	= GETMSGHDRSZ(); /* This will be updated later */
282 
283 	if (model) {
284 		struct dictionary 	*dict;
285 		struct dict_cmd_data     dictdata;
286 		struct dict_object     	*dictappl;
287 
288 		CHECK_FCT_DO( fd_dict_getdict(model, &dict), { free(new); return __ret__; } );
289 		CHECK_FCT_DO( fd_dict_getval(model, &dictdata), { free(new); return __ret__; }  );
290 
291 		new->msg_model = model;
292 		new->msg_public.msg_flags	= dictdata.cmd_flag_val;
293 		new->msg_public.msg_code	= dictdata.cmd_code;
294 
295 		/* Initialize application from the parent, if any */
296 		CHECK_FCT_DO(  fd_dict_search( dict, DICT_APPLICATION, APPLICATION_OF_COMMAND, model, &dictappl, 0), { free(new); return __ret__; }  );
297 		if (dictappl != NULL) {
298 			struct dict_application_data appdata;
299 			CHECK_FCT_DO(  fd_dict_getval(dictappl, &appdata), { free(new); return __ret__; }  );
300 			new->msg_public.msg_appl = appdata.application_id;
301 		}
302 	}
303 
304 	if (flags & MSGFL_ALLOC_ETEID) {
305 		new->msg_public.msg_eteid = fd_msg_eteid_get();
306 	}
307 
308 	/* The new object is ready, return */
309 	*msg = new;
310 	return 0;
311 }
312 
313 static int bufferize_avp(unsigned char * buffer, size_t buflen, size_t * offset,  struct avp * avp);
314 static int parsebuf_list(unsigned char * buf, size_t buflen, struct fd_list * head);
315 static int parsedict_do_chain(struct dictionary * dict, struct fd_list * head, int mandatory, struct fd_pei *error_info);
316 
317 
318 /* Create answer from a request */
fd_msg_new_answer_from_req(struct dictionary * dict,struct msg ** msg,int flags)319 int fd_msg_new_answer_from_req ( struct dictionary * dict, struct msg ** msg, int flags )
320 {
321 	struct dict_object * model = NULL;
322 	struct msg *qry, *ans;
323 	struct session * sess = NULL;
324 
325 	TRACE_ENTRY("%p %x", msg, flags);
326 
327 	/* Check the parameters */
328 	CHECK_PARAMS(  msg );
329 	qry = *msg;
330 	CHECK_PARAMS( CHECK_MSG(qry) && (qry->msg_public.msg_flags & CMD_FLAG_REQUEST) );
331 
332 	if (! (flags & MSGFL_ANSW_NOSID)) {
333 		/* Get the session of the message */
334 		CHECK_FCT_DO( fd_msg_sess_get(dict, qry, &sess, NULL), /* ignore an error */ );
335 	}
336 
337 	/* Find the model for the answer */
338 	if (flags & MSGFL_ANSW_ERROR) {
339 		/* The model is the generic error format */
340 		CHECK_FCT( fd_dict_get_error_cmd(dict, &model) );
341 	} else {
342 		/* The model is the answer corresponding to the query. It supposes that these are defined in the dictionary */
343 		CHECK_FCT_DO(  parsedict_do_msg( dict, qry, 1, NULL), /* continue */  );
344 		if (qry->msg_model) {
345 			CHECK_FCT(  fd_dict_search ( dict, DICT_COMMAND, CMD_ANSWER, qry->msg_model, &model, EINVAL )  );
346 		}
347 	}
348 
349 	/* Create the answer */
350 	CHECK_FCT(  fd_msg_new( model, flags, &ans )  );
351 
352 	/* Set informations in the answer as in the query */
353 	ans->msg_public.msg_code = qry->msg_public.msg_code; /* useful for MSGFL_ANSW_ERROR */
354 	ans->msg_public.msg_appl = qry->msg_public.msg_appl;
355 	ans->msg_public.msg_eteid = qry->msg_public.msg_eteid;
356 	ans->msg_public.msg_hbhid = qry->msg_public.msg_hbhid;
357 
358 	/* Add the Session-Id AVP if session is known */
359 	if (sess && dict) {
360 		static struct dict_object * sess_id_avp = NULL;
361 		os0_t sid;
362 		size_t sidlen;
363 		struct avp * avp;
364 		union avp_value val;
365 
366 		if (!sess_id_avp) {
367 			CHECK_FCT_DO( fd_dict_search( dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &sess_id_avp, ENOENT), { free(ans); return __ret__; } );
368 		}
369 		CHECK_FCT_DO( fd_sess_getsid ( sess, &sid, &sidlen ), { free(ans); return __ret__; } );
370 		CHECK_FCT_DO( fd_msg_avp_new ( sess_id_avp, 0, &avp ), { free(ans); return __ret__; } );
371 		val.os.data = sid;
372 		val.os.len  = sidlen;
373 		CHECK_FCT_DO( fd_msg_avp_setvalue( avp, &val ), { free(avp); free(ans); return __ret__; } );
374 		CHECK_FCT_DO( fd_msg_avp_add( ans, MSG_BRW_FIRST_CHILD, avp ), { free(avp); free(ans); return __ret__; } );
375 		ans->msg_sess = sess;
376 		CHECK_FCT_DO( fd_sess_ref_msg(sess), { free(ans); return __ret__; }  );
377 	}
378 
379 	/* Add all Proxy-Info AVPs from the query if any */
380 	if (! (flags & MSGFL_ANSW_NOPROXYINFO)) {
381 		struct avp * avp;
382 		struct fd_pei pei;
383 		struct fd_list avpcpylist = FD_LIST_INITIALIZER(avpcpylist);
384 
385 		CHECK_FCT_DO(  fd_msg_browse(qry, MSG_BRW_FIRST_CHILD, &avp, NULL) , { free(ans); return __ret__; } );
386 		while (avp) {
387 			if ( (avp->avp_public.avp_code   == AC_PROXY_INFO)
388 			  && (avp->avp_public.avp_vendor == 0) ) {
389 				/* We found a Proxy-Info, need to duplicate it in the answer */
390 
391 				/* In order to avoid dealing with all different possibilities of states, we just create a buffer then parse it */
392 				unsigned char * buf = NULL;
393 				size_t offset = 0;
394 
395 				/* Create a buffer with the content of the AVP. This is easier than going through the list */
396 				CHECK_FCT_DO(  fd_msg_update_length(avp), { free(ans); return __ret__; }  );
397 				CHECK_MALLOC_DO(  buf = malloc(avp->avp_public.avp_len), { free(ans); return __ret__; }  );
398 				CHECK_FCT_DO( bufferize_avp(buf, avp->avp_public.avp_len, &offset, avp), { free(buf); free(ans); return __ret__; }  );
399 
400 				/* Now we parse this buffer to create a copy AVP */
401 				CHECK_FCT_DO( parsebuf_list(buf, avp->avp_public.avp_len, &avpcpylist), { free(buf); free(ans); return __ret__; } );
402 
403 				/* Parse dictionary objects now to remove the dependency on the buffer */
404 				CHECK_FCT_DO( parsedict_do_chain(dict, &avpcpylist, 0, &pei), { /* leaking the avpcpylist -- this should never happen anyway */ free(buf); free(ans); return __ret__; } );
405 
406 				/* Done for this AVP */
407 				free(buf);
408 
409 				/* We move this AVP now so that we do not parse again in next loop */
410 				fd_list_move_end(&ans->msg_chain.children, &avpcpylist);
411 			}
412 			/* move to next AVP in the message, we can have several Proxy-Info instances */
413 			CHECK_FCT_DO( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), { free(ans); return __ret__; } );
414 		}
415 	}
416 
417 	/* associate with query */
418 	ans->msg_query = qry;
419 	qry->msg_associated = 1;
420 
421 	/* Done */
422 	*msg = ans;
423 	return 0;
424 }
425 
426 /***************************************************************************************************************/
427 
428 /* Explore a message */
fd_msg_browse_internal(msg_or_avp * reference,enum msg_brw_dir dir,msg_or_avp ** found,int * depth)429 int fd_msg_browse_internal ( msg_or_avp * reference, enum msg_brw_dir dir, msg_or_avp ** found, int * depth )
430 {
431 	struct msg_avp_chain *result = NULL;
432 	int diff = 0;
433 	struct fd_list *li = NULL;
434 
435 	TRACE_ENTRY("%p %d %p %p", reference, dir, found, depth);
436 
437 	/* Initialize the "found" result if any */
438 	if (found)
439 		*found = NULL;
440 
441 	/* Check the parameters */
442 	CHECK_PARAMS(  VALIDATE_OBJ(reference)  );
443 
444 	TRACE_DEBUG(FCTS, "chaining(%p): nxt:%p prv:%p hea:%p top:%p",
445 			&_C(reference)->chaining,
446 			_C(reference)->chaining.next,
447 			_C(reference)->chaining.prev,
448 			_C(reference)->chaining.head,
449 			_C(reference)->chaining.o);
450 	TRACE_DEBUG(FCTS, "children(%p): nxt:%p prv:%p hea:%p top:%p",
451 			&_C(reference)->children,
452 			_C(reference)->children.next,
453 			_C(reference)->children.prev,
454 			_C(reference)->children.head,
455 			_C(reference)->children.o);
456 
457 	/* Now search */
458 	switch (dir) {
459 		case MSG_BRW_NEXT:
460 			/* Check the reference is an AVP */
461 			CHECK_PARAMS(  _C(reference)->type == MSG_AVP  );
462 
463 			li = &_C(reference)->chaining;
464 
465 			/* Check if the next element is not the sentinel ( ==> the parent) */
466 			if (li->next != li->head)
467 				result = _C(li->next->o);
468 			break;
469 
470 		case MSG_BRW_PREV:
471 			/* Check the reference is an AVP */
472 			CHECK_PARAMS(  _C(reference)->type == MSG_AVP  );
473 
474 			li = &_C(reference)->chaining;
475 
476 			/* Check if the prev element is not the sentinel ( ==> the parent) */
477 			if (li->prev != li->head)
478 				result = _C(li->prev->o);
479 			break;
480 
481 		case MSG_BRW_FIRST_CHILD:
482 			li = &_C(reference)->children;
483 			if (! FD_IS_LIST_EMPTY(li)) {
484 				result = _C(li->next->o);
485 				diff = 1;
486 			}
487 			break;
488 
489 		case MSG_BRW_LAST_CHILD:
490 			li = &_C(reference)->children;
491 			if (! FD_IS_LIST_EMPTY(li)) {
492 				result = _C(li->prev->o);
493 				diff = 1;
494 			}
495 			break;
496 
497 		case MSG_BRW_PARENT:
498 			/* If the object is not chained, it has no parent */
499 			li = &_C(reference)->chaining;
500 			if (li != li->head) {
501 				/* The sentinel is the parent's children list */
502 				result = _C(li->head->o);
503 				diff = -1;
504 			}
505 			break;
506 
507 		case MSG_BRW_WALK:
508 			/* First, try to find a child */
509 			li = &_C(reference)->children;
510 			if ( ! FD_IS_LIST_EMPTY(li) ) {
511 				result = _C(li->next->o);
512 				diff = 1;
513 				break;
514 			}
515 
516 			/* Then try to find a "next" at this level or one of the parent's */
517 			li = &_C(reference)->chaining;
518 			do {
519 				/* If this element has a "next" element, return it */
520 				if (li->next != li->head) {
521 					result = _C(li->next->o);
522 					break;
523 				}
524 				/* otherwise, check if we have a parent */
525 				if (li == li->head) {
526 					/* no parent */
527 					break;
528 				}
529 				/* Go to the parent's chaining information and loop */
530 				diff -= 1;
531 				li = &_C(li->head->o)->chaining;
532 			} while (1);
533 			break;
534 
535 		default:
536 			/* Other directions are invalid */
537 			CHECK_PARAMS( dir = 0 );
538 	}
539 
540 	/* Save the found object, if any */
541 	if (found && result)
542 		*found = (void *)result;
543 
544 	/* Modify the depth according to the walk direction */
545 	if (depth && diff)
546 		(*depth) += diff;
547 
548 	/* Return ENOENT if found was NULL */
549 	if ((!found) && (!result))
550 		return ENOENT;
551 	else
552 		return 0;
553 }
554 
555 /* Add an AVP into a tree */
fd_msg_avp_add(msg_or_avp * reference,enum msg_brw_dir dir,struct avp * avp)556 int fd_msg_avp_add ( msg_or_avp * reference, enum msg_brw_dir dir, struct avp *avp)
557 {
558 	TRACE_ENTRY("%p %d %p", reference, dir, avp);
559 
560 	/* Check the parameters */
561 	CHECK_PARAMS(  VALIDATE_OBJ(reference)  &&  CHECK_AVP(avp)  &&  FD_IS_LIST_EMPTY(&avp->avp_chain.chaining)  );
562 
563 	/* Now insert */
564 	switch (dir) {
565 		case MSG_BRW_NEXT:
566 			/* Check the reference is an AVP -- we do not chain AVPs at same level as msgs. */
567 			CHECK_PARAMS(  _C(reference)->type == MSG_AVP  );
568 
569 			/* Insert the new avp after the reference */
570 			fd_list_insert_after( &_A(reference)->avp_chain.chaining, &avp->avp_chain.chaining );
571 			break;
572 
573 		case MSG_BRW_PREV:
574 			/* Check the reference is an AVP */
575 			CHECK_PARAMS(  _C(reference)->type == MSG_AVP  );
576 
577 			/* Insert the new avp before the reference */
578 			fd_list_insert_before( &_A(reference)->avp_chain.chaining, &avp->avp_chain.chaining );
579 			break;
580 
581 		case MSG_BRW_FIRST_CHILD:
582 			/* Insert the new avp after the children sentinel */
583 			fd_list_insert_after( &_C(reference)->children, &avp->avp_chain.chaining );
584 			break;
585 
586 		case MSG_BRW_LAST_CHILD:
587 			/* Insert the new avp before the children sentinel */
588 			fd_list_insert_before( &_C(reference)->children, &avp->avp_chain.chaining );
589 			break;
590 
591 		default:
592 			/* Other directions are invalid */
593 			CHECK_PARAMS( dir = 0 );
594 	}
595 
596 	return 0;
597 }
598 
599 /* Search a given AVP model in a message or AVP */
fd_msg_search_avp(msg_or_avp * reference,struct dict_object * what,struct avp ** avp)600 int fd_msg_search_avp ( msg_or_avp * reference, struct dict_object * what, struct avp ** avp )
601 {
602 	struct avp * nextavp;
603 	struct dict_avp_data 	dictdata;
604 	enum dict_object_type 	dicttype;
605 
606 	TRACE_ENTRY("%p %p %p", reference, what, avp);
607 
608 	CHECK_PARAMS( VALIDATE_OBJ(reference) && what );
609 
610 	CHECK_PARAMS( (fd_dict_gettype(what, &dicttype) == 0) && (dicttype == DICT_AVP) );
611 	CHECK_FCT(  fd_dict_getval(what, &dictdata)  );
612 
613 	/* Loop on all top AVPs in message or AVP */
614 	CHECK_FCT(  fd_msg_browse(reference, MSG_BRW_FIRST_CHILD, (void *)&nextavp, NULL)  );
615 	while (nextavp) {
616 
617 		if ( (nextavp->avp_public.avp_code   == dictdata.avp_code)
618 		  && (nextavp->avp_public.avp_vendor == dictdata.avp_vendor) ) /* always 0 if no V flag */
619 			break;
620 
621 		/* Otherwise move to next AVP in the message or AVP */
622 		CHECK_FCT( fd_msg_browse(nextavp, MSG_BRW_NEXT, (void *)&nextavp, NULL) );
623 	}
624 
625 	if (avp)
626 		*avp = nextavp;
627 
628 	if (avp && nextavp) {
629 		struct dictionary * dict;
630 		CHECK_FCT( fd_dict_getdict( what, &dict) );
631 		CHECK_FCT_DO( fd_msg_parse_dict( nextavp, dict, NULL ), /* nothing */ );
632 	}
633 
634 	if (avp || nextavp)
635 		return 0;
636 	else
637 		return ENOENT;
638 }
639 
640 
641 /***************************************************************************************************************/
642 /* Deleting objects */
643 
644 /* Destroy and free an AVP or message */
destroy_obj(struct msg_avp_chain * obj)645 static int destroy_obj (struct msg_avp_chain * obj )
646 {
647 	TRACE_ENTRY("%p", obj);
648 
649 	/* Check the parameter is a valid object */
650 	CHECK_PARAMS(  VALIDATE_OBJ(obj) && FD_IS_LIST_EMPTY( &obj->children ) );
651 
652 	/* Unlink this object if needed */
653 	fd_list_unlink( &obj->chaining );
654 
655 	/* Free the octetstring if needed */
656 	if ((obj->type == MSG_AVP) && (_A(obj)->avp_mustfreeos == 1)) {
657 		free(_A(obj)->avp_storage.os.data);
658 	}
659 	/* Free the rawdata if needed */
660 	if ((obj->type == MSG_AVP) && (_A(obj)->avp_rawdata != NULL)) {
661 		free(_A(obj)->avp_rawdata);
662 	}
663 	if ((obj->type == MSG_MSG) && (_M(obj)->msg_rawbuffer != NULL)) {
664 		free(_M(obj)->msg_rawbuffer);
665 	}
666 
667 	if ((obj->type == MSG_MSG) && (_M(obj)->msg_src_id != NULL)) {
668 		free(_M(obj)->msg_src_id);
669 	}
670 
671 	if ((obj->type == MSG_MSG) && (_M(obj)->msg_rtdata != NULL)) {
672 		fd_rtd_free(&_M(obj)->msg_rtdata);
673 	}
674 
675 	if ((obj->type == MSG_MSG) && (_M(obj)->msg_sess != NULL)) {
676 		CHECK_FCT_DO( fd_sess_reclaim_msg ( &_M(obj)->msg_sess ), /* continue */);
677 	}
678 
679 	if ((obj->type == MSG_MSG) && (_M(obj)->msg_pmdl.sentinel.o != NULL)) {
680 		((void (*)(struct fd_msg_pmdl *))_M(obj)->msg_pmdl.sentinel.o)(&_M(obj)->msg_pmdl);
681 	}
682 
683 	/* free the object */
684 	free(obj);
685 
686 	return 0;
687 }
688 
689 /* Destroy an object and all its children */
destroy_tree(struct msg_avp_chain * obj)690 static void destroy_tree(struct msg_avp_chain * obj)
691 {
692 	struct fd_list *rem;
693 
694 	TRACE_ENTRY("%p", obj);
695 
696 	/* Destroy any subtree */
697 	while ( (rem = obj->children.next) != &obj->children)
698 		destroy_tree(_C(rem->o));
699 
700 	/* Then unlink and destroy the object */
701 	CHECK_FCT_DO(  destroy_obj(obj),  /* nothing */  );
702 }
703 
704 /* Free an object and its tree */
fd_msg_free(msg_or_avp * object)705 int fd_msg_free ( msg_or_avp * object )
706 {
707 	TRACE_ENTRY("%p", object);
708 
709 	if (object == NULL)
710 		return 0;
711 
712 	if (CHECK_MSG(object)) {
713 		if (_M(object)->msg_query) {
714 			_M(_M(object)->msg_query)->msg_associated = 0;
715 			CHECK_FCT(  fd_msg_free( _M(object)->msg_query )  );
716 			_M(object)->msg_query = NULL;
717 		} else {
718 			if (_M(object)->msg_associated) {
719 				TRACE_DEBUG(INFO, "Not freeing query %p referenced in an answer (will be freed along the answer).", object);
720 				return 0;
721 			}
722 		}
723 	}
724 
725 	destroy_tree(_C(object));
726 	return 0;
727 }
728 
729 
730 /***************************************************************************************************************/
731 /* Debug functions: dumping */
732 
733 /* messages and AVP formatters */
734 typedef DECLARE_FD_DUMP_PROTOTYPE( (*msg_dump_formatter_msg), struct msg * msg );
735 typedef DECLARE_FD_DUMP_PROTOTYPE( (*msg_dump_formatter_avp), struct avp * avp, int level, int first, int last );
736 
737 /* Core function to process the dumping */
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)738 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 )
739 {
740 	FD_DUMP_HANDLE_OFFSET();
741 
742 	if (!VALIDATE_OBJ(obj)) {
743 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID MESSAGE OR AVP @%p", obj), return NULL);
744 		return *buf;
745 	}
746 
747 	if (force_parsing) {
748 		(void) fd_msg_parse_dict(obj, dict, NULL);
749 	}
750 
751 	switch (_C(obj)->type) {
752 		case MSG_AVP:
753 			CHECK_MALLOC_DO( (*avp_format)(FD_DUMP_STD_PARAMS, (struct avp *)obj, 0, 1, 1), return NULL);
754 			break;
755 
756 		case MSG_MSG:
757 			CHECK_MALLOC_DO( (*msg_format)(FD_DUMP_STD_PARAMS, (struct msg *)obj), return NULL);
758 			break;
759 
760 		default:
761 			ASSERT(0);
762 			free(*buf);
763 			*buf = NULL;
764 			return NULL;
765 	}
766 
767 	if (recurse) {
768 		struct avp * avp = NULL;
769 		int first = 1;
770 		CHECK_FCT_DO(  fd_msg_browse ( obj, MSG_BRW_FIRST_CHILD, &avp, NULL ), avp = NULL );
771 		while (avp) {
772 			struct avp * nextavp = NULL;
773 			CHECK_FCT_DO(  fd_msg_browse ( avp, MSG_BRW_NEXT, &nextavp, NULL ), nextavp = NULL  );
774 			CHECK_MALLOC_DO( (*avp_format)(FD_DUMP_STD_PARAMS, avp, 1, first, nextavp ? 0 : 1), return NULL);
775 			avp = nextavp;
776 			first = 0;
777 		};
778 	}
779 
780 	return *buf;
781 }
782 
783 /*
784  * Tree View message dump
785  */
DECLARE_FD_DUMP_PROTOTYPE(msg_format_treeview,struct msg * msg)786 static DECLARE_FD_DUMP_PROTOTYPE( msg_format_treeview, struct msg * msg )
787 {
788 	if (!CHECK_MSG(msg)) {
789 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID MESSAGE"), return NULL);
790 		return *buf;
791 	}
792 
793 	if (!msg->msg_model) {
794 		if (msg->msg_model_not_found.mnf_code) {
795 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not found in dictionary)\n"), return NULL);
796 		} else {
797 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not searched in dictionary)\n"), return NULL);
798 		}
799 	} else {
800 		enum dict_object_type dicttype;
801 		struct dict_cmd_data  dictdata;
802 		if (fd_dict_gettype(msg->msg_model, &dicttype) || (dicttype != DICT_COMMAND)) {
803 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(invalid model information)\n"), return NULL);
804 		} else if (fd_dict_getval(msg->msg_model, &dictdata)) {
805 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(error getting model information)\n"), return NULL);
806 		} else {
807 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'\n", dictdata.cmd_name), return NULL);
808 		}
809 	}
810 
811 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Version: 0x%02hhX\n", msg->msg_public.msg_version), return NULL);
812 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Length: %d\n", msg->msg_public.msg_length), return NULL);
813 	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);
814 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Command Code: %u\n", msg->msg_public.msg_code), return NULL);
815 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  ApplicationId: %d\n", msg->msg_public.msg_appl), return NULL);
816 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Hop-by-Hop Identifier: 0x%08X\n", msg->msg_public.msg_hbhid), return NULL);
817 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  End-to-End Identifier: 0x%08X\n", msg->msg_public.msg_eteid), return NULL);
818 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "   {internal 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);
819 
820 	return *buf;
821 }
822 
DECLARE_FD_DUMP_PROTOTYPE(avp_format_treeview,struct avp * avp,int level,int first,int last)823 static DECLARE_FD_DUMP_PROTOTYPE( avp_format_treeview, struct avp * avp, int level, int first, int last )
824 {
825 	char * name;
826 	struct dict_avp_data  dictdata;
827 	struct dict_avp_data *dictinfo = NULL;
828 	struct dict_vendor_data  vendordata;
829 	struct dict_vendor_data *vendorinfo = NULL;
830 
831 	if (level) {
832 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
833 	}
834 
835 	if (!CHECK_AVP(avp)) {
836 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID AVP"), return NULL);
837 		return *buf;
838 	}
839 
840 	if (level) {
841 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*sAVP: ", level * 3, ""), return NULL);
842 	}
843 
844 	if (!avp->avp_model) {
845 		if (avp->avp_model_not_found.mnf_code) {
846 			name = "(not found in dictionary)";
847 		} else {
848 			name = "(not searched in dictionary)";
849 		}
850 	} else {
851 		enum dict_object_type dicttype;
852 		if (fd_dict_gettype(avp->avp_model, &dicttype) || (dicttype != DICT_AVP)) {
853 			name = "(invalid model information)";
854 		} else if (fd_dict_getval(avp->avp_model, &dictdata)) {
855 			name = "(error getting model information)";
856 		} else {
857 			name = dictdata.avp_name;
858 			dictinfo = &dictdata;
859 			if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
860 				struct dictionary * dict;
861 				struct dict_object * vendor;
862 				if ((!fd_dict_getdict(avp->avp_model, &dict))
863 				&& (!fd_dict_search(dict, DICT_VENDOR, VENDOR_OF_AVP, avp->avp_model, &vendor, ENOENT))
864 				&& (!fd_dict_getval(vendor, &vendordata))) {
865 					vendorinfo = &vendordata;
866 				}
867 			}
868 		}
869 	}
870 
871 	if (dictinfo) {
872 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%u)", name, avp->avp_public.avp_code), return NULL);
873 	} else {
874 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%u%s", avp->avp_public.avp_code, name), return NULL);
875 	}
876 
877 	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
878 		if (vendorinfo) {
879 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " vend='%s'(%u)", vendorinfo->vendor_name, avp->avp_public.avp_vendor), return NULL);
880 		} else {
881 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " vend=%u", avp->avp_public.avp_vendor), return NULL);
882 		}
883 	}
884 
885 	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);
886 
887 	if (dictinfo && (dictinfo->avp_basetype == AVP_TYPE_GROUPED)) {
888 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(grouped)"), return NULL);
889 		if (level) {
890 			struct avp * inavp = NULL;
891 			int first = 1;
892 			CHECK_FCT_DO(  fd_msg_browse ( avp, MSG_BRW_FIRST_CHILD, &inavp, NULL ), inavp = NULL );
893 			while (inavp) {
894 				struct avp * nextavp = NULL;
895 				CHECK_FCT_DO(  fd_msg_browse ( inavp, MSG_BRW_NEXT, &nextavp, NULL ), inavp = NULL  );
896 				CHECK_MALLOC_DO( avp_format_treeview(FD_DUMP_STD_PARAMS, inavp, level + 1, first, nextavp ? 0 : 1), return NULL);
897 				inavp = nextavp;
898 				first = 0;
899 			};
900 		}
901 	} else {
902 		if (avp->avp_public.avp_value) {
903 			CHECK_MALLOC_DO( fd_dict_dump_avp_value(FD_DUMP_STD_PARAMS, avp->avp_public.avp_value, avp->avp_model, 0, 0), return NULL);
904 		} else if (avp->avp_rawdata) {
905 			CHECK_MALLOC_DO( fd_dump_extend_hexdump(FD_DUMP_STD_PARAMS, avp->avp_rawdata, avp->avp_rawlen, 0, 0), return NULL);
906 		} else {
907 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not set)"), return NULL);
908 		}
909 	}
910 
911 	return *buf;
912 }
913 
914 /* 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)915 DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_treeview, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
916 {
917 	return msg_dump_process(FD_DUMP_STD_PARAMS, msg_format_treeview, avp_format_treeview, obj, dict, force_parsing, recurse);
918 }
919 
920 
921 /*
922  * One-line dumper for compact but complete traces
923  */
DECLARE_FD_DUMP_PROTOTYPE(msg_format_full,struct msg * msg)924 static DECLARE_FD_DUMP_PROTOTYPE( msg_format_full, struct msg * msg )
925 {
926 	int success = 0;
927 	struct dict_cmd_data dictdata;
928 
929 	if (!CHECK_MSG(msg)) {
930 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID MESSAGE"), return NULL);
931 		return *buf;
932 	}
933 
934 	if (!msg->msg_model) {
935 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(no model) "), return NULL);
936 	} else {
937 		enum dict_object_type dicttype=0;
938 		if (fd_dict_gettype(msg->msg_model, &dicttype) || (dicttype != DICT_COMMAND)) {
939 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(invalid model %d) ", dicttype), return NULL);
940 		} else if (fd_dict_getval(msg->msg_model, &dictdata)) {
941 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(error getting model data) "), return NULL);
942 		} else {
943 			success = 1;
944 		}
945 	}
946 	if (msg->msg_public.msg_appl) {
947 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS,
948 				   "%s(%u/%u)[" DUMP_CMDFL_str "], Length=%u, Hop-By-Hop-Id=0x%08x, End-to-End=0x%08x",
949 					success ? dictdata.cmd_name :  "unknown",  msg->msg_public.msg_appl, msg->msg_public.msg_code, DUMP_CMDFL_val(msg->msg_public.msg_flags),
950 					msg->msg_public.msg_length, msg->msg_public.msg_hbhid, msg->msg_public.msg_eteid), return NULL);
951 	} else {
952 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS,
953 				   "%s(%u)[" DUMP_CMDFL_str "], Length=%u, Hop-By-Hop-Id=0x%08x, End-to-End=0x%08x",
954 					success ? dictdata.cmd_name :  "unknown", msg->msg_public.msg_code, DUMP_CMDFL_val(msg->msg_public.msg_flags),
955 					msg->msg_public.msg_length, msg->msg_public.msg_hbhid, msg->msg_public.msg_eteid), return NULL);
956 	}
957 	return *buf;
958 }
959 
DECLARE_FD_DUMP_PROTOTYPE(avp_format_full,struct avp * avp,int level,int first,int last)960 static DECLARE_FD_DUMP_PROTOTYPE( avp_format_full, struct avp * avp, int level, int first, int last )
961 {
962 	int success = 0;
963 	struct dict_avp_data  dictdata;
964 
965 	if (level) {
966 		if ((first) && ((*buf)[*offset - 1] == '=')) {
967 			/* We are first AVP of a grouped AVP */
968 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{ "), return NULL);
969 		} else {
970 			/* We follow another AVP, or a message header */
971 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ", { "), return NULL);
972 		}
973 	}
974 
975 	if (!CHECK_AVP(avp)) {
976 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID AVP"), return NULL);
977 		goto end;
978 	}
979 
980 
981 	if (avp->avp_model) {
982 		enum dict_object_type dicttype;
983 		if (fd_dict_gettype(avp->avp_model, &dicttype) || (dicttype != DICT_AVP)) {
984 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(invalid model: %d) ", dicttype), return NULL);
985 		} else if (fd_dict_getval(avp->avp_model, &dictdata)) {
986 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(error getting model data) "), return NULL);
987 		} else {
988 			success = 1;
989 		}
990 	}
991 
992 	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
993 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s(%u/%u)[" DUMP_AVPFL_str "]=",
994 					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);
995 	} else {
996 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s(%u)[" DUMP_AVPFL_str "]=",
997 					success ? dictdata.avp_name : "unknown", avp->avp_public.avp_code, DUMP_AVPFL_val(avp->avp_public.avp_flags)), return NULL);
998 	}
999 
1000 
1001 	if (success && (dictdata.avp_basetype == AVP_TYPE_GROUPED)) {
1002 		if (level) {
1003 			struct avp * inavp = NULL;
1004 			int first = 1;
1005 			CHECK_FCT_DO(  fd_msg_browse ( avp, MSG_BRW_FIRST_CHILD, &inavp, NULL ), inavp = NULL );
1006 			while (inavp) {
1007 				struct avp * nextavp = NULL;
1008 				CHECK_FCT_DO(  fd_msg_browse ( inavp, MSG_BRW_NEXT, &nextavp, NULL ), inavp = NULL  );
1009 				CHECK_MALLOC_DO( avp_format_full(FD_DUMP_STD_PARAMS, inavp, level + 1, first, nextavp ? 0 : 1), return NULL);
1010 				inavp = nextavp;
1011 				first = 0;
1012 			};
1013 		}
1014 	} else {
1015 		if (avp->avp_public.avp_value) {
1016 			CHECK_MALLOC_DO( fd_dict_dump_avp_value(FD_DUMP_STD_PARAMS, avp->avp_public.avp_value, avp->avp_model, 0, 0), return NULL);
1017 		} else if (avp->avp_rawdata) {
1018 			CHECK_MALLOC_DO( fd_dump_extend_hexdump(FD_DUMP_STD_PARAMS, avp->avp_rawdata, avp->avp_rawlen, 0, 0), return NULL);
1019 		} else {
1020 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not set)"), return NULL);
1021 		}
1022 	}
1023 
1024 end:
1025 	if (level) {
1026 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " }"), return NULL);
1027 	}
1028 
1029 	return *buf;
1030 }
1031 
1032 /* 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)1033 DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_full, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
1034 {
1035 	return msg_dump_process(FD_DUMP_STD_PARAMS, msg_format_full, avp_format_full, obj, dict, force_parsing, recurse);
1036 }
1037 
1038 
1039 
1040 /*
1041  * One-line dumper for compact but complete traces
1042  */
DECLARE_FD_DUMP_PROTOTYPE(msg_format_summary,struct msg * msg)1043 static DECLARE_FD_DUMP_PROTOTYPE( msg_format_summary, struct msg * msg )
1044 {
1045 	if (!CHECK_MSG(msg)) {
1046 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID MESSAGE"), return NULL);
1047 		return *buf;
1048 	}
1049 
1050 	if (!msg->msg_model) {
1051 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(no model)"), return NULL);
1052 	} else {
1053 		enum dict_object_type dicttype;
1054 		struct dict_cmd_data  dictdata;
1055 		if (fd_dict_gettype(msg->msg_model, &dicttype) || (dicttype != DICT_COMMAND) || (fd_dict_getval(msg->msg_model, &dictdata))) {
1056 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(model error)"), return NULL);
1057 		} else {
1058 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'", dictdata.cmd_name), return NULL);
1059 		}
1060 	}
1061 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%u/%u f:" DUMP_CMDFL_str " src:'%s' len:%d",
1062 				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);
1063 
1064 	return *buf;
1065 }
1066 
DECLARE_FD_DUMP_PROTOTYPE(avp_format_summary,struct avp * avp,int level,int first,int last)1067 static DECLARE_FD_DUMP_PROTOTYPE( avp_format_summary, struct avp * avp, int level, int first, int last )
1068 {
1069 	char * name;
1070 	struct dict_avp_data  dictdata;
1071 	struct dict_avp_data *dictinfo = NULL;
1072 	struct dict_vendor_data  vendordata;
1073 	struct dict_vendor_data *vendorinfo = NULL;
1074 
1075 	if (level) {
1076 		if (first) {
1077 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {"), return NULL);
1078 		} else {
1079 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ","), return NULL);
1080 		}
1081 	}
1082 
1083 	if (!CHECK_AVP(avp)) {
1084 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID AVP"), return NULL);
1085 		goto end;
1086 	}
1087 
1088 	if (!level) {
1089 		/* We have been called to explicitely dump this AVP, so we parse its name if available */
1090 		if (!avp->avp_model) {
1091 			name = "(no model)";
1092 		} else {
1093 			enum dict_object_type dicttype;
1094 			if (fd_dict_gettype(avp->avp_model, &dicttype) || (dicttype != DICT_AVP) || (fd_dict_getval(avp->avp_model, &dictdata))) {
1095 				name = "(model error)";
1096 			} else {
1097 				name = dictdata.avp_name;
1098 				dictinfo = &dictdata;
1099 				if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
1100 					struct dictionary * dict;
1101 					struct dict_object * vendor;
1102 					if ((!fd_dict_getdict(avp->avp_model, &dict))
1103 					&& (!fd_dict_search(dict, DICT_VENDOR, VENDOR_OF_AVP, avp->avp_model, &vendor, ENOENT))
1104 					&& (!fd_dict_getval(vendor, &vendordata))) {
1105 						vendorinfo = &vendordata;
1106 					}
1107 				}
1108 			}
1109 		}
1110 
1111 		if (dictinfo) {
1112 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%u)", name, avp->avp_public.avp_code), return NULL);
1113 		} else {
1114 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%u%s", avp->avp_public.avp_code, name), return NULL);
1115 		}
1116 
1117 		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
1118 			if (vendorinfo) {
1119 				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " V='%s'(%u)", vendorinfo->vendor_name, avp->avp_public.avp_vendor), return NULL);
1120 			} else {
1121 				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " V=%u", avp->avp_public.avp_vendor), return NULL);
1122 			}
1123 		}
1124 
1125 		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);
1126 
1127 		if ((!dictinfo) || (dictinfo->avp_basetype != AVP_TYPE_GROUPED)) {
1128 			if (avp->avp_public.avp_value) {
1129 				CHECK_MALLOC_DO( fd_dict_dump_avp_value(FD_DUMP_STD_PARAMS, avp->avp_public.avp_value, avp->avp_model, 0, 0), return NULL);
1130 			} else if (avp->avp_rawdata) {
1131 				CHECK_MALLOC_DO( fd_dump_extend_hexdump(FD_DUMP_STD_PARAMS, avp->avp_rawdata, avp->avp_rawlen, 0, 0), return NULL);
1132 			} else {
1133 				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not set)"), return NULL);
1134 			}
1135 		}
1136 	} else {
1137 		/* For embedded AVPs, we only display (vendor,) code & length */
1138 		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
1139 			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "V:%u/", avp->avp_public.avp_vendor), return NULL);
1140 		}
1141 		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);
1142 	}
1143 
1144 end:
1145 	if ((level) && (last)) {
1146 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "}"), return NULL);
1147 	}
1148 
1149 	return *buf;
1150 }
1151 
1152 /* 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)1153 DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_summary, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
1154 {
1155 	return msg_dump_process(FD_DUMP_STD_PARAMS, msg_format_summary, avp_format_summary, obj, dict, force_parsing, recurse);
1156 }
1157 
1158 /***************************************************************************************************************/
1159 /* Simple meta-data management */
1160 
1161 /* Retrieve the model of an object */
fd_msg_model(msg_or_avp * reference,struct dict_object ** model)1162 int fd_msg_model ( msg_or_avp * reference, struct dict_object ** model )
1163 {
1164 	TRACE_ENTRY("%p %p", reference, model);
1165 
1166 	/* Check the parameters */
1167 	CHECK_PARAMS(  model && VALIDATE_OBJ(reference)  );
1168 
1169 	/* copy the model reference */
1170 	switch (_C(reference)->type) {
1171 		case MSG_AVP:
1172 			*model = _A(reference)->avp_model;
1173 			break;
1174 
1175 		case MSG_MSG:
1176 			*model = _M(reference)->msg_model;
1177 			break;
1178 
1179 		default:
1180 			CHECK_PARAMS(0);
1181 	}
1182 
1183 	return 0;
1184 }
1185 
1186 /* Retrieve the address of the msg_public field of a message */
fd_msg_hdr(struct msg * msg,struct msg_hdr ** pdata)1187 int fd_msg_hdr ( struct msg *msg, struct msg_hdr **pdata )
1188 {
1189 	TRACE_ENTRY("%p %p", msg, pdata);
1190 	CHECK_PARAMS(  CHECK_MSG(msg) && pdata  );
1191 
1192 	*pdata = &msg->msg_public;
1193 	return 0;
1194 }
1195 
1196 /* Retrieve the address of the avp_public field of an avp */
fd_msg_avp_hdr(struct avp * avp,struct avp_hdr ** pdata)1197 int fd_msg_avp_hdr ( struct avp *avp, struct avp_hdr **pdata )
1198 {
1199 	TRACE_ENTRY("%p %p", avp, pdata);
1200 	CHECK_PARAMS(  CHECK_AVP(avp) && pdata  );
1201 
1202 	*pdata = &avp->avp_public;
1203 	return 0;
1204 }
1205 
1206 /* Associate answers and queries */
fd_msg_answ_associate(struct msg * answer,struct msg * query)1207 int fd_msg_answ_associate( struct msg * answer, struct msg * query )
1208 {
1209 	TRACE_ENTRY( "%p %p", answer, query );
1210 
1211 	CHECK_PARAMS(  CHECK_MSG(answer) && CHECK_MSG(query) && (answer->msg_query == NULL )  );
1212 
1213 	answer->msg_query = query;
1214 	query->msg_associated = 1;
1215 
1216 	return 0;
1217 }
1218 
fd_msg_answ_getq(struct msg * answer,struct msg ** query)1219 int fd_msg_answ_getq( struct msg * answer, struct msg ** query )
1220 {
1221 	TRACE_ENTRY( "%p %p", answer, query );
1222 
1223 	CHECK_PARAMS(  CHECK_MSG(answer) && query  );
1224 
1225 	*query = answer->msg_query;
1226 
1227 	return 0;
1228 }
1229 
fd_msg_answ_detach(struct msg * answer)1230 int fd_msg_answ_detach( struct msg * answer )
1231 {
1232 	TRACE_ENTRY( "%p", answer );
1233 
1234 	CHECK_PARAMS(  CHECK_MSG(answer) );
1235 
1236 	answer->msg_query->msg_associated = 0;
1237 	answer->msg_query = NULL;
1238 
1239 	return 0;
1240 }
1241 
1242 /* Associate / get answer callbacks */
fd_msg_anscb_associate(struct msg * msg,void (* anscb)(void *,struct msg **),void * data,void (* expirecb)(void *,DiamId_t,size_t,struct msg **),const struct timespec * timeout)1243 int fd_msg_anscb_associate( struct msg * msg, void ( *anscb)(void *, struct msg **), void  * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout )
1244 {
1245 	TRACE_ENTRY("%p %p %p %p", msg, anscb, expirecb, data);
1246 
1247 	/* Check the parameters */
1248 	CHECK_PARAMS( CHECK_MSG(msg) );
1249 
1250 	if (! (msg->msg_public.msg_flags & CMD_FLAG_REQUEST ))
1251 		return anscb ? EINVAL : 0; /* we associate with requests only */
1252 
1253 	CHECK_PARAMS( (anscb == NULL)    || (msg->msg_cb.anscb == NULL) ); /* We are not overwriting a cb */
1254 	CHECK_PARAMS( (expirecb == NULL) || (msg->msg_cb.expirecb == NULL) ); /* We are not overwriting a cb */
1255 
1256 	/* Associate callback and data with the message, if any */
1257 	if (anscb) {
1258 		msg->msg_cb.anscb = anscb;
1259 		msg->msg_cb.data = data;
1260 	}
1261 	if (expirecb) {
1262 		msg->msg_cb.expirecb = expirecb;
1263 		msg->msg_cb.data = data;
1264 		if (timeout) {
1265 			memcpy(&msg->msg_cb.timeout, timeout, sizeof(struct timespec));
1266 		}
1267 	}
1268 
1269 	return 0;
1270 }
1271 
1272 /* Remove a callback */
fd_msg_anscb_reset(struct msg * msg,int clear_anscb,int clear_expirecb)1273 int fd_msg_anscb_reset(struct msg * msg, int clear_anscb, int clear_expirecb)
1274 {
1275 	TRACE_ENTRY("%p %d %d", msg, clear_anscb, clear_expirecb);
1276 
1277 	/* Check the parameters */
1278 	CHECK_PARAMS( CHECK_MSG(msg) );
1279 
1280 	if (clear_anscb) {
1281 		msg->msg_cb.anscb = NULL;
1282 		msg->msg_cb.data = NULL;
1283 	}
1284 	if (clear_expirecb) {
1285 		msg->msg_cb.expirecb = NULL;
1286 		memset(&msg->msg_cb.timeout, 0, sizeof(struct timespec));
1287 	}
1288 
1289 	return 0;
1290 }
1291 
1292 
fd_msg_anscb_get(struct msg * msg,void (** anscb)(void *,struct msg **),void (** expirecb)(void *,DiamId_t,size_t,struct msg **),void ** data)1293 int fd_msg_anscb_get( struct msg * msg, void (**anscb)(void *, struct msg **), void (**expirecb)(void *, DiamId_t, size_t, struct msg **), void ** data )
1294 {
1295 	TRACE_ENTRY("%p %p %p %p", msg, anscb, expirecb, data);
1296 
1297 	/* Check the parameters */
1298 	CHECK_PARAMS( CHECK_MSG(msg) );
1299 
1300 	/* Copy the result */
1301 	if (anscb)
1302 		*anscb = msg->msg_cb.anscb;
1303 	if (data)
1304 		*data  = msg->msg_cb.data;
1305 	if (expirecb)
1306 		*expirecb = msg->msg_cb.expirecb;
1307 
1308 	return 0;
1309 }
1310 
fd_msg_anscb_gettimeout(struct msg * msg)1311 struct timespec *fd_msg_anscb_gettimeout( struct msg * msg )
1312 {
1313 	TRACE_ENTRY("%p", msg);
1314 
1315 	/* Check the parameters */
1316 	CHECK_PARAMS_DO( CHECK_MSG(msg), return NULL );
1317 
1318 	if (!msg->msg_cb.timeout.tv_sec) {
1319 		return NULL;
1320 	}
1321 
1322 	return &msg->msg_cb.timeout;
1323 }
1324 
1325 /* Associate routing lists */
fd_msg_rt_associate(struct msg * msg,struct rt_data * rtd)1326 int fd_msg_rt_associate( struct msg * msg, struct rt_data * rtd )
1327 {
1328 	TRACE_ENTRY( "%p %p", msg, rtd );
1329 
1330 	CHECK_PARAMS(  CHECK_MSG(msg) && rtd  );
1331 
1332 	msg->msg_rtdata = rtd;
1333 
1334 	return 0;
1335 }
1336 
fd_msg_rt_get(struct msg * msg,struct rt_data ** rtd)1337 int fd_msg_rt_get( struct msg * msg, struct rt_data ** rtd )
1338 {
1339 	TRACE_ENTRY( "%p %p", msg, rtd );
1340 
1341 	CHECK_PARAMS(  CHECK_MSG(msg) && rtd  );
1342 
1343 	*rtd = msg->msg_rtdata;
1344 
1345 	return 0;
1346 }
1347 
1348 /* Find if a message is routable */
fd_msg_is_routable(struct msg * msg)1349 int fd_msg_is_routable ( struct msg * msg )
1350 {
1351 	TRACE_ENTRY("%p", msg);
1352 
1353 	CHECK_PARAMS_DO(  CHECK_MSG(msg),  return 0 /* pretend the message is not routable */ );
1354 
1355 	if ( ! msg->msg_routable ) {
1356 		/* To define if a message is routable, we rely on the "PXY" flag (for application 0). */
1357 		msg->msg_routable = ((msg->msg_public.msg_appl != 0) || (msg->msg_public.msg_flags & CMD_FLAG_PROXIABLE)) ? 1 : 2;
1358 
1359 		/* Note : the 'real' criteria according to the Diameter I-D is that the message is
1360 		 routable if and only if the "Destination-Realm" AVP is required by the command ABNF.
1361 		 We could make a test for this here, but it's more computational work and our test
1362 		 seems accurate (until proven otherwise...) */
1363 	}
1364 
1365 	return (msg->msg_routable == 1) ? 1 : 0;
1366 }
1367 
1368 /* cache the dictionary model for next function to avoid re-searching at every incoming message */
1369 static struct dict_object *cached_avp_rr_model = NULL;
1370 static struct dictionary  *cached_avp_rr_dict  = NULL;
1371 static pthread_mutex_t     cached_avp_rr_lock = PTHREAD_MUTEX_INITIALIZER;
1372 
1373 /* Associate source peer */
fd_msg_source_set(struct msg * msg,DiamId_t diamid,size_t diamidlen)1374 int fd_msg_source_set( struct msg * msg, DiamId_t diamid, size_t diamidlen )
1375 {
1376 	TRACE_ENTRY( "%p %p %zd", msg, diamid, diamidlen);
1377 
1378 	/* Check we received a valid message */
1379 	CHECK_PARAMS( CHECK_MSG(msg) );
1380 
1381 	/* Cleanup any previous source */
1382 	free(msg->msg_src_id); msg->msg_src_id = NULL; msg->msg_src_id_len = 0;
1383 
1384 	/* If the request is to cleanup the source, we are done */
1385 	if (diamid == NULL) {
1386 		return 0;
1387 	}
1388 
1389 	/* Otherwise save the new informations */
1390 	CHECK_MALLOC( msg->msg_src_id = os0dup(diamid, diamidlen) );
1391 	msg->msg_src_id_len = diamidlen;
1392 	/* done */
1393 	return 0;
1394 }
1395 
1396 /* Associate source peer */
fd_msg_source_setrr(struct msg * msg,DiamId_t diamid,size_t diamidlen,struct dictionary * dict)1397 int fd_msg_source_setrr( struct msg * msg, DiamId_t diamid, size_t diamidlen, struct dictionary * dict )
1398 {
1399 	struct dict_object 	*avp_rr_model = NULL;
1400 	avp_code_t 		 code = AC_ROUTE_RECORD;
1401 	struct avp 		*avp;
1402 	union avp_value		 val;
1403 
1404 	TRACE_ENTRY( "%p %p %zd %p", msg, diamid, diamidlen, dict);
1405 
1406 	/* Check we received a valid message */
1407 	CHECK_PARAMS( CHECK_MSG(msg) && dict );
1408 
1409 	/* Lock the cached values */
1410 	CHECK_POSIX( pthread_mutex_lock(&cached_avp_rr_lock) );
1411 	if (cached_avp_rr_dict == dict) {
1412 		avp_rr_model = cached_avp_rr_model;
1413 	}
1414 	CHECK_POSIX( pthread_mutex_unlock(&cached_avp_rr_lock) );
1415 
1416 	/* If it was not cached */
1417 	if (!avp_rr_model) {
1418 		/* Find the model for Route-Record in the dictionary */
1419 		CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE, &code, &avp_rr_model, ENOENT) );
1420 
1421 		/* Now cache this result */
1422 		CHECK_POSIX( pthread_mutex_lock(&cached_avp_rr_lock) );
1423 		cached_avp_rr_dict  = dict;
1424 		cached_avp_rr_model = avp_rr_model;
1425 		CHECK_POSIX( pthread_mutex_unlock(&cached_avp_rr_lock) );
1426 	}
1427 
1428 	/* Create the AVP with this model */
1429 	CHECK_FCT( fd_msg_avp_new ( avp_rr_model, 0, &avp ) );
1430 
1431 	/* Set the AVP value with the diameter id */
1432 	memset(&val, 0, sizeof(val));
1433 	val.os.data = (uint8_t *)diamid;
1434 	val.os.len  = diamidlen;
1435 	CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
1436 
1437 	/* Add the AVP in the message */
1438 	CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
1439 
1440 	/* done */
1441 	return 0;
1442 }
1443 
fd_msg_source_get(struct msg * msg,DiamId_t * diamid,size_t * diamidlen)1444 int fd_msg_source_get( struct msg * msg, DiamId_t* diamid, size_t * diamidlen )
1445 {
1446 	TRACE_ENTRY( "%p %p %p", msg, diamid, diamidlen);
1447 
1448 	/* Check we received valid parameters */
1449 	CHECK_PARAMS( CHECK_MSG(msg) );
1450 	CHECK_PARAMS( diamid );
1451 
1452 	/* Copy the informations */
1453 	*diamid = msg->msg_src_id;
1454 
1455 	if (diamidlen)
1456 		*diamidlen = msg->msg_src_id_len;
1457 
1458 	/* done */
1459 	return 0;
1460 }
1461 
1462 /* Associate a session with a message, use only when the session was just created */
fd_msg_sess_set(struct msg * msg,struct session * session)1463 int fd_msg_sess_set(struct msg * msg, struct session * session)
1464 {
1465 	TRACE_ENTRY("%p %p", msg, session);
1466 
1467 	/* Check we received valid parameters */
1468 	CHECK_PARAMS( CHECK_MSG(msg) );
1469 	CHECK_PARAMS( session );
1470 	CHECK_PARAMS( msg->msg_sess == NULL );
1471 
1472 	msg->msg_sess = session;
1473 	return 0;
1474 }
1475 
1476 
1477 /* Retrieve the session of the message */
fd_msg_sess_get(struct dictionary * dict,struct msg * msg,struct session ** session,int * new)1478 int fd_msg_sess_get(struct dictionary * dict, struct msg * msg, struct session ** session, int * new)
1479 {
1480 	struct avp * avp;
1481 
1482 	TRACE_ENTRY("%p %p %p", msg, session, new);
1483 
1484 	/* Check we received valid parameters */
1485 	CHECK_PARAMS( CHECK_MSG(msg) );
1486 	CHECK_PARAMS( session );
1487 
1488 	/* If we already resolved the session, just send it back */
1489 	if (msg->msg_sess) {
1490 		*session = msg->msg_sess;
1491 		if (new)
1492 			*new = 0;
1493 		return 0;
1494 	}
1495 
1496 	/* OK, we have to search for Session-Id AVP -- it is usually the first AVP, but let's be permissive here */
1497 	/* -- note: we accept messages that have not yet been dictionary parsed... */
1498 	CHECK_FCT(  fd_msg_browse(msg, MSG_BRW_FIRST_CHILD, &avp, NULL)  );
1499 	while (avp) {
1500 		if ( (avp->avp_public.avp_code   == AC_SESSION_ID)
1501 		  && (avp->avp_public.avp_vendor == 0) )
1502 			break;
1503 
1504 		/* Otherwise move to next AVP in the message */
1505 		CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) );
1506 	}
1507 
1508 	if (!avp) {
1509 		TRACE_DEBUG(FULL, "No Session-Id AVP found in message %p", msg);
1510 		*session = NULL;
1511 		return 0;
1512 	}
1513 
1514 	if (!avp->avp_model) {
1515 		CHECK_FCT( fd_msg_parse_dict ( avp, dict, NULL ) );
1516 	}
1517 
1518 	ASSERT( avp->avp_public.avp_value );
1519 
1520 	/* Resolve the session and we are done */
1521 	if (avp->avp_public.avp_value->os.len > 0) {
1522 		CHECK_FCT( fd_sess_fromsid_msg ( avp->avp_public.avp_value->os.data, avp->avp_public.avp_value->os.len, &msg->msg_sess, new) );
1523 		*session = msg->msg_sess;
1524 	} else {
1525 		TRACE_DEBUG(FULL, "Session-Id AVP with 0-byte length found in message %p", msg);
1526 		*session = NULL;
1527 	}
1528 
1529 	return 0;
1530 }
1531 
1532 /* Retrieve the location of the pmd list for the message; return NULL if failed */
fd_msg_pmdl_get(struct msg * msg)1533 struct fd_msg_pmdl * fd_msg_pmdl_get(struct msg * msg)
1534 {
1535 	CHECK_PARAMS_DO( CHECK_MSG(msg), return NULL );
1536 	return &msg->msg_pmdl;
1537 }
1538 
1539 
1540 /******************* End-to-end counter *********************/
1541 static uint32_t fd_eteid;
1542 static pthread_mutex_t fd_eteid_lck = PTHREAD_MUTEX_INITIALIZER;
1543 
fd_msg_eteid_init(void)1544 void fd_msg_eteid_init(void)
1545 {
1546 	uint32_t t = (uint32_t)time(NULL);
1547 	srand48(t);
1548 	fd_eteid = (t << 20) | ((uint32_t)lrand48() & ( (1 << 20) - 1 ));
1549 }
1550 
fd_msg_eteid_get(void)1551 uint32_t fd_msg_eteid_get ( void )
1552 {
1553 	uint32_t ret;
1554 
1555 	CHECK_POSIX_DO( pthread_mutex_lock(&fd_eteid_lck), /* continue */ );
1556 
1557 	ret = fd_eteid ++;
1558 
1559 	CHECK_POSIX_DO( pthread_mutex_unlock(&fd_eteid_lck), /* continue */ );
1560 
1561 	return ret;
1562 }
1563 
1564 /***************************************************************************************************************/
1565 /* Manage AVPs values */
1566 
1567 /* Set the value of an AVP */
fd_msg_avp_setvalue(struct avp * avp,union avp_value * value)1568 int fd_msg_avp_setvalue ( struct avp *avp, union avp_value *value )
1569 {
1570 	enum dict_avp_basetype type = -1;
1571 
1572 	TRACE_ENTRY("%p %p", avp, value);
1573 
1574 	/* Check parameter */
1575 	CHECK_PARAMS(  CHECK_AVP(avp) && avp->avp_model  );
1576 
1577 	/* Retrieve information from the AVP model */
1578 	{
1579 		enum dict_object_type dicttype;
1580 		struct dict_avp_data  dictdata;
1581 
1582 		CHECK_PARAMS( (fd_dict_gettype(avp->avp_model, &dicttype) == 0) && (dicttype == DICT_AVP) );
1583 		CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
1584 		type = dictdata.avp_basetype;
1585 		CHECK_PARAMS(  type != AVP_TYPE_GROUPED  );
1586 	}
1587 
1588 	/* First, clean any previous value */
1589 	if (avp->avp_mustfreeos != 0) {
1590 		free(avp->avp_storage.os.data);
1591 		avp->avp_mustfreeos = 0;
1592 	}
1593 
1594 	memset(&avp->avp_storage, 0, sizeof(union avp_value));
1595 
1596 	/* If the request was to delete a value: */
1597 	if (!value) {
1598 		avp->avp_public.avp_value = NULL;
1599 		return 0;
1600 	}
1601 
1602 	/* Now we have to set the value */
1603 	memcpy(&avp->avp_storage, value, sizeof(union avp_value));
1604 
1605 	/* Duplicate an octetstring if needed. */
1606 	if (type == AVP_TYPE_OCTETSTRING) {
1607 		CHECK_MALLOC(  avp->avp_storage.os.data = os0dup(value->os.data, value->os.len)  );
1608 		avp->avp_mustfreeos = 1;
1609 	}
1610 
1611 	/* Set the data pointer of the public part */
1612 	avp->avp_public.avp_value = &avp->avp_storage;
1613 
1614 	return 0;
1615 }
1616 
1617 /* Set the value of an AVP, using formatted data */
fd_msg_avp_value_encode(void * data,struct avp * avp)1618 int fd_msg_avp_value_encode ( void *data, struct avp *avp )
1619 {
1620 	enum dict_avp_basetype type = -1;
1621 	struct dict_type_data type_data;
1622 
1623 	TRACE_ENTRY("%p %p", data, avp);
1624 
1625 	/* Check parameter */
1626 	CHECK_PARAMS(  CHECK_AVP(avp) && avp->avp_model  );
1627 
1628 	/* Retrieve information from the AVP model and it's parent type */
1629 	{
1630 		enum dict_object_type dicttype;
1631 		struct dict_avp_data  dictdata;
1632 		struct dictionary   * dict;
1633 		struct dict_object  * parenttype = NULL;
1634 
1635 		/* First check the base type of the AVP */
1636 		CHECK_PARAMS( (fd_dict_gettype(avp->avp_model, &dicttype) == 0) && (dicttype == DICT_AVP) );
1637 		CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
1638 		type = dictdata.avp_basetype;
1639 		CHECK_PARAMS(  type != AVP_TYPE_GROUPED  );
1640 
1641 		/* Then retrieve information about the parent's type (= derived type) */
1642 		CHECK_FCT(  fd_dict_getdict( avp->avp_model, &dict )  );
1643 		CHECK_FCT(  fd_dict_search( dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &parenttype, EINVAL)  );
1644 		CHECK_FCT(  fd_dict_getval(parenttype, &type_data)  );
1645 		if (type_data.type_encode == NULL) {
1646 			TRACE_DEBUG(INFO, "This AVP type does not provide a callback to encode formatted data. ENOTSUP.");
1647 			return ENOTSUP;
1648 		}
1649 	}
1650 
1651 	/* Ok, now we can encode the value */
1652 
1653 	/* First, clean any previous value */
1654 	if (avp->avp_mustfreeos != 0) {
1655 		free(avp->avp_storage.os.data);
1656 		avp->avp_mustfreeos = 0;
1657 	}
1658 	avp->avp_public.avp_value = NULL;
1659 	memset(&avp->avp_storage, 0, sizeof(union avp_value));
1660 
1661 	/* Now call the type's callback to encode the data */
1662 	CHECK_FCT(  (*type_data.type_encode)(data, &avp->avp_storage)  );
1663 
1664 	/* If an octetstring has been allocated, let's mark it to be freed */
1665 	if (type == AVP_TYPE_OCTETSTRING)
1666 		avp->avp_mustfreeos = 1;
1667 
1668 	/* Set the data pointer of the public part */
1669 	avp->avp_public.avp_value = &avp->avp_storage;
1670 
1671 	return 0;
1672 }
1673 
1674 /* Interpret the value of an AVP into formatted data */
fd_msg_avp_value_interpret(struct avp * avp,void * data)1675 int fd_msg_avp_value_interpret ( struct avp *avp, void *data )
1676 {
1677 	struct dict_type_data type_data;
1678 
1679 	TRACE_ENTRY("%p %p", avp, data);
1680 
1681 	/* Check parameter */
1682 	CHECK_PARAMS(  CHECK_AVP(avp) && avp->avp_model && avp->avp_public.avp_value  );
1683 
1684 	/* Retrieve information about the AVP parent type */
1685 	{
1686 		struct dictionary   * dict;
1687 		struct dict_object  * parenttype = NULL;
1688 
1689 		CHECK_FCT(  fd_dict_getdict( avp->avp_model, &dict )  );
1690 		CHECK_FCT(  fd_dict_search( dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &parenttype, EINVAL)  );
1691 		CHECK_FCT(  fd_dict_getval(parenttype, &type_data)  );
1692 		if (type_data.type_interpret == NULL) {
1693 			TRACE_DEBUG(INFO, "This AVP type does not provide a callback to interpret value in formatted data. ENOTSUP.");
1694 			return ENOTSUP;
1695 		}
1696 	}
1697 
1698 	/* Ok, now we can interpret the value */
1699 
1700 	CHECK_FCT(  (*type_data.type_interpret)(avp->avp_public.avp_value, data)  );
1701 
1702 	return 0;
1703 }
1704 
1705 /***************************************************************************************************************/
1706 /* Creating a buffer from memory objects (bufferize a struct msg) */
1707 
1708 /* Following macros are used to store 32 and 64 bit fields into a buffer in network byte order */
1709 #define PUT_in_buf_32( _u32data, _bufptr ) {							\
1710 	*(uint32_t *)(_bufptr) = htonl((uint32_t)(_u32data));					\
1711 }
1712 
1713 /* The location is not on 64b boundary, so we split the writing in two operations to avoid sigbus */
1714 #define PUT_in_buf_64( _u64data, _bufptr ) {							\
1715 	uint64_t __v = htonll((uint64_t)(_u64data));						\
1716 	memcpy(_bufptr, &__v, sizeof(__v));							\
1717 }
1718 
1719 /* Write a message header in the buffer */
bufferize_msg(unsigned char * buffer,size_t buflen,size_t * offset,struct msg * msg)1720 static int bufferize_msg(unsigned char * buffer, size_t buflen, size_t * offset, struct msg * msg)
1721 {
1722 	TRACE_ENTRY("%p %zd %p %p", buffer, buflen, offset, msg);
1723 
1724 	if ((buflen - *offset) < GETMSGHDRSZ())
1725 		return ENOSPC;
1726 
1727 	if (*offset & 0x3)
1728 		return EFAULT;	/* We are supposed to start on 32 bit boundaries */
1729 
1730 	PUT_in_buf_32(msg->msg_public.msg_length, buffer + *offset);
1731 	buffer[*offset] = msg->msg_public.msg_version;
1732 	*offset += 4;
1733 
1734 	PUT_in_buf_32(msg->msg_public.msg_code, buffer + *offset);
1735 	buffer[*offset] = msg->msg_public.msg_flags;
1736 	*offset += 4;
1737 
1738 	PUT_in_buf_32(msg->msg_public.msg_appl, buffer + *offset);
1739 	*offset += 4;
1740 
1741 	PUT_in_buf_32(msg->msg_public.msg_hbhid, buffer + *offset);
1742 	*offset += 4;
1743 
1744 	PUT_in_buf_32(msg->msg_public.msg_eteid, buffer + *offset);
1745 	*offset += 4;
1746 
1747 	return 0;
1748 }
1749 
1750 static int bufferize_chain(unsigned char * buffer, size_t buflen, size_t * offset, struct fd_list * list);
1751 
1752 /* Write an AVP in the buffer */
bufferize_avp(unsigned char * buffer,size_t buflen,size_t * offset,struct avp * avp)1753 static int bufferize_avp(unsigned char * buffer, size_t buflen, size_t * offset,  struct avp * avp)
1754 {
1755 	struct dict_avp_data dictdata;
1756 
1757 	TRACE_ENTRY("%p %zd %p %p", buffer, buflen, offset, avp);
1758 
1759 	if ((buflen - *offset) < avp->avp_public.avp_len)
1760 		return ENOSPC;
1761 
1762 	/* Write the header */
1763 	PUT_in_buf_32(avp->avp_public.avp_code, buffer + *offset);
1764 	*offset += 4;
1765 
1766 	PUT_in_buf_32(avp->avp_public.avp_len, buffer + *offset);
1767 	buffer[*offset] = avp->avp_public.avp_flags;
1768 	*offset += 4;
1769 
1770 	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
1771 		PUT_in_buf_32(avp->avp_public.avp_vendor, buffer + *offset);
1772 		*offset += 4;
1773 	}
1774 
1775 	/* Then we must write the AVP value */
1776 
1777 	if (avp->avp_model == NULL) {
1778 		/* In the case where we don't know the type of AVP, just copy the raw data or source */
1779 		CHECK_PARAMS( avp->avp_source || avp->avp_rawdata );
1780 
1781 		if ( avp->avp_rawdata != NULL ) {
1782 			/* the content was stored in rawdata */
1783 			memcpy(&buffer[*offset], avp->avp_rawdata, avp->avp_rawlen);
1784 			*offset += PAD4(avp->avp_rawlen);
1785 		} else {
1786 			/* the message was not parsed completely */
1787 			size_t datalen = avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags);
1788 			memcpy(&buffer[*offset], avp->avp_source, datalen);
1789 			*offset += PAD4(datalen);
1790 		}
1791 
1792 	} else {
1793 		/* The AVP is defined in the dictionary */
1794 		CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
1795 
1796 		CHECK_PARAMS( ( dictdata.avp_basetype == AVP_TYPE_GROUPED ) || avp->avp_public.avp_value );
1797 
1798 		switch (dictdata.avp_basetype) {
1799 			case AVP_TYPE_GROUPED:
1800 				return bufferize_chain(buffer, buflen, offset, &avp->avp_chain.children);
1801 
1802 			case AVP_TYPE_OCTETSTRING:
1803 				if (avp->avp_public.avp_value->os.len)
1804 					memcpy(&buffer[*offset], avp->avp_public.avp_value->os.data, avp->avp_public.avp_value->os.len);
1805 				*offset += PAD4(avp->avp_public.avp_value->os.len);
1806 				break;
1807 
1808 			case AVP_TYPE_INTEGER32:
1809 				PUT_in_buf_32(avp->avp_public.avp_value->i32, buffer + *offset);
1810 				*offset += 4;
1811 				break;
1812 
1813 			case AVP_TYPE_INTEGER64:
1814 				PUT_in_buf_64(avp->avp_public.avp_value->i64, buffer + *offset);
1815 				*offset += 8;
1816 				break;
1817 
1818 			case AVP_TYPE_UNSIGNED32:
1819 				PUT_in_buf_32(avp->avp_public.avp_value->u32, buffer + *offset);
1820 				*offset += 4;
1821 				break;
1822 
1823 			case AVP_TYPE_UNSIGNED64:
1824 				PUT_in_buf_64(avp->avp_public.avp_value->u64, buffer + *offset);
1825 				*offset += 8;
1826 				break;
1827 
1828 			case AVP_TYPE_FLOAT32:
1829 				/* We read the f32 as "u32" here to avoid casting to uint make decimals go away.
1830 				 The alternative would be something like "*(uint32_t *)(& f32)" but
1831 				 then the compiler complains about strict-aliasing rules. */
1832 				PUT_in_buf_32(avp->avp_public.avp_value->u32, buffer + *offset);
1833 				*offset += 4;
1834 				break;
1835 
1836 			case AVP_TYPE_FLOAT64:
1837 				/* Same remark as previously */
1838 				PUT_in_buf_64(avp->avp_public.avp_value->u64, buffer + *offset);
1839 				*offset += 8;
1840 				break;
1841 
1842 			default:
1843 				ASSERT(0);
1844 		}
1845 	}
1846 	return 0;
1847 }
1848 
1849 /* Write a chain of AVPs in the buffer */
bufferize_chain(unsigned char * buffer,size_t buflen,size_t * offset,struct fd_list * list)1850 static int bufferize_chain(unsigned char * buffer, size_t buflen, size_t * offset, struct fd_list * list)
1851 {
1852 	struct fd_list * avpch;
1853 
1854 	TRACE_ENTRY("%p %zd %p %p", buffer, buflen, offset, list);
1855 
1856 	for (avpch = list->next; avpch != list; avpch = avpch->next) {
1857 		/* Bufferize the AVP */
1858 		CHECK_FCT( bufferize_avp(buffer, buflen, offset, _A(avpch->o))  );
1859 	}
1860 	return 0;
1861 }
1862 
1863 /* Create the message buffer, in network-byte order. We browse the tree twice, this could be probably improved if needed */
fd_msg_bufferize(struct msg * msg,unsigned char ** buffer,size_t * len)1864 int fd_msg_bufferize ( struct msg * msg, unsigned char ** buffer, size_t * len )
1865 {
1866 	int ret = 0;
1867 	unsigned char * buf = NULL;
1868 	size_t offset = 0;
1869 
1870 	TRACE_ENTRY("%p %p %p", msg, buffer, len);
1871 
1872 	/* Check the parameters */
1873 	CHECK_PARAMS(  buffer && CHECK_MSG(msg)  );
1874 
1875 	/* Update the length. This also checks that all AVP have their values set */
1876 	CHECK_FCT(  fd_msg_update_length(msg)  );
1877 
1878 	/* Now allocate a buffer to store the message */
1879 	CHECK_MALLOC(  buf = malloc(msg->msg_public.msg_length)  );
1880 
1881 	/* Clear the memory, so that the padding is always 0 (should not matter) */
1882 	memset(buf, 0, msg->msg_public.msg_length);
1883 
1884 	/* Write the message header in the buffer */
1885 	CHECK_FCT_DO( ret = bufferize_msg(buf, msg->msg_public.msg_length, &offset, msg),
1886 		{
1887 			free(buf);
1888 			return ret;
1889 		}  );
1890 
1891 	/* Write the list of AVPs */
1892 	CHECK_FCT_DO( ret = bufferize_chain(buf, msg->msg_public.msg_length, &offset, &msg->msg_chain.children),
1893 		{
1894 			free(buf);
1895 			return ret;
1896 		}  );
1897 
1898 	ASSERT(offset == msg->msg_public.msg_length); /* or the msg_update_length is buggy */
1899 
1900 	if (len) {
1901 		*len = offset;
1902 	}
1903 
1904 	*buffer = buf;
1905 	return 0;
1906 }
1907 
1908 
1909 /***************************************************************************************************************/
1910 /* Parsing buffers and building AVP objects lists (not parsing the AVP values which requires dictionary knowledge) */
1911 
1912 /* Parse a buffer containing a supposed list of AVPs */
parsebuf_list(unsigned char * buf,size_t buflen,struct fd_list * head)1913 static int parsebuf_list(unsigned char * buf, size_t buflen, struct fd_list * head)
1914 {
1915 	size_t offset = 0;
1916 
1917 	TRACE_ENTRY("%p %zd %p", buf, buflen, head);
1918 
1919 	while (offset < buflen) {
1920 		struct avp * avp;
1921 
1922 		if (buflen - offset < AVPHDRSZ_NOVEND) {
1923 			TRACE_DEBUG(INFO, "truncated buffer: remaining only %zd bytes", buflen - offset);
1924 			return EBADMSG;
1925 		}
1926 
1927 		/* Create a new AVP object */
1928 		CHECK_MALLOC(  avp = malloc (sizeof(struct avp))  );
1929 
1930 		init_avp(avp);
1931 
1932 		/* Initialize the header */
1933 		avp->avp_public.avp_code    = ntohl(*(uint32_t *)(buf + offset));
1934 		avp->avp_public.avp_flags   = buf[offset + 4];
1935 		avp->avp_public.avp_len     = ((uint32_t)buf[offset+5]) << 16 |  ((uint32_t)buf[offset+6]) << 8 |  ((uint32_t)buf[offset+7]) ;
1936 
1937 		offset += 8;
1938 
1939 		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
1940 			if (buflen - offset < 4) {
1941 				TRACE_DEBUG(INFO, "truncated buffer: remaining only %zd bytes for vendor and data", buflen - offset);
1942 				free(avp);
1943 				return EBADMSG;
1944 			}
1945 			avp->avp_public.avp_vendor  = ntohl(*(uint32_t *)(buf + offset));
1946 			offset += 4;
1947 		}
1948 
1949 		/* Check the length is valid */
1950 		if ( avp->avp_public.avp_len < GETAVPHDRSZ(avp->avp_public.avp_flags) ) {
1951 			TRACE_DEBUG(INFO, "Invalid AVP size %d",
1952 					avp->avp_public.avp_len);
1953 			free(avp);
1954 			return EBADMSG;
1955 		}
1956 
1957 		/* Check there is enough remaining data in the buffer */
1958 		if ( (avp->avp_public.avp_len > GETAVPHDRSZ(avp->avp_public.avp_flags))
1959 		&& (buflen - offset < avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags))) {
1960 			TRACE_DEBUG(INFO, "truncated buffer: remaining only %zd bytes for data, and avp data size is %d",
1961 					buflen - offset,
1962 					avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags));
1963 			free(avp);
1964 			return EBADMSG;
1965 		}
1966 
1967 		/* buf[offset] is now the beginning of the data */
1968 		avp->avp_source = &buf[offset];
1969 
1970 		/* Now eat the data and eventual padding */
1971 		offset += PAD4(avp->avp_public.avp_len - GETAVPHDRSZ(avp->avp_public.avp_flags));
1972 
1973 		/* And insert this avp in the list, at the end */
1974 		fd_list_insert_before( head, &avp->avp_chain.chaining );
1975 	}
1976 
1977 	return 0;
1978 }
1979 
1980 /* Create a message object from a buffer. Dictionary objects are not resolved, AVP contents are not interpreted, buffer is saved in msg */
fd_msg_parse_buffer(unsigned char ** buffer,size_t buflen,struct msg ** msg)1981 int fd_msg_parse_buffer ( unsigned char ** buffer, size_t buflen, struct msg ** msg )
1982 {
1983 	struct msg * new = NULL;
1984 	int ret = 0;
1985 	uint32_t msglen = 0;
1986 	unsigned char * buf;
1987 
1988 	TRACE_ENTRY("%p %zd %p", buffer, buflen, msg);
1989 
1990 	CHECK_PARAMS(  buffer &&  *buffer  &&  msg  &&  (buflen >= GETMSGHDRSZ())  );
1991 	buf = *buffer;
1992 
1993 	if ( buf[0] != DIAMETER_VERSION) {
1994 		TRACE_DEBUG(INFO, "Invalid version in message: %d (supported: %d)", buf[0], DIAMETER_VERSION);
1995 		return EBADMSG;
1996 	}
1997 
1998 	msglen = ntohl(*(uint32_t *)buf) & 0x00ffffff;
1999 	if ( buflen < msglen ) {
2000 		TRACE_DEBUG(INFO, "Truncated message (%zd / %d)", buflen, msglen );
2001 		return EBADMSG;
2002 	}
2003 	if ( msglen < GETMSGHDRSZ() ) {
2004 		TRACE_DEBUG(INFO, "Invalid message length (%d)", msglen );
2005 		return EBADMSG;
2006 	}
2007 
2008 	/* Create a new object */
2009 	CHECK_MALLOC( new = malloc (sizeof(struct msg)) );
2010 
2011 	/* Initialize the fields */
2012 	init_msg(new);
2013 
2014 	/* Now read from the buffer */
2015 	new->msg_public.msg_version = buf[0];
2016 	new->msg_public.msg_length = msglen;
2017 
2018 	new->msg_public.msg_flags = buf[4];
2019 	new->msg_public.msg_code = ntohl(*(uint32_t *)(buf+4)) & 0x00ffffff;
2020 
2021 	new->msg_public.msg_appl = ntohl(*(uint32_t *)(buf+8));
2022 	new->msg_public.msg_hbhid = ntohl(*(uint32_t *)(buf+12));
2023 	new->msg_public.msg_eteid = ntohl(*(uint32_t *)(buf+16));
2024 
2025 	/* Parse the AVP list */
2026 	CHECK_FCT_DO( ret = parsebuf_list(buf + GETMSGHDRSZ(), buflen - GETMSGHDRSZ(), &new->msg_chain.children), { destroy_tree(_C(new)); return ret; }  );
2027 
2028 	/* Parsing successful */
2029 	new->msg_rawbuffer = buf;
2030 	*buffer = NULL;
2031 	*msg = new;
2032 	return 0;
2033 }
2034 
2035 
2036 /***************************************************************************************************************/
2037 /* Parsing messages and AVP with dictionary information */
2038 
2039 /* Resolve dictionary objects of the cmd and avp instances, from their headers.
2040  * When the model is found, the data is interpreted from the avp_source buffer and copied to avp_storage.
2041  * When the model is not found, the data is copied as rawdata and saved (in case we FW the message).
2042  * Therefore, after this function has been called, the source buffer can be freed.
2043  * For command, if the dictionary model is not found, an error is returned.
2044  */
2045 
2046 static char error_message[256];
2047 
2048 /* Process an AVP. If we are not in recheck, the avp_source must be set. */
parsedict_do_avp(struct dictionary * dict,struct avp * avp,int mandatory,struct fd_pei * error_info)2049 static int parsedict_do_avp(struct dictionary * dict, struct avp * avp, int mandatory, struct fd_pei *error_info)
2050 {
2051 	struct dict_avp_data dictdata;
2052 	struct dict_type_data derivedtypedata;
2053 	struct dict_object * avp_derived_type = NULL;
2054 	uint8_t * source;
2055 
2056 	TRACE_ENTRY("%p %p %d %p", dict, avp, mandatory, error_info);
2057 
2058 	/* First check we received an AVP as input */
2059 	CHECK_PARAMS(  CHECK_AVP(avp) );
2060 
2061 	if (avp->avp_model != NULL) {
2062 		/* the model has already been resolved. we do check it is still valid */
2063 
2064 		CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
2065 
2066 		if ( avp->avp_public.avp_code == dictdata.avp_code  ) {
2067 			/* Ok then just process the children if any */
2068 			return parsedict_do_chain(dict, &avp->avp_chain.children, mandatory && (avp->avp_public.avp_flags & AVP_FLAG_MANDATORY), error_info);
2069 		} else {
2070 			/* We just erase the old model */
2071 			avp->avp_model = NULL;
2072 		}
2073 	}
2074 
2075 	/* Check if we already searched for this model without success */
2076 	if ((avp->avp_model_not_found.mnf_code != avp->avp_public.avp_code)
2077 	||  (avp->avp_model_not_found.mnf_vendor != avp->avp_public.avp_vendor)) {
2078 
2079 		/* Now try and resolve the model from the avp code and vendor */
2080 		if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
2081 			struct dict_avp_request_ex avpreq;
2082 			memset(&avpreq, 0, sizeof(avpreq));
2083 			avpreq.avp_vendor.vendor_id = avp->avp_public.avp_vendor;
2084 			avpreq.avp_data.avp_code = avp->avp_public.avp_code;
2085 			CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_STRUCT, &avpreq, &avp->avp_model, 0));
2086 		} else {
2087 			/* no vendor */
2088 			CHECK_FCT( fd_dict_search ( dict, DICT_AVP, AVP_BY_CODE, &avp->avp_public.avp_code, &avp->avp_model, 0));
2089 		}
2090 
2091 		if (!avp->avp_model) {
2092 			avp->avp_model_not_found.mnf_code = avp->avp_public.avp_code;
2093 			avp->avp_model_not_found.mnf_vendor = avp->avp_public.avp_vendor;
2094 		}
2095 	}
2096 
2097 	/* First handle the case where we have not found this AVP in the dictionary */
2098 	if (!avp->avp_model) {
2099 
2100 		if (mandatory && (avp->avp_public.avp_flags & AVP_FLAG_MANDATORY)) {
2101 			TRACE_DEBUG(INFO, "Unsupported mandatory AVP found");
2102 			if (error_info) {
2103 				error_info->pei_errcode = "DIAMETER_AVP_UNSUPPORTED";
2104 				error_info->pei_avp = avp;
2105 			} else {
2106 				char * buf = NULL;
2107 				size_t buflen;
2108 				CHECK_MALLOC(fd_msg_dump_treeview(&buf, &buflen, NULL, avp, NULL, 0, 0));
2109 				LOG_E("Unsupported AVP: %s", buf);
2110 				free(buf);
2111 			}
2112 			return ENOTSUP;
2113 		}
2114 
2115 		if (avp->avp_source) {
2116 			/* we must copy the data from the source to the internal buffer area */
2117 			CHECK_PARAMS( !avp->avp_rawdata  );
2118 
2119 			avp->avp_rawlen = avp->avp_public.avp_len - GETAVPHDRSZ( avp->avp_public.avp_flags );
2120 
2121 			if (avp->avp_rawlen) {
2122 				CHECK_MALLOC(  avp->avp_rawdata = malloc(avp->avp_rawlen)  );
2123 
2124 				memcpy(avp->avp_rawdata, avp->avp_source, avp->avp_rawlen);
2125 			}
2126 
2127 			avp->avp_source = NULL;
2128 
2129 			TRACE_DEBUG(FULL, "Unsupported optional AVP found, raw source data saved in avp_rawdata.");
2130 		}
2131 
2132 		return 0;
2133 	}
2134 
2135 	/* Ok we have resolved the object. Now we need to interpret its content. */
2136 
2137 	CHECK_FCT(  fd_dict_getval(avp->avp_model, &dictdata)  );
2138 
2139 	if (avp->avp_rawdata) {
2140 		/* This happens if the dictionary object was defined after the first check */
2141 		avp->avp_source = avp->avp_rawdata;
2142 	}
2143 
2144 	/* A bit of sanity here... */
2145 	ASSERT(CHECK_BASETYPE(dictdata.avp_basetype));
2146 
2147 	/* Check the size is valid */
2148 	if ((avp_value_sizes[dictdata.avp_basetype] != 0) &&
2149 	    (avp->avp_public.avp_len - GETAVPHDRSZ( avp->avp_public.avp_flags ) != avp_value_sizes[dictdata.avp_basetype])) {
2150 		TRACE_DEBUG(INFO, "The AVP size is not suitable for the type");
2151 		if (error_info) {
2152 			error_info->pei_errcode = "DIAMETER_INVALID_AVP_LENGTH";
2153 			error_info->pei_avp = avp;
2154 			snprintf(error_message, sizeof(error_message), "I expected a size of %d for this AVP according to my dictionary", avp_value_sizes[dictdata.avp_basetype]);
2155 			error_info->pei_message = error_message;
2156 		} else {
2157 			char * buf = NULL;
2158 			size_t buflen;
2159 			CHECK_MALLOC(fd_msg_dump_treeview(&buf, &buflen, NULL, avp, NULL, 0, 0));
2160 			LOG_E("Invalid length AVP: %s", buf);
2161 			free(buf);
2162 		}
2163 		avp->avp_model = NULL;
2164 		return EBADMSG;
2165 	}
2166 
2167 	source = avp->avp_source;
2168 	avp->avp_source = NULL;
2169 
2170 	/* Now get the value inside */
2171 	switch (dictdata.avp_basetype) {
2172 		case AVP_TYPE_GROUPED: {
2173 			int ret;
2174 
2175 			/* This is a grouped AVP, so let's parse the list of AVPs inside */
2176 			CHECK_FCT_DO(  ret = parsebuf_list(source, avp->avp_public.avp_len - GETAVPHDRSZ( avp->avp_public.avp_flags ), &avp->avp_chain.children),
2177 				{
2178 					if ((ret == EBADMSG) && (error_info)) {
2179 						error_info->pei_errcode = "DIAMETER_INVALID_AVP_VALUE";
2180 						error_info->pei_avp = avp;
2181 						snprintf(error_message, sizeof(error_message), "I cannot parse this AVP as a Grouped AVP");
2182 						error_info->pei_message = error_message;
2183 					}
2184 					avp->avp_source = source;
2185 					return ret;
2186 				}  );
2187 
2188 			return parsedict_do_chain(dict, &avp->avp_chain.children, mandatory && (avp->avp_public.avp_flags & AVP_FLAG_MANDATORY), error_info);
2189 		}
2190 
2191 		case AVP_TYPE_OCTETSTRING:
2192 			/* We just have to copy the string into the storage area */
2193 			CHECK_PARAMS_DO( avp->avp_public.avp_len >= GETAVPHDRSZ( avp->avp_public.avp_flags ),
2194 				{
2195 					if (error_info) {
2196 						error_info->pei_errcode = "DIAMETER_INVALID_AVP_LENGTH";
2197 						error_info->pei_avp = avp;
2198 					}
2199 					avp->avp_source = source;
2200 					return EBADMSG;
2201 				} );
2202 			avp->avp_storage.os.len = avp->avp_public.avp_len - GETAVPHDRSZ( avp->avp_public.avp_flags );
2203 			CHECK_MALLOC(  avp->avp_storage.os.data = os0dup(source, avp->avp_storage.os.len)  );
2204 			avp->avp_mustfreeos = 1;
2205 			break;
2206 
2207 		case AVP_TYPE_INTEGER32:
2208 			avp->avp_storage.i32 = (int32_t)ntohl(*(uint32_t *)source);
2209 			break;
2210 
2211 		case AVP_TYPE_INTEGER64:
2212 			/* the storage might not be aligned on 64b boundary, so no direct indirection here is possible */
2213 			{
2214 				uint64_t __stor;
2215 				memcpy(&__stor, source, sizeof(__stor));
2216 				avp->avp_storage.i64 = (int64_t)ntohll(__stor);
2217 			}
2218 			break;
2219 
2220 		case AVP_TYPE_UNSIGNED32:
2221 		case AVP_TYPE_FLOAT32: /* For float, we must not cast, or the value is changed. Instead we use implicit cast by changing the member of the union */
2222 			avp->avp_storage.u32 = (uint32_t)ntohl(*(uint32_t *)source);
2223 			break;
2224 
2225 		case AVP_TYPE_UNSIGNED64:
2226 		case AVP_TYPE_FLOAT64: /* same as 32 bits */
2227 			{
2228 				uint64_t __stor;
2229 				memcpy(&__stor, source, sizeof(__stor));
2230 				avp->avp_storage.u64 = (uint64_t)ntohll(__stor);
2231 			}
2232 			break;
2233 
2234 	}
2235 
2236 	/* Is there a derived type check function ? */
2237 	CHECK_FCT ( fd_dict_search ( dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &avp_derived_type, 0) );
2238 	if (avp_derived_type) {
2239 		CHECK_FCT(  fd_dict_getval(avp_derived_type, &derivedtypedata)  );
2240 		if (derivedtypedata.type_check != NULL) {
2241 			char * err;
2242 			int ret = (*derivedtypedata.type_check)( derivedtypedata.type_check_param, &avp->avp_storage, &err );
2243 
2244 			if (ret != 0) {
2245 				TRACE_DEBUG(INFO, "The AVP failed to pass the dictionary validation");
2246 				if (error_info) {
2247 						error_info->pei_errcode = "DIAMETER_INVALID_AVP_VALUE";
2248 						error_info->pei_avp = avp;
2249 						snprintf(error_message, sizeof(error_message), "%s", err);
2250 						error_info->pei_message = error_message;
2251 				} else {
2252 					char * buf = NULL;
2253 					size_t buflen;
2254 					CHECK_MALLOC(fd_msg_dump_treeview(&buf, &buflen, NULL, avp, NULL, 0, 0));
2255 					LOG_E("Invalid AVP: %s", buf);
2256 					free(buf);
2257 				}
2258 				return ret; /* should we just return EBADMSG? */
2259 			}
2260 		}
2261 	}
2262 
2263 	/* The value is now set, so set the data pointer and return 0 */
2264 	avp->avp_public.avp_value = &avp->avp_storage;
2265 	return 0;
2266 }
2267 
2268 /* Process a list of AVPs */
parsedict_do_chain(struct dictionary * dict,struct fd_list * head,int mandatory,struct fd_pei * error_info)2269 static int parsedict_do_chain(struct dictionary * dict, struct fd_list * head, int mandatory, struct fd_pei *error_info)
2270 {
2271 	struct fd_list * avpch;
2272 
2273 	TRACE_ENTRY("%p %p %d %p", dict, head, mandatory, error_info);
2274 
2275 	/* Sanity check */
2276 	ASSERT ( head == head->head );
2277 
2278 	/* Now process the list */
2279 	for (avpch=head->next; avpch != head; avpch = avpch->next) {
2280 		CHECK_FCT(  parsedict_do_avp(dict, _A(avpch->o), mandatory, error_info)  );
2281 	}
2282 
2283 	/* Done */
2284 	return 0;
2285 }
2286 
2287 /* Process a msg header. */
parsedict_do_msg(struct dictionary * dict,struct msg * msg,int only_hdr,struct fd_pei * error_info)2288 static int parsedict_do_msg(struct dictionary * dict, struct msg * msg, int only_hdr, struct fd_pei *error_info)
2289 {
2290 	int ret = 0;
2291 
2292 	TRACE_ENTRY("%p %p %d %p", dict, msg, only_hdr, error_info);
2293 
2294 	CHECK_PARAMS(  CHECK_MSG(msg)  );
2295 
2296 	/* First, check if we already have a model. */
2297 	if (msg->msg_model != NULL) {
2298 		/* Check if this model is still valid for the message data */
2299 #ifndef NDEBUG
2300 		enum dict_object_type 	 dicttype;
2301 #endif
2302 		struct dict_cmd_data     data;
2303 		ASSERT(((fd_dict_gettype(msg->msg_model, &dicttype) == 0) && (dicttype == DICT_COMMAND)));
2304 		(void)fd_dict_getval( msg->msg_model, &data);
2305 		if ((data.cmd_code != msg->msg_public.msg_code)
2306 		||  ((data.cmd_flag_val & data.cmd_flag_mask) != (msg->msg_public.msg_flags && data.cmd_flag_mask))) {
2307 			msg->msg_model = NULL;
2308 		} else {
2309 			goto chain;
2310 		}
2311 	}
2312 
2313 	/* Check if we already searched for this model without success */
2314 	if ((msg->msg_model_not_found.mnf_code == msg->msg_public.msg_code)
2315 	&& (msg->msg_model_not_found.mnf_flags == msg->msg_public.msg_flags)) {
2316 		goto no_model;
2317 	} else {
2318 		msg->msg_model_not_found.mnf_code = 0;
2319 	}
2320 
2321 	/* Look for the model from the header */
2322 	CHECK_FCT_DO( ret = fd_dict_search ( dict, DICT_COMMAND,
2323 			(msg->msg_public.msg_flags & CMD_FLAG_REQUEST) ? CMD_BY_CODE_R : CMD_BY_CODE_A,
2324 			&msg->msg_public.msg_code,
2325 			&msg->msg_model, ENOTSUP),
2326 		{
2327 			if (ret == ENOTSUP) {
2328 				/* update the model not found info */
2329 				msg->msg_model_not_found.mnf_code = msg->msg_public.msg_code;
2330 				msg->msg_model_not_found.mnf_flags = msg->msg_public.msg_flags;
2331 				goto no_model;
2332 			}
2333 			return ret;
2334 		} );
2335 chain:
2336 	if (!only_hdr) {
2337 		/* Then process the children */
2338 		ret = parsedict_do_chain(dict, &msg->msg_chain.children, 1, error_info);
2339 
2340 		/* Free the raw buffer if any */
2341 		if ((ret == 0) && (msg->msg_rawbuffer != NULL)) {
2342 			free(msg->msg_rawbuffer);
2343 			msg->msg_rawbuffer=NULL;
2344 		}
2345 	}
2346 
2347 	return ret;
2348 no_model:
2349 	if (error_info) {
2350 		error_info->pei_errcode = "DIAMETER_COMMAND_UNSUPPORTED";
2351 		error_info->pei_protoerr = 1;
2352 	}
2353 	return ENOTSUP;
2354 }
2355 
fd_msg_parse_dict(msg_or_avp * object,struct dictionary * dict,struct fd_pei * error_info)2356 int fd_msg_parse_dict ( msg_or_avp * object, struct dictionary * dict, struct fd_pei *error_info )
2357 {
2358 	TRACE_ENTRY("%p %p %p", dict, object, error_info);
2359 
2360 	CHECK_PARAMS(  VALIDATE_OBJ(object)  );
2361 
2362 	if (error_info)
2363 		memset(error_info, 0, sizeof(struct fd_pei));
2364 
2365 	switch (_C(object)->type) {
2366 		case MSG_MSG:
2367 			return parsedict_do_msg(dict, _M(object), 0, error_info);
2368 
2369 		case MSG_AVP:
2370 			return parsedict_do_avp(dict, _A(object), 0, error_info);
2371 
2372 		default:
2373 			ASSERT(0);
2374 	}
2375 	return EINVAL;
2376 }
2377 
2378 /***************************************************************************************************************/
2379 /* Parsing messages and AVP for rules (ABNF) compliance */
2380 
2381 /* This function is used to get stats (first occurence position, last occurence position, number of occurences)
2382    of AVP instances of a given model in a chain of AVP */
parserules_stat_avps(struct dict_object * model_avp,struct fd_list * list,int * count,int * firstpos,int * lastpos)2383 static void parserules_stat_avps( struct dict_object * model_avp, struct fd_list *list, int * count, int * firstpos, int * lastpos)
2384 {
2385 	struct fd_list * li;
2386 	int curpos = 0; /* The current position in the list */
2387 
2388 	TRACE_ENTRY("%p %p %p %p %p", model_avp, list, count, firstpos, lastpos);
2389 
2390 	*count = 0;	/* number of instances found */
2391 	*firstpos = 0;	/* position of the first instance */
2392 	*lastpos = 0;	/* position of the last instance, starting from the end */
2393 
2394 	for (li = list->next; li != list; li = li->next) {
2395 		/* Increment the current position counter */
2396 		curpos++;
2397 
2398 		/* If we previously saved a "lastpos" information, increment it */
2399 		if (*lastpos != 0)
2400 			(*lastpos)++;
2401 
2402 		/* Check the type of the next AVP. We can compare the references directly, it is safe. */
2403 		if (_A(li->o)->avp_model == model_avp) {
2404 
2405 			/* This AVP is of the type we are searching */
2406 			(*count)++;
2407 
2408 			/* If we don't have yet a "firstpos", save it */
2409 			if (*firstpos == 0)
2410 				*firstpos = curpos;
2411 
2412 			/* Reset the lastpos */
2413 			(*lastpos) = 1;
2414 		}
2415 	}
2416 }
2417 
2418 /* We use this structure as parameter for the next function */
2419 struct parserules_data {
2420 	struct fd_list  * sentinel;  	/* Sentinel of the list of children AVP */
2421 	struct fd_pei 	* pei;   	/* If the rule conflicts, save the error here */
2422 };
2423 
2424 /* Create an empty AVP of a given model (to use in Failed-AVP) */
empty_avp(struct dict_object * model_avp)2425 static struct avp * empty_avp(struct dict_object * model_avp)
2426 {
2427 	struct avp * avp = NULL;
2428 	struct dict_avp_data avp_info;
2429 	union avp_value val;
2430 	unsigned char os[1] = { '\0' };
2431 
2432 	/* Create an instance */
2433 	CHECK_FCT_DO( fd_msg_avp_new(model_avp, 0, &avp ), return NULL );
2434 
2435 	/* Type of the AVP */
2436 	CHECK_FCT_DO( fd_dict_getval(model_avp, &avp_info), return NULL );
2437 
2438 	/* Set an initial size */
2439 	avp->avp_public.avp_len = GETAVPHDRSZ( avp->avp_public.avp_flags ) + avp_value_sizes[avp_info.avp_basetype];
2440 
2441 	/* Prepare the empty value */
2442 	memset(&val, 0, sizeof(val));
2443 	switch (avp_info.avp_basetype) {
2444 		case AVP_TYPE_OCTETSTRING:
2445 			val.os.data = os;
2446 			val.os.len  = sizeof(os);
2447 			avp->avp_public.avp_len += val.os.len;
2448 		case AVP_TYPE_INTEGER32:
2449 		case AVP_TYPE_INTEGER64:
2450 		case AVP_TYPE_UNSIGNED32:
2451 		case AVP_TYPE_UNSIGNED64:
2452 		case AVP_TYPE_FLOAT32:
2453 		case AVP_TYPE_FLOAT64:
2454 			CHECK_FCT_DO( fd_msg_avp_setvalue(avp, &val), return NULL );
2455 		case AVP_TYPE_GROUPED:
2456 			/* For AVP_TYPE_GROUPED we don't do anything */
2457 			break;
2458 		default:
2459 			ASSERT(0); /* not handled */
2460 	}
2461 
2462 	return avp;
2463 }
2464 
2465 /* Check that a list of AVPs is compliant with a given rule -- will be iterated on the list of rules */
parserules_check_one_rule(void * data,struct dict_rule_data * rule)2466 static int parserules_check_one_rule(void * data, struct dict_rule_data *rule)
2467 {
2468 	int count, first, last, min;
2469 	struct parserules_data * pr_data = data;
2470 	char * avp_name = "<unresolved name>";
2471 
2472 	TRACE_ENTRY("%p %p", data, rule);
2473 
2474 	/* Get statistics of the AVP concerned by this rule in the parent instance */
2475 	parserules_stat_avps( rule->rule_avp, pr_data->sentinel, &count, &first, &last);
2476 
2477 	if (TRACE_BOOL(INFO))
2478 	{
2479 		struct dict_avp_data avpdata;
2480 		int ret;
2481 		ret = fd_dict_getval(rule->rule_avp, &avpdata);
2482 		if (ret == 0)
2483 			avp_name = avpdata.avp_name;
2484 
2485 		TRACE_DEBUG(ANNOYING, "Checking rule: p:%d(%d) m/M:%2d/%2d. Counted %d (first: %d, last:%d) of AVP '%s'",
2486 					rule->rule_position,
2487 					rule->rule_order,
2488 					rule->rule_min,
2489 					rule->rule_max,
2490 					count,
2491 					first,
2492 					last,
2493 					avp_name
2494 				);
2495 	}
2496 
2497 	/* Now check the rule is not conflicting */
2498 
2499 	/* Check the "min" value */
2500 	if ((min = rule->rule_min) == -1) {
2501 		if (rule->rule_position == RULE_OPTIONAL)
2502 			min = 0;
2503 		else
2504 			min = 1;
2505 	}
2506 	if (count < min) {
2507 		fd_log_error("Conflicting rule: the number of occurences (%d) is < the rule min (%d) for '%s'.", count, min, avp_name);
2508 		if (pr_data->pei) {
2509 			pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
2510 			pr_data->pei->pei_avp = empty_avp(rule->rule_avp);
2511 			pr_data->pei->pei_avp_free = 1;
2512 		}
2513 		return EBADMSG;
2514 	}
2515 
2516 	/* Check the "max" value */
2517 	if ((rule->rule_max != -1) && (count > rule->rule_max)) {
2518 		fd_log_error("Conflicting rule: the number of occurences (%d) is > the rule max (%d) for '%s'.", count, rule->rule_max, avp_name);
2519 		if (pr_data->pei) {
2520 			if (rule->rule_max == 0)
2521 				pr_data->pei->pei_errcode = "DIAMETER_AVP_NOT_ALLOWED";
2522 			else
2523 				pr_data->pei->pei_errcode = "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES";
2524 			pr_data->pei->pei_avp = empty_avp(rule->rule_avp); /* Well we are supposed to return the (max + 1)th instance of the AVP instead... Pfff... */ TODO("Improve...");
2525 			pr_data->pei->pei_avp_free = 1;
2526 		}
2527 		return EBADMSG;
2528 	}
2529 
2530 	/* Check the position and order (if relevant) */
2531 	switch (rule->rule_position) {
2532 		case RULE_OPTIONAL:
2533 		case RULE_REQUIRED:
2534 			/* No special position constraints */
2535 			break;
2536 
2537 		case RULE_FIXED_HEAD:
2538 			/* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *after* its fixed position */
2539 			if (first > rule->rule_order) {
2540 				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);
2541 				if (pr_data->pei) {
2542 					pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
2543 					pr_data->pei->pei_message = "AVP was not in its fixed position";
2544 					pr_data->pei->pei_avp = empty_avp(rule->rule_avp);
2545 					pr_data->pei->pei_avp_free = 1;
2546 				}
2547 				return EBADMSG;
2548 			}
2549 			break;
2550 
2551 		case RULE_FIXED_TAIL:
2552 			/* Since "0*1<fixed>" is a valid rule specifier, we only reject cases where the AVP appears *before* its fixed position */
2553 			if (last > rule->rule_order) {	/* We have a ">" here because we count in reverse order (i.e. from the end) */
2554 				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);
2555 				if (pr_data->pei) {
2556 					pr_data->pei->pei_errcode = "DIAMETER_MISSING_AVP";
2557 					pr_data->pei->pei_message = "AVP was not in its fixed position";
2558 					pr_data->pei->pei_avp = empty_avp(rule->rule_avp);
2559 					pr_data->pei->pei_avp_free = 1;
2560 				}
2561 				return EBADMSG;
2562 			}
2563 			break;
2564 
2565 		default:
2566 			/* What is this position ??? */
2567 			ASSERT(0);
2568 			return ENOTSUP;
2569 	}
2570 
2571 	/* We've checked all the parameters */
2572 	return 0;
2573 }
2574 
2575 /* Check the rules recursively */
parserules_do(struct dictionary * dict,msg_or_avp * object,struct fd_pei * error_info,int mandatory)2576 static int parserules_do ( struct dictionary * dict, msg_or_avp * object, struct fd_pei *error_info, int mandatory)
2577 {
2578 	struct parserules_data data;
2579 	struct dict_object * model = NULL;
2580 
2581 	TRACE_ENTRY("%p %p %p %d", dict, object, error_info, mandatory);
2582 
2583 	/* object has already been checked and dict-parsed when we are called. */
2584 
2585 	/* First, handle the cases where there is no model */
2586 	{
2587 		if (CHECK_MSG(object)) {
2588 			if ( _M(object)->msg_public.msg_flags & CMD_FLAG_ERROR ) {
2589 				/* The case of error messages: the ABNF is different */
2590 				CHECK_FCT( fd_dict_get_error_cmd(dict, &model) );
2591 			} else {
2592 				model = _M(object)->msg_model;
2593 			}
2594 			/* Commands MUST be supported in the dictionary */
2595 			if (model == NULL) {
2596 				TRACE_DEBUG(INFO, "Message with no dictionary model. EBADMSG");
2597 				if (error_info) {
2598 					error_info->pei_errcode = "DIAMETER_COMMAND_UNSUPPORTED";
2599 					error_info->pei_protoerr = 1;
2600 				}
2601 				return EBADMSG;
2602 			}
2603 		}
2604 
2605 		/* AVP with the 'M' flag must also be recognized in the dictionary -- except inside an optional grouped AVP */
2606 		if (CHECK_AVP(object) && ((model = _A(object)->avp_model) == NULL)) {
2607 			if ( mandatory && (_A(object)->avp_public.avp_flags & AVP_FLAG_MANDATORY)) {
2608 				/* Return an error in this case */
2609 				TRACE_DEBUG(INFO, "Mandatory AVP with no dictionary model. EBADMSG");
2610 				if (error_info) {
2611 					error_info->pei_errcode = "DIAMETER_AVP_UNSUPPORTED";
2612 					error_info->pei_avp = object;
2613 				}
2614 				return EBADMSG;
2615 			} else {
2616 				/* We don't know any rule for this object, so assume OK */
2617 				TRACE_DEBUG(FULL, "Unknown informational AVP, ignoring...");
2618 				return 0;
2619 			}
2620 		}
2621 	}
2622 
2623 	/* At this point we know "model" is set and points to the object's model */
2624 
2625 	/* If we are an AVP with no children, just return OK */
2626 	if (CHECK_AVP(object)) {
2627 		struct dict_avp_data	dictdata;
2628 		CHECK_FCT(  fd_dict_getval(model, &dictdata)  );
2629 		if (dictdata.avp_basetype != AVP_TYPE_GROUPED) {
2630 			/* This object has no children and no rules */
2631 			return 0;
2632 		}
2633 	}
2634 
2635 	/* If this object has children, first check the rules for all its children */
2636 	{
2637 		int is_child_mand = 0;
2638 		struct fd_list * ch = NULL;
2639 		if (  CHECK_MSG(object)
2640 		   || (mandatory && (_A(object)->avp_public.avp_flags & AVP_FLAG_MANDATORY)) )
2641 			is_child_mand = 1;
2642 		for (ch = _C(object)->children.next; ch != &_C(object)->children; ch = ch->next) {
2643 			CHECK_FCT(  parserules_do ( dict, _C(ch->o), error_info, is_child_mand )  );
2644 		}
2645 	}
2646 
2647 	/* Now check all rules of this object */
2648 	data.sentinel = &_C(object)->children;
2649 	data.pei  = error_info;
2650 	CHECK_FCT( fd_dict_iterate_rules ( model, &data, parserules_check_one_rule ) );
2651 
2652 	return 0;
2653 }
2654 
fd_msg_parse_rules(msg_or_avp * object,struct dictionary * dict,struct fd_pei * error_info)2655 int fd_msg_parse_rules ( msg_or_avp * object, struct dictionary * dict, struct fd_pei *error_info)
2656 {
2657 	TRACE_ENTRY("%p %p %p", object, dict, error_info);
2658 
2659 	if (error_info)
2660 		memset(error_info, 0, sizeof(struct fd_pei));
2661 
2662 	/* Resolve the dictionary objects when missing. This also validates the object. */
2663 	CHECK_FCT(  fd_msg_parse_dict ( object, dict, error_info )  );
2664 
2665 	/* Call the recursive function */
2666 	return parserules_do ( dict, object, error_info, 1 ) ;
2667 }
2668 
2669 /***************************************************************************************************************/
2670 
2671 /* Compute the lengh of an object and its subtree. */
fd_msg_update_length(msg_or_avp * object)2672 int fd_msg_update_length ( msg_or_avp * object )
2673 {
2674 	size_t sz = 0;
2675 	struct dict_object * model;
2676 	union {
2677 		struct dict_cmd_data   cmddata;
2678 		struct dict_avp_data   avpdata;
2679 	} dictdata;
2680 
2681 	TRACE_ENTRY("%p", object);
2682 
2683 	/* Get the model of the object. This also validates the object */
2684 	CHECK_FCT( fd_msg_model ( object, &model ) );
2685 
2686 	/* Get the information of the model */
2687 	if (model) {
2688 		CHECK_FCT(  fd_dict_getval(model, &dictdata)  );
2689 	} else {
2690 		/* For unknown AVP, just don't change the size */
2691 		if (_C(object)->type == MSG_AVP)
2692 			return 0;
2693 	}
2694 
2695 	/* Deal with easy cases: AVPs without children */
2696 	if ((_C(object)->type == MSG_AVP) && (dictdata.avpdata.avp_basetype != AVP_TYPE_GROUPED)) {
2697 		/* Sanity check */
2698 		ASSERT(FD_IS_LIST_EMPTY(&_A(object)->avp_chain.children));
2699 
2700 		/* Now check that the data is set in the AVP */
2701 		CHECK_PARAMS(  _A(object)->avp_public.avp_value  );
2702 
2703 		sz = GETAVPHDRSZ( _A(object)->avp_public.avp_flags );
2704 
2705 		switch (dictdata.avpdata.avp_basetype) {
2706 			case AVP_TYPE_OCTETSTRING:
2707 				sz += _A(object)->avp_public.avp_value->os.len;
2708 				break;
2709 
2710 			case AVP_TYPE_INTEGER32:
2711 			case AVP_TYPE_INTEGER64:
2712 			case AVP_TYPE_UNSIGNED32:
2713 			case AVP_TYPE_UNSIGNED64:
2714 			case AVP_TYPE_FLOAT32:
2715 			case AVP_TYPE_FLOAT64:
2716 				sz += avp_value_sizes[dictdata.avpdata.avp_basetype];
2717 				break;
2718 
2719 			default:
2720 				/* Something went wrong... */
2721 				ASSERT(0);
2722 		}
2723 	}
2724 	else  /* message or grouped AVP */
2725 	{
2726 		struct fd_list * ch = NULL;
2727 
2728 		/* First, compute the header size */
2729 		if (_C(object)->type == MSG_AVP) {
2730 			sz = GETAVPHDRSZ( _A(object)->avp_public.avp_flags );
2731 		} else {
2732 			sz = GETMSGHDRSZ( );
2733 		}
2734 
2735 		/* Recurse in all children and update the sz information */
2736 		for (ch = _C(object)->children.next; ch != &_C(object)->children; ch = ch->next) {
2737 			CHECK_FCT(  fd_msg_update_length ( ch->o )  );
2738 
2739 			/* Add the padded size to the parent */
2740 			sz += PAD4( _A(ch->o)->avp_public.avp_len );
2741 		}
2742 	}
2743 
2744 	/* When we arrive here, the "sz" variable contains the size to write in the object */
2745 	if (_C(object)->type == MSG_AVP)
2746 		_A(object)->avp_public.avp_len = sz;
2747 	else
2748 		_M(object)->msg_public.msg_length = sz;
2749 
2750 	return 0;
2751 }
2752 
2753 /***************************************************************************************************************/
2754 /* Macro to check if further callbacks must be called */
2755 #define TEST_ACTION_STOP()					\
2756 	if ((*msg == NULL) || (*action != DISP_ACT_CONT))	\
2757 		goto out;
2758 
2759 /* Call all dispatch callbacks for a given message */
fd_msg_dispatch(struct msg ** msg,struct session * session,enum disp_action * action,char ** error_code,char ** drop_reason,struct msg ** drop_msg)2760 int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action, char ** error_code, char ** drop_reason, struct msg ** drop_msg)
2761 {
2762 	struct dictionary  * dict;
2763 	struct dict_object * app;
2764 	struct dict_object * cmd;
2765 	struct avp * avp;
2766 	struct fd_list * cb_list;
2767 	int ret = 0, r2;
2768 
2769 	TRACE_ENTRY("%p %p %p %p", msg, session, action, error_code);
2770 	CHECK_PARAMS( msg && CHECK_MSG(*msg) && action);
2771 
2772 	if (error_code)
2773 		*error_code = NULL;
2774 	if (drop_reason)
2775 		*drop_reason = NULL;
2776 	*action = DISP_ACT_CONT;
2777 
2778 	/* Take the dispatch lock */
2779 	CHECK_FCT( pthread_rwlock_rdlock(&fd_disp_lock) );
2780 	pthread_cleanup_push( fd_cleanup_rwlock, &fd_disp_lock );
2781 
2782 	/* First, call the DISP_HOW_ANY callbacks */
2783 	CHECK_FCT_DO( ret = fd_disp_call_cb_int( NULL, msg, NULL, session, action, NULL, NULL, NULL, NULL, drop_reason, drop_msg ), goto out );
2784 
2785 	TEST_ACTION_STOP();
2786 
2787 	/* If we don't know the model at this point, we stop cause we cannot get the dictionary. It's invalid: an error should already have been trigged by ANY callbacks */
2788 	CHECK_PARAMS_DO(cmd = (*msg)->msg_model, { ret = EINVAL; goto out; } );
2789 
2790 	/* Now resolve message application */
2791 	CHECK_FCT_DO( ret = fd_dict_getdict( cmd, &dict ), goto out );
2792 	CHECK_FCT_DO( ret = fd_dict_search( dict, DICT_APPLICATION, APPLICATION_BY_ID, &(*msg)->msg_public.msg_appl, &app, 0 ), goto out );
2793 
2794 	if (app == NULL) {
2795 		if ((*msg)->msg_public.msg_flags & CMD_FLAG_REQUEST) {
2796 			if (error_code)
2797 				*error_code = "DIAMETER_APPLICATION_UNSUPPORTED";
2798 			*action = DISP_ACT_ERROR;
2799 		} else {
2800 			*drop_reason = "Internal error: Received this answer to a local query with an unsupported application";
2801 			*drop_msg = *msg;
2802 			*msg = NULL;
2803 		}
2804 		goto out;
2805 	}
2806 
2807 	/* So start browsing the message */
2808 	CHECK_FCT_DO( ret = fd_msg_browse( *msg, MSG_BRW_FIRST_CHILD, &avp, NULL ), goto out );
2809 	while (avp != NULL) {
2810 		/* For unknown AVP, we don't have a callback registered, so just skip */
2811 		if (avp->avp_model) {
2812 			struct dict_object * enumval = NULL;
2813 
2814 			/* Get the list of callback for this AVP */
2815 			CHECK_FCT_DO( ret = fd_dict_disp_cb(DICT_AVP, avp->avp_model, &cb_list), goto out );
2816 
2817 			/* We search enumerated values only in case of non-grouped AVP */
2818 			if ( avp->avp_public.avp_value ) {
2819 				struct dict_object * type;
2820 				/* Check if the AVP has a constant value */
2821 				CHECK_FCT_DO( ret = fd_dict_search(dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &type, 0), goto out );
2822 				if (type) {
2823 					struct dict_enumval_request req;
2824 					memset(&req, 0, sizeof(struct dict_enumval_request));
2825 					req.type_obj = type;
2826 					memcpy( &req.search.enum_value, avp->avp_public.avp_value, sizeof(union avp_value) );
2827 					CHECK_FCT_DO( ret = fd_dict_search(dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enumval, 0), goto out );
2828 				}
2829 			}
2830 
2831 			/* Call the callbacks */
2832 			CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, avp, session, action, app, cmd, avp->avp_model, enumval, drop_reason, drop_msg ), goto out );
2833 			TEST_ACTION_STOP();
2834 		}
2835 		/* Go to next AVP */
2836 		CHECK_FCT_DO(  ret = fd_msg_browse( avp, MSG_BRW_WALK, &avp, NULL ), goto out );
2837 	}
2838 
2839 	/* Now call command and application callbacks */
2840 	CHECK_FCT_DO( ret = fd_dict_disp_cb(DICT_COMMAND, cmd, &cb_list), goto out );
2841 	CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, NULL, session, action, app, cmd, NULL, NULL, drop_reason, drop_msg ), goto out );
2842 	TEST_ACTION_STOP();
2843 
2844 	if (app) {
2845 		CHECK_FCT_DO( ret = fd_dict_disp_cb(DICT_APPLICATION, app, &cb_list), goto out );
2846 		CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, NULL, session, action, app, cmd, NULL, NULL, drop_reason, drop_msg ), goto out );
2847 		TEST_ACTION_STOP();
2848 	}
2849 out:
2850 	; /* some systems would complain without this */
2851 	pthread_cleanup_pop(0);
2852 
2853 	CHECK_POSIX_DO(r2 = pthread_rwlock_unlock(&fd_disp_lock), /* ignore */ );
2854 	return ret ?: r2;
2855 }
2856 
2857 
2858