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