Navigation


source: freeDiameter/libfdcore/messages.c

Last change on this file was 1554:566bb46cc73f, checked in by Sebastien Decugis <sdecugis@freediameter.net>, 5 months ago

Updated copyright information

File size: 17.9 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@freediameter.net>                                                  *
4*                                                                                                        *
5* Copyright (c) 2020, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37
38static struct dict_object * dict_avp_SI  = NULL; /* Session-Id */
39static struct dict_object * dict_avp_OH  = NULL; /* Origin-Host */
40static struct dict_object * dict_avp_OR  = NULL; /* Origin-Realm */
41static struct dict_object * dict_avp_EM  = NULL; /* Error-Message */
42static struct dict_object * dict_avp_ERH = NULL; /* Error-Reporting-Host */
43static struct dict_object * dict_avp_FAVP= NULL; /* Failed-AVP */
44static struct dict_object * dict_avp_RC  = NULL; /* Result-Code */
45static struct dict_object * dict_avp_ER  = NULL; /* Experimental-Result */
46static struct dict_object * dict_avp_VI  = NULL; /* Vendor-Id */
47static struct dict_object * dict_avp_ERC = NULL; /* Experimental-Result-Code */
48struct dict_object * fd_dict_avp_OSI = NULL; /* Origin-State-Id */
49struct dict_object * fd_dict_cmd_CER = NULL; /* Capabilities-Exchange-Request */
50struct dict_object * fd_dict_cmd_DWR = NULL; /* Device-Watchdog-Request */
51struct dict_object * fd_dict_avp_DC  = NULL; /* Disconnect-Cause */
52struct dict_object * fd_dict_cmd_DPR = NULL; /* Disconnect-Peer-Request */
53
54/* Resolve the dictionary objects */
55int fd_msg_init(void)
56{
57        TRACE_ENTRY("");
58
59        /* Initialize the dictionary objects that we may use frequently */
60        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id",         &dict_avp_SI , ENOENT)  );
61        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host",        &dict_avp_OH  , ENOENT)  );
62        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm",       &dict_avp_OR  , ENOENT)  );
63        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id",    &fd_dict_avp_OSI , ENOENT)  );
64
65        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code",        &dict_avp_RC  , ENOENT)  );
66        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message",      &dict_avp_EM  , ENOENT)  );
67        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT)  );
68        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP",         &dict_avp_FAVP, ENOENT)  );
69        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &dict_avp_ER, ENOENT)  );
70        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id",          &dict_avp_VI, ENOENT)  );
71        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result-Code", &dict_avp_ERC, ENOENT)  );
72
73        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause",   &fd_dict_avp_DC , ENOENT)  );
74
75        CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) );
76        CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) );
77        CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) );
78
79
80        return 0;
81}
82
83/* Add Origin-Host, Origin-Realm, Origin-State-Id AVPS at the end of the message */
84int fd_msg_add_origin ( struct msg * msg, int osi )
85{
86        union avp_value val;
87        struct avp * avp_OH  = NULL;
88        struct avp * avp_OR  = NULL;
89        struct avp * avp_OSI = NULL;
90
91        TRACE_ENTRY("%p", msg);
92        CHECK_PARAMS(  msg  );
93
94        /* Create the Origin-Host AVP */
95        CHECK_FCT( fd_msg_avp_new( dict_avp_OH, 0, &avp_OH ) );
96
97        /* Set its value */
98        memset(&val, 0, sizeof(val));
99        val.os.data = (os0_t)fd_g_config->cnf_diamid;
100        val.os.len  = fd_g_config->cnf_diamid_len;
101        CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) );
102
103        /* Add it to the message */
104        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OH ) );
105
106
107        /* Create the Origin-Realm AVP */
108        CHECK_FCT( fd_msg_avp_new( dict_avp_OR, 0, &avp_OR ) );
109
110        /* Set its value */
111        memset(&val, 0, sizeof(val));
112        val.os.data = (os0_t)fd_g_config->cnf_diamrlm;
113        val.os.len  = fd_g_config->cnf_diamrlm_len;
114        CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) );
115
116        /* Add it to the message */
117        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OR ) );
118
119        if (osi) {
120                /* Create the Origin-State-Id AVP */
121                CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) );
122
123                /* Set its value */
124                memset(&val, 0, sizeof(val));
125                val.u32 = fd_g_config->cnf_orstateid;
126                CHECK_FCT( fd_msg_avp_setvalue( avp_OSI, &val ) );
127
128                /* Add it to the message */
129                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) );
130        }
131
132        return 0;
133}
134
135/* Create a new Session-Id and add at the beginning of the message. */
136int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen )
137{
138        union avp_value val;
139        struct avp * avp  = NULL;
140        struct session * sess = NULL;
141        os0_t sid;
142        size_t sidlen;
143
144        TRACE_ENTRY("%p %p %zd", msg, opt, optlen);
145        CHECK_PARAMS(  msg  );
146
147        /* Check there is not already a session in the message */
148        CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) );
149        CHECK_PARAMS( sess == NULL );
150
151        /* Ok, now create the session */
152        CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) );
153        CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) );
154
155        /* Create an AVP to hold it */
156        CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) );
157
158        /* Set its value */
159        memset(&val, 0, sizeof(val));
160        val.os.data = sid;
161        val.os.len  = sidlen;
162        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
163
164        /* Add it to the message */
165        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) );
166
167        /* Save the session associated with the message */
168        CHECK_FCT( fd_msg_sess_set( msg, sess) );
169
170        /* Done! */
171        return 0;
172}
173
174
175/* Add Result-Code or Experimental-Result, and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */
176int fd_msg_add_result( struct msg * msg, vendor_id_t vendor, struct dict_object * restype, char * rescode, char * errormsg, struct avp * optavp, int type_id )
177{
178        union avp_value val;
179        uint32_t rc_val = 0;
180        int set_e_bit=0;
181        int std_err_msg=0;
182
183        TRACE_ENTRY("%p %d %p %s %p %p %d", msg, vendor, restype, rescode, errormsg, optavp, type_id);
184
185        CHECK_PARAMS(  msg && restype && rescode  );
186
187        /* Find the enum value corresponding to the rescode string, this will give the class of error */
188        {
189                struct dict_object * enum_obj = NULL;
190
191                /* Search in the restype */
192                struct dict_enumval_request req;
193                memset(&req, 0, sizeof(struct dict_enumval_request));
194                req.type_obj = restype;
195
196                /* Now search for the value given as parameter */
197                req.search.enum_name = rescode;
198                CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enum_obj, ENOTSUP)  );
199
200                /* finally retrieve its data */
201                CHECK_FCT_DO(  fd_dict_getval( enum_obj, &(req.search) ), return EINVAL );
202
203                /* copy the found value, we're done */
204                rc_val = req.search.enum_value.u32;
205        }
206
207        if (type_id == 1) {
208                /* Add the Origin-Host and Origin-Realm AVP */
209                CHECK_FCT( fd_msg_add_origin ( msg, 0 ) );
210        }
211
212        if (vendor == 0) {
213                /* Vendor 0; create the Result-Code AVP */
214                struct avp * avp_RC  = NULL;
215                CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) );
216
217                /* Set its value */
218                memset(&val, 0, sizeof(val));
219                val.u32  = rc_val;
220                CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) );
221
222                /* Add it to the message */
223                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) );
224        } else {
225                /* Vendor !0; create the Experimental-Result AVP */
226                struct avp * avp_ER  = NULL;
227                CHECK_FCT( fd_msg_avp_new( dict_avp_ER, 0, &avp_ER ) );
228
229                /* Create the Vendor-Id AVP and add to Experimental-Result */
230                {
231                        struct avp * avp_VI  = NULL;
232                        CHECK_FCT( fd_msg_avp_new( dict_avp_VI, 0, &avp_VI ) );
233
234                        /* Set Vendor-Id value to vendor */
235                        memset(&val, 0, sizeof(val));
236                        val.u32  = vendor;
237                        CHECK_FCT( fd_msg_avp_setvalue( avp_VI, &val ) );
238
239                        /* Add it to Experimental-Result */
240                        CHECK_FCT( fd_msg_avp_add( avp_ER, MSG_BRW_LAST_CHILD, avp_VI ) );
241                }
242
243                /* Create the Experimental-Result-Code AVP and add to Experimental-Result */
244                {
245                        struct avp * avp_ERC  = NULL;
246                        CHECK_FCT( fd_msg_avp_new( dict_avp_ERC, 0, &avp_ERC ) );
247
248                        /* Set Experimental-Result-Code value to rc_val */
249                        memset(&val, 0, sizeof(val));
250                        val.u32  = rc_val;
251                        CHECK_FCT( fd_msg_avp_setvalue( avp_ERC, &val ) );
252
253                        /* Add it to Experimental-Result */
254                        CHECK_FCT( fd_msg_avp_add( avp_ER, MSG_BRW_LAST_CHILD, avp_ERC ) );
255                }
256
257                /* Add it to the message */
258                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ER ) );
259        }
260
261        if (type_id == 2) {
262                /* Add the Error-Reporting-Host AVP */
263                struct avp * avp_ERH = NULL;
264                CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) );
265
266                /* Set its value */
267                memset(&val, 0, sizeof(val));
268                val.os.data = (uint8_t *)fd_g_config->cnf_diamid;
269                val.os.len  = fd_g_config->cnf_diamid_len;
270                CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) );
271
272                /* Add it to the message */
273                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) );
274        }
275
276        /* Now add the optavp in a Failed-AVP if provided */
277        if (optavp) {
278                struct avp * avp_FAVP= NULL;
279                struct avp * optavp_cpy = NULL;
280                struct avp_hdr *opt_hdr, *optcpy_hdr;
281                struct dict_object * opt_model = NULL;
282                int is_grouped = 0;
283
284                /* Create the Failed-AVP AVP */
285                CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) );
286
287                /* Was this AVP a grouped one? Best effort only here */
288                if (!fd_msg_model ( optavp, &opt_model ) && (opt_model != NULL)) {
289                        struct dict_avp_data  dictdata;
290                        CHECK_FCT(  fd_dict_getval(opt_model, &dictdata)  );
291                        if (dictdata.avp_basetype == AVP_TYPE_GROUPED)
292                                is_grouped = 1;
293                }
294
295                /* Create a new AVP with a copy of the data of the invalid or missing AVP */
296                optavp_cpy = optavp;
297
298                if (is_grouped) {
299                        CHECK_FCT( fd_msg_avp_new( opt_model, 0, &optavp_cpy) );
300                } else {
301                        CHECK_FCT( fd_msg_avp_new( NULL, AVPFL_SET_BLANK_VALUE | AVPFL_SET_RAWDATA_FROM_AVP, &optavp_cpy) );
302
303                        CHECK_FCT( fd_msg_avp_hdr(optavp, &opt_hdr) );
304                        CHECK_FCT( fd_msg_avp_hdr(optavp_cpy, &optcpy_hdr) );
305                        memcpy(optcpy_hdr, opt_hdr, sizeof(struct avp_hdr));
306                }
307
308                /* Add the passed AVP inside it */
309                CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp_cpy ) );
310
311                /* And add to the message */
312                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_FAVP ) );
313        }
314
315
316        /* Deal with the 'E' bit and the error message */
317        switch (rc_val / 1000) {
318                case 1: /* Informational */
319                case 2: /* Success */
320                        /* Nothing special here: no E bit, no error message unless one is specified */
321                        break;
322
323                case 3: /* Protocol Errors */
324                        set_e_bit = 1;
325                        std_err_msg = 1;
326                        break;
327
328                case 4: /* Transcient Failure */
329                case 5: /* Permanent Failure */
330                        if (rc_val == 5017) /* DIAMETER_NO_COMMON_SECURITY */ {
331                                set_e_bit = 1;
332                        }
333                default:
334                        std_err_msg = 1;
335                        break;
336
337        }
338
339        {
340                struct msg_hdr * hdr = NULL;
341
342                CHECK_FCT(  fd_msg_hdr( msg, &hdr )  );
343
344                if (set_e_bit)
345                        hdr->msg_flags |= CMD_FLAG_ERROR;
346                else
347                        hdr->msg_flags &= ~ CMD_FLAG_ERROR;
348        }
349
350        if (std_err_msg || errormsg) {
351                /* Add the Error-Message AVP */
352                struct avp * avp_EM  = NULL;
353                CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) );
354
355                /* Set its value */
356                memset(&val, 0, sizeof(val));
357
358                if (errormsg) {
359                        val.os.data = (uint8_t *)errormsg;
360                        val.os.len  = strlen(errormsg);
361                } else {
362                        val.os.data = (uint8_t *)rescode;
363                        val.os.len  = strlen(rescode);
364                }
365                CHECK_FCT( fd_msg_avp_setvalue( avp_EM, &val ) );
366
367                /* Add it to the message */
368                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) );
369        }
370
371        return 0;
372}
373
374int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id )
375{
376        struct dict_object * restype = NULL;
377        CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &restype, ENOENT ) );
378        return fd_msg_add_result(msg, 0, restype, rescode, errormsg, optavp, type_id);
379}
380
381static int fd_msg_send_int( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout )
382{
383        struct msg_hdr *hdr;
384        DiamId_t diamid;
385
386        /* Save the callback in the message, with the timeout */
387        CHECK_FCT(  fd_msg_anscb_associate( *pmsg, anscb, data, expirecb, timeout )  );
388
389        /* If this is a new request, call the HOOK_MESSAGE_LOCAL hook */
390        if ( (fd_msg_hdr(*pmsg, &hdr) == 0)
391         &&  (hdr->msg_flags & CMD_FLAG_REQUEST)
392         &&  (fd_msg_source_get(*pmsg, &diamid, NULL) == 0)
393         &&  (diamid == NULL)) {
394                fd_hook_call(HOOK_MESSAGE_LOCAL, *pmsg, NULL, NULL, fd_msg_pmdl_get(*pmsg));
395        }
396
397        /* Post the message in the outgoing queue */
398        CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) );
399
400        return 0;
401}
402
403/* Send a message and optionally register a callback for an answer */
404int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data )
405{
406        TRACE_ENTRY("%p %p %p", pmsg, anscb, data);
407        CHECK_PARAMS( pmsg );
408
409        return fd_msg_send_int(pmsg, anscb, data, NULL, NULL);
410}
411
412/* The variation of the same function with a timeout callback */
413int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout )
414{
415        TRACE_ENTRY("%p %p %p %p %p", pmsg, anscb, data, expirecb, timeout);
416        CHECK_PARAMS( pmsg && expirecb && timeout );
417
418        return fd_msg_send_int(pmsg, anscb, data, expirecb, timeout);
419}
420
421
422/* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */
423int fd_msg_parse_or_error( struct msg ** msg, struct msg **error)
424{
425        int ret = 0;
426        struct msg * m;
427        struct msg_hdr * hdr = NULL;
428        struct fd_pei   pei;
429
430        TRACE_ENTRY("%p", msg);
431
432        CHECK_PARAMS(msg && *msg && error);
433        m = *msg;
434        *error = NULL;
435
436        /* Parse the message against our dictionary */
437        ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei);
438        if      ((ret != EBADMSG)       /* Parsing grouped AVP failed / Conflicting rule found */
439                && (ret != ENOTSUP))    /* Command is not supported / Mandatory AVP is not supported */
440                return ret; /* 0 or another error */
441
442        /* Log */
443        fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, m, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(m));
444
445        CHECK_FCT( fd_msg_hdr(m, &hdr) );
446
447        /* Now create an answer error if the message is a query */
448        if (hdr->msg_flags & CMD_FLAG_REQUEST) {
449
450                /* Create the error message */
451                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &m, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) );
452
453                /* Set the error code */
454                CHECK_FCT( fd_msg_rescode_set(m, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) );
455
456                /* free the pei AVP to avoid memory leak */
457                if (pei.pei_avp_free) {
458                        fd_msg_free(pei.pei_avp);
459                }
460
461                *msg = NULL;
462                *error = m;
463
464        } else {
465                do { /* Rescue error messages */
466                        struct avp * avp;
467                        union avp_value * rc = NULL;
468
469                        /* Search the Result-Code AVP */
470                        CHECK_FCT_DO(  fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL), break  );
471                        while (avp) {
472                                struct avp_hdr * ahdr;
473                                CHECK_FCT_DO(  fd_msg_avp_hdr( avp, &ahdr ), break  );
474
475                                if ((ahdr->avp_code == AC_RESULT_CODE) && (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) ) {
476                                        /* Parse this AVP */
477                                        if (fd_msg_parse_dict(avp, fd_g_config->cnf_dict, &pei) < 0) {
478                                                TRACE_DEBUG(INFO, "error parsing Result-Code AVP");
479                                                rc = NULL;
480                                                break;
481                                        }
482                                        rc = ahdr->avp_value;
483                                        if (rc == NULL) {
484                                                TRACE_DEBUG(INFO, "invalid Result-Code AVP");
485                                                break;
486                                        }
487                                        break;
488                                }
489
490                                /* Go to next AVP */
491                                CHECK_FCT_DO(  fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), break  );
492                        }
493
494                        if (rc) {
495                                switch (rc->u32 / 1000) {
496                                        case 1: /* 1xxx : Informational */
497                                        case 2: /* 2xxx : Sucess */
498                                                /* In these cases, we want the message to validate the ABNF, so we will discard the bad message */
499                                                break;
500
501                                        default: /* Other errors */
502                                                /* We let the application decide what to do with the message, we rescue it */
503                                                *error = m;
504                                }
505                        }
506                } while (0);
507        }
508
509        return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */
510}
Note: See TracBrowser for help on using the repository browser.