diff options
| author | Sukchan Lee <acetcom@gmail.com> | 2021-03-21 13:14:26 +0900 |
|---|---|---|
| committer | Sukchan Lee <acetcom@gmail.com> | 2021-03-21 13:14:26 +0900 |
| commit | 32d46d3f43485e171b1e28117d0db049dfc829b0 (patch) | |
| tree | b3506d614932f50730e023391600287676ac0c08 /libfdcore/messages.c | |
| parent | e07f3955e6d0f59f272fd21d3b21a5e2eac17426 (diff) | |
Release freeDiameter v1.5.0main
Diffstat (limited to 'libfdcore/messages.c')
| -rw-r--r-- | libfdcore/messages.c | 261 |
1 files changed, 158 insertions, 103 deletions
diff --git a/libfdcore/messages.c b/libfdcore/messages.c index c13bfff..e0f8a56 100644 --- a/libfdcore/messages.c +++ b/libfdcore/messages.c @@ -2,7 +2,7 @@ * Software License Agreement (BSD License) * * Author: Sebastien Decugis <sdecugis@freediameter.net> * * * -* Copyright (c) 2015, WIDE Project and NICT * +* Copyright (c) 2020, WIDE Project and NICT * * All rights reserved. * * * * Redistribution and use of this software in source and binary forms, with or without modification, are * @@ -42,6 +42,9 @@ static struct dict_object * dict_avp_EM = NULL; /* Error-Message */ static struct dict_object * dict_avp_ERH = NULL; /* Error-Reporting-Host */ static struct dict_object * dict_avp_FAVP= NULL; /* Failed-AVP */ static struct dict_object * dict_avp_RC = NULL; /* Result-Code */ +static struct dict_object * dict_avp_ER = NULL; /* Experimental-Result */ +static struct dict_object * dict_avp_VI = NULL; /* Vendor-Id */ +static struct dict_object * dict_avp_ERC = NULL; /* Experimental-Result-Code */ struct dict_object * fd_dict_avp_OSI = NULL; /* Origin-State-Id */ struct dict_object * fd_dict_cmd_CER = NULL; /* Capabilities-Exchange-Request */ struct dict_object * fd_dict_cmd_DWR = NULL; /* Device-Watchdog-Request */ @@ -52,25 +55,28 @@ struct dict_object * fd_dict_cmd_DPR = NULL; /* Disconnect-Peer-Request */ int fd_msg_init(void) { TRACE_ENTRY(""); - + /* Initialize the dictionary objects that we may use frequently */ CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &dict_avp_SI , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &dict_avp_OH , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &dict_avp_OR , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id", &fd_dict_avp_OSI , ENOENT) ); - + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &dict_avp_RC , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &dict_avp_EM , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &dict_avp_FAVP, ENOENT) ); - + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &dict_avp_ER, ENOENT) ); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id", &dict_avp_VI, ENOENT) ); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result-Code", &dict_avp_ERC, ENOENT) ); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", &fd_dict_avp_DC , ENOENT) ); - + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) ); CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) ); CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) ); - - + + return 0; } @@ -81,35 +87,35 @@ int fd_msg_add_origin ( struct msg * msg, int osi ) struct avp * avp_OH = NULL; struct avp * avp_OR = NULL; struct avp * avp_OSI = NULL; - + TRACE_ENTRY("%p", msg); CHECK_PARAMS( msg ); - + /* Create the Origin-Host AVP */ CHECK_FCT( fd_msg_avp_new( dict_avp_OH, 0, &avp_OH ) ); - + /* Set its value */ memset(&val, 0, sizeof(val)); val.os.data = (os0_t)fd_g_config->cnf_diamid; val.os.len = fd_g_config->cnf_diamid_len; CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) ); - + /* Add it to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OH ) ); - - + + /* Create the Origin-Realm AVP */ CHECK_FCT( fd_msg_avp_new( dict_avp_OR, 0, &avp_OR ) ); - + /* Set its value */ memset(&val, 0, sizeof(val)); val.os.data = (os0_t)fd_g_config->cnf_diamrlm; val.os.len = fd_g_config->cnf_diamrlm_len; CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) ); - + /* Add it to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OR ) ); - + if (osi) { /* Create the Origin-State-Id AVP */ CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) ); @@ -122,7 +128,7 @@ int fd_msg_add_origin ( struct msg * msg, int osi ) /* Add it to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) ); } - + return 0; } @@ -134,93 +140,127 @@ int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen ) struct session * sess = NULL; os0_t sid; size_t sidlen; - + TRACE_ENTRY("%p %p %zd", msg, opt, optlen); CHECK_PARAMS( msg ); - + /* Check there is not already a session in the message */ CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) ); CHECK_PARAMS( sess == NULL ); - + /* Ok, now create the session */ CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) ); CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) ); - + /* Create an AVP to hold it */ CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) ); - + /* Set its value */ memset(&val, 0, sizeof(val)); val.os.data = sid; val.os.len = sidlen; CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) ); - + /* Add it to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) ); - + /* Save the session associated with the message */ CHECK_FCT( fd_msg_sess_set( msg, sess) ); - + /* Done! */ return 0; } -/* Add Result-Code and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */ -int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id ) +/* Add Result-Code or Experimental-Result, and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */ +int 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 ) { union avp_value val; - struct avp * avp_RC = NULL; - struct avp * avp_EM = NULL; - struct avp * avp_ERH = NULL; - struct avp * avp_FAVP= NULL; uint32_t rc_val = 0; int set_e_bit=0; int std_err_msg=0; - - TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id); - - CHECK_PARAMS( msg && rescode ); - + + TRACE_ENTRY("%p %d %p %s %p %p %d", msg, vendor, restype, rescode, errormsg, optavp, type_id); + + CHECK_PARAMS( msg && restype && rescode ); + /* Find the enum value corresponding to the rescode string, this will give the class of error */ { struct dict_object * enum_obj = NULL; + + /* Search in the restype */ struct dict_enumval_request req; memset(&req, 0, sizeof(struct dict_enumval_request)); - - /* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */ - CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) ); - + req.type_obj = restype; + /* Now search for the value given as parameter */ req.search.enum_name = rescode; CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enum_obj, ENOTSUP) ); - + /* finally retrieve its data */ CHECK_FCT_DO( fd_dict_getval( enum_obj, &(req.search) ), return EINVAL ); - + /* copy the found value, we're done */ rc_val = req.search.enum_value.u32; } - + if (type_id == 1) { /* Add the Origin-Host and Origin-Realm AVP */ CHECK_FCT( fd_msg_add_origin ( msg, 0 ) ); } - - /* Create the Result-Code AVP */ - CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) ); - - /* Set its value */ - memset(&val, 0, sizeof(val)); - val.u32 = rc_val; - CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) ); - - /* Add it to the message */ - CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) ); - + + if (vendor == 0) { + /* Vendor 0; create the Result-Code AVP */ + struct avp * avp_RC = NULL; + CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) ); + + /* Set its value */ + memset(&val, 0, sizeof(val)); + val.u32 = rc_val; + CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) ); + + /* Add it to the message */ + CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) ); + } else { + /* Vendor !0; create the Experimental-Result AVP */ + struct avp * avp_ER = NULL; + CHECK_FCT( fd_msg_avp_new( dict_avp_ER, 0, &avp_ER ) ); + + /* Create the Vendor-Id AVP and add to Experimental-Result */ + { + struct avp * avp_VI = NULL; + CHECK_FCT( fd_msg_avp_new( dict_avp_VI, 0, &avp_VI ) ); + + /* Set Vendor-Id value to vendor */ + memset(&val, 0, sizeof(val)); + val.u32 = vendor; + CHECK_FCT( fd_msg_avp_setvalue( avp_VI, &val ) ); + + /* Add it to Experimental-Result */ + CHECK_FCT( fd_msg_avp_add( avp_ER, MSG_BRW_LAST_CHILD, avp_VI ) ); + } + + /* Create the Experimental-Result-Code AVP and add to Experimental-Result */ + { + struct avp * avp_ERC = NULL; + CHECK_FCT( fd_msg_avp_new( dict_avp_ERC, 0, &avp_ERC ) ); + + /* Set Experimental-Result-Code value to rc_val */ + memset(&val, 0, sizeof(val)); + val.u32 = rc_val; + CHECK_FCT( fd_msg_avp_setvalue( avp_ERC, &val ) ); + + /* Add it to Experimental-Result */ + CHECK_FCT( fd_msg_avp_add( avp_ER, MSG_BRW_LAST_CHILD, avp_ERC ) ); + } + + /* Add it to the message */ + CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ER ) ); + } + if (type_id == 2) { /* Add the Error-Reporting-Host AVP */ - + struct avp * avp_ERH = NULL; CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) ); /* Set its value */ @@ -231,60 +271,60 @@ int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struc /* Add it to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) ); - } - - /* Now add the optavp in a FailedAVP if provided */ + + /* Now add the optavp in a Failed-AVP if provided */ if (optavp) { + struct avp * avp_FAVP= NULL; struct avp * optavp_cpy = NULL; struct avp_hdr *opt_hdr, *optcpy_hdr; struct dict_object * opt_model = NULL; int is_grouped = 0; - + /* Create the Failed-AVP AVP */ CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) ); - + /* Was this AVP a grouped one? Best effort only here */ if (!fd_msg_model ( optavp, &opt_model ) && (opt_model != NULL)) { struct dict_avp_data dictdata; CHECK_FCT( fd_dict_getval(opt_model, &dictdata) ); - if (dictdata.avp_basetype == AVP_TYPE_GROUPED) + if (dictdata.avp_basetype == AVP_TYPE_GROUPED) is_grouped = 1; } - + /* Create a new AVP with a copy of the data of the invalid or missing AVP */ optavp_cpy = optavp; - + if (is_grouped) { CHECK_FCT( fd_msg_avp_new( opt_model, 0, &optavp_cpy) ); } else { CHECK_FCT( fd_msg_avp_new( NULL, AVPFL_SET_BLANK_VALUE | AVPFL_SET_RAWDATA_FROM_AVP, &optavp_cpy) ); - + CHECK_FCT( fd_msg_avp_hdr(optavp, &opt_hdr) ); CHECK_FCT( fd_msg_avp_hdr(optavp_cpy, &optcpy_hdr) ); memcpy(optcpy_hdr, opt_hdr, sizeof(struct avp_hdr)); } - + /* Add the passed AVP inside it */ CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp_cpy ) ); - + /* And add to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_FAVP ) ); } - - + + /* Deal with the 'E' bit and the error message */ switch (rc_val / 1000) { case 1: /* Informational */ case 2: /* Success */ /* Nothing special here: no E bit, no error message unless one is specified */ break; - + case 3: /* Protocol Errors */ set_e_bit = 1; std_err_msg = 1; break; - + case 4: /* Transcient Failure */ case 5: /* Permanent Failure */ if (rc_val == 5017) /* DIAMETER_NO_COMMON_SECURITY */ { @@ -293,28 +333,28 @@ int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struc default: std_err_msg = 1; break; - + } - + { struct msg_hdr * hdr = NULL; - + CHECK_FCT( fd_msg_hdr( msg, &hdr ) ); - + if (set_e_bit) hdr->msg_flags |= CMD_FLAG_ERROR; else hdr->msg_flags &= ~ CMD_FLAG_ERROR; } - + if (std_err_msg || errormsg) { /* Add the Error-Message AVP */ - + struct avp * avp_EM = NULL; CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) ); /* Set its value */ memset(&val, 0, sizeof(val)); - + if (errormsg) { val.os.data = (uint8_t *)errormsg; val.os.len = strlen(errormsg); @@ -327,18 +367,25 @@ int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struc /* Add it to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) ); } - + return 0; } +int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id ) +{ + struct dict_object * restype = NULL; + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &restype, ENOENT ) ); + return fd_msg_add_result(msg, 0, restype, rescode, errormsg, optavp, type_id); +} + static 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 ) { struct msg_hdr *hdr; DiamId_t diamid; - + /* Save the callback in the message, with the timeout */ CHECK_FCT( fd_msg_anscb_associate( *pmsg, anscb, data, expirecb, timeout ) ); - + /* If this is a new request, call the HOOK_MESSAGE_LOCAL hook */ if ( (fd_msg_hdr(*pmsg, &hdr) == 0) && (hdr->msg_flags & CMD_FLAG_REQUEST) @@ -346,10 +393,10 @@ static int fd_msg_send_int( struct msg ** pmsg, void (*anscb)(void *, struct msg && (diamid == NULL)) { fd_hook_call(HOOK_MESSAGE_LOCAL, *pmsg, NULL, NULL, fd_msg_pmdl_get(*pmsg)); } - + /* Post the message in the outgoing queue */ CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) ); - + return 0; } @@ -358,7 +405,7 @@ int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void { TRACE_ENTRY("%p %p %p", pmsg, anscb, data); CHECK_PARAMS( pmsg ); - + return fd_msg_send_int(pmsg, anscb, data, NULL, NULL); } @@ -367,7 +414,7 @@ int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg * { TRACE_ENTRY("%p %p %p %p %p", pmsg, anscb, data, expirecb, timeout); CHECK_PARAMS( pmsg && expirecb && timeout ); - + return fd_msg_send_int(pmsg, anscb, data, expirecb, timeout); } @@ -379,70 +426,78 @@ int fd_msg_parse_or_error( struct msg ** msg, struct msg **error) struct msg * m; struct msg_hdr * hdr = NULL; struct fd_pei pei; - + TRACE_ENTRY("%p", msg); - + CHECK_PARAMS(msg && *msg && error); m = *msg; *error = NULL; - + /* Parse the message against our dictionary */ ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei); if ((ret != EBADMSG) /* Parsing grouped AVP failed / Conflicting rule found */ && (ret != ENOTSUP)) /* Command is not supported / Mandatory AVP is not supported */ return ret; /* 0 or another error */ - + /* Log */ fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, m, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(m)); - + CHECK_FCT( fd_msg_hdr(m, &hdr) ); - + /* Now create an answer error if the message is a query */ if (hdr->msg_flags & CMD_FLAG_REQUEST) { - + /* Create the error message */ CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &m, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) ); - + /* Set the error code */ CHECK_FCT( fd_msg_rescode_set(m, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) ); - + /* free the pei AVP to avoid memory leak */ if (pei.pei_avp_free) { fd_msg_free(pei.pei_avp); } - + *msg = NULL; *error = m; - + } else { do { /* Rescue error messages */ struct avp * avp; union avp_value * rc = NULL; - + /* Search the Result-Code AVP */ CHECK_FCT_DO( fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL), break ); while (avp) { struct avp_hdr * ahdr; CHECK_FCT_DO( fd_msg_avp_hdr( avp, &ahdr ), break ); - + if ((ahdr->avp_code == AC_RESULT_CODE) && (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) ) { /* Parse this AVP */ - ASSERT( ahdr->avp_value ); + if (fd_msg_parse_dict(avp, fd_g_config->cnf_dict, &pei) < 0) { + TRACE_DEBUG(INFO, "error parsing Result-Code AVP"); + rc = NULL; + break; + } rc = ahdr->avp_value; + if (rc == NULL) { + TRACE_DEBUG(INFO, "invalid Result-Code AVP"); + break; + } break; } - + /* Go to next AVP */ CHECK_FCT_DO( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), break ); } - + if (rc) { switch (rc->u32 / 1000) { case 1: /* 1xxx : Informational */ case 2: /* 2xxx : Sucess */ /* In these cases, we want the message to validate the ABNF, so we will discard the bad message */ break; - + default: /* Other errors */ /* We let the application decide what to do with the message, we rescue it */ *error = m; @@ -450,6 +505,6 @@ int fd_msg_parse_or_error( struct msg ** msg, struct msg **error) } } while (0); } - + return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */ } |
