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