# HG changeset patch # User Sebastien Decugis # Date 1253862728 -32400 # Node ID c5c99c73c2bf5c2521580bff8ca437ed6b271480 # Parent fc7c18867cf74c6351aac05863cebebcf8b739f6 Added some extensions and functions in the daemon diff -r fc7c18867cf7 -r c5c99c73c2bf doc/freediameter.conf.sample --- a/doc/freediameter.conf.sample Thu Sep 24 14:01:48 2009 +0900 +++ b/doc/freediameter.conf.sample Fri Sep 25 16:12:08 2009 +0900 @@ -128,5 +128,6 @@ TcTimer = 60; TwTimer = 6; NoRelay; -#LoadExtension = "extensions/sample.fdx"; -LoadExtension = "extensions/sample.fdx":"conf/sample.conf"; +LoadExtension = "extensions/dbg_monitor.fdx"; +LoadExtension = "extensions/dict_nasreq.fdx"; +LoadExtension = "extensions/dict_eap.fdx"; diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/CMakeLists.txt --- a/extensions/CMakeLists.txt Thu Sep 24 14:01:48 2009 +0900 +++ b/extensions/CMakeLists.txt Fri Sep 25 16:12:08 2009 +0900 @@ -17,15 +17,15 @@ #### # Diameter applications dictionary -# OPTION(BUILD_DICT_NASREQ "Build NASREQ (RFC4005) Dictionary definitions?" ON) -# IF (BUILD_DICT_NASREQ) -# SUBDIRS(dict_nasreq) -# ENDIF (BUILD_DICT_NASREQ) +OPTION(BUILD_DICT_NASREQ "Build NASREQ (RFC4005) Dictionary definitions?" ON) + IF (BUILD_DICT_NASREQ) + SUBDIRS(dict_nasreq) + ENDIF (BUILD_DICT_NASREQ) -# OPTION(BUILD_DICT_EAP "Build Diameter EAP (RFC4072) Dictionary definitions?" ON) -# IF (BUILD_DICT_EAP) -# SUBDIRS(dict_eap) -# ENDIF (BUILD_DICT_EAP) +OPTION(BUILD_DICT_EAP "Build Diameter EAP (RFC4072) Dictionary definitions?" ON) + IF (BUILD_DICT_EAP) + SUBDIRS(dict_eap) + ENDIF (BUILD_DICT_EAP) @@ -58,11 +58,16 @@ #### # Debug / development extensions -OPTION(BUILD_SAMPLE "Build sample? (Simple extension to demonstrate extension mechanism, for developpers only)" OFF) +OPTION(BUILD_SAMPLE "Build sample.fdx? (Simple extension to demonstrate extension mechanism, for developpers only)" OFF) IF (BUILD_SAMPLE) SUBDIRS(_sample) ENDIF (BUILD_SAMPLE) +OPTION(BUILD_MONITOR "Build monitor.fdx? (display periodical debug information on the console)" OFF) + IF (BUILD_MONITOR) + SUBDIRS(dbg_monitor) + ENDIF (BUILD_MONITOR) + # OPTION(BUILD_RT_ANY "Build rt_any? (Routing extension sending message to any peer available, for testing purpose only)" OFF) # IF (BUILD_RT_ANY) # SUBDIRS(rt_any) diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/_sample/CMakeLists.txt --- a/extensions/_sample/CMakeLists.txt Thu Sep 24 14:01:48 2009 +0900 +++ b/extensions/_sample/CMakeLists.txt Fri Sep 25 16:12:08 2009 +0900 @@ -2,4 +2,4 @@ PROJECT("Sample extension" C) # Compile as a module -FD_ADD_EXTENSION(sample sample.c fini.c) +FD_ADD_EXTENSION(dbg_sample sample.c fini.c) diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/_sample/fini.c --- a/extensions/_sample/fini.c Thu Sep 24 14:01:48 2009 +0900 +++ b/extensions/_sample/fini.c Fri Sep 25 16:12:08 2009 +0900 @@ -33,13 +33,13 @@ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *********************************************************************************************************/ -/* Sample extension exit point */ - #include +/* The function MUST be called this */ void fd_ext_fini(void) { - fd_log_debug("Extension is terminated... Bye!\n"); + /* This code is executed when the daemon is exiting; cleanup management should be placed here */ + TRACE_DEBUG(INFO, "Extension is terminated... Bye!"); return ; } diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/_sample/sample.c --- a/extensions/_sample/sample.c Thu Sep 24 14:01:48 2009 +0900 +++ b/extensions/_sample/sample.c Fri Sep 25 16:12:08 2009 +0900 @@ -44,18 +44,21 @@ /* The extension-specific initialization code */ static int sample_main(char * conffile) { + /* The debug macro from main tree can be used the same way */ TRACE_ENTRY("%p", conffile); - fprintf(stdout, "I am extension " __FILE__ " running on host %s\n", fd_g_config->diam_id); + /* This is how we access daemon's global vars */ + fprintf(stdout, "I am extension " __FILE__ " running on host %s.", fd_g_config->cnf_diamid); + /* The configuration file name is received in the conffile var. It's up to extension to parse it */ if (conffile) { fprintf(stdout, "I should parse my configuration file there: %s\n", conffile); } else { fprintf(stdout, "I received no configuration file to parse\n"); } - /* Use the dictionary for test */ - fd_log_debug("Let's create that 'Example-AVP'...\n"); + /* Functions from the libfreediameter can also be used as demonstrated here: */ + TRACE_DEBUG(INFO, "Let's create that 'Example-AVP'..."); { struct dict_object * origin_host_avp = NULL; struct dict_object * session_id_avp = NULL; @@ -63,22 +66,27 @@ struct dict_rule_data rule_data = { NULL, RULE_REQUIRED, 0, -1, 1 }; struct dict_avp_data example_avp_data = { 999999, 0, "Example-AVP", AVP_FLAG_VENDOR , 0, AVP_TYPE_GROUPED }; - CHECK_FCT( fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT)); - CHECK_FCT( fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT)); + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT)); + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT)); - CHECK_FCT( fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp )); + CHECK_FCT( fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp )); rule_data.rule_avp = origin_host_avp; rule_data.rule_min = 1; rule_data.rule_max = 1; - CHECK_FCT( fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL )); + CHECK_FCT( fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &rule_data, example_avp_avp, NULL )); rule_data.rule_avp = session_id_avp; rule_data.rule_min = 1; rule_data.rule_max = -1; - CHECK_FCT( fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL )); + CHECK_FCT( fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &rule_data, example_avp_avp, NULL )); + + fd_dict_dump_object(example_avp_avp); } - fd_log_debug("'Example-AVP' created without error\n"); + TRACE_DEBUG(INFO, "'Example-AVP' created without error\n"); + /* The initialization function returns an error code with the standard POSIX meaning (ENOMEM, and so on) */ return 0; } + +/* See file fini.c for an example of destructor */ diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/dbg_monitor/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/dbg_monitor/CMakeLists.txt Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,3 @@ +# Monitoring extension +PROJECT("Monitor extension" C) +FD_ADD_EXTENSION(dbg_monitor monitor.c) diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/dbg_monitor/monitor.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/dbg_monitor/monitor.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,96 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* Monitoring extension: + - periodically display queues and peers information + - upon SIGUSR1, display additional debug information + */ + +#include +#include + +static int monitor_main(char * conffile); + +EXTENSION_ENTRY("monitor", monitor_main); + +/* Function called on receipt of SIGUSR1 */ +static void got_sig(int signal) +{ + CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_DICT, NULL), /* continue */); + CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_CONFIG, NULL), /* continue */); + CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_EXT, NULL), /* continue */); +} +/* Thread to display periodical debug information */ +static pthread_t thr; +static void * mn_thr(void * arg) +{ + sigset_t sig; + struct sigaction act; + fd_log_threadname("Monitor thread"); + + /* Catch signal SIGUSR1 */ + memset(&act, 0, sizeof(act)); + act.sa_handler = got_sig; + CHECK_SYS_DO( sigaction(SIGUSR1, &act, NULL), /* conitnue */ ); + sigemptyset(&sig); + sigaddset(&sig, SIGUSR1); + CHECK_POSIX_DO( pthread_sigmask(SIG_UNBLOCK, &sig, NULL), /* conitnue */ ); + + /* Loop */ + while (1) { + sleep(60); + TRACE_DEBUG(NONE, "Monitor information"); + CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_QUEUES, NULL), /* continue */); + CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_DUMP_PEERS, NULL), /* continue */); + pthread_testcancel(); + } + + return NULL; +} + +static int monitor_main(char * conffile) +{ + TRACE_ENTRY("%p", conffile); + CHECK_POSIX( pthread_create( &thr, NULL, mn_thr, NULL ) ); + return 0; +} + +void fd_ext_fini(void) +{ + TRACE_ENTRY(); + CHECK_FCT_DO( fd_thr_term(&thr), /* continue */ ); + return ; +} + diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/dict_eap/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/dict_eap/CMakeLists.txt Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,5 @@ +# The dict_nasreq extension +PROJECT("Diameter EAP (RFC4072) dictionary definitions" C) + +# Compile as a module +FD_ADD_EXTENSION(dict_eap dict_eap.c) diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/dict_eap/dict_eap.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/dict_eap/dict_eap.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,530 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* + * Dictionary definitions of objects specified in Diameter EAP application (RFC4072). + */ +#include + +/* The content of this file follows the same structure as dict_base_proto.c */ + +#define CHECK_dict_new( _type, _data, _parent, _ref ) \ + CHECK_FCT( fd_dict_new( fd_g_config->cnf_dict, (_type), (_data), (_parent), (_ref)) ); + +#define CHECK_dict_search( _type, _criteria, _what, _result ) \ + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) ); + +struct local_rules_definition { + char *avp_name; + enum rule_position position; + int min; + int max; +}; + +#define RULE_ORDER( _position ) ((((_position) == RULE_FIXED_HEAD) || ((_position) == RULE_FIXED_TAIL)) ? 1 : 0 ) + +#define PARSE_loc_rules( _rulearray, _parent) { \ + int __ar; \ + for (__ar=0; __ar < sizeof(_rulearray) / sizeof((_rulearray)[0]); __ar++) { \ + struct dict_rule_data __data = { NULL, \ + (_rulearray)[__ar].position, \ + 0, \ + (_rulearray)[__ar].min, \ + (_rulearray)[__ar].max}; \ + __data.rule_order = RULE_ORDER(__data.rule_position); \ + CHECK_FCT( fd_dict_search( \ + fd_g_config->cnf_dict, \ + DICT_AVP, \ + AVP_BY_NAME, \ + (_rulearray)[__ar].avp_name, \ + &__data.rule_avp, 0 ) ); \ + if ( !__data.rule_avp ) { \ + TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_name ); \ + return ENOENT; \ + } \ + CHECK_FCT_DO( fd_dict_new( fd_g_config->cnf_dict, DICT_RULE, &__data, _parent, NULL), \ + { \ + TRACE_DEBUG(INFO, "Error on rule with AVP '%s'", \ + (_rulearray)[__ar].avp_name ); \ + return EINVAL; \ + } ); \ + } \ +} + +#define enumval_def_u32( _val_, _str_ ) \ + { _str_, { .u32 = _val_ }} + +#define enumval_def_os( _len_, _val_, _str_ ) \ + { _str_, { .os = { .data = (unsigned char *)_val_, .len = _len_ }}} + + +static int deap_entry(char * conffile) +{ + struct dict_object * eap; + TRACE_ENTRY("%p", conffile); + + /* Since we need many AVP from the NASREQ application, check that it is already defined in the dictionary */ + { + application_id_t nasreqid = 1; + CHECK_FCT_DO( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_ID, &nasreqid, NULL, ENOENT), + { + fprintf(stderr, "The dict_eap extension needs definitions from NASREQ application (RFC4005).\n" + "Please load the 'dict_nasreq' extension prior to this one.\n"); + return ENOTSUP; + } ); + } + + /* Applications section */ + { + /* EAP (RFC 4072) */ + { + struct dict_application_data data = { 5, "Diameter Extensible Authentication Protocol (EAP) Application" }; + CHECK_dict_new( DICT_APPLICATION, &data , NULL, &eap); + } + } + + /* AVP section */ + { + /* EAP-Payload */ + { + /* + The EAP-Payload AVP (AVP Code 462) is of type OctetString and is used + to encapsulate the actual EAP packet that is being exchanged between + the EAP client and the home Diameter server. + */ + struct dict_avp_data data = { + 462, /* Code */ + 0, /* Vendor */ + "EAP-Payload", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* EAP-Reissued-Payload */ + { + /* + The EAP-Reissued-Payload AVP (AVP Code 463) is of type OctetString. + */ + struct dict_avp_data data = { + 463, /* Code */ + 0, /* Vendor */ + "EAP-Reissued-Payload", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* EAP-Master-Session-Key */ + { + /* + The EAP-Master-Session-Key AVP (AVP Code 464) is of type OctetString. + It contains keying material for protecting the communications between + the user and the NAS. Exactly how this keying material is used + depends on the link layer in question, and is beyond the scope of + this document. + */ + struct dict_avp_data data = { + 464, /* Code */ + 0, /* Vendor */ + "EAP-Master-Session-Key", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* EAP-Key-Name */ + { + /* + The EAP-Key-Name AVP (Radius Attribute Type 102) is of type + OctetString. It contains an opaque key identifier (name) generated + by the EAP method. Exactly how this name is used depends on the link + layer in question, and is beyond the scope of this document (see + [EAPKey] for more discussion). + + Note that not all link layers use this name, and currently most EAP + methods do not generate it. Since the NAS operates in pass-through + mode, it cannot know the Key-Name before receiving it from the AAA + server. As a result, a Key-Name AVP sent in a Diameter-EAP-Request + MUST NOT contain any data. A home Diameter server receiving a + Diameter-EAP-Request with a Key-Name AVP with non-empty data MUST + silently discard the AVP. In addition, the home Diameter server + SHOULD include this AVP in Diameter-EAP-Response only if an empty + EAP-Key-Name AVP was present in Diameter-EAP-Request. + */ + struct dict_avp_data data = { + 102, /* Code */ + 0, /* Vendor */ + "EAP-Key-Name", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Accounting-EAP-Auth-Method */ + { + /* + The Accounting-EAP-Auth-Method AVP (AVP Code 465) is of type + Unsigned64. In case of expanded types [EAP, Section 5.7], this AVP + contains the value ((Vendor-Id * 2^32) + Vendor-Type). + */ + struct dict_avp_data data = { + 465, /* Code */ + 0, /* Vendor */ + "Accounting-EAP-Auth-Method", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED64 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + } + +/********************/ +/* Commands section */ +/********************/ + { + /* To avoid defining global variables for all the AVP that we use here, we do search the dictionary in each sub-block. + * This is far from optimal, but the code is clearer like this, and the time it requires at execution is not noticeable. + */ + /* Diameter-EAP-Request (DER) Command */ + { + /* + The Diameter-EAP-Request (DER) command, indicated by the Command-Code + field set to 268 and the 'R' bit set in the Command Flags field, is + sent by a Diameter client to a Diameter server, and conveys an + EAP-Response from the EAP client. The Diameter-EAP-Request MUST + contain one EAP-Payload AVP containing the actual EAP payload. An + EAP-Payload AVP with no data MAY be sent to the Diameter server to + initiate an EAP authentication session. + + The DER message MAY be the result of a multi-round authentication + exchange that occurs when the DEA is received with the Result-Code + AVP set to DIAMETER_MULTI_ROUND_AUTH [BASE]. A subsequent DER + message MUST include any State AVPs [NASREQ] that were present in the + DEA. For re-authentication, it is recommended that the Identity + request be skipped in order to reduce the number of authentication + round trips. This is only possible when the user's identity is + already known by the home Diameter server. + + Message format + + ::= < Diameter Header: 268, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Request-Type } + [ Destination-Host ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Origin-State-Id ] + [ Port-Limit ] + [ User-Name ] + { EAP-Payload } + [ EAP-Key-Name ] + [ Service-Type ] + [ State ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Connect-Info ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IP-Netmask ] + [ Framed-MTU ] + [ Framed-Protocol ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + */ + struct dict_object * cmd; + struct dict_cmd_data data = { + 268, /* Code */ + "Diameter-EAP-Request", /* Name */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_RETRANSMIT | CMD_FLAG_ERROR, /* Fixed flags */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ + }; + struct local_rules_definition rules[] = + { { "Session-Id", RULE_FIXED_HEAD, -1, 1 } + ,{ "Auth-Application-Id", RULE_REQUIRED, -1, 1 } + ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } + ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } + ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } + ,{ "Auth-Request-Type", RULE_REQUIRED, -1, 1 } + ,{ "Destination-Host", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Identifier", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IPv6-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Id", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Origin-State-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Port-Limit", RULE_OPTIONAL, -1, 1 } + ,{ "User-Name", RULE_OPTIONAL, -1, 1 } + ,{ "EAP-Payload", RULE_REQUIRED, -1, 1 } + ,{ "EAP-Key-Name", RULE_OPTIONAL, -1, 1 } + ,{ "Service-Type", RULE_OPTIONAL, -1, 1 } + ,{ "State", RULE_OPTIONAL, -1, 1 } + ,{ "Authorization-Lifetime", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Grace-Period", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Session-State", RULE_OPTIONAL, -1, 1 } + ,{ "Callback-Number", RULE_OPTIONAL, -1, 1 } + ,{ "Called-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Calling-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Originating-Line-Info", RULE_OPTIONAL, -1, 1 } + ,{ "Connect-Info", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Compression", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-Interface-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Prefix", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IP-Netmask", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-MTU", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "Tunneling", RULE_OPTIONAL, -1,-1 } + ,{ "Proxy-Info", RULE_OPTIONAL, -1,-1 } + ,{ "Route-Record", RULE_OPTIONAL, -1,-1 } + }; + + CHECK_dict_new( DICT_COMMAND, &data , eap, &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Diameter-EAP-Answer (DEA) Command */ + { + /* + The Diameter-EAP-Answer (DEA) message, indicated by the Command-Code + field set to 268 and the 'R' bit cleared in the Command Flags field, + is sent by the Diameter server to the client for one of the following + reasons: + + 1. The message is part of a multi-round authentication exchange, and + the server is expecting a subsequent Diameter-EAP-Request. This + is indicated by setting the Result-Code to + DIAMETER_MULTI_ROUND_AUTH, and MAY include zero or more State + AVPs. + + 2. The EAP client has been successfully authenticated and + authorized, in which case the message MUST include the + Result-Code AVP indicating success, and SHOULD include an + EAP-Payload of type EAP-Success. This event MUST cause the + access device to provide service to the EAP client. + + 3. The EAP client has not been successfully authenticated and/or + authorized, and the Result-Code AVP is set to indicate failure. + This message SHOULD include an EAP-Payload, but this AVP is not + used to determine whether service is to be provided. + + If the message from the Diameter client included a request for + authorization, a successful response MUST include the authorization + AVPs that are relevant to the service being provided. + + Message format + + ::= < Diameter Header: 268, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Request-Type } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ EAP-Payload ] + [ EAP-Reissued-Payload ] + [ EAP-Master-Session-Key ] + [ EAP-Key-Name ] + [ Multi-Round-Time-Out ] + [ Accounting-EAP-Auth-Method ] + [ Service-Type ] + * [ Class ] + * [ Configuration-Token ] + [ Acct-Interim-Interval ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Re-Auth-Request-Type ] + [ Session-Timeout ] + [ State ] + * [ Reply-Message ] + [ Origin-State-Id ] + * [ Filter-Id ] + [ Port-Limit ] + [ Callback-Id ] + [ Callback-Number ] + [ Framed-Appletalk-Link ] + * [ Framed-Appletalk-Network ] + [ Framed-Appletalk-Zone ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IP-Netmask ] + * [ Framed-Route ] + [ Framed-Pool ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ Framed-Routing ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + * [ Tunneling ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + */ + struct dict_object * cmd; + struct dict_cmd_data data = { + 268, /* Code */ + "Diameter-EAP-Answer", /* Name */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE, /* Fixed flags */ + CMD_FLAG_PROXIABLE /* Fixed flag values */ + }; + struct local_rules_definition rules[] = + { { "Session-Id", RULE_FIXED_HEAD, -1, 1 } + ,{ "Auth-Application-Id", RULE_REQUIRED, -1, 1 } + ,{ "Auth-Request-Type", RULE_REQUIRED, -1, 1 } + ,{ "Result-Code", RULE_REQUIRED, -1, 1 } + ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } + ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } + ,{ "User-Name", RULE_OPTIONAL, -1, 1 } + ,{ "EAP-Payload", RULE_OPTIONAL, -1, 1 } + ,{ "EAP-Reissued-Payload", RULE_OPTIONAL, -1, 1 } + ,{ "EAP-Master-Session-Key", RULE_OPTIONAL, -1, 1 } + ,{ "EAP-Key-Name", RULE_OPTIONAL, -1, 1 } + ,{ "Multi-Round-Time-Out", RULE_OPTIONAL, -1, 1 } + ,{ "Accounting-EAP-Auth-Method", RULE_OPTIONAL, -1, 1 } + ,{ "Service-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Class", RULE_OPTIONAL, -1,-1 } + ,{ "Configuration-Token", RULE_OPTIONAL, -1,-1 } + ,{ "Acct-Interim-Interval", RULE_OPTIONAL, -1, 1 } + ,{ "Error-Message", RULE_OPTIONAL, -1, 1 } + ,{ "Error-Reporting-Host", RULE_OPTIONAL, -1, 1 } + ,{ "Failed-AVP", RULE_OPTIONAL, -1,-1 } + ,{ "Idle-Timeout", RULE_OPTIONAL, -1, 1 } + ,{ "Authorization-Lifetime", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Grace-Period", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Session-State", RULE_OPTIONAL, -1, 1 } + ,{ "Re-Auth-Request-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Session-Timeout", RULE_OPTIONAL, -1, 1 } + ,{ "State", RULE_OPTIONAL, -1, 1 } + ,{ "Reply-Message", RULE_OPTIONAL, -1,-1 } + ,{ "Origin-State-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Filter-Id", RULE_OPTIONAL, -1,-1 } + ,{ "Port-Limit", RULE_OPTIONAL, -1, 1 } + ,{ "Callback-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Callback-Number", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-AppleTalk-Link", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-AppleTalk-Network", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-AppleTalk-Zone", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Compression", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-Interface-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Prefix", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IPv6-Pool", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Route", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IP-Netmask", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Route", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-Pool", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPX-Network", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-MTU", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Routing", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Filter-Rule", RULE_OPTIONAL, -1,-1 } + ,{ "QoS-Filter-Rule", RULE_OPTIONAL, -1,-1 } + ,{ "Tunneling", RULE_OPTIONAL, -1,-1 } + ,{ "Redirect-Host", RULE_OPTIONAL, -1,-1 } + ,{ "Redirect-Host-Usage", RULE_OPTIONAL, -1, 1 } + ,{ "Redirect-Max-Cache-Time", RULE_OPTIONAL, -1, 1 } + ,{ "Proxy-Info", RULE_OPTIONAL, -1,-1 } + }; + + CHECK_dict_new( DICT_COMMAND, &data , eap, &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Accounting-Request */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + Attribute Name | ACR | ACA | + ---------------------------------------|-----+-----+ + Accounting-EAP-Auth-Method | 0+ | 0 | + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Accounting-EAP-Auth-Method", RULE_OPTIONAL, -1,-1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &cmd); + PARSE_loc_rules( rules, cmd ); + } + + } + + TRACE_DEBUG(INFO, "Extension 'Dictionary definitions for EAP' initialized"); + return 0; +} + +EXTENSION_ENTRY("dict_eap", deap_entry); diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/dict_nasreq/CMakeLists.txt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/dict_nasreq/CMakeLists.txt Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,5 @@ +# The dict_nasreq extension +PROJECT("Diameter NASREQ (RFC4005) dictionary definitions" C) + +# Compile as a module +FD_ADD_EXTENSION(dict_nasreq dict_nasreq.c) diff -r fc7c18867cf7 -r c5c99c73c2bf extensions/dict_nasreq/dict_nasreq.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/extensions/dict_nasreq/dict_nasreq.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,3735 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* + * Dictionary definitions of objects specified in Diameter NASREQ (RFC4005). + */ +#include + +/* The content of this file follows the same structure as dict_base_proto.c */ + +#define CHECK_dict_new( _type, _data, _parent, _ref ) \ + CHECK_FCT( fd_dict_new( fd_g_config->cnf_dict, (_type), (_data), (_parent), (_ref)) ); + +#define CHECK_dict_search( _type, _criteria, _what, _result ) \ + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, (_type), (_criteria), (_what), (_result), ENOENT) ); + +struct local_rules_definition { + char *avp_name; + enum rule_position position; + int min; + int max; +}; + +#define RULE_ORDER( _position ) ((((_position) == RULE_FIXED_HEAD) || ((_position) == RULE_FIXED_TAIL)) ? 1 : 0 ) + +#define PARSE_loc_rules( _rulearray, _parent) { \ + int __ar; \ + for (__ar=0; __ar < sizeof(_rulearray) / sizeof((_rulearray)[0]); __ar++) { \ + struct dict_rule_data __data = { NULL, \ + (_rulearray)[__ar].position, \ + 0, \ + (_rulearray)[__ar].min, \ + (_rulearray)[__ar].max}; \ + __data.rule_order = RULE_ORDER(__data.rule_position); \ + CHECK_FCT( fd_dict_search( \ + fd_g_config->cnf_dict, \ + DICT_AVP, \ + AVP_BY_NAME, \ + (_rulearray)[__ar].avp_name, \ + &__data.rule_avp, 0 ) ); \ + if ( !__data.rule_avp ) { \ + TRACE_DEBUG(INFO, "AVP Not found: '%s'", (_rulearray)[__ar].avp_name ); \ + return ENOENT; \ + } \ + CHECK_FCT_DO( fd_dict_new( fd_g_config->cnf_dict, DICT_RULE, &__data, _parent, NULL), \ + { \ + TRACE_DEBUG(INFO, "Error on rule with AVP '%s'", \ + (_rulearray)[__ar].avp_name ); \ + return EINVAL; \ + } ); \ + } \ +} + +#define enumval_def_u32( _val_, _str_ ) \ + { _str_, { .u32 = _val_ }} + +#define enumval_def_os( _len_, _val_, _str_ ) \ + { _str_, { .os = { .data = (unsigned char *)_val_, .len = _len_ }}} + + +static int dnr_entry(char * conffile) +{ + struct dict_object * nasreq; + TRACE_ENTRY("%p", conffile); + + /* No Vendors definitions */ + + /* Applications section */ + { + /* NASREQ (RFC 4005) */ + { + struct dict_application_data data = { 1, "Diameter Network Access Server Application" }; + CHECK_dict_new( DICT_APPLICATION, &data, NULL, &nasreq); + } + } + + /* Derived AVP types section */ + { + /* QoSFilterRule */ + { + /* + The QosFilterRule format is derived from the OctetString AVP Base + Format. It uses the ASCII charset. Packets may be marked or + metered based on the following information: + + Direction (in or out) + Source and destination IP address (possibly masked) + Protocol + Source and destination port (lists or ranges) + DSCP values (no mask or range) + + Rules for the appropriate direction are evaluated in order; the + first matched rule terminates the evaluation. Each packet is + evaluated once. If no rule matches, the packet is treated as best + effort. An access device unable to interpret or apply a QoS rule + SHOULD NOT terminate the session. + + QoSFilterRule filters MUST follow the following format: + + action dir proto from src to dst [options] + + tag - Mark packet with a specific DSCP + [DIFFSERV]. The DSCP option MUST be + included. + meter - Meter traffic. The metering options + MUST be included. + + dir The format is as described under IPFilterRule. + + proto The format is as described under IPFilterRule. + + src and dst The format is as described under IPFilterRule. + + options: + + DSCP + Color values as defined in [DIFFSERV]. Exact + matching of DSCP values is required (no masks or + ranges). + + metering + The metering option provides Assured Forwarding, + as defined in [DIFFSERVAF], and MUST be present + if the action is set to meter. The rate option is + the throughput, in bits per second, used + by the access device to mark packets. Traffic + over the rate is marked with the color_over + codepoint, and traffic under the rate is marked + with the color_under codepoint. The color_under + and color_over options contain the drop + preferences and MUST conform to the recommended + codepoint keywords described in [DIFFSERVAF] + (e.g., AF13). + + The metering option also supports the strict + limit on traffic required by Expedited + Forwarding, as defined in [DIFFSERVEF]. The + color_over option may contain the keyword "drop" + to prevent forwarding of traffic that exceeds the + rate parameter. + + The rule syntax is a modified subset of ipfw(8) from FreeBSD, + and the ipfw.c code may provide a useful base for + implementations. + */ + struct dict_type_data data = { AVP_TYPE_OCTETSTRING, "QoSFilterRule" , NULL , NULL }; + CHECK_dict_new( DICT_TYPE, &data , NULL, NULL); + } + + } + + /* AVP section */ + { + struct dict_object * UTF8String_type; + struct dict_object * IPFilterRule_type; + struct dict_object * QoSFilterRule_type; + CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "UTF8String", &UTF8String_type); + CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "IPFilterRule", &IPFilterRule_type); + CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "QoSFilterRule", &QoSFilterRule_type); + +/******************************** + * NAS Session AVPs * + ********************************/ + /* NAS-Port */ + { + /* + The NAS-Port AVP (AVP Code 5) is of type Unsigned32 and contains the + physical or virtual port number of the NAS which is authenticating + the user. Note that "port" is meant in its sense as a service + connection on the NAS, not as an IP protocol identifier. + + Either NAS-Port or NAS-Port-Id (AVP Code 87) SHOULD be present in + AA-Request (AAR) commands if the NAS differentiates among its ports. + */ + struct dict_avp_data data = { + 5, /* Code */ + 0, /* Vendor */ + "NAS-Port", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* NAS-Port-Id */ + { + /* + The NAS-Port-Id AVP (AVP Code 87) is of type UTF8String and consists + of ASCII text identifying the port of the NAS authenticating the + user. Note that "port" is meant in its sense as a service connection + on the NAS, not as an IP protocol identifier. + + Either NAS-Port or NAS-Port-Id SHOULD be present in AA-Request (AAR) + commands if the NAS differentiates among its ports. NAS-Port-Id is + intended for use by NASes that cannot conveniently number their + ports. + */ + struct dict_avp_data data = { + 87, /* Code */ + 0, /* Vendor */ + "NAS-Port-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* NAS-Port-Type */ + { + /* + The NAS-Port-Type AVP (AVP Code 61) is of type Enumerated and + contains the type of the port on which the NAS is authenticating the + user. This AVP SHOULD be present if the NAS uses the same NAS-Port + number ranges for different service types concurrently. + + The supported values are defined in [RADIUSTypes]. The following + list is informational and subject to change by the IANA. + + http://www.iana.org/assignments/radius-types + Sub-registry: Values for RADIUS Attribute 61, NAS-Port-Type + Reference: [RFC2865] + + Extract on 2009.06.01: + 0 Async [RFC2865] + 1 Sync [RFC2865] + 2 ISDN Sync [RFC2865] + 3 ISDN Async V.120 [RFC2865] + 4 ISDN Async V.110 [RFC2865] + 5 Virtual [RFC2865] + 6 PIAFS [RFC2865] + 7 HDLC Clear Channel [RFC2865] + 8 X.25 [RFC2865] + 9 X.75 [RFC2865] + 10 G.3 Fax [RFC2865] + 11 SDSL - Symmetric DSL [RFC2865] + 12 ADSL-CAP - Asymmetric DSL, Carrierless Amplitude Phase Modulation [RFC2865] + 13 ADSL-DMT - Asymmetric DSL, Discrete Multi-Tone [RFC2865] + 14 IDSL - ISDN Digital Subscriber Line [RFC2865] + 15 Ethernet [RFC2865] + 16 xDSL - Digital Subscriber Line of unknown type [RFC2865] + 17 Cable [RFC2865] + 18 Wireless - Other [RFC2865] + 19 Wireless - IEEE 802.11 [RFC2865] + 20 Token-Ring [RFC3580] + 21 FDDI [RFC3580] + 22 Wireless - CDMA2000 [McCann] + 23 Wireless - UMTS [McCann] + 24 Wireless - 1X-EV [McCann] + 25 IAPP [IEEE 802.11F][Kerry] + 26 FTTP - Fiber to the Premises [Nyce] + 27 Wireless - IEEE 802.16 [IEEE 802.16] 12 December 2006 + 28 Wireless - IEEE 802.20 [IEEE 802.20] 12 December 2006 + 29 Wireless - IEEE 802.22 [IEEE 802.22] 12 December 2006 + 30 PPPoA - PPP over ATM [RFC4603] + 31 PPPoEoA - PPP over Ethernet over ATM [RFC4603] + 32 PPPoEoE - PPP over Ethernet over Ethernet [RFC4603] + 33 PPPoEoVLAN - PPP over Ethernet over VLAN [RFC4603] + 34 PPPoEoQinQ - PPP over Ethernet over IEEE 802.1QinQ [RFC4603] + 35 xPON - Passive Optical Network [Hublet][Yan] 19 June 2007 + */ + + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(NAS-Port-Type)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 0, "Async [RFC2865]"), + enumval_def_u32( 1, "Sync [RFC2865]"), + enumval_def_u32( 2, "ISDN Sync [RFC2865]"), + enumval_def_u32( 3, "ISDN Async V.120 [RFC2865]"), + enumval_def_u32( 4, "ISDN Async V.110 [RFC2865]"), + enumval_def_u32( 5, "Virtual [RFC2865]"), + enumval_def_u32( 6, "PIAFS [RFC2865]"), + enumval_def_u32( 7, "HDLC Clear Channel [RFC2865]"), + enumval_def_u32( 8, "X.25 [RFC2865]"), + enumval_def_u32( 9, "X.75 [RFC2865]"), + enumval_def_u32(10, "G.3 Fax [RFC2865]"), + enumval_def_u32(11, "SDSL - Symmetric DSL [RFC2865]"), + enumval_def_u32(12, "ADSL-CAP - Asymmetric DSL, Carrierless Amplitude Phase Modulation [RFC2865]"), + enumval_def_u32(13, "ADSL-DMT - Asymmetric DSL, Discrete Multi-Tone [RFC2865]"), + enumval_def_u32(14, "IDSL - ISDN Digital Subscriber Line [RFC2865]"), + enumval_def_u32(15, "Ethernet [RFC2865]"), + enumval_def_u32(16, "xDSL - Digital Subscriber Line of unknown type [RFC2865]"), + enumval_def_u32(17, "Cable [RFC2865]"), + enumval_def_u32(18, "Wireless - Other [RFC2865]"), + enumval_def_u32(19, "Wireless - IEEE 802.11 [RFC2865]"), + enumval_def_u32(20, "Token-Ring [RFC3580]"), + enumval_def_u32(21, "FDDI [RFC3580]"), + enumval_def_u32(22, "Wireless - CDMA2000 [McCann]"), + enumval_def_u32(23, "Wireless - UMTS [McCann]"), + enumval_def_u32(24, "Wireless - 1X-EV [McCann]"), + enumval_def_u32(25, "IAPP [IEEE 802.11F][Kerry]"), + enumval_def_u32(26, "FTTP - Fiber to the Premises [Nyce]"), + enumval_def_u32(27, "Wireless - IEEE 802.16 [IEEE 802.16]"), + enumval_def_u32(28, "Wireless - IEEE 802.20 [IEEE 802.20]"), + enumval_def_u32(29, "Wireless - IEEE 802.22 [IEEE 802.22]"), + enumval_def_u32(30, "PPPoA - PPP over ATM [RFC4603]"), + enumval_def_u32(31, "PPPoEoA - PPP over Ethernet over ATM [RFC4603]"), + enumval_def_u32(32, "PPPoEoE - PPP over Ethernet over Ethernet [RFC4603]"), + enumval_def_u32(33, "PPPoEoVLAN - PPP over Ethernet over VLAN [RFC4603]"), + enumval_def_u32(34, "PPPoEoQinQ - PPP over Ethernet over IEEE 802.1QinQ [RFC4603]"), + enumval_def_u32(35, "xPON - Passive Optical Network [Hublet][Yan]") + }; + struct dict_avp_data data = { + 61, /* Code */ + 0, /* Vendor */ + "NAS-Port-Type", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Called-Station-Id */ + { + /* + The Called-Station-Id AVP (AVP Code 30) is of type UTF8String and + allows the NAS to send the ASCII string describing the layer 2 + address the user contacted in the request. For dialup access, this + can be a phone number obtained by using Dialed Number Identification + (DNIS) or a similar technology. Note that this may be different from + the phone number the call comes in on. For use with IEEE 802 access, + the Called-Station-Id MAY contain a MAC address formatted as + described in [RAD802.1X]. It SHOULD only be present in + authentication and/or authorization requests. + + If the Auth-Request-Type AVP is set to authorization-only and the + User-Name AVP is absent, the Diameter Server MAY perform + authorization based on this field. This can be used by a NAS to + request whether a call should be answered based on the DNIS. + */ + struct dict_avp_data data = { + 30, /* Code */ + 0, /* Vendor */ + "Called-Station-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* Calling-Station-Id */ + { + /* + The Calling-Station-Id AVP (AVP Code 31) is of type UTF8String and + allows the NAS to send the ASCII string describing the layer 2 + address from which the user connected in the request. For dialup + access, this is the phone number the call came from, using Automatic + Number Identification (ANI) or a similar technology. For use with + IEEE 802 access, the Calling-Station-Id AVP MAY contain a MAC + address, formated as described in [RAD802.1X]. It SHOULD only be + present in authentication and/or authorization requests. + + If the Auth-Request-Type AVP is set to authorization-only and the + User-Name AVP is absent, the Diameter Server MAY perform + authorization based on this field. This can be used by a NAS to + request whether a call should be answered based on the layer 2 + address (ANI, MAC Address, etc.) + */ + struct dict_avp_data data = { + 31, /* Code */ + 0, /* Vendor */ + "Calling-Station-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* Connect-Info */ + { + /* + The Connect-Info AVP (AVP Code 77) is of type UTF8String and is sent + in the AA-Request message or ACR STOP message. When sent in the + Access-Request, it indicates the nature of the user's connection. + The connection speed SHOULD be included at the beginning of the first + Connect-Info AVP in the message. If the transmit and receive + connection speeds differ, both may be included in the first AVP with + the transmit speed listed first (the speed the NAS modem transmits + at), then a slash (/), then the receive speed, and then other + optional information. + + For example: "28800 V42BIS/LAPM" or "52000/31200 V90" + + More than one Connect-Info attribute may be present in an + Accounting-Request packet to accommodate expected efforts by the ITU + to have modems report more connection information in a standard + format that might exceed 252 octets. + + If sent in the ACR STOP, this attribute may summarize statistics + relating to session quality. For example, in IEEE 802.11, the + Connect-Info attribute may contain information on the number of link + layer retransmissions. The exact format of this attribute is + implementation specific. + */ + struct dict_avp_data data = { + 77, /* Code */ + 0, /* Vendor */ + "Connect-Info", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* Originating-Line-Info */ + { + /* + The Originating-Line-Info AVP (AVP Code 94) is of type OctetString + and is sent by the NAS system to convey information about the origin + of the call from an SS7 system. + + The originating line information (OLI) element indicates the nature + and/or characteristics of the line from which a call originated + (e.g., pay phone, hotel, cellular). Telephone companies are starting + to offer OLI to their customers as an option over Primary Rate + Interface (PRI). Internet Service Providers (ISPs) can use OLI in + addition to Called-Station-Id and Calling-Station-Id attributes to + differentiate customer calls and to define different services. + + The Value field contains two octets (00 - 99). ANSI T1.113 and + BELLCORE 394 can be used for additional information about these + values and their use. For more information on current assignment + values, see [http://www.nanpa.com/number_resource_info/ani_ii_assignments.html]. + + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_OCTETSTRING, "Enumerated*(Originating-Line-Info)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_os( 2, "00", "Plain Old Telephone Service (POTS)"), + enumval_def_os( 2, "01", "Multiparty Line (more than 2)"), + enumval_def_os( 2, "02", "ANI Failure"), + enumval_def_os( 2, "06", "Station Level Rating"), + enumval_def_os( 2, "07", "Special Operator Handling Required"), + enumval_def_os( 2, "20", "Automatic Identified Outward Dialing (AIOD)"), + enumval_def_os( 2, "23", "Coin or Non-Coin"), + enumval_def_os( 2, "24", "Toll Free Service (Non-Pay Origination)"), + enumval_def_os( 2, "25", "Toll Free Service (Pay Origination)"), + enumval_def_os( 2, "27", "Toll Free Service (Coin Control Origination)"), + enumval_def_os( 2, "29", "Prison/Inmate Service"), + enumval_def_os( 2, "30", "Intercept (Blank)"), + enumval_def_os( 2, "31", "Intercept (Trouble)"), + enumval_def_os( 2, "32", "Intercept (Regular)"), + enumval_def_os( 2, "34", "Telco Operator Handled Call"), + enumval_def_os( 2, "52", "Outward Wide Area Telecommunications Service (OUTWATS)"), + enumval_def_os( 2, "60", "Telecommunications Relay Service (TRS)(Unrestricted)"), + enumval_def_os( 2, "61", "Cellular/Wireless PCS (Type 1)"), + enumval_def_os( 2, "62", "Cellular/Wireless PCS (Type 2)"), + enumval_def_os( 2, "63", "Cellular/Wireless PCS (Roaming)"), + enumval_def_os( 2, "66", "TRS (Hotel)"), + enumval_def_os( 2, "67", "TRS (Restricted)"), + enumval_def_os( 2, "70", "Pay Station, No Coin Control"), + enumval_def_os( 2, "93", "Access for Private Virtual Network Service") + }; + struct dict_avp_data data = { + 94, /* Code */ + 0, /* Vendor */ + "Originating-Line-Info", /* Name */ + AVP_FLAG_VENDOR, /* Fixed flags */ + 0, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Reply-Message */ + { + /* + The Reply-Message AVP (AVP Code 18) is of type UTF8String and + contains text that MAY be displayed to the user. When used in an + AA-Answer message with a successful Result-Code AVP, it indicates + success. When found in an AAA message with a Result-Code other than + DIAMETER_SUCCESS, the AVP contains a failure message. + + The Reply-Message AVP MAY indicate dialog text to prompt the user + before another AA-Request attempt. When used in an AA-Answer with a + Result-Code of DIAMETER_MULTI_ROUND_AUTH or in an Re-Auth-Request + message, it MAY contain a dialog text to prompt the user for a + response. + + Multiple Reply-Messages MAY be included, and if any are displayed, + they MUST be displayed in the same order as they appear in the + Diameter message. + */ + struct dict_avp_data data = { + 18, /* Code */ + 0, /* Vendor */ + "Reply-Message", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + +/******************************** + * NAS Authentication AVPs * + ********************************/ + /* User-Password */ + { + /* + The User-Password AVP (AVP Code 2) is of type OctetString and + contains the password of the user to be authenticated, or the user's + input in a multi-round authentication exchange. + + The User-Password AVP contains a user password or one-time password + and therefore represents sensitive information. As required in + [BASE], Diameter messages are encrypted by using IPsec or TLS. + Unless this AVP is used for one-time passwords, the User-Password AVP + SHOULD NOT be used in untrusted proxy environments without encrypting + it by using end-to-end security techniques, such as the proposed CMS + Security [DiamCMS]. + + The clear-text password (prior to encryption) MUST NOT be longer than + 128 bytes in length. + */ + struct dict_avp_data data = { + 2, /* Code */ + 0, /* Vendor */ + "User-Password", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Password-Retry */ + { + /* + The Password-Retry AVP (AVP Code 75) is of type Unsigned32 and MAY be + included in the AA-Answer if the Result-Code indicates an + authentication failure. The value of this AVP indicates how many + authentication attempts a user is permitted before being + disconnected. This AVP is primarily intended for use when the + Framed-Protocol AVP (see section 6.10.1) is set to ARAP. + */ + struct dict_avp_data data = { + 75, /* Code */ + 0, /* Vendor */ + "Password-Retry", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Prompt */ + { + /* + The Prompt AVP (AVP Code 76) is of type Enumerated and MAY be present + in the AA-Answer message. When present, it is used by the NAS to + determine whether the user's response, when entered, should be + echoed. + + The supported values are listed in http://www.iana.org/assignments/radius-types + Sub-registry: Values for RADIUS Attribute 76, Prompt + Reference: [RFC2869] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Prompt)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 0, "No Echo [RFC2869]"), + enumval_def_u32( 1, "Echo [RFC2869]") + }; + struct dict_avp_data data = { + 76, /* Code */ + 0, /* Vendor */ + "Prompt", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* CHAP-Algorithm */ + { + /* + The CHAP-Algorithm AVP (AVP Code 403) is of type Enumerated and + contains the algorithm identifier used in the computation of the CHAP + response [PPPCHAP]. The following values are currently supported: + + CHAP with MD5 5 + The CHAP response is computed by using the procedure described + in [PPPCHAP]. This algorithm requires that the CHAP-Response + AVP MUST be present in the CHAP-Auth AVP. + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(CHAP-Algorithm)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 5, "CHAP with MD5") + }; + struct dict_avp_data adata = { + 403, /* Code */ + 0, /* Vendor */ + "CHAP-Algorithm", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &adata , type, NULL); + } + + /* CHAP-Ident */ + { + /* + The CHAP-Ident AVP (AVP Code 404) is of type OctetString and contains + the 1 octet CHAP Identifier used in the computation of the CHAP + response [PPPCHAP]. + */ + struct dict_avp_data adata = { + 404, /* Code */ + 0, /* Vendor */ + "CHAP-Ident", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , NULL, NULL); + } + + /* CHAP-Response */ + { + /* + The CHAP-Response AVP (AVP Code 405) is of type OctetString and + contains the 16 octet authentication data provided by the user in + response to the CHAP challenge [PPPCHAP]. + */ + struct dict_avp_data adata = { + 405, /* Code */ + 0, /* Vendor */ + "CHAP-Response", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , NULL, NULL); + } + + /* CHAP-Auth */ + { + /* + The CHAP-Auth AVP (AVP Code 402) is of type Grouped and contains the + information necessary to authenticate a user using the PPP + Challenge-Handshake Authentication Protocol (CHAP) [PPPCHAP]. If the + CHAP-Auth AVP is found in a message, the CHAP-Challenge AVP MUST be + present as well. The optional AVPs containing the CHAP response + depend upon the value of the CHAP-Algorithm AVP. The grouped AVP has + the following ABNF grammar: + + CHAP-Auth ::= < AVP Header: 402 > + { CHAP-Algorithm } + { CHAP-Ident } + [ CHAP-Response ] + * [ AVP ] + */ + struct dict_object * avp; + struct dict_avp_data data = { + 402, /* Code */ + 0, /* Vendor */ + "CHAP-Auth", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_GROUPED /* base type of data */ + }; + struct local_rules_definition rules[] = + { { "CHAP-Algorithm", RULE_REQUIRED, -1, 1 } + ,{ "CHAP-Ident", RULE_REQUIRED, -1, 1 } + ,{ "CHAP-Response", RULE_OPTIONAL, -1, 1 } + }; + + CHECK_dict_new( DICT_AVP, &data , NULL, &avp); + PARSE_loc_rules( rules, avp ); + } + + /* CHAP-Challenge */ + { + /* + The CHAP-Challenge AVP (AVP Code 60) is of type OctetString and + contains the CHAP Challenge sent by the NAS to the CHAP peer + [PPPCHAP]. + */ + struct dict_avp_data data = { + 60, /* Code */ + 0, /* Vendor */ + "CHAP-Challenge", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* ARAP-Password */ + { + /* + The ARAP-Password AVP (AVP Code 70) is of type OctetString and is + only present when the Framed-Protocol AVP (see section 6.10.1) is + included in the message and is set to ARAP. This AVP MUST NOT be + present if either the User-Password or the CHAP-Auth AVP is present. + See [RADIUSExt] for more information on the contents of this AVP. + */ + struct dict_avp_data data = { + 70, /* Code */ + 0, /* Vendor */ + "ARAP-Password", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* ARAP-Challenge-Response */ + { + /* + The ARAP-Challenge-Response AVP (AVP Code 84) is of type OctetString + and is only present when the Framed-Protocol AVP (see section 6.10.1) + is included in the message and is set to ARAP. This AVP contains an + 8 octet response to the dial-in client's challenge. The RADIUS + server calculates this value by taking the dial-in client's challenge + from the high-order 8 octets of the ARAP-Password AVP and performing + DES encryption on this value with the authenticating user's password + as the key. If the user's password is fewer than 8 octets in length, + the password is padded at the end with NULL octets to a length of 8 + before it is used as a key. + */ + struct dict_avp_data data = { + 84, /* Code */ + 0, /* Vendor */ + "ARAP-Challenge-Response", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* ARAP-Security */ + { + /* + The ARAP-Security AVP (AVP Code 73) is of type Unsigned32 and MAY be + present in the AA-Answer message if the Framed-Protocol AVP (see + section 6.10.1) is set to the value of ARAP, and the Result-Code AVP + is set to DIAMETER_MULTI_ROUND_AUTH. See [RADIUSExt] for more + information on the format of this AVP. + */ + struct dict_avp_data data = { + 73, /* Code */ + 0, /* Vendor */ + "ARAP-Security", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* ARAP-Security-Data */ + { + /* + The ARAP-Security-Data AVP (AVP Code 74) is of type OctetString and MAY be + present in the AA-Request or AA-Answer message if the Framed-Protocol + AVP is set to the value of ARAP, and the Result-Code AVP is set to + DIAMETER_MULTI_ROUND_AUTH. This AVP contains the security module + challenge or response associated with the ARAP Security Module + specified in ARAP-Security. + */ + struct dict_avp_data data = { + 74, /* Code */ + 0, /* Vendor */ + "ARAP-Security-Data", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + +/******************************** + * NAS Authorization AVPs * + ********************************/ + /* Service-Type */ + { + /* + The Service-Type AVP (AVP Code 6) is of type Enumerated and contains + the type of service the user has requested or the type of service to + be provided. One such AVP MAY be present in an authentication and/or + authorization request or response. A NAS is not required to + implement all of these service types. It MUST treat unknown or + unsupported Service-Types received in a response as a failure and end + the session with a DIAMETER_INVALID_AVP_VALUE Result-Code. + + When used in a request, the Service-Type AVP SHOULD be considered a + hint to the server that the NAS believes the user would prefer the + kind of service indicated. The server is not required to honor the + hint. Furthermore, if the service specified by the server is + supported, but not compatible with the current mode of access, the + NAS MUST fail to start the session. The NAS MUST also generate the + appropriate error message(s). + + The following values have been defined for the Service-Type AVP. The + complete list of defined values can be found in [RADIUS] and + [RADIUSTypes]. + + Registry Name: Radius Attribute Values + Reference: [RFC2865][RFC3575] + + Sub-registry: Values for RADIUS Attribute 6, Service-Type + Reference: [RFC2865][RFC3575] + + 1 Login + 2 Framed + 3 Callback Login + 4 Callback Framed + 5 Outbound + 6 Administrative + 7 NAS Prompt + 8 Authenticate Only + 9 Callback NAS Prompt + 10 Call Check + 11 Callback Administrative + 12 Voice [Chiba] + 13 Fax [Chiba] + 14 Modem Relay [Chiba] + 15 IAPP-Register [IEEE 802.11f][Kerry] + 16 IAPP-AP-Check [IEEE 802.11f][Kerry] + 17 Authorize Only [RFC3576] + + The following values are further qualified: + + Login 1 + The user should be connected to a host. The message MAY + include additional AVPs defined in sections 6.16 or 6.17. + + Framed 2 + A Framed Protocol, such as PPP or SLIP, should be started for + the User. The message MAY include additional AVPs defined in + section 6.10, or section 7 for tunneling services. + + Callback Login 3 + The user should be disconnected and called back, then connected + to a host. The message MAY include additional AVPs defined in + this section. + + Callback Framed 4 + The user should be disconnected and called back, and then a + Framed Protocol, such as PPP or SLIP, should be started for the + User. The message MAY include additional AVPs defined in + section 6.10, or in section 7 for tunneling services. + + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Service-Type)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 1, "Login"), + enumval_def_u32( 2, "Framed"), + enumval_def_u32( 3, "Callback Login"), + enumval_def_u32( 4, "Callback Framed"), + enumval_def_u32( 5, "Outbound"), + enumval_def_u32( 6, "Administrative"), + enumval_def_u32( 7, "NAS Prompt"), + enumval_def_u32( 8, "Authenticate Only"), + enumval_def_u32( 9, "Callback NAS Prompt"), + enumval_def_u32(10, "Call Check"), + enumval_def_u32(11, "Callback Administrative"), + enumval_def_u32(12, "Voice [Chiba]"), + enumval_def_u32(13, "Fax [Chiba]"), + enumval_def_u32(14, "Modem Relay [Chiba]"), + enumval_def_u32(15, "IAPP-Register [IEEE 802.11f][Kerry]"), + enumval_def_u32(16, "IAPP-AP-Check [IEEE 802.11f][Kerry]"), + enumval_def_u32(17, "Authorize Only [RFC3576]") + }; + struct dict_avp_data data = { + 6, /* Code */ + 0, /* Vendor */ + "Service-Type", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Callback-Number */ + { + /* + The Callback-Number AVP (AVP Code 19) is of type UTF8String and + contains a dialing string to be used for callback. It MAY be used in + an authentication and/or authorization request as a hint to the + server that a Callback service is desired, but the server is not + required to honor the hint in the corresponding response. + */ + struct dict_avp_data data = { + 19, /* Code */ + 0, /* Vendor */ + "Callback-Number", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* Callback-Id */ + { + /* + The Callback-Id AVP (AVP Code 20) is of type UTF8String and contains + the name of a place to be called, to be interpreted by the NAS. This + AVP MAY be present in an authentication and/or authorization + response. + + This AVP is not roaming-friendly as it assumes that the Callback-Id + is configured on the NAS. Using the Callback-Number AVP therefore + preferable. + */ + struct dict_avp_data data = { + 20, /* Code */ + 0, /* Vendor */ + "Callback-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* Idle-Timeout */ + { + /* + The Idle-Timeout AVP (AVP Code 28) is of type Unsigned32 and sets the + maximum number of consecutive seconds of idle connection allowable to + the user before termination of the session or before a prompt is + issued. The default is none, or system specific. + */ + struct dict_avp_data data = { + 28, /* Code */ + 0, /* Vendor */ + "Idle-Timeout", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Port-Limit */ + { + /* + The Port-Limit AVP (AVP Code 62) is of type Unsigned32 and sets the + maximum number of ports the NAS provides to the user. It MAY be used + in an authentication and/or authorization request as a hint to the + server that multilink PPP [PPPMP] service is desired, but the server + is not required to honor the hint in the corresponding response. + */ + struct dict_avp_data data = { + 62, /* Code */ + 0, /* Vendor */ + "Port-Limit", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* NAS-Filter-Rule */ + { + /* + The NAS-Filter-Rule AVP (AVP Code 400) is of type IPFilterRule and + provides filter rules that need to be configured on the NAS for the + user. One or more of these AVPs MAY be present in an authorization + response. + */ + struct dict_avp_data data = { + 400, /* Code */ + 0, /* Vendor */ + "NAS-Filter-Rule", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , IPFilterRule_type, NULL); + } + + /* Filter-Id */ + { + /* + The Filter-Id AVP (AVP Code 11) is of type UTF8String and contains + the name of the filter list for this user. Zero or more Filter-Id + AVPs MAY be sent in an authorization answer. + + Identifying a filter list by name allows the filter to be used on + different NASes without regard to filter-list implementation details. + However, this AVP is not roaming friendly, as filter naming differs + from one service provider to another. + + In non-RADIUS environments, it is RECOMMENDED that the NAS-Filter- + Rule AVP be used instead. + */ + struct dict_avp_data data = { + 11, /* Code */ + 0, /* Vendor */ + "Filter-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* Configuration-Token */ + { + /* + The Configuration-Token AVP (AVP Code 78) is of type OctetString and + is sent by a Diameter Server to a Diameter Proxy Agent or Translation + Agent in an AA-Answer command to indicate a type of user profile to + be used. It should not be sent to a Diameter Client (NAS). + + The format of the Data field of this AVP is site specific. + */ + struct dict_avp_data data = { + 78, /* Code */ + 0, /* Vendor */ + "Configuration-Token", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* QoS-Filter-Rule */ + { + /* + The QoS-Filter-Rule AVP (AVP Code 407) is of type QoSFilterRule and + provides QoS filter rules that need to be configured on the NAS for + the user. One or more such AVPs MAY be present in an authorization + response. + */ + struct dict_avp_data data = { + 407, /* Code */ + 0, /* Vendor */ + "QoS-Filter-Rule", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , QoSFilterRule_type, NULL); + } + +/*** Framed Access Authorization AVPs ***/ + + /* Framed-Protocol */ + { + /* + The Framed-Protocol AVP (AVP Code 7) is of type Enumerated and + contains the framing to be used for framed access. This AVP MAY be + present in both requests and responses. The supported values are + listed in [RADIUSTypes]. + + Sub-registry: Values for RADIUS Attribute 7, Framed-Protocol + Reference: [RFC2865] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Framed-Protocol)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 1, "PPP"), + enumval_def_u32( 2, "SLIP"), + enumval_def_u32( 3, "AppleTalk Remote Access Protocol (ARAP)"), + enumval_def_u32( 4, "Gandalf proprietary SingleLink/MultiLink protocol"), + enumval_def_u32( 5, "Xylogics proprietary IPX/SLIP"), + enumval_def_u32( 6, "X.75 Synchronous"), + enumval_def_u32( 7, "GPRS PDP Context [Moore]") + }; + struct dict_avp_data data = { + 7, /* Code */ + 0, /* Vendor */ + "Framed-Protocol", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Framed-Routing */ + { + /* + The Framed-Routing AVP (AVP Code 10) is of type Enumerated and + contains the routing method for the user when the user is a router to + a network. This AVP SHOULD only be present in authorization + responses. The supported values are listed in [RADIUSTypes]. + + Sub-registry: Values for RADIUS Attribute 10, Framed-Routing + Reference: [RFC2865] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Framed-Routing)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 0, "None"), + enumval_def_u32( 1, "Send routing packets"), + enumval_def_u32( 2, "Listen for routing packets"), + enumval_def_u32( 3, "Send and Listen") + }; + struct dict_avp_data data = { + 10, /* Code */ + 0, /* Vendor */ + "Framed-Routing", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Framed-MTU */ + { + /* + The Framed-MTU AVP (AVP Code 12) is of type Unsigned32 and contains + the Maximum Transmission Unit to be configured for the user, when it + is not negotiated by some other means (such as PPP). This AVP SHOULD + only be present in authorization responses. The MTU value MUST be in + the range from 64 to 65535. + */ + struct dict_avp_data data = { + 12, /* Code */ + 0, /* Vendor */ + "Framed-MTU", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Framed-Compression */ + { + /* + The Framed-Compression AVP (AVP Code 13) is of type Enumerated and + contains the compression protocol to be used for the link. It MAY be + used in an authorization request as a hint to the server that a + specific compression type is desired, but the server is not required + to honor the hint in the corresponding response. + + More than one compression protocol AVP MAY be sent. The NAS is + responsible for applying the proper compression protocol to the + appropriate link traffic. + + The supported values are listed in [RADIUSTypes]. + Sub-registry: Values for RADIUS Attribute 13, Framed-Compression + Reference: [RFC2865] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Framed-Compression)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 0, "None"), + enumval_def_u32( 1, "VJ TCP/IP header compression"), + enumval_def_u32( 2, "IPX header compression"), + enumval_def_u32( 3, "Stac-LZS compression") + }; + struct dict_avp_data data = { + 13, /* Code */ + 0, /* Vendor */ + "Framed-Compression", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + +/*** IP Access Authorization AVPs ***/ + + /* Framed-IP-Address */ + { + /* + The Framed-IP-Address AVP (AVP Code 8) [RADIUS] is of type + OctetString and contains an IPv4 address of the type specified in the + attribute value to be configured for the user. It MAY be used in an + authorization request as a hint to the server that a specific address + is desired, but the server is not required to honor the hint in the + corresponding response. + + Two values have special significance: 0xFFFFFFFF and 0xFFFFFFFE. The + value 0xFFFFFFFF indicates that the NAS should allow the user to + select an address (i.e., negotiated). The value 0xFFFFFFFE indicates + that the NAS should select an address for the user (e.g., assigned + from a pool of addresses kept by the NAS). + */ + struct dict_avp_data data = { + 8, /* Code */ + 0, /* Vendor */ + "Framed-IP-Address", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Framed-IP-Netmask */ + { + /* + The Framed-IP-Netmask AVP (AVP Code 9) is of type OctetString and + contains the four octets of the IPv4 netmask to be configured for the + user when the user is a router to a network. It MAY be used in an + authorization request as a hint to the server that a specific netmask + is desired, but the server is not required to honor the hint in the + corresponding response. This AVP MUST be present in a response if + the request included this AVP with a value of 0xFFFFFFFF. + */ + struct dict_avp_data data = { + 9, /* Code */ + 0, /* Vendor */ + "Framed-IP-Netmask", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Framed-Route */ + { + /* + The Framed-Route AVP (AVP Code 22) is of type UTF8String and contains + the ASCII routing information to be configured for the user on the + NAS. Zero or more of these AVPs MAY be present in an authorization + response. + + The string MUST contain a destination prefix in dotted quad form + optionally followed by a slash and a decimal length specifier stating + how many high-order bits of the prefix should be used. This is + followed by a space, a gateway address in dotted quad form, a space, + and one or more metrics separated by spaces; for example, + + "192.168.1.0/24 192.168.1.1 1". + + The length specifier may be omitted, in which case it should default + to 8 bits for class A prefixes, to 16 bits for class B prefixes, and + to 24 bits for class C prefixes; for example, + + "192.168.1.0 192.168.1.1 1". + + Whenever the gateway address is specified as "0.0.0.0" the IP address + of the user SHOULD be used as the gateway address. + */ + struct dict_avp_data data = { + 22, /* Code */ + 0, /* Vendor */ + "Framed-Route", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* Framed-Pool */ + { + /* + The Framed-Pool AVP (AVP Code 88) is of type OctetString and contains + the name of an assigned address pool that SHOULD be used to assign an + address for the user. If a NAS does not support multiple address + pools, the NAS SHOULD ignore this AVP. Address pools are usually + used for IP addresses but can be used for other protocols if the NAS + supports pools for those protocols. + + Although specified as type OctetString for compatibility with RADIUS + [RADIUSExt], the encoding of the Data field SHOULD also conform to + the rules for the UTF8String Data Format. + */ + struct dict_avp_data data = { + 88, /* Code */ + 0, /* Vendor */ + "Framed-Pool", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Framed-Interface-Id */ + { + /* + The Framed-Interface-Id AVP (AVP Code 96) is of type Unsigned64 and + contains the IPv6 interface identifier to be configured for the user. + It MAY be used in authorization requests as a hint to the server that + a specific interface id is desired, but the server is not required to + honor the hint in the corresponding response. + */ + struct dict_avp_data data = { + 96, /* Code */ + 0, /* Vendor */ + "Framed-Interface-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED64 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Framed-IPv6-Prefix */ + { + /* + The Framed-IPv6-Prefix AVP (AVP Code 97) is of type OctetString and + contains the IPv6 prefix to be configured for the user. One or more + AVPs MAY be used in authorization requests as a hint to the server + that specific IPv6 prefixes are desired, but the server is not + required to honor the hint in the corresponding response. + */ + struct dict_avp_data data = { + 97, /* Code */ + 0, /* Vendor */ + "Framed-IPv6-Prefix", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Framed-IPv6-Route */ + { + /* + The Framed-IPv6-Route AVP (AVP Code 99) is of type UTF8String and + contains the ASCII routing information to be configured for the user + on the NAS. Zero or more of these AVPs MAY be present in an + authorization response. + + The string MUST contain an IPv6 address prefix followed by a slash + and a decimal length specifier stating how many high order bits of + the prefix should be used. This is followed by a space, a gateway + address in hexadecimal notation, a space, and one or more metrics + separated by spaces; for example, + + "2000:0:0:106::/64 2000::106:a00:20ff:fe99:a998 1". + + Whenever the gateway address is the IPv6 unspecified address, the IP + address of the user SHOULD be used as the gateway address, such as + in: + + "2000:0:0:106::/64 :: 1". + */ + struct dict_avp_data data = { + 99, /* Code */ + 0, /* Vendor */ + "Framed-IPv6-Route", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* Framed-IPv6-Pool */ + { + /* + The Framed-IPv6-Pool AVP (AVP Code 100) is of type OctetString and + contains the name of an assigned pool that SHOULD be used to assign + an IPv6 prefix for the user. If the access device does not support + multiple prefix pools, it MUST ignore this AVP. + + Although specified as type OctetString for compatibility with RADIUS + [RADIUSIPv6], the encoding of the Data field SHOULD also conform to + the rules for the UTF8String Data Format. + */ + struct dict_avp_data data = { + 100, /* Code */ + 0, /* Vendor */ + "Framed-IPv6-Pool", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + +/*** IPX Access ***/ + + /* Framed-IPX-Network */ + { + /* + The Framed-IPX-Network AVP (AVP Code 23) is of type Unsigned32 and + contains the IPX Network number to be configured for the user. It + MAY be used in an authorization request as a hint to the server that + a specific address is desired, but the server is not required to + honor the hint in the corresponding response. + + Two addresses have special significance: 0xFFFFFFFF and 0xFFFFFFFE. + The value 0xFFFFFFFF indicates that the NAS should allow the user to + select an address (i.e., Negotiated). The value 0xFFFFFFFE indicates + that the NAS should select an address for the user (e.g., assign it + from a pool of one or more IPX networks kept by the NAS). + */ + struct dict_avp_data data = { + 23, /* Code */ + 0, /* Vendor */ + "Framed-IPX-Network", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + +/*** AppleTalk Network Access ***/ + + /* Framed-AppleTalk-Link */ + { + /* + The Framed-AppleTalk-Link AVP (AVP Code 37) is of type Unsigned32 and + contains the AppleTalk network number that should be used for the + serial link to the user, which is another AppleTalk router. This AVP + MUST only be present in an authorization response and is never used + when the user is not another router. + + Despite the size of the field, values range from 0 to 65,535. The + special value of 0 indicates an unnumbered serial link. A value of 1 + to 65,535 means that the serial line between the NAS and the user + should be assigned that value as an AppleTalk network number. + */ + struct dict_avp_data data = { + 37, /* Code */ + 0, /* Vendor */ + "Framed-AppleTalk-Link", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Framed-AppleTalk-Network */ + { + /* + The Framed-AppleTalk-Network AVP (AVP Code 38) is of type Unsigned32 + and contains the AppleTalk Network number that the NAS should probe + to allocate an AppleTalk node for the user. This AVP MUST only be + present in an authorization response and is never used when the user + is not another router. Multiple instances of this AVP indicate that + the NAS may probe, using any of the network numbers specified. + + Despite the size of the field, values range from 0 to 65,535. The + special value 0 indicates that the NAS should assign a network for + the user, using its default cable range. A value between 1 and + 65,535 (inclusive) indicates to the AppleTalk Network that the NAS + should probe to find an address for the user. + */ + struct dict_avp_data data = { + 38, /* Code */ + 0, /* Vendor */ + "Framed-AppleTalk-Network", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Framed-AppleTalk-Zone */ + { + /* + The Framed-AppleTalk-Zone AVP (AVP Code 39) is of type OctetString + and contains the AppleTalk Default Zone to be used for this user. + This AVP MUST only be present in an authorization response. Multiple + instances of this AVP in the same message are not allowed. + + The codification of this field's allowed range is outside the scope + of this specification. + */ + struct dict_avp_data data = { + 39, /* Code */ + 0, /* Vendor */ + "Framed-AppleTalk-Zone", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + +/*** AppleTalk Remote Access [RFC2869] ***/ + + /* ARAP-Features */ + { + /* + The ARAP-Features AVP (AVP Code 71) is of type OctetString and MAY be + present in the AA-Accept message if the Framed-Protocol AVP is set to + the value of ARAP. See [RADIUSExt] for more information about the + format of this AVP. + */ + struct dict_avp_data data = { + 71, /* Code */ + 0, /* Vendor */ + "ARAP-Features", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* ARAP-Zone-Access */ + { + /* + The ARAP-Zone-Access AVP (AVP Code 72) is of type Enumerated and MAY + be present in the AA-Accept message if the Framed-Protocol AVP is set + to the value of ARAP. + + The supported values are listed in [RADIUSTypes] and defined in + [RADIUSExt]. + Sub-registry: Values for RADIUS Attribute 72, ARAP-Zone-Access + Reference: [RFC2869] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(ARAP-Zone-Access)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 1, "Only allow access to default zone [RFC2869]"), + enumval_def_u32( 2, "Use zone filter inclusively [RFC2869]"), + enumval_def_u32( 3, "Not used [RFC2869]"), + enumval_def_u32( 4, "Use zone filter exclusively [RFC2869]") + }; + struct dict_avp_data data = { + 72, /* Code */ + 0, /* Vendor */ + "ARAP-Zone-Access", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + +/*** Non-Framed Access Authorization AVPs ***/ + + /* Login-IP-Host */ + { + /* + The Login-IP-Host AVP (AVP Code 14) [RADIUS] is of type OctetString + and contains the IPv4 address of a host with which to connect the + user when the Login-Service AVP is included. It MAY be used in an + AA-Request command as a hint to the Diameter Server that a specific + host is desired, but the Diameter Server is not required to honor the + hint in the AA-Answer. + + Two addresses have special significance: all ones and 0. The value + of all ones indicates that the NAS SHOULD allow the user to select an + address. The value 0 indicates that the NAS SHOULD select a host to + connect the user to. + */ + struct dict_object *type; + uint32_t allzeros = 0; + uint32_t allones = (uint32_t) -1; + struct dict_type_data tdata = { AVP_TYPE_OCTETSTRING, "Enumerated(Login-IP-Host)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_os( 4, &allzeros, "(0) NAS selects the host"), + enumval_def_os( 4, &allones , "(1) User selects the address") + }; + struct dict_avp_data data = { + 14, /* Code */ + 0, /* Vendor */ + "Login-IP-Host", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Login-IPv6-Host */ + { + /* + The Login-IPv6-Host AVP (AVP Code 98) [RADIUSIPv6] is of type + OctetString and contains the IPv6 address of a host with which to + connect the user when the Login-Service AVP is included. It MAY be + used in an AA-Request command as a hint to the Diameter Server that a + specific host is desired, but the Diameter Server is not required to + honor the hint in the AA-Answer. + + Two addresses have special significance: + + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF and 0. The value + 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF indicates that the NAS SHOULD + allow the user to select an address. The value 0 indicates that the + NAS SHOULD select a host to connect the user to. + + */ + struct dict_object *type; + unsigned char allzeros[16]; + unsigned char allones[16]; + struct dict_type_data tdata = { AVP_TYPE_OCTETSTRING, "Enumerated(Login-IPv6-Host)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_os( 16, &allzeros, "(0) NAS selects the host"), + enumval_def_os( 16, &allones , "(1) User selects the address") + }; + struct dict_avp_data data = { + 98, /* Code */ + 0, /* Vendor */ + "Login-IPv6-Host", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + int i; + memset(allzeros, 0, sizeof(allzeros)); + memset(allones, 0xff, sizeof(allones)); + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Login-Service */ + { + /* + The Login-Service AVP (AVP Code 15) is of type Enumerated and + contains the service that should be used to connect the user to the + login host. This AVP SHOULD only be present in authorization + responses. + + The supported values are listed in [RADIUSTypes]. + Sub-registry: Values for RADIUS Attribute 15, Login-Service + Reference: [RFC2865] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Login-Service)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 0, "Telnet"), + enumval_def_u32( 1, "Rlogin"), + enumval_def_u32( 2, "TCP Clear"), + enumval_def_u32( 3, "PortMaster (proprietary)"), + enumval_def_u32( 4, "LAT"), + enumval_def_u32( 5, "X25-PAD"), + enumval_def_u32( 6, "X25-T3POS"), + enumval_def_u32( 8, "TCP Clear Quiet (suppresses any NAS-generated connect string)") + }; + struct dict_avp_data data = { + 15, /* Code */ + 0, /* Vendor */ + "Login-Service", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + +/*** TCP Services ***/ + + /* Login-TCP-Port */ + { + /* + The Login-TCP-Port AVP (AVP Code 16) is of type Unsigned32 and + contains the TCP port with which the user is to be connected when the + Login-Service AVP is also present. This AVP SHOULD only be present + in authorization responses. The value MUST NOT be greater than + 65,535. + */ + struct dict_avp_data data = { + 16, /* Code */ + 0, /* Vendor */ + "Login-TCP-Port", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + +/*** LAT Services ***/ + + /* Login-LAT-Service */ + { + /* + The Login-LAT-Service AVP (AVP Code 34) is of type OctetString and + contains the system with which the user is to be connected by LAT. + It MAY be used in an authorization request as a hint to the server + that a specific service is desired, but the server is not required to + honor the hint in the corresponding response. This AVP MUST only be + present in the response if the Login-Service AVP states that LAT is + desired. + + Administrators use this service attribute when dealing with clustered + systems, such as a VAX or Alpha cluster. In these environments, + several different time-sharing hosts share the same resources (disks, + printers, etc.), and administrators often configure each host to + offer access (service) to each of the shared resources. In this + case, each host in the cluster advertises its services through LAT + broadcasts. + + Sophisticated users often know which service providers (machines) are + faster and tend to use a node name when initiating a LAT connection. + Some administrators want particular users to use certain machines as + a primitive form of load balancing (although LAT knows how to do load + balancing itself). + + The String field contains the identity of the LAT service to use. + The LAT Architecture allows this string to contain $ (dollar), - + (hyphen), . (period), _ (underscore), numerics, upper- and lowercase + alphabetics, and the ISO Latin-1 character set extension [ISOLatin]. + All LAT string comparisons are case insensitive. + */ + struct dict_avp_data data = { + 34, /* Code */ + 0, /* Vendor */ + "Login-LAT-Service", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Login-LAT-Node */ + { + /* + The Login-LAT-Node AVP (AVP Code 35) is of type OctetString and + contains the Node with which the user is to be automatically + connected by LAT. It MAY be used in an authorization request as a + hint to the server that a specific LAT node is desired, but the + server is not required to honor the hint in the corresponding + response. This AVP MUST only be present in a response if the Login- + Service-Type AVP is set to LAT. + + The String field contains the identity of the LAT service to use. + The LAT Architecture allows this string to contain $ (dollar), - + (hyphen), . (period), _ (underscore), numerics, upper- and lowercase + alphabetics, and the ISO Latin-1 character set extension [ISOLatin]. + All LAT string comparisons are case insensitive. + */ + struct dict_avp_data data = { + 35, /* Code */ + 0, /* Vendor */ + "Login-LAT-Node", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Login-LAT-Group */ + { + /* + The Login-LAT-Group AVP (AVP Code 36) is of type OctetString and + contains a string identifying the LAT group codes this user is + authorized to use. It MAY be used in an authorization request as a + hint to the server that a specific group is desired, but the server + is not required to honor the hint in the corresponding response. + This AVP MUST only be present in a response if the Login-Service-Type + AVP is set to LAT. + + LAT supports 256 different group codes, which LAT uses as a form of + access rights. LAT encodes the group codes as a 256-bit bitmap. + + Administrators can assign one or more of the group code bits at the + LAT service provider; it will only accept LAT connections that have + these group codes set in the bitmap. The administrators assign a + bitmap of authorized group codes to each user. LAT gets these from + the operating system and uses them in its requests to the service + providers. + + The codification of the range of allowed usage of this field is + outside the scope of this specification. + */ + struct dict_avp_data data = { + 36, /* Code */ + 0, /* Vendor */ + "Login-LAT-Group", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Login-LAT-Port */ + { + /* + The Login-LAT-Port AVP (AVP Code 63) is of type OctetString and + contains the Port with which the user is to be connected by LAT. It + MAY be used in an authorization request as a hint to the server that + a specific port is desired, but the server is not required to honor + the hint in the corresponding response. This AVP MUST only be + present in a response if the Login-Service-Type AVP is set to LAT. + + The String field contains the identity of the LAT service to use. + The LAT Architecture allows this string to contain $ (dollar), - + (hyphen), . (period), _ (underscore), numerics, upper- and lower-case + alphabetics, and the ISO Latin-1 character set extension [ISOLatin]. + All LAT string comparisons are case insensitive. + */ + struct dict_avp_data data = { + 63, /* Code */ + 0, /* Vendor */ + "Login-LAT-Port", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + +/******************************** + * NAS Tunneling AVPs * + ********************************/ + /* Tunnel-Type */ + { + /* + The Tunnel-Type AVP (AVP Code 64) is of type Enumerated and contains + the tunneling protocol(s) to be used (in the case of a tunnel + initiator) or in use (in the case of a tunnel terminator). It MAY be + used in an authorization request as a hint to the server that a + specific tunnel type is desired, but the server is not required to + honor the hint in the corresponding response. + + The Tunnel-Type AVP SHOULD also be included in Accounting-Request + messages. + + A tunnel initiator is not required to implement any of these tunnel + types. If a tunnel initiator receives a response that contains only + unknown or unsupported Tunnel-Types, the tunnel initiator MUST behave + as though a response were received with the Result-Code indicating a + failure. + + The supported values are listed in [RADIUSTypes]. + Sub-registry: Values for RADIUS Attribute 64, Tunnel-Type + Reference: [RFC2868] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Tunnel-Type)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 1, "Point-to-Point Tunneling Protocol (PPTP) [RFC2868]"), + enumval_def_u32( 2, "Layer Two Forwarding (L2F) [RFC2868]"), + enumval_def_u32( 3, "Layer Two Tunneling Protocol (L2TP) [RFC2868]"), + enumval_def_u32( 4, "Ascend Tunnel Management Protocol (ATMP) [RFC2868]"), + enumval_def_u32( 5, "Virtual Tunneling Protocol (VTP) [RFC2868]"), + enumval_def_u32( 6, "IP Authentication Header in the Tunnel-mode (AH) [RFC2868]"), + enumval_def_u32( 7, "IP-in-IP Encapsulation (IP-IP) [RFC2868]"), + enumval_def_u32( 8, "Minimal IP-in-IP Encapsulation (MIN-IP-IP) [RFC2868]"), + enumval_def_u32( 9, "IP Encapsulating Security Payload in the Tunnel-mode (ESP) [RFC2868]"), + enumval_def_u32(10, "Generic Route Encapsulation (GRE) [RFC2868]"), + enumval_def_u32(11, "Bay Dial Virtual Services (DVS) [RFC2868]"), + enumval_def_u32(12, "IP-in-IP Tunneling [RFC2868]"), + enumval_def_u32(13, "Virtual LANs (VLAN) [RFC3580]") + }; + struct dict_avp_data adata = { + 64, /* Code */ + 0, /* Vendor */ + "Tunnel-Type", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &adata , type, NULL); + } + + /* Tunnel-Medium-Type */ + { + /* + The Tunnel-Medium-Type AVP (AVP Code 65) is of type Enumerated and + contains the transport medium to use when creating a tunnel for + protocols (such as L2TP) that can operate over multiple transports. + It MAY be used in an authorization request as a hint to the server + that a specific medium is desired, but the server is not required to + honor the hint in the corresponding response. + + The supported values are listed in [RADIUSTypes]. + Sub-registry: Values for RADIUS Attribute 65, Tunnel-Medium-Type + Reference: [RFC2868] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Tunnel-Medium-Type)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 1, "IPv4 (IP version 4) [RFC2868]"), + enumval_def_u32( 2, "IPv6 (IP version 6) [RFC2868]"), + enumval_def_u32( 3, "NSAP [RFC2868]"), + enumval_def_u32( 4, "HDLC (8-bit multidrop) [RFC2868]"), + enumval_def_u32( 5, "BBN 1822 [RFC2868]"), + enumval_def_u32( 6, "802 (includes all 802 media plus Ethernet \"canonical format\") [RFC2868]"), + enumval_def_u32( 7, "E.163 (POTS) [RFC2868]"), + enumval_def_u32( 8, "E.164 (SMDS, Frame Relay, ATM) [RFC2868]"), + enumval_def_u32( 9, "F.69 (Telex) [RFC2868]"), + enumval_def_u32(10, "X.121 (X.25, Frame Relay) [RFC2868]"), + enumval_def_u32(11, "IPX [RFC2868]"), + enumval_def_u32(12, "Appletalk [RFC2868]"), + enumval_def_u32(13, "Decnet IV [RFC2868]"), + enumval_def_u32(14, "Banyan Vines [RFC2868]"), + enumval_def_u32(15, "E.164 with NSAP format subaddress [RFC2868]") + }; + struct dict_avp_data adata = { + 65, /* Code */ + 0, /* Vendor */ + "Tunnel-Medium-Type", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &adata , type, NULL); + } + + /* Tunnel-Client-Endpoint */ + { + /* + The Tunnel-Client-Endpoint AVP (AVP Code 66) is of type UTF8String + and contains the address of the initiator end of the tunnel. It MAY + be used in an authorization request as a hint to the server that a + specific endpoint is desired, but the server is not required to honor + the hint in the corresponding response. + + This AVP SHOULD be included in the corresponding Accounting-Request + messages, in which case it indicates the address from which the + tunnel was initiated. This AVP, along with the Tunnel-Server- + Endpoint and Session-Id AVP [BASE], MAY be used to provide a globally + unique means to identify a tunnel for accounting and auditing + purposes. + + If Tunnel-Medium-Type is IPv4 (1), then this string is either the + fully qualified domain name (FQDN) of the tunnel client machine, or a + "dotted-decimal" IP address. Implementations MUST support the + dotted-decimal format and SHOULD support the FQDN format for IP + addresses. + + If Tunnel-Medium-Type is IPv6 (2), then this string is either the + FQDN of the tunnel client machine, or a text representation of the + address in either the preferred or alternate form [IPv6Addr]. + Conforming implementations MUST support the preferred form and SHOULD + support both the alternate text form and the FQDN format for IPv6 + addresses. + + If Tunnel-Medium-Type is neither IPv4 nor IPv6, then this string is a + tag referring to configuration data local to the Diameter client that + describes the interface or medium-specific client address to use. + */ + struct dict_avp_data adata = { + 66, /* Code */ + 0, /* Vendor */ + "Tunnel-Client-Endpoint", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , UTF8String_type, NULL); + } + + /* Tunnel-Server-Endpoint */ + { + /* + The Tunnel-Server-Endpoint AVP (AVP Code 67) is of type UTF8String + and contains the address of the server end of the tunnel. It MAY be + used in an authorization request as a hint to the server that a + specific endpoint is desired, but the server is not required to honor + the hint in the corresponding response. + + This AVP SHOULD be included in the corresponding Accounting-Request + messages, in which case it indicates the address from which the + tunnel was initiated. This AVP, along with the Tunnel-Client- + Endpoint and Session-Id AVP [BASE], MAY be used to provide a globally + unique means to identify a tunnel for accounting and auditing + purposes. + + If Tunnel-Medium-Type is IPv4 (1), then this string is either the + fully qualified domain name (FQDN) of the tunnel server machine, or a + "dotted-decimal" IP address. Implementations MUST support the + dotted-decimal format and SHOULD support the FQDN format for IP + addresses. + + If Tunnel-Medium-Type is IPv6 (2), then this string is either the + FQDN of the tunnel server machine, or a text representation of the + address in either the preferred or alternate form [IPv6Addr]. + Implementations MUST support the preferred form and SHOULD support + both the alternate text form and the FQDN format for IPv6 addresses. + + If Tunnel-Medium-Type is not IPv4 or IPv6, this string is a tag + referring to configuration data local to the Diameter client that + describes the interface or medium-specific server address to use. + */ + struct dict_avp_data adata = { + 67, /* Code */ + 0, /* Vendor */ + "Tunnel-Server-Endpoint", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , UTF8String_type, NULL); + } + + /* Tunnel-Password */ + { + /* + The Tunnel-Password AVP (AVP Code 69) is of type OctetString and may + contain a password to be used to authenticate to a remote server. + The Tunnel-Password AVP contains sensitive information. This value + is not protected in the same manner as RADIUS [RADTunnels]. + + As required in [BASE], Diameter messages are encrypted by using IPsec + or TLS. The Tunnel-Password AVP SHOULD NOT be used in untrusted + proxy environments without encrypting it by using end-to-end security + techniques, such as CMS Security [DiamCMS]. + */ + struct dict_avp_data adata = { + 69, /* Code */ + 0, /* Vendor */ + "Tunnel-Password", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , NULL, NULL); + } + + /* Tunnel-Private-Group-Id */ + { + /* + The Tunnel-Private-Group-Id AVP (AVP Code 81) is of type OctetString + and contains the group Id for a particular tunneled session. The + Tunnel-Private-Group-Id AVP MAY be included in an authorization + request if the tunnel initiator can predetermine the group resulting + from a particular connection. It SHOULD be included in the + authorization response if this tunnel session is to be treated as + belonging to a particular private group. Private groups may be used + to associate a tunneled session with a particular group of users. + For example, it MAY be used to facilitate routing of unregistered IP + addresses through a particular interface. This AVP SHOULD be + included in the Accounting-Request messages that pertain to the + tunneled session. + */ + struct dict_avp_data adata = { + 81, /* Code */ + 0, /* Vendor */ + "Tunnel-Private-Group-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , NULL, NULL); + } + + /* Tunnel-Assignment-Id */ + { + /* + The Tunnel-Assignment-Id AVP (AVP Code 82) is of type OctetString and + is used to indicate to the tunnel initiator the particular tunnel to + which a session is to be assigned. Some tunneling protocols, such as + [PPTP] and [L2TP], allow for sessions between the same two tunnel + endpoints to be multiplexed over the same tunnel and also for a given + session to use its own dedicated tunnel. This attribute provides a + mechanism for Diameter to inform the tunnel initiator (e.g., PAC, + LAC) whether to assign the session to a multiplexed tunnel or to a + separate tunnel. Furthermore, it allows for sessions sharing + multiplexed tunnels to be assigned to different multiplexed tunnels. + + A particular tunneling implementation may assign differing + characteristics to particular tunnels. For example, different + tunnels may be assigned different QoS parameters. Such tunnels may + be used to carry either individual or multiple sessions. The + Tunnel-Assignment-Id attribute thus allows the Diameter server to + indicate that a particular session is to be assigned to a tunnel + providing an appropriate level of service. It is expected that any + QoS-related Diameter tunneling attributes defined in the future + accompanying this one will be associated by the tunnel initiator with + the Id given by this attribute. In the meantime, any semantic given + to a particular Id string is a matter left to local configuration in + the tunnel initiator. + + The Tunnel-Assignment-Id AVP is of significance only to Diameter and + the tunnel initiator. The Id it specifies is only intended to be of + local use to Diameter and the tunnel initiator. The Id assigned by + the tunnel initiator is not conveyed to the tunnel peer. + + This attribute MAY be included in authorization responses. The + tunnel initiator receiving this attribute MAY choose to ignore it and + to assign the session to an arbitrary multiplexed or non-multiplexed + tunnel between the desired endpoints. This AVP SHOULD also be + included in the Accounting-Request messages pertaining to the + tunneled session. + + If a tunnel initiator supports the Tunnel-Assignment-Id AVP, then it + should assign a session to a tunnel in the following manner: + + - If this AVP is present and a tunnel exists between the + specified endpoints with the specified Id, then the session + should be assigned to that tunnel. + + - If this AVP is present and no tunnel exists between the + specified endpoints with the specified Id, then a new tunnel + should be established for the session and the specified Id + should be associated with the new tunnel. + + - If this AVP is not present, then the session is assigned to an + unnamed tunnel. If an unnamed tunnel does not yet exist + between the specified endpoints, then it is established and + used for this session and for subsequent ones established + without the Tunnel-Assignment-Id attribute. A tunnel initiator + MUST NOT assign a session for which a Tunnel-Assignment-Id AVP + was not specified to a named tunnel (i.e., one that was + initiated by a session specifying this AVP). + + Note that the same Id may be used to name different tunnels if these + tunnels are between different endpoints. + + */ + struct dict_avp_data adata = { + 82, /* Code */ + 0, /* Vendor */ + "Tunnel-Assignment-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , NULL, NULL); + } + + /* Tunnel-Preference */ + { + /* + The Tunnel-Preference AVP (AVP Code 83) is of type Unsigned32 and is + used to identify the relative preference assigned to each tunnel when + more than one set of tunneling AVPs is returned within separate + Grouped-AVP AVPs. It MAY be used in an authorization request as a + hint to the server that a specific preference is desired, but the + server is not required to honor the hint in the corresponding + response. + + For example, suppose that AVPs describing two tunnels are returned by + the server, one with a Tunnel-Type of PPTP and the other with a + Tunnel-Type of L2TP. If the tunnel initiator supports only one of + the Tunnel-Types returned, it will initiate a tunnel of that type. + If, however, it supports both tunnel protocols, it SHOULD use the + value of the Tunnel-Preference AVP to decide which tunnel should be + started. The tunnel with the lowest numerical value in the Value + field of this AVP SHOULD be given the highest preference. The values + assigned to two or more instances of the Tunnel-Preference AVP within + a given authorization response MAY be identical. In this case, the + tunnel initiator SHOULD use locally configured metrics to decide + which set of AVPs to use. + */ + struct dict_avp_data adata = { + 83, /* Code */ + 0, /* Vendor */ + "Tunnel-Preference", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , NULL, NULL); + } + + /* Tunnel-Client-Auth-Id */ + { + /* + The Tunnel-Client-Auth-Id AVP (AVP Code 90) is of type UTF8String and + specifies the name used by the tunnel initiator during the + authentication phase of tunnel establishment. It MAY be used in an + authorization request as a hint to the server that a specific + preference is desired, but the server is not required to honor the + hint in the corresponding response. This AVP MUST be present in the + authorization response if an authentication name other than the + default is desired. This AVP SHOULD be included in the Accounting- + Request messages pertaining to the tunneled session. + */ + struct dict_avp_data adata = { + 90, /* Code */ + 0, /* Vendor */ + "Tunnel-Client-Auth-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , UTF8String_type, NULL); + } + + /* Tunnel-Server-Auth-Id */ + { + /* + The Tunnel-Server-Auth-Id AVP (AVP Code 91) is of type UTF8String and + specifies the name used by the tunnel terminator during the + authentication phase of tunnel establishment. It MAY be used in an + authorization request as a hint to the server that a specific + preference is desired, but the server is not required to honor the + hint in the corresponding response. This AVP MUST be present in the + authorization response if an authentication name other than the + default is desired. This AVP SHOULD be included in the Accounting- + Request messages pertaining to the tunneled session. + */ + struct dict_avp_data adata = { + 91, /* Code */ + 0, /* Vendor */ + "Tunnel-Server-Auth-Id", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &adata , UTF8String_type, NULL); + } + + /* Tunneling */ + { + /* + The Tunneling AVP (AVP Code 401) is of type Grouped and contains the + following AVPs, used to describe a compulsory tunnel service: + [RADTunnels], [RADTunlAcct]. Its data field has the following ABNF + grammar: + + Tunneling ::= < AVP Header: 401 > + { Tunnel-Type } + { Tunnel-Medium-Type } + { Tunnel-Client-Endpoint } + { Tunnel-Server-Endpoint } + [ Tunnel-Preference ] + [ Tunnel-Client-Auth-Id ] + [ Tunnel-Server-Auth-Id ] + [ Tunnel-Assignment-Id ] + [ Tunnel-Password ] + [ Tunnel-Private-Group-Id ] + */ + struct dict_object * avp; + struct dict_avp_data data = { + 401, /* Code */ + 0, /* Vendor */ + "Tunneling", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_GROUPED /* base type of data */ + }; + struct local_rules_definition rules[] = + { { "Tunnel-Type", RULE_REQUIRED, -1, 1 } + ,{ "Tunnel-Medium-Type", RULE_REQUIRED, -1, 1 } + ,{ "Tunnel-Client-Endpoint", RULE_REQUIRED, -1, 1 } + ,{ "Tunnel-Server-Endpoint", RULE_REQUIRED, -1, 1 } + ,{ "Tunnel-Preference", RULE_OPTIONAL, -1, 1 } + ,{ "Tunnel-Client-Auth-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Tunnel-Server-Auth-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Tunnel-Assignment-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Tunnel-Password", RULE_OPTIONAL, -1, 1 } + ,{ "Tunnel-Private-Group-Id", RULE_OPTIONAL, -1, 1 } + }; + + CHECK_dict_new( DICT_AVP, &data , NULL, &avp); + PARSE_loc_rules( rules, avp ); + } + +/******************************** + * NAS Accounting AVPs * + ********************************/ + /* Accounting-Input-Octets */ + { + /* + The Accounting-Input-Octets AVP (AVP Code 363) is of type Unsigned64 + and contains the number of octets received from the user. + + For NAS usage, this AVP indicates how many octets have been received + from the port in the course of this session. It can only be present + in ACR messages with an Accounting-Record-Type of INTERIM_RECORD or + STOP_RECORD. + */ + struct dict_avp_data data = { + 363, /* Code */ + 0, /* Vendor */ + "Accounting-Input-Octets", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED64 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Accounting-Output-Octets */ + { + /* + The Accounting-Output-Octets AVP (AVP Code 364) is of type Unsigned64 + and contains the number of octets sent to the user. + + For NAS usage, this AVP indicates how many octets have been sent to + the port in the course of this session. It can only be present in + ACR messages with an Accounting-Record-Type of INTERIM_RECORD or + STOP_RECORD. + */ + struct dict_avp_data data = { + 364, /* Code */ + 0, /* Vendor */ + "Accounting-Output-Octets", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED64 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Accounting-Input-Packets */ + { + /* + The Accounting-Input-Packets (AVP Code 365) is of type Unsigned64 and + contains the number of packets received from the user. + + For NAS usage, this AVP indicates how many packets have been received + from the port over the course of a session being provided to a Framed + User. It can only be present in ACR messages with an Accounting- + Record-Type of INTERIM_RECORD or STOP_RECORD. + */ + struct dict_avp_data data = { + 365, /* Code */ + 0, /* Vendor */ + "Accounting-Input-Packets", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED64 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Accounting-Output-Packets */ + { + /* + The Accounting-Output-Packets (AVP Code 366) is of type Unsigned64 + and contains the number of IP packets sent to the user. + + For NAS usage, this AVP indicates how many packets have been sent to + the port over the course of a session being provided to a Framed + User. It can only be present in ACR messages with an Accounting- + Record-Type of INTERIM_RECORD or STOP_RECORD. + */ + struct dict_avp_data data = { + 366, /* Code */ + 0, /* Vendor */ + "Accounting-Output-Packets", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED64 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Acct-Session-Time */ + { + /* + The Acct-Session-Time AVP (AVP Code 46) is of type Unsigned32 and + indicates the length of the current session in seconds. It can only + be present in ACR messages with an Accounting-Record-Type of + INTERIM_RECORD or STOP_RECORD. + */ + struct dict_avp_data data = { + 46, /* Code */ + 0, /* Vendor */ + "Acct-Session-Time", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Acct-Authentic */ + { + /* + The Acct-Authentic AVP (AVP Code 45) is of type Enumerated and + specifies how the user was authenticated. The supported values are + listed in [RADIUSTypes]. + Sub-registry: Values for RADIUS Attribute 45, Acct-Authentic + Reference: [RFC2866] + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Acct-Authentic)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 1, "RADIUS"), + enumval_def_u32( 2, "Local"), + enumval_def_u32( 3, "Remote"), + enumval_def_u32( 4, "Diameter") + }; + struct dict_avp_data data = { + 45, /* Code */ + 0, /* Vendor */ + "Acct-Authentic", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Accounting-Auth-Method */ + { + /* + The Accounting-Auth-Method AVP (AVP Code 406) is of type Enumerated. + A NAS MAY include this AVP in an Accounting-Request message to + indicate the method used to authenticate the user. (Note that this + is equivalent to the RADIUS MS-Acct-Auth-Type VSA attribute). + + The following values are defined: + + 1 PAP + 2 CHAP + 3 MS-CHAP-1 + 4 MS-CHAP-2 + 5 EAP + 7 None + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Accounting-Auth-Method)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 1, "PAP"), + enumval_def_u32( 2, "CHAP"), + enumval_def_u32( 3, "MS-CHAP-1"), + enumval_def_u32( 4, "MS-CHAP-2"), + enumval_def_u32( 5, "EAP"), + enumval_def_u32( 7, "None") + }; + struct dict_avp_data data = { + 406, /* Code */ + 0, /* Vendor */ + "Accounting-Auth-Method", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + /* Acct-Delay-Time */ + { + /* + The Acct-Delay-Time AVP (AVP Code 41) is of type Unsigned32 and + indicates the number of seconds the Diameter client has been trying + to send the Accounting-Request (ACR). The accounting server may + subtract this value from the time when the ACR arrives at the server + to calculate the approximate time of the event that caused the ACR to + be generated. + + This AVP is not used for retransmissions at the transport level (TCP + or SCTP). Rather, it may be used when an ACR command cannot be + transmitted because there is no appropriate peer to transmit it to or + was rejected because it could not be delivered. In these cases, the + command MAY be buffered and transmitted later, when an appropriate + peer-connection is available or after sufficient time has passed that + the destination-host may be reachable and operational. If the ACR is + resent in this way, the Acct-Delay-Time AVP SHOULD be included. The + value of this AVP indicates the number of seconds that elapsed + between the time of the first attempt at transmission and the current + attempt. + */ + struct dict_avp_data data = { + 41, /* Code */ + 0, /* Vendor */ + "Acct-Delay-Time", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Acct-Link-Count */ + { + /* + The Acct-Link-Count AVP (AVP Code 51) is of type Unsigned32 and + indicates the total number of links that have been active (current or + closed) in a given multilink session at the time the accounting + record is generated. This AVP MAY be included in Accounting-Requests + for any session that may be part of a multilink service. + + The Acct-Link-Count AVP may be used to make it easier for an + accounting server to know when it has all the records for a given + multilink service. When the number of Accounting-Requests received + with Accounting-Record-Type = STOP_RECORD and with the same Acct- + Multi-Session-Id and unique Session-Ids equals the largest value of + Acct-Link-Count seen in those Accounting-Requests, all STOP_RECORD + Accounting-Requests for that multilink service have been received. + + The following example, showing eight Accounting-Requests, illustrates + how the Acct-Link-Count AVP is used. In the table below, only the + relevant AVPs are shown, although additional AVPs containing + accounting information will be present in the Accounting-Requests. + + Acct-Multi- Accounting- Acct- + Session-Id Session-Id Record-Type Link-Count + -------------------------------------------------------- + "...10" "...10" START_RECORD 1 + "...10" "...11" START_RECORD 2 + "...10" "...11" STOP_RECORD 2 + "...10" "...12" START_RECORD 3 + "...10" "...13" START_RECORD 4 + "...10" "...12" STOP_RECORD 4 + "...10" "...13" STOP_RECORD 4 + "...10" "...10" STOP_RECORD 4 + + */ + struct dict_avp_data data = { + 51, /* Code */ + 0, /* Vendor */ + "Acct-Link-Count", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Acct-Tunnel-Connection */ + { + /* + The Acct-Tunnel-Connection AVP (AVP Code 68) is of type OctetString + and contains the identifier assigned to the tunnel session. This + AVP, along with the Tunnel-Client-Endpoint and Tunnel-Server-Endpoint + AVPs, may be used to provide a means to uniquely identify a tunnel + session for auditing purposes. + + The format of the identifier in this AVP depends upon the value of + the Tunnel-Type AVP. For example, to identify an L2TP tunnel + connection fully, the L2TP Tunnel Id and Call Id might be encoded in + this field. The exact encoding of this field is implementation + dependent. + */ + struct dict_avp_data data = { + 68, /* Code */ + 0, /* Vendor */ + "Acct-Tunnel-Connection", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Acct-Tunnel-Packets-Lost */ + { + /* + The Acct-Tunnel-Packets-Lost AVP (AVP Code 86) is of type Unsigned32 + and contains the number of packets lost on a given link. + */ + struct dict_avp_data data = { + 86, /* Code */ + 0, /* Vendor */ + "Acct-Tunnel-Packets-Lost", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + +/*********************************** + * Compatibility with RADIUS AVPs * + ***********************************/ + /* NAS-Identifier */ + { + /* + The NAS-Identifier AVP (AVP Code 32) [RADIUS] is of type UTF8String + and contains the identity of the NAS providing service to the user. + This AVP SHOULD only be added by a RADIUS/Diameter Translation Agent. + When this AVP is present, the Origin-Host AVP identifies the NAS + providing service to the user. + + In RADIUS it would be possible for a rogue NAS to forge the NAS- + Identifier attribute. Diameter/RADIUS translation agents SHOULD + attempt to check a received NAS-Identifier attribute against the + source address of the RADIUS packet, by doing an A/AAAA RR query. If + the NAS-Identifier attribute contains an FQDN, then such a query + would resolve to an IP address matching the source address. However, + the NAS-Identifier attribute is not required to contain an FQDN, so + such a query could fail. If it fails, an error should be logged, but + no action should be taken, other than a reverse lookup on the source + address and insert the resulting FQDN into the Route-Record AVP. + + Diameter agents and servers SHOULD check whether a NAS-Identifier AVP + corresponds to an entry in the Route-Record AVP. If no match is + found, then an error is logged, but no other action is taken. + */ + struct dict_avp_data data = { + 32, /* Code */ + 0, /* Vendor */ + "NAS-Identifier", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , UTF8String_type, NULL); + } + + /* NAS-IP-Address */ + { + /* + The NAS-IP-Address AVP (AVP Code 4) [RADIUS] is of type OctetString + and contains the IP Address of the NAS providing service to the user. + This AVP SHOULD only be added by a RADIUS/Diameter Translation Agent. + When this AVP is present, the Origin-Host AVP identifies the NAS + providing service to the user. + + In RADIUS it would be possible for a rogue NAS to forge the NAS-IP- + Address attribute value. Diameter/RADIUS translation agents MUST + check a received NAS-IP-Address or NAS-IPv6-Address attribute against + the source address of the RADIUS packet. If they do not match and + the Diameter/RADIUS translation agent does not know whether the + packet was sent by a RADIUS proxy or NAS (e.g., no Proxy-State + attribute), then by default it is assumed that the source address + corresponds to a RADIUS proxy, and that the NAS Address is behind + that proxy, potentially with some additional RADIUS proxies in + between. The Diameter/RADIUS translation agent MUST insert entries + in the Route-Record AVP corresponding to the apparent route. This + implies doing a reverse lookup on the source address and NAS-IP- + Address or NAS-IPv6-Address attributes to determine the corresponding + FQDNs. + + If the source address and the NAS-IP-Address or NAS-IPv6-Address do + not match, and the Diameter/RADIUS translation agent knows that it is + talking directly to the NAS (e.g., there are no RADIUS proxies + between it and the NAS), then the error should be logged, and the + packet MUST be discarded. + + Diameter agents and servers MUST check whether the NAS-IP-Address AVP + corresponds to an entry in the Route-Record AVP. This is done by + doing a reverse lookup (PTR RR) for the NAS-IP-Address to retrieve + the corresponding FQDN, and by checking for a match with the Route- + Record AVP. If no match is found, then an error is logged, but no + other action is taken. + */ + struct dict_avp_data data = { + 4, /* Code */ + 0, /* Vendor */ + "NAS-IP-Address", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* NAS-IPv6-Address */ + { + /* + The NAS-IPv6-Address AVP (AVP Code 95) [RADIUSIPv6] is of type + OctetString and contains the IPv6 Address of the NAS providing + service to the user. This AVP SHOULD only be added by a + RADIUS/Diameter Translation Agent. When this AVP is present, the + Origin-Host AVP identifies the NAS providing service to the user. + + In RADIUS it would be possible for a rogue NAS to forge the NAS- + IPv6-Address attribute. Diameter/RADIUS translation agents MUST + check a received NAS-IPv6-Address attribute against the source + address of the RADIUS packet. If they do not match and the + Diameter/RADIUS translation agent does not know whether the packet + was sent by a RADIUS proxy or NAS (e.g., no Proxy-State attribute), + then by default it is assumed that the source address corresponds to + a RADIUS proxy, and that the NAS-IPv6-Address is behind that proxy, + potentially with some additional RADIUS proxies in between. The + Diameter/RADIUS translation agent MUST insert entries in the Route- + Record AVP corresponding to the apparent route. This implies doing a + reverse lookup on the source address and NAS-IPv6-Address attributes + to determine the corresponding FQDNs. + + If the source address and the NAS-IPv6-Address do not match, and the + Diameter/RADIUS translation agent knows that it is talking directly + to the NAS (e.g., there are no RADIUS proxies between it and the + NAS), then the error should be logged, and the packet MUST be + discarded. + + Diameter agents and servers MUST check whether the NAS-IPv6-Address + AVP corresponds to an entry in the Route-Record AVP. This is done by + doing a reverse lookup (PTR RR) for the NAS-IPv6-Address to retrieve + the corresponding FQDN, and by checking for a match with the Record- + Route AVP. If no match is found, then an error is logged, but no + other action is taken. + */ + struct dict_avp_data data = { + 95, /* Code */ + 0, /* Vendor */ + "NAS-IPv6-Address", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* State */ + { + /* + The State AVP (AVP Code 24) [RADIUS] is of type OctetString and has + two uses in the Diameter NAS application. + + The State AVP MAY be sent by a Diameter Server to a NAS in an AA- + Response command that contains a Result-Code of + DIAMETER_MULTI_ROUND_AUTH. If so, the NAS MUST return it unmodified + in the subsequent AA-Request command. + + The State AVP MAY also be sent by a Diameter Server to a NAS in an + AA-Response command that also includes a Termination-Action AVP with + the value of AA-REQUEST. If the NAS performs the Termination-Action + by sending a new AA-Request command upon termination of the current + service, it MUST return the State AVP unmodified in the new request + command. + + In either usage, the NAS MUST NOT interpret the AVP locally. Usage + of the State AVP is implementation dependent. + */ + struct dict_avp_data data = { + 24, /* Code */ + 0, /* Vendor */ + "State", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_OCTETSTRING /* base type of data */ + }; + CHECK_dict_new( DICT_AVP, &data , NULL, NULL); + } + + /* Termination-Cause mapping */ + { + + struct dict_object *type; + struct dict_enumval_data tvals[] = { + enumval_def_u32(11, "[RADIUS] User Request"), + enumval_def_u32(12, "[RADIUS] Lost Carrier"), + enumval_def_u32(13, "[RADIUS] Lost Service"), + enumval_def_u32(14, "[RADIUS] Idle Timeout"), + enumval_def_u32(15, "[RADIUS] Session Timeout"), + enumval_def_u32(16, "[RADIUS] Admin Reset"), + enumval_def_u32(17, "[RADIUS] Admin Reboot"), + enumval_def_u32(18, "[RADIUS] Port Error"), + enumval_def_u32(19, "[RADIUS] NAS Error"), + enumval_def_u32(20, "[RADIUS] NAS Request"), + enumval_def_u32(21, "[RADIUS] NAS Reboot"), + enumval_def_u32(22, "[RADIUS] Port Unneeded"), + enumval_def_u32(23, "[RADIUS] Port Preempted"), + enumval_def_u32(24, "[RADIUS] Port Suspended"), + enumval_def_u32(25, "[RADIUS] Service Unavailable"), + enumval_def_u32(26, "[RADIUS] Callback"), + enumval_def_u32(27, "[RADIUS] User Error"), + enumval_def_u32(28, "[RADIUS] Host Request"), + enumval_def_u32(29, "[RADIUS] Supplicant Restart"), + enumval_def_u32(30, "[RADIUS] Reauthentication Failure"), + enumval_def_u32(31, "[RADIUS] Port Reinit"), + enumval_def_u32(32, "[RADIUS] Port Disabled") + }; + int i; + + CHECK_dict_search( DICT_TYPE, TYPE_BY_NAME, "Enumerated(Termination-Cause)", &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + + } + + /* Origin-AAA-Protocol */ + { + /* + The Origin-AAA-Protocol AVP (AVP Code 408) is of the type Enumerated + and should be inserted in a Diameter message translated by a gateway + system from another AAA protocol, such as RADIUS. It identifies the + source protocol of the message to the Diameter system receiving the + message. + + The supported values are: + + 1 RADIUS + */ + struct dict_object *type; + struct dict_type_data tdata = { AVP_TYPE_UNSIGNED32, "Enumerated(Origin-AAA-Protocol)" , NULL, NULL}; + struct dict_enumval_data tvals[] = { + enumval_def_u32( 1, "RADIUS") + }; + struct dict_avp_data data = { + 408, /* Code */ + 0, /* Vendor */ + "Origin-AAA-Protocol", /* Name */ + AVP_FLAG_VENDOR | AVP_FLAG_MANDATORY, /* Fixed flags */ + AVP_FLAG_MANDATORY, /* Fixed flag values */ + AVP_TYPE_UNSIGNED32 /* base type of data */ + }; + int i; + /* Create the Enumerated type, enumerated values, and the AVP */ + CHECK_dict_new( DICT_TYPE, &tdata , NULL, &type); + for (i = 0; i < sizeof(tvals) / sizeof(tvals[0]); i++) { + CHECK_dict_new( DICT_ENUMVAL, &tvals[i], type, NULL); + } + CHECK_dict_new( DICT_AVP, &data , type, NULL); + } + + } + +/********************/ +/* Commands section */ +/********************/ + { + /* To avoid defining global variables for all the AVP that we use here, we do search the dictionary in each sub-block. + * This is far from optimal, but the code is clearer like this, and the time it requires at execution is not noticeable. + */ + + /* AA-Request (AAR) Command */ + { + /* + The AA-Request (AAR), which is indicated by setting the Command-Code + field to 265 and the 'R' bit in the Command Flags field, is used to + request authentication and/or authorization for a given NAS user. + The type of request is identified through the Auth-Request-Type AVP + [BASE]. The recommended value for most RADIUS interoperabily + situations is AUTHORIZE_AUTHENTICATE. + + If Authentication is requested, the User-Name attribute SHOULD be + present, as well as any additional authentication AVPs that would + carry the password information. A request for authorization SHOULD + only include the information from which the authorization will be + performed, such as the User-Name, Called-Station-Id, or Calling- + Station-Id AVPs. All requests SHOULD contain AVPs uniquely + identifying the source of the call, such as Origin-Host and NAS-Port. + Certain networks MAY use different AVPs for authorization purposes. + A request for authorization will include some AVPs defined in section + 6. + + It is possible for a single session to be authorized first and then + for an authentication request to follow. + + This AA-Request message MAY be the result of a multi-round + authentication exchange, which occurs when the AA-Answer message is + received with the Result-Code AVP set to DIAMETER_MULTI_ROUND_AUTH. + A subsequent AAR message SHOULD be sent, with the User-Password AVP + that includes the user's response to the prompt, and MUST include any + State AVPs that were present in the AAA message. + + Message Format + ::= < Diameter Header: 265, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Request-Type } + [ Destination-Host ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Port-Limit ] + [ User-Name ] + [ User-Password ] + [ Service-Type ] + [ State ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Connect-Info ] + [ CHAP-Auth ] + [ CHAP-Challenge ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IP-Netmask ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ ARAP-Password ] + [ ARAP-Security ] + * [ ARAP-Security-Data ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + */ + struct dict_object * cmd; + struct dict_cmd_data data = { + 265, /* Code */ + "AA-Request", /* Name */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE | CMD_FLAG_RETRANSMIT | CMD_FLAG_ERROR, /* Fixed flags */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE /* Fixed flag values */ + }; + struct local_rules_definition rules[] = + { { "Session-Id", RULE_FIXED_HEAD, -1, 1 } + ,{ "Auth-Application-Id", RULE_REQUIRED, -1, 1 } + ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } + ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } + ,{ "Destination-Realm", RULE_REQUIRED, -1, 1 } + ,{ "Auth-Request-Type", RULE_REQUIRED, -1, 1 } + ,{ "Destination-Host", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Identifier", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IPv6-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Id", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "Origin-State-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Port-Limit", RULE_OPTIONAL, -1, 1 } + ,{ "User-Name", RULE_OPTIONAL, -1, 1 } + ,{ "User-Password", RULE_OPTIONAL, -1, 1 } + ,{ "Service-Type", RULE_OPTIONAL, -1, 1 } + ,{ "State", RULE_OPTIONAL, -1, 1 } + ,{ "Authorization-Lifetime", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Grace-Period", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Session-State", RULE_OPTIONAL, -1, 1 } + ,{ "Callback-Number", RULE_OPTIONAL, -1, 1 } + ,{ "Called-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Calling-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Originating-Line-Info", RULE_OPTIONAL, -1, 1 } + ,{ "Connect-Info", RULE_OPTIONAL, -1, 1 } + ,{ "CHAP-Auth", RULE_OPTIONAL, -1, 1 } + ,{ "CHAP-Challenge", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Compression", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-Interface-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Prefix", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IP-Netmask", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-MTU", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "ARAP-Password", RULE_OPTIONAL, -1, 1 } + ,{ "ARAP-Security", RULE_OPTIONAL, -1, 1 } + ,{ "ARAP-Security-Data", RULE_OPTIONAL, -1,-1 } + ,{ "Login-IP-Host", RULE_OPTIONAL, -1,-1 } + ,{ "Login-IPv6-Host", RULE_OPTIONAL, -1,-1 } + ,{ "Login-LAT-Group", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Node", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Port", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Service", RULE_OPTIONAL, -1, 1 } + ,{ "Tunneling", RULE_OPTIONAL, -1,-1 } + ,{ "Proxy-Info", RULE_OPTIONAL, -1,-1 } + ,{ "Route-Record", RULE_OPTIONAL, -1,-1 } + }; + + CHECK_dict_new( DICT_COMMAND, &data , nasreq, &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* AA-Answer (AAA) Command */ + { + /* + The AA-Answer (AAA) message is indicated by setting the Command-Code + field to 265 and clearing the 'R' bit in the Command Flags field. It + is sent in response to the AA-Request (AAR) message. If + authorization was requested, a successful response will include the + authorization AVPs appropriate for the service being provided, as + defined in section 6. + + For authentication exchanges requiring more than a single round trip, + the server MUST set the Result-Code AVP to DIAMETER_MULTI_ROUND_AUTH. + An AAA message with this result code MAY include one Reply-Message or + more and MAY include zero or one State AVPs. + + If the Reply-Message AVP was present, the network access server + SHOULD send the text to the user's client to display to the user, + instructing the client to prompt the user for a response. For + example, this capability can be achieved in PPP via PAP. If the + access client is unable to prompt the user for a new response, it + MUST treat the AA-Answer (AAA) with the Reply-Message AVP as an error + and deny access. + + Message Format + + ::= < Diameter Header: 265, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Request-Type } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Service-Type ] + * [ Class ] + * [ Configuration-Token ] + [ Acct-Interim-Interval ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Auth-Session-State ] + [ Re-Auth-Request-Type ] + [ Multi-Round-Time-Out ] + [ Session-Timeout ] + [ State ] + * [ Reply-Message ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Filter-Id ] + [ Password-Retry ] + [ Port-Limit ] + [ Prompt ] + [ ARAP-Challenge-Response ] + [ ARAP-Features ] + [ ARAP-Security ] + * [ ARAP-Security-Data ] + [ ARAP-Zone-Access ] + [ Callback-Id ] + [ Callback-Number ] + [ Framed-Appletalk-Link ] + * [ Framed-Appletalk-Network ] + [ Framed-Appletalk-Zone ] + * [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IP-Netmask ] + * [ Framed-Route ] + [ Framed-Pool ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Protocol ] + [ Framed-Routing ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + [ Login-Service ] + [ Login-TCP-Port ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + * [ Tunneling ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + */ + struct dict_object * cmd; + struct dict_cmd_data data = { + 265, /* Code */ + "AA-Answer", /* Name */ + CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE, /* Fixed flags */ + CMD_FLAG_PROXIABLE /* Fixed flag values */ + }; + struct local_rules_definition rules[] = + { { "Session-Id", RULE_FIXED_HEAD, -1, 1 } + ,{ "Auth-Application-Id", RULE_REQUIRED, -1, 1 } + ,{ "Auth-Request-Type", RULE_REQUIRED, -1, 1 } + ,{ "Result-Code", RULE_REQUIRED, -1, 1 } + ,{ "Origin-Host", RULE_REQUIRED, -1, 1 } + ,{ "Origin-Realm", RULE_REQUIRED, -1, 1 } + ,{ "User-Name", RULE_OPTIONAL, -1, 1 } + ,{ "Service-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Class", RULE_OPTIONAL, -1,-1 } + ,{ "Configuration-Token", RULE_OPTIONAL, -1,-1 } + ,{ "Acct-Interim-Interval", RULE_OPTIONAL, -1, 1 } + ,{ "Error-Message", RULE_OPTIONAL, -1, 1 } + ,{ "Error-Reporting-Host", RULE_OPTIONAL, -1, 1 } + ,{ "Failed-AVP", RULE_OPTIONAL, -1,-1 } + ,{ "Idle-Timeout", RULE_OPTIONAL, -1, 1 } + ,{ "Authorization-Lifetime", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Grace-Period", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Session-State", RULE_OPTIONAL, -1, 1 } + ,{ "Re-Auth-Request-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Multi-Round-Time-Out", RULE_OPTIONAL, -1, 1 } + ,{ "Session-Timeout", RULE_OPTIONAL, -1, 1 } + ,{ "State", RULE_OPTIONAL, -1, 1 } + ,{ "Reply-Message", RULE_OPTIONAL, -1,-1 } + ,{ "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "Origin-State-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Filter-Id", RULE_OPTIONAL, -1,-1 } + ,{ "Password-Retry", RULE_OPTIONAL, -1, 1 } + ,{ "Port-Limit", RULE_OPTIONAL, -1, 1 } + ,{ "Prompt", RULE_OPTIONAL, -1, 1 } + ,{ "ARAP-Challenge-Response", RULE_OPTIONAL, -1, 1 } + ,{ "ARAP-Features", RULE_OPTIONAL, -1, 1 } + ,{ "ARAP-Security", RULE_OPTIONAL, -1, 1 } + ,{ "ARAP-Security-Data", RULE_OPTIONAL, -1,-1 } + ,{ "ARAP-Zone-Access", RULE_OPTIONAL, -1, 1 } + ,{ "Callback-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Callback-Number", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-AppleTalk-Link", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-AppleTalk-Network", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-AppleTalk-Zone", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Compression", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-Interface-Id", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Prefix", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IPv6-Pool", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Route", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IP-Netmask", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-Route", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-Pool", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPX-Network", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-MTU", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Routing", RULE_OPTIONAL, -1, 1 } + ,{ "Login-IP-Host", RULE_OPTIONAL, -1,-1 } + ,{ "Login-IPv6-Host", RULE_OPTIONAL, -1,-1 } + ,{ "Login-LAT-Group", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Node", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Port", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Service", RULE_OPTIONAL, -1, 1 } + ,{ "Login-Service", RULE_OPTIONAL, -1, 1 } + ,{ "Login-TCP-Port", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Filter-Rule", RULE_OPTIONAL, -1,-1 } + ,{ "QoS-Filter-Rule", RULE_OPTIONAL, -1,-1 } + ,{ "Tunneling", RULE_OPTIONAL, -1,-1 } + ,{ "Redirect-Host", RULE_OPTIONAL, -1,-1 } + ,{ "Redirect-Host-Usage", RULE_OPTIONAL, -1, 1 } + ,{ "Redirect-Max-Cache-Time", RULE_OPTIONAL, -1, 1 } + ,{ "Proxy-Info", RULE_OPTIONAL, -1,-1 } + }; + + CHECK_dict_new( DICT_COMMAND, &data , nasreq, &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Re-Auth-Request */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + ::= < Diameter Header: 258, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + { Re-Auth-Request-Type } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Framed-IP-Address ] + [ Framed-IPv6-Prefix ] + [ Framed-Interface-Id ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ State ] + * [ Class ] + [ Reply-Message ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Identifier", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IPv6-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Id", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Service-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Prefix", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Interface-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Called-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Calling-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Originating-Line-Info", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Session-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Multi-Session-Id", RULE_OPTIONAL, -1, 1 } + ,{ "State", RULE_OPTIONAL, -1, 1 } + ,{ "Class", RULE_OPTIONAL, -1,-1 } + ,{ "Reply-Message", RULE_OPTIONAL, -1,-1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Re-Auth-Request", &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Re-Auth-Answer */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + + ::= < Diameter Header: 258, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirected-Host ] + [ Redirected-Host-Usage ] + [ Redirected-Host-Cache-Time ] + [ Service-Type ] + * [ Configuration-Token ] + [ Idle-Timeout ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Re-Auth-Request-Type ] + [ State ] + * [ Class ] + * [ Reply-Message ] + [ Prompt ] + * [ Proxy-Info ] + * [ AVP ] + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "Service-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Configuration-Token", RULE_OPTIONAL, -1,-1 } + ,{ "Idle-Timeout", RULE_OPTIONAL, -1, 1 } + ,{ "Authorization-Lifetime", RULE_OPTIONAL, -1, 1 } + ,{ "Auth-Grace-Period", RULE_OPTIONAL, -1, 1 } + ,{ "Re-Auth-Request-Type", RULE_OPTIONAL, -1, 1 } + ,{ "State", RULE_OPTIONAL, -1, 1 } + ,{ "Class", RULE_OPTIONAL, -1,-1 } + ,{ "Reply-Message", RULE_OPTIONAL, -1,-1 } + ,{ "Prompt", RULE_OPTIONAL, -1, 1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Re-Auth-Answer", &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Session-Termination-Request */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + + ::= < Diameter Header: 275, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Termination-Cause } + [ User-Name ] + [ Destination-Host ] + * [ Class ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Session-Termination-Request", &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Session-Termination-Answer */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + ::= < Diameter Header: 275, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + * [ Class ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Redirect-Host ] + [ Redirect-Host-Usase ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Session-Termination-Answer", &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Abort-Session-Request */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + ::= < Diameter Header: 274, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Framed-IP-Address ] + [ Framed-IPv6-Prefix ] + [ Framed-Interface-Id ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + [ Originating-Line-Info ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ State ] + * [ Class ] + * [ Reply-Message ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Identifier", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IPv6-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Id", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Service-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Prefix", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Interface-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Called-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Calling-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Originating-Line-Info", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Session-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Multi-Session-Id", RULE_OPTIONAL, -1, 1 } + ,{ "State", RULE_OPTIONAL, -1, 1 } + ,{ "Class", RULE_OPTIONAL, -1,-1 } + ,{ "Reply-Message", RULE_OPTIONAL, -1,-1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Abort-Session-Request", &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Abort-Session-Answer */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + ::= < Diameter Header: 274, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ State] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirected-Host ] + [ Redirected-Host-Usage ] + [ Redirected-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "State", RULE_REQUIRED, -1, 1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Abort-Session-Answer", &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Accounting-Request */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + ::= < Diameter Header: 271, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Accounting-Record-Type } + { Accounting-Record-Number } + [ Acct-Application-Id ] + [ Vendor-Specific-Application-Id ] + [ User-Name ] + [ Accounting-Sub-Session-Id ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ Destination-Host ] + [ Event-Timestamp ] + [ Acct-Delay-Time ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + * [ Class ] + [ Service-Type ] + [ Termination-Cause ] + [ Accounting-Input-Octets ] + [ Accounting-Input-Packets ] + [ Accounting-Output-Octets ] + [ Accounting-Output-Packets ] + [ Acct-Authentic ] + [ Accounting-Auth-Method ] + [ Acct-Link-Count ] + [ Acct-Session-Time ] + [ Acct-Tunnel-Connection ] + [ Acct-Tunnel-Packets-Lost ] + [ Callback-Id ] + [ Callback-Number ] + [ Called-Station-Id ] + [ Calling-Station-Id ] + * [ Connection-Info ] + [ Originating-Line-Info ] + [ Authorization-Lifetime ] + [ Session-Timeout ] + [ Idle-Timeout ] + [ Port-Limit ] + [ Accounting-Realtime-Required ] + [ Acct-Interim-Interval ] + * [ Filter-Id ] + * [ NAS-Filter-Rule ] + * [ Qos-Filter-Rule ] + [ Framed-AppleTalk-Link ] + [ Framed-AppleTalk-Network ] + [ Framed-AppleTalk-Zone ] + [ Framed-Compression ] + [ Framed-Interface-Id ] + [ Framed-IP-Address ] + [ Framed-IP-Netmask ] + * [ Framed-IPv6-Prefix ] + [ Framed-IPv6-Pool ] + * [ Framed-IPv6-Route ] + [ Framed-IPX-Network ] + [ Framed-MTU ] + [ Framed-Pool ] + [ Framed-Protocol ] + * [ Framed-Route ] + [ Framed-Routing ] + * [ Login-IP-Host ] + * [ Login-IPv6-Host ] + [ Login-LAT-Group ] + [ Login-LAT-Node ] + [ Login-LAT-Port ] + [ Login-LAT-Service ] + [ Login-Service ] + [ Login-TCP-Port ] + * [ Tunneling ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Delay-Time", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Identifier", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-IPv6-Address", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Id", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Port-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Class", RULE_OPTIONAL, -1,-1 } + ,{ "Service-Type", RULE_OPTIONAL, -1, 1 } + ,{ "Termination-Cause", RULE_OPTIONAL, -1, 1 } + ,{ "Accounting-Input-Octets", RULE_OPTIONAL, -1, 1 } + ,{ "Accounting-Input-Packets", RULE_OPTIONAL, -1, 1 } + ,{ "Accounting-Output-Octets", RULE_OPTIONAL, -1, 1 } + ,{ "Accounting-Output-Packets", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Authentic", RULE_OPTIONAL, -1, 1 } + ,{ "Accounting-Auth-Method", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Link-Count", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Session-Time", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Tunnel-Connection", RULE_OPTIONAL, -1, 1 } + ,{ "Acct-Tunnel-Packets-Lost", RULE_OPTIONAL, -1, 1 } + ,{ "Callback-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Callback-Number", RULE_OPTIONAL, -1, 1 } + ,{ "Called-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Calling-Station-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Connect-Info", RULE_OPTIONAL, -1,-1 } + ,{ "Originating-Line-Info", RULE_OPTIONAL, -1, 1 } + ,{ "Authorization-Lifetime", RULE_OPTIONAL, -1, 1 } + ,{ "Session-Timeout", RULE_OPTIONAL, -1, 1 } + ,{ "Idle-Timeout", RULE_OPTIONAL, -1, 1 } + ,{ "Port-Limit", RULE_OPTIONAL, -1, 1 } + ,{ "Filter-Id", RULE_OPTIONAL, -1,-1 } + ,{ "NAS-Filter-Rule", RULE_OPTIONAL, -1,-1 } + ,{ "QoS-Filter-Rule", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-AppleTalk-Link", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-AppleTalk-Network", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-AppleTalk-Zone", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Compression", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Interface-Id", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IP-Address", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Prefix", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IPv6-Pool", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPv6-Route", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-IP-Netmask", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Route", RULE_OPTIONAL, -1,-1 } + ,{ "Framed-Pool", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-IPX-Network", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-MTU", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "Framed-Routing", RULE_OPTIONAL, -1, 1 } + ,{ "Login-IP-Host", RULE_OPTIONAL, -1,-1 } + ,{ "Login-IPv6-Host", RULE_OPTIONAL, -1,-1 } + ,{ "Login-LAT-Group", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Node", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Port", RULE_OPTIONAL, -1, 1 } + ,{ "Login-LAT-Service", RULE_OPTIONAL, -1, 1 } + ,{ "Login-Service", RULE_OPTIONAL, -1, 1 } + ,{ "Login-TCP-Port", RULE_OPTIONAL, -1, 1 } + ,{ "Tunneling", RULE_OPTIONAL, -1,-1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &cmd); + PARSE_loc_rules( rules, cmd ); + } + + /* Accounting-Answer */ + { + /* + Add additional rules of the ABNF (compared to Base definition): + + ::= < Diameter Header: 271, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + { Accounting-Record-Type } + { Accounting-Record-Number } + [ Acct-Application-Id ] + [ Vendor-Specific-Application-Id ] + [ User-Name ] + [ Accounting-Sub-Session-Id ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Event-Timestamp ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + [ NAS-Identifier ] + [ NAS-IP-Address ] + [ NAS-IPv6-Address ] + [ NAS-Port ] + [ NAS-Port-Id ] + [ NAS-Port-Type ] + [ Service-Type ] + [ Termination-Cause ] + [ Accounting-Realtime-Required ] + [ Acct-Interim-Interval ] + * [ Class ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + */ + struct dict_object * cmd; + struct local_rules_definition rules[] = + { { "Origin-AAA-Protocol", RULE_OPTIONAL, -1, 1 } + ,{ "NAS-Identifier", RULE_REQUIRED, -1, 1 } + ,{ "NAS-IP-Address", RULE_REQUIRED, -1, 1 } + ,{ "NAS-IPv6-Address", RULE_REQUIRED, -1, 1 } + ,{ "NAS-Port", RULE_REQUIRED, -1, 1 } + ,{ "NAS-Port-Id", RULE_REQUIRED, -1, 1 } + ,{ "NAS-Port-Type", RULE_REQUIRED, -1, 1 } + ,{ "Service-Type", RULE_REQUIRED, -1, 1 } + ,{ "Termination-Cause", RULE_REQUIRED, -1, 1 } + }; + + CHECK_dict_search( DICT_COMMAND, CMD_BY_NAME, "Accounting-Answer", &cmd); + PARSE_loc_rules( rules, cmd ); + } + } + + TRACE_DEBUG(INFO, "Extension 'Dictionary definitions for NASREQ' initialized"); + return 0; +} + +EXTENSION_ENTRY("dict_nasreq", dnr_entry); diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/CMakeLists.txt --- a/freeDiameter/CMakeLists.txt Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/CMakeLists.txt Fri Sep 25 16:12:08 2009 +0900 @@ -10,8 +10,11 @@ SET(FD_COMMON_SRC fD.h config.c + dispatch.c extensions.c dict_base_proto.c + messages.c + queues.c ) SET(FD_COMMON_GEN_SRC diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/config.c --- a/freeDiameter/config.c Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/config.c Fri Sep 25 16:12:08 2009 +0900 @@ -42,25 +42,25 @@ { TRACE_ENTRY(); - fd_g_config->eyec = EYEC_CONFIG; - fd_g_config->conf_file = DEFAULT_CONF_FILE; + fd_g_config->cnf_eyec = EYEC_CONFIG; + fd_g_config->cnf_file = DEFAULT_CONF_FILE; + + fd_g_config->cnf_timer_tc = 30; + fd_g_config->cnf_timer_tw = 30; - fd_g_config->loc_port = 3868; - fd_g_config->loc_port_tls = 3869; - fd_g_config->loc_sctp_str = 30; - fd_list_init(&fd_g_config->loc_endpoints, NULL); - + fd_g_config->cnf_port = 3868; + fd_g_config->cnf_port_tls = 3869; + fd_g_config->cnf_sctp_str = 30; + fd_list_init(&fd_g_config->cnf_endpoints, NULL); + fd_list_init(&fd_g_config->cnf_apps, NULL); #ifdef DISABLE_SCTP - fd_g_config->flags.no_sctp = 1; + fd_g_config->cnf_flags.no_sctp = 1; #endif /* DISABLE_SCTP */ - fd_g_config->timer_tc = 30; - fd_g_config->timer_tw = 30; + fd_g_config->cnf_orstateid = (uint32_t) time(NULL); - fd_g_config->or_state_id = (uint32_t) time(NULL); - - CHECK_FCT( fd_dict_init(&fd_g_config->g_dict) ); - CHECK_FCT( fd_fifo_new(&fd_g_config->g_fifo_main) ); + CHECK_FCT( fd_dict_init(&fd_g_config->cnf_dict) ); + CHECK_FCT( fd_fifo_new(&fd_g_config->cnf_main_ev) ); return 0; } @@ -72,39 +72,56 @@ fd_log_debug("-- Configuration :\n"); fd_log_debug(" Debug trace level ...... : %+d\n", fd_g_debug_lvl); - fd_log_debug(" Configuration file ..... : %s\n", fd_g_config->conf_file); - fd_log_debug(" Diameter Identity ...... : %s (l:%Zi)\n", fd_g_config->diam_id, fd_g_config->diam_id_len); - fd_log_debug(" Diameter Realm ......... : %s (l:%Zi)\n", fd_g_config->diam_realm, fd_g_config->diam_realm_len); - fd_log_debug(" Local port ............. : %hu\n", fd_g_config->loc_port); - fd_log_debug(" Local secure port ...... : %hu\n", fd_g_config->loc_port_tls); - fd_log_debug(" Number of SCTP streams . : %hu\n", fd_g_config->loc_sctp_str); - if (FD_IS_LIST_EMPTY(&fd_g_config->loc_endpoints)) { + fd_log_debug(" Configuration file ..... : %s\n", fd_g_config->cnf_file); + fd_log_debug(" Diameter Identity ...... : %s (l:%Zi)\n", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len); + fd_log_debug(" Diameter Realm ......... : %s (l:%Zi)\n", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len); + fd_log_debug(" Tc Timer ............... : %u\n", fd_g_config->cnf_timer_tc); + fd_log_debug(" Tw Timer ............... : %u\n", fd_g_config->cnf_timer_tw); + fd_log_debug(" Local port ............. : %hu\n", fd_g_config->cnf_port); + fd_log_debug(" Local secure port ...... : %hu\n", fd_g_config->cnf_port_tls); + fd_log_debug(" Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str); + if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) { fd_log_debug(" Local endpoints ........ : Default (use all available)\n"); } else { - struct fd_list * li = fd_g_config->loc_endpoints.next; + struct fd_list * li = fd_g_config->cnf_endpoints.next; fd_log_debug(" Local endpoints ........ : "); - while (li != &fd_g_config->loc_endpoints) { + while (li != &fd_g_config->cnf_endpoints) { struct fd_endpoint * ep = (struct fd_endpoint *)li; - if (li != fd_g_config->loc_endpoints.next) fd_log_debug(" "); + if (li != fd_g_config->cnf_endpoints.next) fd_log_debug(" "); sSA_DUMP_NODE( &ep->ss, NI_NUMERICHOST ); fd_log_debug("\n"); li = li->next; } } - fd_log_debug(" Flags : - IP ........... : %s\n", fd_g_config->flags.no_ip4 ? "DISABLED" : "Enabled"); - fd_log_debug(" - IPv6 ......... : %s\n", fd_g_config->flags.no_ip6 ? "DISABLED" : "Enabled"); - fd_log_debug(" - Relay app .... : %s\n", fd_g_config->flags.no_fwd ? "DISABLED" : "Enabled"); - fd_log_debug(" - TCP .......... : %s\n", fd_g_config->flags.no_tcp ? "DISABLED" : "Enabled"); + if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_apps)) { + fd_log_debug(" Local applications ..... : (none)\n"); + } else { + struct fd_list * li = fd_g_config->cnf_apps.next; + fd_log_debug(" Local applications ..... : "); + while (li != &fd_g_config->cnf_apps) { + struct fd_app * app = (struct fd_app *)li; + if (li != fd_g_config->cnf_apps.next) fd_log_debug(" "); + fd_log_debug("App: %u\t%s%s%s\tVnd: %u\n", + app->appid, + app->flags.auth ? "Au" : "--", + app->flags.acct ? "Ac" : "--", + app->flags.common ? "C" : "-", + app->vndid); + li = li->next; + } + } + fd_log_debug(" Flags : - IP ........... : %s\n", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled"); + fd_log_debug(" - IPv6 ......... : %s\n", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled"); + fd_log_debug(" - Relay app .... : %s\n", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled"); + fd_log_debug(" - TCP .......... : %s\n", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled"); #ifdef DISABLE_SCTP fd_log_debug(" - SCTP ......... : DISABLED (at compilation)\n"); #else /* DISABLE_SCTP */ - fd_log_debug(" - SCTP ......... : %s\n", fd_g_config->flags.no_sctp ? "DISABLED" : "Enabled"); + fd_log_debug(" - SCTP ......... : %s\n", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled"); #endif /* DISABLE_SCTP */ - fd_log_debug(" - Pref. proto .. : %s\n", fd_g_config->flags.pr_tcp ? "TCP" : "SCTP"); - fd_log_debug(" - TLS method ... : %s\n", fd_g_config->flags.tls_alg ? "INBAND" : "Separate port"); - fd_log_debug(" Tc Timer ............... : %u\n", fd_g_config->timer_tc); - fd_log_debug(" Tw Timer ............... : %u\n", fd_g_config->timer_tw); - fd_log_debug(" Origin-State-Id ........ : %u\n", fd_g_config->or_state_id); + fd_log_debug(" - Pref. proto .. : %s\n", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP"); + fd_log_debug(" - TLS method ... : %s\n", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port"); + fd_log_debug(" Origin-State-Id ........ : %u\n", fd_g_config->cnf_orstateid); } /* Parse the configuration file (using the yacc parser) */ @@ -112,12 +129,12 @@ { extern FILE * fddin; - TRACE_DEBUG (FULL, "Parsing configuration file: %s", fd_g_config->conf_file); + TRACE_DEBUG (FULL, "Parsing configuration file: %s", fd_g_config->cnf_file); - fddin = fopen(fd_g_config->conf_file, "r"); + fddin = fopen(fd_g_config->cnf_file, "r"); if (fddin == NULL) { int ret = errno; - fprintf(stderr, "Unable to open configuration file %s for reading: %s\n", fd_g_config->conf_file, strerror(ret)); + fprintf(stderr, "Unable to open configuration file %s for reading: %s\n", fd_g_config->cnf_file, strerror(ret)); return ret; } @@ -128,7 +145,7 @@ fclose(fddin); /* Resolve hostname if not provided */ - if (fd_g_config->diam_id == NULL) { + if (fd_g_config->cnf_diamid == NULL) { #ifndef HOST_NAME_MAX #define HOST_NAME_MAX 1024 #endif /* HOST_NAME_MAX */ @@ -151,36 +168,36 @@ buf, gai_strerror(ret)); return EINVAL; } - CHECK_MALLOC( fd_g_config->diam_id = strdup(info->ai_canonname) ); + CHECK_MALLOC( fd_g_config->cnf_diamid = strdup(info->ai_canonname) ); freeaddrinfo(info); } /* cache the length of the diameter id for the session module */ - fd_g_config->diam_id_len = strlen(fd_g_config->diam_id); + fd_g_config->cnf_diamid_len = strlen(fd_g_config->cnf_diamid); /* Handle the realm part */ - if (fd_g_config->diam_realm == NULL) { + if (fd_g_config->cnf_diamrlm == NULL) { char * start = NULL; /* Check the diameter identity is a fqdn */ - start = strchr(fd_g_config->diam_id, '.'); + start = strchr(fd_g_config->cnf_diamid, '.'); if ((start == NULL) || (start[1] == '\0')) { fprintf(stderr, "Unable to extract realm from the LocalIdentity '%s'.\n" "Please fix your LocalIdentity setting or provide LocalRealm.\n", - fd_g_config->diam_id); + fd_g_config->cnf_diamid); return EINVAL; } - CHECK_MALLOC( fd_g_config->diam_realm = strdup( start + 1 ) ); + CHECK_MALLOC( fd_g_config->cnf_diamrlm = strdup( start + 1 ) ); } - fd_g_config->diam_realm_len = strlen(fd_g_config->diam_realm); + fd_g_config->cnf_diamrlm_len = strlen(fd_g_config->cnf_diamrlm); /* Validate some flags */ - if (fd_g_config->flags.no_ip4 && fd_g_config->flags.no_ip6) { + if (fd_g_config->cnf_flags.no_ip4 && fd_g_config->cnf_flags.no_ip6) { fprintf(stderr, "IP and IPv6 cannot be disabled at the same time.\n"); return EINVAL; } - if (fd_g_config->flags.no_tcp && fd_g_config->flags.no_sctp) { + if (fd_g_config->cnf_flags.no_tcp && fd_g_config->cnf_flags.no_sctp) { fprintf(stderr, "TCP and SCTP cannot be disabled at the same time.\n"); return EINVAL; } diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/dispatch.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/dispatch.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,100 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct ) +{ + vendor_id_t vid = 0; + application_id_t aid = 0; + struct fd_list * li; + int skip = 0; + + TRACE_ENTRY("%p %p %d %d", app, vendor, auth, acct); + CHECK_PARAMS( app && (auth || acct) ); + + { + enum dict_object_type type = 0; + struct dict_application_data data; + CHECK_FCT( fd_dict_gettype(app, &type) ); + CHECK_PARAMS( type == DICT_APPLICATION ); + CHECK_FCT( fd_dict_getval(app, &data) ); + aid = data.application_id; + } + + + /* Now insert in the list ordered by appid. Avoid duplicates */ + for (li = &fd_g_config->cnf_apps; li->next != &fd_g_config->cnf_apps; li = li->next) { + struct fd_app * na = (struct fd_app *)(li->next); + if (na->appid < aid) + continue; + + if (na->appid > aid) + break; + + /* Otherwise, we merge with existing entry -- ignore vendor id in this case */ + skip = 1; + + if (auth) + na->flags.auth = 1; + if (acct) + na->flags.acct = 1; + break; + } + + if (!skip) { + struct fd_app * new = NULL; + + if (vendor) { + enum dict_object_type type = 0; + struct dict_vendor_data data; + CHECK_FCT( fd_dict_gettype(vendor, &type) ); + CHECK_PARAMS( type == DICT_VENDOR ); + CHECK_FCT( fd_dict_getval(vendor, &data) ); + vid = data.vendor_id; + } + + CHECK_MALLOC( new = malloc(sizeof(struct fd_app)) ); + memset(new, 0, sizeof(struct fd_app)); + fd_list_init(&new->chain, NULL); + new->flags.auth = (auth ? 1 : 0); + new->flags.acct = (acct ? 1 : 0); + new->vndid = vid; + new->appid = aid; + fd_list_insert_after(li, &new->chain); + } + + return 0; +} diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/extensions.c --- a/freeDiameter/extensions.c Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/extensions.c Fri Sep 25 16:12:08 2009 +0900 @@ -80,6 +80,20 @@ return 0; } +/* Dump the list */ +void fd_ext_dump(void) +{ + struct fd_list * li; + + fd_log_debug("Dumping extensions list :\n"); + + for (li = ext_list.next; li != &ext_list; li = li->next) + { + struct fd_ext_info * ext = (struct fd_ext_info *)li; + fd_log_debug(" - '%s'[%s] is %sloaded\n", ext->filename, ext->conffile?:"no conf", ext->handler ? "" : "not "); + } +} + /* Load all extensions in the list */ int fd_ext_load() { diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/fD.h --- a/freeDiameter/fD.h Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/fD.h Fri Sep 25 16:12:08 2009 +0900 @@ -41,11 +41,6 @@ #include #include -/* Events codespace for fd_g_config->g_fifo_main */ -enum { - FM_TERMINATE = 1000 /* request to terminate */ -}; - /* Configuration */ int fd_conf_init(); void fd_conf_dump(); @@ -56,8 +51,20 @@ int fd_ext_init(); int fd_ext_add( char * filename, char * conffile ); int fd_ext_load(); +void fd_ext_dump(void); int fd_ext_fini(void); +/* Messages */ +int fd_msg_init(void); + +/* Global message queues */ +extern struct fifo * fd_g_incoming; /* all messages received from other peers, except local messages (CER, ...) */ +extern struct fifo * fd_g_outgoing; /* messages to be sent to other peers on the network following routing procedure */ +extern struct fifo * fd_g_local; /* messages to be handled to local extensions */ +/* Message queues */ +int fd_queues_init(void); +int fd_queues_fini(void); + /* Create all the dictionary objects defined in the Diameter base RFC. */ int fd_dict_base_protocol(struct dictionary * dict); diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/fdd.y --- a/freeDiameter/fdd.y Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/fdd.y Fri Sep 25 16:12:08 2009 +0900 @@ -62,11 +62,11 @@ void yyerror (YYLTYPE *ploc, struct fd_config * conf, char const *s) { if (ploc->first_line != ploc->last_line) - fprintf(stderr, "%s:%d.%d-%d.%d : %s\n", conf->conf_file, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); + fprintf(stderr, "%s:%d.%d-%d.%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); else if (ploc->first_column != ploc->last_column) - fprintf(stderr, "%s:%d.%d-%d : %s\n", conf->conf_file, ploc->first_line, ploc->first_column, ploc->last_column, s); + fprintf(stderr, "%s:%d.%d-%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, ploc->last_column, s); else - fprintf(stderr, "%s:%d.%d : %s\n", conf->conf_file, ploc->first_line, ploc->first_column, s); + fprintf(stderr, "%s:%d.%d : %s\n", conf->cnf_file, ploc->first_line, ploc->first_column, s); } %} @@ -110,31 +110,47 @@ conffile: /* Empty is OK */ | conffile localidentity | conffile localrealm + | conffile tctimer + | conffile twtimer | conffile localport | conffile localsecport + | conffile sctpstreams + | conffile listenon + | conffile norelay | conffile noip | conffile noip6 | conffile notcp | conffile nosctp | conffile prefertcp | conffile oldtls - | conffile sctpstreams - | conffile listenon - | conffile tctimer - | conffile twtimer - | conffile norelay | conffile loadext ; localidentity: LOCALIDENTITY '=' QSTRING ';' { - conf->diam_id = $3; + conf->cnf_diamid = $3; } ; localrealm: LOCALREALM '=' QSTRING ';' { - conf->diam_realm = $3; + conf->cnf_diamrlm = $3; + } + ; + +tctimer: TCTIMER '=' INTEGER ';' + { + CHECK_PARAMS_DO( ($3 > 0), + { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); + conf->cnf_timer_tc = (unsigned int)$3; + } + ; + +twtimer: TWTIMER '=' INTEGER ';' + { + CHECK_PARAMS_DO( ($3 > 5), + { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); + conf->cnf_timer_tw = (unsigned int)$3; } ; @@ -142,7 +158,7 @@ { CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16), { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); - conf->loc_port = (uint16_t)$3; + conf->cnf_port = (uint16_t)$3; } ; @@ -150,43 +166,7 @@ { CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16), { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); - conf->loc_port_tls = (uint16_t)$3; - } - ; - -noip: NOIP ';' - { - conf->flags.no_ip4 = 1; - } - ; - -noip6: NOIP6 ';' - { - conf->flags.no_ip6 = 1; - } - ; - -notcp: NOTCP ';' - { - conf->flags.no_tcp = 1; - } - ; - -nosctp: NOSCTP ';' - { - conf->flags.no_sctp = 1; - } - ; - -prefertcp: PREFERTCP ';' - { - conf->flags.pr_tcp = 1; - } - ; - -oldtls: OLDTLS ';' - { - conf->flags.tls_alg = 1; + conf->cnf_port_tls = (uint16_t)$3; } ; @@ -194,7 +174,7 @@ { CHECK_PARAMS_DO( ($3 > 0) && ($3 < 1<<16), { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); - conf->loc_sctp_str = (uint16_t)$3; + conf->cnf_sctp_str = (uint16_t)$3; } ; @@ -217,29 +197,49 @@ memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen); free($3); freeaddrinfo(ai); - fd_list_insert_before(&conf->loc_endpoints, &ep->chain); - } - ; - -tctimer: TCTIMER '=' INTEGER ';' - { - CHECK_PARAMS_DO( ($3 > 0), - { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); - conf->timer_tc = (unsigned int)$3; - } - ; - -twtimer: TWTIMER '=' INTEGER ';' - { - CHECK_PARAMS_DO( ($3 > 5), - { yyerror (&yylloc, conf, "Invalid value"); YYERROR; } ); - conf->timer_tw = (unsigned int)$3; + fd_list_insert_before(&conf->cnf_endpoints, &ep->chain); } ; norelay: NORELAY ';' { - conf->flags.no_fwd = 1; + conf->cnf_flags.no_fwd = 1; + } + ; + +noip: NOIP ';' + { + conf->cnf_flags.no_ip4 = 1; + } + ; + +noip6: NOIP6 ';' + { + conf->cnf_flags.no_ip6 = 1; + } + ; + +notcp: NOTCP ';' + { + conf->cnf_flags.no_tcp = 1; + } + ; + +nosctp: NOSCTP ';' + { + conf->cnf_flags.no_sctp = 1; + } + ; + +prefertcp: PREFERTCP ';' + { + conf->cnf_flags.pr_tcp = 1; + } + ; + +oldtls: OLDTLS ';' + { + conf->cnf_flags.tls_alg = 1; } ; diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/main.c --- a/freeDiameter/main.c Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/main.c Fri Sep 25 16:12:08 2009 +0900 @@ -38,6 +38,101 @@ #include #include +/* forward declarations */ +static void * sig_hdl(void * arg); +static int main_cmdline(int argc, char *argv[]); + +/* The static configuration structure */ +static struct fd_config conf; +struct fd_config * fd_g_config = &conf; + +/* freeDiameter starting point */ +int main(int argc, char * argv[]) +{ + int ret; + pthread_t sig_th; + sigset_t sig_all; + + memset(fd_g_config, 0, sizeof(struct fd_config)); + sigfillset(&sig_all); + CHECK_POSIX( pthread_sigmask(SIG_BLOCK, &sig_all, NULL) ); + + /* Initialize the library */ + CHECK_FCT( fd_lib_init() ); + + /* Name this thread */ + fd_log_threadname("Main"); + + /* Initialize the config */ + CHECK_FCT( fd_conf_init() ); + + /* Parse the command-line */ + CHECK_FCT( main_cmdline(argc, argv) ); + + /* Allow SIGINT and SIGTERM from this point */ + CHECK_POSIX( pthread_create(&sig_th, NULL, sig_hdl, NULL) ); + + /* Add definitions of the base protocol */ + CHECK_FCT( fd_dict_base_protocol(fd_g_config->cnf_dict) ); + + /* Initialize other modules */ + CHECK_FCT( fd_ext_init() ); + CHECK_FCT( fd_queues_init() ); + CHECK_FCT( fd_msg_init() ); + + /* Parse the configuration file */ + CHECK_FCT( fd_conf_parse() ); + + /* Load the dynamic extensions */ + CHECK_FCT( fd_ext_load() ); + + /* Start the peer state machines */ + + + /* Now, just wait for events */ + TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); + fd_conf_dump(); + while (1) { + int code; + CHECK_FCT_DO( fd_event_get(fd_g_config->cnf_main_ev, &code, NULL), break ); + switch (code) { + case FDEV_DUMP_DICT: + fd_dict_dump(fd_g_config->cnf_dict); + break; + + case FDEV_DUMP_EXT: + fd_ext_dump(); + break; + + case FDEV_DUMP_QUEUES: + fd_fifo_dump(0, "Incoming messages", fd_g_incoming, fd_msg_dump_walk); + fd_fifo_dump(0, "Outgoing messages", fd_g_outgoing, fd_msg_dump_walk); + fd_fifo_dump(0, "Local messages", fd_g_local, fd_msg_dump_walk); + break; + + case FDEV_DUMP_CONFIG: + fd_conf_dump(); + break; + + + case FDEV_TERMINATE: + ret = 0; + goto end; + + default: + TRACE_DEBUG(INFO, "Unexpected event in the daemon (%d), ignored.\n", code); + } + } + +end: + TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon is stopping..."); + + /* cleanups */ + CHECK_FCT_DO( fd_ext_fini(), /* continue */ ); + CHECK_FCT_DO( fd_thr_term(&sig_th), /* continue */ ); + + return ret; +} /* Display package version */ static void main_version_core(void) @@ -121,7 +216,7 @@ case 'c': /* Read configuration from this file instead of the default location.. */ CHECK_PARAMS( optarg ); - fd_g_config->conf_file = optarg; + fd_g_config->cnf_file = optarg; break; case 'd': /* Increase verbosity of debug messages. */ @@ -158,7 +253,6 @@ # define SIGNALSTR(sig) ("") #endif /* HAVE_SIGNALENT_H */ - /* signal handler */ static void * sig_hdl(void * arg) { @@ -175,79 +269,7 @@ CHECK_SYS_DO( sigwait(&sig_main, &sig), TRACE_DEBUG(INFO, "Error in sigwait function") ); TRACE_DEBUG(INFO, "Received signal %s (%d), exiting", SIGNALSTR(sig), sig); - CHECK_FCT_DO( fd_event_send(fd_g_config->g_fifo_main, FM_TERMINATE, NULL), exit(2) ); + CHECK_FCT_DO( fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), exit(2) ); return NULL; } -/* The static configuration structure */ -static struct fd_config conf; -struct fd_config * fd_g_config = &conf; - -/* Entry point */ -int main(int argc, char * argv[]) -{ - int ret; - pthread_t sig_th; - sigset_t sig_all; - - memset(fd_g_config, 0, sizeof(struct fd_config)); - sigfillset(&sig_all); - CHECK_POSIX( pthread_sigmask(SIG_BLOCK, &sig_all, NULL) ); - - /* Initialize the library */ - CHECK_FCT( fd_lib_init() ); - - /* Name this thread */ - fd_log_threadname("Main"); - - /* Initialize the config */ - CHECK_FCT( fd_conf_init() ); - - /* Parse the command-line */ - CHECK_FCT( main_cmdline(argc, argv) ); - - /* Allow SIGINT and SIGTERM from this point */ - CHECK_POSIX( pthread_create(&sig_th, NULL, sig_hdl, NULL) ); - - /* Add definitions of the base protocol */ - CHECK_FCT( fd_dict_base_protocol(fd_g_config->g_dict) ); - - /* Initialize other modules */ - CHECK_FCT( fd_ext_init() ); - - /* Parse the configuration file */ - CHECK_FCT( fd_conf_parse() ); - - /* Load the dynamic extensions */ - CHECK_FCT( fd_ext_load() ); - - /* Start the peer state machines */ - - - /* Now, just wait for events */ - TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized."); - fd_conf_dump(); - while (1) { - int code; - CHECK_FCT_DO( fd_event_get(fd_g_config->g_fifo_main, &code, NULL), break ); - switch (code) { - case FM_TERMINATE: - ret = 0; - goto end; - - default: - TRACE_DEBUG(INFO, "Unexpected event in the daemon (%d), terminating.\n", code); - ret = -1; - goto end; - } - } - -end: - TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon is stopping..."); - - /* cleanups */ - CHECK_FCT_DO( fd_ext_fini(), /* continue */ ); - CHECK_FCT_DO( fd_thr_term(&sig_th), /* continue */ ); - - return ret; -} diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/messages.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/messages.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,266 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +static struct dict_object * dict_avp_OH = NULL; /* Origin-Host */ +static struct dict_object * dict_avp_OR = NULL; /* Origin-Realm */ +static struct dict_object * dict_avp_OSI = NULL; /* Origin-State-Id */ +static struct dict_object * dict_avp_RC = NULL; /* Result-Code */ +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 */ + +/* Resolve the dictionary objects */ +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, "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", &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) ); + + return 0; +} + +/* Add Origin-Host, Origin-Realm, Origin-State-Id AVPS at the end of the message */ +int fd_msg_add_origin ( struct msg * msg, int osi ) +{ + union avp_value val; + 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 = (unsigned char *)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 = (unsigned char *)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( dict_avp_OSI, 0, &avp_OSI ) ); + + /* Set its value */ + memset(&val, 0, sizeof(val)); + val.u32 = fd_g_config->cnf_orstateid; + CHECK_FCT( fd_msg_avp_setvalue( avp_OSI, &val ) ); + + /* Add it to the message */ + CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) ); + } + + 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 ) +{ + 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 ); + + /* Find the enum value corresponding to the rescode string, this will give the class of error */ + { + struct dict_object * enum_obj = NULL; + struct dict_enumval_request req; + memset(&req, 0, sizeof(struct dict_enumval_request)); + + /* First, get the enumerated type of the Result-Code AVP */ + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) ); + + /* 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 (type_id == 2) { + /* Add the Error-Reporting-Host AVP */ + + CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) ); + + /* Set its value */ + memset(&val, 0, sizeof(val)); + val.os.data = (unsigned char *)fd_g_config->cnf_diamid; + val.os.len = fd_g_config->cnf_diamid_len; + CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) ); + + /* 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 */ + if (optavp) { + /* Create the Failed-AVP AVP */ + CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) ); + + /* Add the passed AVP inside it */ + CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp ) ); + + /* 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 */ + 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 */ + + 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 = (unsigned char *)errormsg; + val.os.len = strlen(errormsg); + } else { + val.os.data = (unsigned char *)rescode; + val.os.len = strlen(rescode); + } + CHECK_FCT( fd_msg_avp_setvalue( avp_EM, &val ) ); + + /* Add it to the message */ + CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) ); + } + + return 0; +} + +/* Send a message and optionaly register a callback for an answer */ +int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data ) +{ + TRACE_ENTRY("%p %p %p", pmsg, anscb, data); + CHECK_PARAMS( pmsg ); + + /* Save the callback in the message */ + CHECK_FCT( fd_msg_anscb_associate( *pmsg, anscb, data ) ); + + /* Post the message in the outgoing queue */ + CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) ); + + return 0; +} + diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/queues.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/queues.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,65 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +/* The global message queues */ +struct fifo * fd_g_incoming = NULL; +struct fifo * fd_g_outgoing = NULL; +struct fifo * fd_g_local = NULL; + +/* Initialize the message queues. */ +int fd_queues_init(void) +{ + TRACE_ENTRY(); + CHECK_FCT( fd_fifo_new ( &fd_g_incoming ) ); + CHECK_FCT( fd_fifo_new ( &fd_g_outgoing ) ); + CHECK_FCT( fd_fifo_new ( &fd_g_local ) ); + return 0; +} + +/* Destroy the message queues */ +int fd_queues_fini(void) +{ + TRACE_ENTRY(); + + /* Stop the providing threads */ + /* Empty all contents */ + /* Now, delete the queues */ + CHECK_FCT( fd_fifo_del ( &fd_g_incoming ) ); + CHECK_FCT( fd_fifo_del ( &fd_g_outgoing ) ); + CHECK_FCT( fd_fifo_del ( &fd_g_local ) ); + return 0; +} diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/routing.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/routing.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,37 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/tests/CMakeLists.txt --- a/freeDiameter/tests/CMakeLists.txt Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/tests/CMakeLists.txt Fri Sep 25 16:12:08 2009 +0900 @@ -14,7 +14,7 @@ testlist testdict testmesg - testqueues + testfifo testsess testdisp ) diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/tests/testdict.c --- a/freeDiameter/tests/testdict.c Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/tests/testdict.c Fri Sep 25 16:12:08 2009 +0900 @@ -66,24 +66,24 @@ /* Create two vendors */ - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_VENDOR, &vendor1_data , NULL, &obj1 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_VENDOR, &vendor2_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_VENDOR, &vendor1_data , NULL, &obj1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_VENDOR, &vendor2_data , NULL, NULL ) ); /* Check we always retrieve the correct vendor object */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) ); CHECK( obj1, obj2); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 1", &obj2, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 1", &obj2, ENOENT ) ); CHECK( obj1, obj2); /* Check the error conditions */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) ); vendor_id = 735673; /* Not defined */ - CHECK( ENOENT, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) ); - CHECK( ENOENT, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", NULL, ENOENT ) ); - CHECK( ENOENT, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) ); - CHECK( ENOENT, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOENT ) ); - CHECK( ENOTSUP, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOTSUP ) ); + CHECK( ENOENT, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, NULL, ENOENT ) ); + CHECK( ENOENT, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", NULL, ENOENT ) ); + CHECK( ENOENT, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_ID, &vendor_id, &obj2, ENOENT ) ); + CHECK( ENOENT, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOENT ) ); + CHECK( ENOTSUP, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_NAME, "Vendor test 3", &obj2, ENOTSUP ) ); /* Check the get_* functions */ CHECK( 0, fd_dict_getval ( obj1, &vendor1_data ) ); @@ -93,10 +93,10 @@ CHECK( EINVAL, fd_dict_getval ( (struct dict_object *)"not an object", &vendor1_data ) ); /* Create the application with vendor1 as parent */ - CHECK( EINVAL, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app1_data , (struct dict_object *)"bad object", &obj2 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app1_data , obj1, &obj2 ) ); + CHECK( EINVAL, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app1_data , (struct dict_object *)"bad object", &obj2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app1_data , obj1, &obj2 ) ); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_VENDOR, VENDOR_OF_APPLICATION, obj2, &obj3, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_OF_APPLICATION, obj2, &obj3, ENOENT ) ); CHECK( obj1, obj3); /* Creating and searching the other objects is already done in dictionary initialization */ @@ -111,20 +111,20 @@ struct dict_rule_data rule_data = { NULL, RULE_REQUIRED, -1, -1 }; struct dict_avp_data example_avp_data = { 999999, 0, "Example-AVP", AVP_FLAG_VENDOR , 0, AVP_TYPE_GROUPED }; - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT ) ); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host_avp, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &session_id_avp, ENOENT ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &example_avp_data , NULL, &example_avp_avp ) ); rule_data.rule_avp = origin_host_avp; rule_data.rule_min = 1; rule_data.rule_max = 1; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) ); rule_data.rule_avp = session_id_avp; rule_data.rule_min = 1; rule_data.rule_max = -1; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &rule_data, example_avp_avp, NULL ) ); CHECK( 0, fd_dict_iterate_rules ( example_avp_avp, &nbr, iter_test) ); CHECK( 2, nbr ); diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/tests/testdisp.c --- a/freeDiameter/tests/testdisp.c Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/tests/testdisp.c Fri Sep 25 16:12:08 2009 +0900 @@ -127,15 +127,15 @@ struct dict_enumval_data enu1_data = { "ENU test 1", { .u32 = 1 }}; struct dict_enumval_data enu2_data = { "ENU test 2", { .u32 = 2 }}; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app1_data, NULL, &app1 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app2_data, NULL, &app2 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_COMMAND, &cmd1_data, NULL, &cmd1 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_COMMAND, &cmd2_data, NULL, &cmd2 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data, NULL, &enutype ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp1_data, NULL, &avp1 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp2_data, enutype, &avp2 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &enu1_data, enutype, &enu1 ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &enu2_data, enutype, &enu2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app1_data, NULL, &app1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app2_data, NULL, &app2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd1_data, NULL, &cmd1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd2_data, NULL, &cmd2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data, NULL, &enutype ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp1_data, NULL, &avp1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp2_data, enutype, &avp2 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &enu1_data, enutype, &enu1 ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &enu2_data, enutype, &enu2 ) ); } /* Register first handler, very simple test */ @@ -668,6 +668,34 @@ CHECK( 0, fd_disp_unregister( &hdl[4] ) ); } + /* Test application support advertisement */ + { + struct dict_object * vnd; + struct dict_vendor_data vnd_data = { 1, "Vendor test" }; + struct fd_app * app; + + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_VENDOR, &vnd_data, NULL, &vnd ) ); + + CHECK( EINVAL, fd_disp_app_support ( vnd, NULL, 1, 0 ) ); + CHECK( EINVAL, fd_disp_app_support ( app1, NULL, 0, 0 ) ); + CHECK( 0, fd_disp_app_support ( app1, NULL, 1, 0 ) ); + CHECK( 0, fd_disp_app_support ( app1, NULL, 0, 1 ) ); + CHECK( 0, fd_disp_app_support ( app2, vnd, 1, 0 ) ); + + app = (struct fd_app *)(fd_g_config->cnf_apps.next); + CHECK( 1, app->appid ); + CHECK( 1, app->flags.auth ); + CHECK( 1, app->flags.acct ); + app = (struct fd_app *)(fd_g_config->cnf_apps.prev); + CHECK( 2, app->appid ); + CHECK( 1, app->flags.auth ); + CHECK( 0, app->flags.acct ); + + #if 0 + fd_conf_dump(); + #endif + } + /* That's all for the tests yet */ PASSTEST(); } diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/tests/testfifo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/tests/testfifo.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,423 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "tests.h" + +/* Structure for testing threshold function */ +static struct thrh_test { + struct fifo * queue; /* pointer to the queue */ + int h_calls; /* number of calls of h_cb */ + int l_calls; /* number of calls of l_cb */ +} thrh_td; + +/* Callbacks for threasholds test */ +void thrh_cb_h(struct fifo *queue, void **data) +{ + if (thrh_td.h_calls == thrh_td.l_calls) { + CHECK( NULL, *data ); + *data = &thrh_td; + } else { + CHECK( *data, &thrh_td ); + } + CHECK( queue, thrh_td.queue ); + + /* Update the count */ + thrh_td.h_calls ++; +} +void thrh_cb_l(struct fifo *queue, void **data) +{ + CHECK( 1, data ? 1 : 0 ); + CHECK( *data, &thrh_td ); + + /* Check the queue parameter is correct */ + CHECK( queue, thrh_td.queue ); + + /* Update the count */ + thrh_td.l_calls ++; + /* Cleanup the data ptr if needed */ + if (thrh_td.l_calls == thrh_td.h_calls) + *data = NULL; + /* done */ +} + + +/* Structure that is passed to the test function */ +struct test_data { + struct fifo * queue; /* pointer to the queue */ + pthread_barrier_t * bar; /* if not NULL, barrier to synchronize before getting messages */ + struct timespec * ts; /* if not NULL, use a timedget instead of a get */ + int nbr; /* number of messages to retrieve from the queue */ +}; + +/* The test function, to be threaded */ +static void * test_fct(void * data) +{ + int ret = 0, i; + struct msg * msg = NULL; + struct test_data * td = (struct test_data *) data; + + if (td->bar != NULL) { + ret = pthread_barrier_wait(td->bar); + if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { + CHECK( 0, ret); + } else { + CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* just for the traces */ + } + } + + for (i=0; i< td->nbr; i++) { + if (td->ts != NULL) { + CHECK( 0, fd_fifo_timedget(td->queue, &msg, td->ts) ); + } else { + CHECK( 0, fd_fifo_get(td->queue, &msg) ); + } + } + + return NULL; +} + + +/* Main test routine */ +int main(int argc, char *argv[]) +{ + struct timespec ts; + + struct msg * msg1 = NULL; + struct msg * msg2 = NULL; + struct msg * msg3 = NULL; + + /* First, initialize the daemon modules */ + INIT_FD(); + + /* Prolog: create the messages */ + { + struct dict_object * acr_model = NULL; + struct dict_object * cer_model = NULL; + struct dict_object * dwr_model = NULL; + + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) ); + CHECK( 0, fd_msg_new ( acr_model, 0, &msg1 ) ); + CHECK( 0, fd_msg_new ( cer_model, 0, &msg2 ) ); + CHECK( 0, fd_msg_new ( dwr_model, 0, &msg3 ) ); + } + + /* Basic operation */ + { + struct fifo * queue = NULL; + int count; + struct msg * msg = NULL; + + /* Create the queue */ + CHECK( 0, fd_fifo_new(&queue) ); + + /* Check the count is 0 */ + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 0, count); + + /* Now enqueue */ + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + msg = msg2; + CHECK( 0, fd_fifo_post(queue, &msg) ); + msg = msg3; + CHECK( 0, fd_fifo_post(queue, &msg) ); + + /* Check the count is 3 */ + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 3, count); + + /* Retrieve the first message using fd_fifo_get */ + CHECK( 0, fd_fifo_get(queue, &msg) ); + CHECK( msg1, msg); + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 2, count); + + /* Retrieve the second message using fd_fifo_timedget */ + CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); + ts.tv_sec += 1; /* Set the timeout to 1 second */ + CHECK( 0, fd_fifo_timedget(queue, &msg, &ts) ); + CHECK( msg2, msg); + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 1, count); + + /* Retrieve the third message using meq_tryget */ + CHECK( 0, fd_fifo_tryget(queue, &msg) ); + CHECK( msg3, msg); + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 0, count); + + /* Check that another meq_tryget does not block */ + CHECK( EWOULDBLOCK, fd_fifo_tryget(queue, &msg) ); + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 0, count); + + /* We're done for basic tests */ + CHECK( 0, fd_fifo_del(&queue) ); + } + + /* Test robustness, ensure no messages are lost */ + { +#define NBR_MSG 200 +#define NBR_THREADS 60 + struct fifo *queue = NULL; + pthread_barrier_t bar; + struct test_data td_1; + struct test_data td_2; + struct msg *msgs[NBR_MSG * NBR_THREADS * 2], *msg; + pthread_t thr [NBR_THREADS * 2]; + struct dict_object *dwr_model = NULL; + int count; + int i; + + /* Create the queue */ + CHECK( 0, fd_fifo_new(&queue) ); + + /* Create the barrier */ + CHECK( 0, pthread_barrier_init(&bar, NULL, NBR_THREADS * 2 + 1) ); + + /* Initialize the ts */ + CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); + ts.tv_sec += 2; /* Set the timeout to 2 second */ + + /* Create the messages */ + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) ); + for (i = 0; i < NBR_MSG * NBR_THREADS * 2; i++) { + CHECK( 0, fd_msg_new ( dwr_model, 0, &msgs[i] ) ); + } + + /* Initialize the test data structures */ + td_1.queue = queue; + td_1.bar = &bar; + td_1.ts = &ts; + td_1.nbr = NBR_MSG; + td_2.queue = queue; + td_2.bar = &bar; + td_2.ts = NULL; + td_2.nbr = NBR_MSG; + + /* Create the threads */ + for (i=0; i < NBR_THREADS * 2; i++) { + CHECK( 0, pthread_create( &thr[i], NULL, test_fct, (i & 1) ? &td_1 : &td_2 ) ); + } + + /* Synchronize everyone */ + { + int ret = pthread_barrier_wait(&bar); + if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { + CHECK( 0, ret); + } else { + CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* for trace only */ + } + } + + /* Now post all the messages */ + for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) { + msg = msgs[i]; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } + + /* Join all threads. This blocks if messages are lost... */ + for (i=0; i < NBR_THREADS * 2; i++) { + CHECK( 0, pthread_join( thr[i], NULL ) ); + } + + /* Check the count of the queue is back to 0 */ + CHECK( 0, fd_fifo_length(queue, &count) ); + CHECK( 0, count); + + /* Destroy this queue and the messages */ + CHECK( 0, fd_fifo_del(&queue) ); + for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) { + CHECK( 0, fd_msg_free( msgs[i] ) ); + } + } + + /* Test thread cancelation */ + { + struct fifo *queue = NULL; + pthread_barrier_t bar; + struct test_data td; + pthread_t th; + + /* Create the queue */ + CHECK( 0, fd_fifo_new(&queue) ); + + /* Create the barrier */ + CHECK( 0, pthread_barrier_init(&bar, NULL, 2) ); + + /* Initialize the ts */ + CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); + ts.tv_sec += 2; /* Set the timeout to 2 second */ + + /* Initialize the test data structures */ + td.queue = queue; + td.bar = &bar; + td.ts = &ts; + td.nbr = 1; + + /* Create the thread */ + CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) ); + + /* Wait for the thread to be running */ + { + int ret = pthread_barrier_wait(&bar); + if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { + CHECK( 0, ret); + } else { + CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret ); + } + } + + /* Now cancel the thread */ + CHECK( 0, pthread_cancel( th ) ); + + /* Join it */ + CHECK( 0, pthread_join( th, NULL ) ); + + /* Do the same with the other function */ + td.ts = NULL; + + /* Create the thread */ + CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) ); + + /* Wait for the thread to be running */ + { + int ret = pthread_barrier_wait(&bar); + if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { + CHECK( 0, ret); + } else { + CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret ); + } + } + + /* Now cancel the thread */ + CHECK( 0, pthread_cancel( th ) ); + + /* Join it */ + CHECK( 0, pthread_join( th, NULL ) ); + + /* Destroy the queue */ + CHECK( 0, fd_fifo_del(&queue) ); + } + + /* Test the threashold function */ + { + struct fifo * queue = NULL; + int i; + struct msg * msg = NULL; + + /* Create the queue */ + CHECK( 0, fd_fifo_new(&queue) ); + + /* Prepare the test data */ + memset(&thrh_td, 0, sizeof(thrh_td)); + thrh_td.queue = queue; + + /* Set the thresholds for the queue */ + CHECK( 0, fd_fifo_setthrhd ( queue, NULL, 6, thrh_cb_h, 4, thrh_cb_l ) ); + + /* Post 5 messages, no cb must be called. */ + for (i=0; i<5; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 5 msg in queue */ + CHECK( 0, thrh_td.h_calls ); + CHECK( 0, thrh_td.l_calls ); + + /* Get all these messages, and check again */ + for (i=0; i<5; i++) { + CHECK( 0, fd_fifo_get(queue, &msg) ); + } /* 0 msg in queue */ + CHECK( 0, thrh_td.h_calls ); + CHECK( 0, thrh_td.l_calls ); + + /* Now, post 6 messages, the high threashold */ + for (i=0; i<6; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 6 msg in queue */ + CHECK( 1, thrh_td.h_calls ); + CHECK( 0, thrh_td.l_calls ); + + /* Remove 2 messages, to reach the low threshold */ + for (i=0; i<2; i++) { + CHECK( 0, fd_fifo_get(queue, &msg) ); + } /* 4 msg in queue */ + CHECK( 1, thrh_td.h_calls ); + CHECK( 1, thrh_td.l_calls ); + + /* Come again at the high threshold */ + for (i=0; i<2; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 6 msg in queue */ + CHECK( 2, thrh_td.h_calls ); + CHECK( 1, thrh_td.l_calls ); + + /* Suppose the queue continues to grow */ + for (i=0; i<6; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 12 msg in queue */ + CHECK( 3, thrh_td.h_calls ); + CHECK( 1, thrh_td.l_calls ); + for (i=0; i<5; i++) { + msg = msg1; + CHECK( 0, fd_fifo_post(queue, &msg) ); + } /* 17 msg in queue */ + CHECK( 3, thrh_td.h_calls ); + CHECK( 1, thrh_td.l_calls ); + + /* Now the queue goes back to 0 messages */ + for (i=0; i<17; i++) { + CHECK( 0, fd_fifo_get(queue, &msg) ); + } /* 0 msg in queue */ + CHECK( 3, thrh_td.h_calls ); + CHECK( 3, thrh_td.l_calls ); + + /* We're done for this test */ + CHECK( 0, fd_fifo_del(&queue) ); + } + + /* Delete the messages */ + CHECK( 0, fd_msg_free( msg1 ) ); + CHECK( 0, fd_msg_free( msg2 ) ); + CHECK( 0, fd_msg_free( msg3 ) ); + + /* That's all for the tests yet */ + PASSTEST(); +} diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/tests/testmesg.c --- a/freeDiameter/tests/testmesg.c Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/tests/testmesg.c Fri Sep 25 16:12:08 2009 +0900 @@ -50,7 +50,7 @@ struct dict_object * acr_model = NULL; /* Now find the ACR dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); /* Create the instance, using the templates */ CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) ); @@ -70,7 +70,7 @@ struct dict_object * pi_model = NULL; /* Now find the ACR dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &pi_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Proxy-Info", &pi_model, ENOENT ) ); /* Create the instance, using the templates */ CHECK( 0, fd_msg_avp_new ( pi_model, 0, &pi ) ); @@ -132,7 +132,7 @@ struct dict_object * rr_model = NULL; /* Now find the dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &rr_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Route-Record", &rr_model, ENOENT ) ); /* Create the instance, using the templates */ CHECK( 0, fd_msg_avp_new ( rr_model, 0, &avp1 ) ); @@ -160,7 +160,7 @@ struct dict_object * acr_model = NULL; /* Now find the ACR dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); /* Create the instance, using the templates */ CHECK( 0, fd_msg_new ( acr_model, 0, &acr ) ); @@ -172,25 +172,25 @@ struct dict_object * vendor; { struct dict_vendor_data vendor_data = { 73565, "Vendor test" }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_VENDOR, &vendor_data , NULL, &vendor ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_VENDOR, &vendor_data , NULL, &vendor ) ); } { struct dict_application_data app_data = { 73566, "Application test" }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_APPLICATION, &app_data , vendor, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_APPLICATION, &app_data , vendor, NULL ) ); } { struct dict_avp_data avp_data = { 73567, 0, "AVP Test - no vendor - f32", 0, 0, AVP_TYPE_FLOAT32 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_object * type = NULL; struct dict_type_data type_data = { AVP_TYPE_INTEGER64, "Int64 test" }; struct dict_avp_data avp_data = { 73568, 73565, "AVP Test - i64", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER64 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data , NULL, &type ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) ); } { @@ -201,19 +201,19 @@ struct dict_enumval_data val3 = { "i32 const test (val -5)",{ .i32 = -5 } }; struct dict_avp_data avp_data = { 73569, 73565, "AVP Test - enumi32", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_INTEGER32 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data , NULL, &type ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val3 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val3 , type, NULL ) ); } { struct dict_object * type = NULL; struct dict_type_data type_data = { AVP_TYPE_OCTETSTRING, "OS test" }; struct dict_avp_data avp_data = { 73570, 73565, "AVP Test - os", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data , NULL, &type ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) ); } { @@ -224,31 +224,31 @@ struct dict_enumval_data val3 = { "os const test (waa)", { .os = { (unsigned char *)"waaad", 3 } } }; struct dict_avp_data avp_data = { 73571, 73565, "AVP Test - enumos", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_OCTETSTRING }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_TYPE, &type_data , NULL, &type ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_ENUMVAL, &val3 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val3 , type, NULL ) ); } { struct dict_object * gavp = NULL; struct dict_avp_data avp_data = { 73572, 73565, "AVP Test - grouped", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, &gavp ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, &gavp ) ); /* Macro to search AVP and create a rule */ #define ADD_RULE( _parent, _vendor, _avpname, _pos, _min, _max, _ord ) { \ struct dict_object * _avp = NULL; \ struct dict_avp_request _req = { (_vendor), 0, (_avpname) }; \ struct dict_rule_data _data; \ - CHECK( 0, fd_dict_search( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\ + CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\ _data.rule_avp = _avp; \ _data.rule_position = (_pos); \ _data.rule_order = (_ord); \ _data.rule_min = (_min); \ _data.rule_max = (_max); \ - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_RULE, &_data , (_parent), NULL ) ); \ + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_RULE, &_data , (_parent), NULL ) ); \ } ADD_RULE(gavp, 73565, "AVP Test - os", RULE_OPTIONAL, -1, -1, 0); @@ -260,8 +260,8 @@ struct dict_object * command = NULL; struct dict_cmd_data cmd_data = { 73573, "Test-Command-Request", CMD_FLAG_REQUEST, CMD_FLAG_REQUEST }; - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) ); - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_COMMAND, &cmd_data , application, &command ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd_data , application, &command ) ); ADD_RULE(command, 0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD, -1, 1, 1); ADD_RULE(command, 73565, "AVP Test - i64", RULE_REQUIRED, -1, -1, 0); ADD_RULE(command, 73565, "AVP Test - enumi32", RULE_OPTIONAL, -1, -1, 0); @@ -274,7 +274,7 @@ struct dict_object * gavp = NULL; struct dict_avp_data avp_data = { 73574, 73565, "AVP Test - rules", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_GROUPED }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, &gavp ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, &gavp ) ); ADD_RULE(gavp, 0, "AVP Test - no vendor - f32", RULE_FIXED_HEAD, 0, 1, 1); ADD_RULE(gavp, 73565, "AVP Test - i64", RULE_FIXED_HEAD, -1, 1, 2); @@ -302,11 +302,11 @@ struct avp * avp = NULL; union avp_value value; - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) ); /* Check an error is trigged if the AVP has no value set */ { - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) ); CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) ); CHECK( 0, fd_msg_avp_new ( avp_model, 0, &avp ) ); @@ -328,7 +328,7 @@ #define ADD_AVP( _parent, _position, _avpi, _avpvendor, _avpname) { \ struct dict_object * _avp = NULL; \ struct dict_avp_request _req = { (_avpvendor), 0, (_avpname) }; \ - CHECK( 0, fd_dict_search( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\ + CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT));\ CHECK( 0, fd_msg_avp_new ( _avp, 0, &_avpi ) ); \ CHECK( 0, fd_msg_avp_add ( (_parent), (_position), _avpi ) ); \ } @@ -377,11 +377,11 @@ struct dict_enumval_request request; CHECK( 0, fd_msg_model ( avpi, &avp_model ) ); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); memset(&request, 0, sizeof(request)); request.type_obj = type_model; request.search.enum_name = "i32 const test (val 2)"; - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); CHECK( 0, fd_dict_getval ( value_model, &request.search ) ); CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) ); #if 0 @@ -398,11 +398,11 @@ struct dict_enumval_request request; CHECK( 0, fd_msg_model ( avpi, &avp_model ) ); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); memset(&request, 0, sizeof(request)); request.type_obj = type_model; request.search.enum_name = "i32 const test (val -5)"; - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); CHECK( 0, fd_dict_getval ( value_model, &request.search ) ); CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) ); #if 0 @@ -457,11 +457,11 @@ struct dict_enumval_request request; CHECK( 0, fd_msg_model ( avpi, &avp_model ) ); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); memset(&request, 0, sizeof(request)); request.type_obj = type_model; request.search.enum_name = "os const test (waaad)"; - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); CHECK( 0, fd_dict_getval ( value_model, &request.search ) ); CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) ); #if 0 @@ -482,11 +482,11 @@ struct dict_enumval_request request; CHECK( 0, fd_msg_model ( avpi, &avp_model ) ); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, avp_model, &type_model, ENOENT ) ); memset(&request, 0, sizeof(request)); request.type_obj = type_model; request.search.enum_name = "os const test (waa)"; - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &request, &value_model, ENOENT ) ); CHECK( 0, fd_dict_getval ( value_model, &request.search ) ); CHECK( 0, fd_msg_avp_setvalue ( avpi, &request.search.enum_value ) ); #if 0 @@ -653,7 +653,7 @@ struct avp_hdr * avpdata = NULL; /* Now find the ACR dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "AVP Test - no vendor - f32", &avp_model, ENOENT ) ); CPYBUF(); CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) ); @@ -679,7 +679,7 @@ /* Change the command-code */ buf_cpy[5] = 0x11; CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) ); - CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); + CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_config->cnf_dict ) ); /* reset */ CHECK( 0, fd_msg_free ( msg ) ); @@ -694,7 +694,7 @@ /* Check that we cannot support this message now */ CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) ); - CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); + CHECK( ENOTSUP, fd_msg_parse_dict( msg, fd_g_config->cnf_dict ) ); /* reset */ CHECK( 0, fd_msg_free ( msg ) ); @@ -708,7 +708,7 @@ /* Check that we can support this message now */ CHECK( 0, fd_msg_parse_buffer( &buf_cpy, 344, &msg) ); - CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); + CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict ) ); #if 0 fd_msg_dump_walk(0, msg); @@ -719,7 +719,7 @@ } CHECK( 0, fd_msg_parse_buffer( &buf, 344, &msg) ); - CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); + CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict ) ); #if 0 fd_msg_dump_walk(0, msg); #endif @@ -729,7 +729,7 @@ { struct dict_object * rule; - CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->g_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &rule ) ); /* Use the "AVP Test - rules" AVP to test the rules */ { @@ -748,26 +748,26 @@ ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - grouped" ); /* Check the message is still conform */ - CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->g_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &rule ) ); /* The first avp is optional in fixed position, so remove it and check the message is still OK */ CHECK( 0, fd_msg_browse ( tavp, MSG_BRW_FIRST_CHILD, &childavp, NULL) ); CHECK( 0, fd_msg_free ( childavp ) ); - CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->g_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &rule ) ); ADD_AVP( tavp, MSG_BRW_FIRST_CHILD, childavp, 0, "AVP Test - no vendor - f32" ); /* Now break some rules and check it is detected */ #define CHECK_CONFLICT( _msg, _ruleavp, _avpvendor ) { \ struct dict_object * _rule; \ - CHECK( EBADMSG, fd_msg_parse_rules( _msg, fd_g_config->g_dict, &_rule ) ); \ + CHECK( EBADMSG, fd_msg_parse_rules( _msg, fd_g_config->cnf_dict, &_rule ) ); \ if ((_ruleavp) == NULL) { \ CHECK( NULL, _rule); \ } else { \ struct dict_rule_data _ruledata; \ struct dict_object * _avp; \ struct dict_avp_request _req = { (_avpvendor), 0, (_ruleavp) }; \ - CHECK( 0, fd_dict_search( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT)); \ + CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT)); \ CHECK( 0, fd_dict_getval( _rule, &_ruledata ) ); \ CHECK( _avp, _ruledata.rule_avp ); \ } \ @@ -823,7 +823,7 @@ ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" ); /* The message is still conform */ - CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->g_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &rule ) ); /* Now break the rule */ ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" ); @@ -864,10 +864,10 @@ struct sockaddr_in6 sin6, *psin6; /* Find the CER dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) ); /* Now find the Host-IP-Address dictionary object */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &hia_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &hia_model, ENOENT ) ); /* Create the msg instance */ CHECK( 0, fd_msg_new ( cer_model, 0, &cer ) ); @@ -944,7 +944,7 @@ /* Ok, now let's recreate the message */ CHECK( 0, fd_msg_parse_buffer( &buf, 64, &cer) ); - CHECK( 0, fd_msg_parse_dict( cer, fd_g_config->g_dict ) ); + CHECK( 0, fd_msg_parse_dict( cer, fd_g_config->cnf_dict ) ); /* Get the pointers to the first and last AVP */ CHECK( 0, fd_msg_browse( cer, MSG_BRW_FIRST_CHILD, &avp4, NULL) ); @@ -971,31 +971,31 @@ { { struct dict_avp_data avp_data = { 91001, 0, "AVP Test 2 - os", 0, 0, AVP_TYPE_OCTETSTRING }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91002, 0, "AVP Test 2 - i32", 0, 0, AVP_TYPE_INTEGER32 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91003, 0, "AVP Test 2 - i64", 0, 0, AVP_TYPE_INTEGER64 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91004, 0, "AVP Test 2 - u32", 0, 0, AVP_TYPE_UNSIGNED32 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91005, 0, "AVP Test 2 - u64", 0, 0, AVP_TYPE_UNSIGNED64 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91006, 0, "AVP Test 2 - f32", 0, 0, AVP_TYPE_FLOAT32 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { struct dict_avp_data avp_data = { 91007, 0, "AVP Test 2 - f64", 0, 0, AVP_TYPE_FLOAT64 }; - CHECK( 0, fd_dict_new ( fd_g_config->g_dict, DICT_AVP, &avp_data , NULL, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , NULL, NULL ) ); } { @@ -1009,7 +1009,7 @@ struct avp_hdr * avpdata = NULL; struct msg_hdr * msgdata = NULL; - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) ); + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Request", &cmd_model, ENOENT ) ); /* Create a message */ CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) ); @@ -1174,7 +1174,7 @@ CHECK( 0, fd_msg_free( msg ) ); CHECK( 0, fd_msg_parse_buffer( &buf, 148, &msg) ); - CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->g_dict ) ); + CHECK( 0, fd_msg_parse_dict( msg, fd_g_config->cnf_dict ) ); #if 0 fd_msg_dump_walk(0, msg); #endif diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/tests/testqueues.c --- a/freeDiameter/tests/testqueues.c Thu Sep 24 14:01:48 2009 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,423 +0,0 @@ -/********************************************************************************************************* -* Software License Agreement (BSD License) * -* Author: Sebastien Decugis * -* * -* Copyright (c) 2009, WIDE Project and NICT * -* All rights reserved. * -* * -* Redistribution and use of this software in source and binary forms, with or without modification, are * -* permitted provided that the following conditions are met: * -* * -* * Redistributions of source code must retain the above * -* copyright notice, this list of conditions and the * -* following disclaimer. * -* * -* * Redistributions in binary form must reproduce the above * -* copyright notice, this list of conditions and the * -* following disclaimer in the documentation and/or other * -* materials provided with the distribution. * -* * -* * Neither the name of the WIDE Project or NICT nor the * -* names of its contributors may be used to endorse or * -* promote products derived from this software without * -* specific prior written permission of WIDE Project and * -* NICT. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * -* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * -* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -*********************************************************************************************************/ - -#include "tests.h" - -/* Structure for testing threshold function */ -static struct thrh_test { - struct fifo * queue; /* pointer to the queue */ - int h_calls; /* number of calls of h_cb */ - int l_calls; /* number of calls of l_cb */ -} thrh_td; - -/* Callbacks for threasholds test */ -void thrh_cb_h(struct fifo *queue, void **data) -{ - if (thrh_td.h_calls == thrh_td.l_calls) { - CHECK( NULL, *data ); - *data = &thrh_td; - } else { - CHECK( *data, &thrh_td ); - } - CHECK( queue, thrh_td.queue ); - - /* Update the count */ - thrh_td.h_calls ++; -} -void thrh_cb_l(struct fifo *queue, void **data) -{ - CHECK( 1, data ? 1 : 0 ); - CHECK( *data, &thrh_td ); - - /* Check the queue parameter is correct */ - CHECK( queue, thrh_td.queue ); - - /* Update the count */ - thrh_td.l_calls ++; - /* Cleanup the data ptr if needed */ - if (thrh_td.l_calls == thrh_td.h_calls) - *data = NULL; - /* done */ -} - - -/* Structure that is passed to the test function */ -struct test_data { - struct fifo * queue; /* pointer to the queue */ - pthread_barrier_t * bar; /* if not NULL, barrier to synchronize before getting messages */ - struct timespec * ts; /* if not NULL, use a timedget instead of a get */ - int nbr; /* number of messages to retrieve from the queue */ -}; - -/* The test function, to be threaded */ -static void * test_fct(void * data) -{ - int ret = 0, i; - struct msg * msg = NULL; - struct test_data * td = (struct test_data *) data; - - if (td->bar != NULL) { - ret = pthread_barrier_wait(td->bar); - if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { - CHECK( 0, ret); - } else { - CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* just for the traces */ - } - } - - for (i=0; i< td->nbr; i++) { - if (td->ts != NULL) { - CHECK( 0, fd_fifo_timedget(td->queue, &msg, td->ts) ); - } else { - CHECK( 0, fd_fifo_get(td->queue, &msg) ); - } - } - - return NULL; -} - - -/* Main test routine */ -int main(int argc, char *argv[]) -{ - struct timespec ts; - - struct msg * msg1 = NULL; - struct msg * msg2 = NULL; - struct msg * msg3 = NULL; - - /* First, initialize the daemon modules */ - INIT_FD(); - - /* Prolog: create the messages */ - { - struct dict_object * acr_model = NULL; - struct dict_object * cer_model = NULL; - struct dict_object * dwr_model = NULL; - - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) ); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) ); - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) ); - CHECK( 0, fd_msg_new ( acr_model, 0, &msg1 ) ); - CHECK( 0, fd_msg_new ( cer_model, 0, &msg2 ) ); - CHECK( 0, fd_msg_new ( dwr_model, 0, &msg3 ) ); - } - - /* Basic operation */ - { - struct fifo * queue = NULL; - int count; - struct msg * msg = NULL; - - /* Create the queue */ - CHECK( 0, fd_fifo_new(&queue) ); - - /* Check the count is 0 */ - CHECK( 0, fd_fifo_length(queue, &count) ); - CHECK( 0, count); - - /* Now enqueue */ - msg = msg1; - CHECK( 0, fd_fifo_post(queue, &msg) ); - msg = msg2; - CHECK( 0, fd_fifo_post(queue, &msg) ); - msg = msg3; - CHECK( 0, fd_fifo_post(queue, &msg) ); - - /* Check the count is 3 */ - CHECK( 0, fd_fifo_length(queue, &count) ); - CHECK( 3, count); - - /* Retrieve the first message using fd_fifo_get */ - CHECK( 0, fd_fifo_get(queue, &msg) ); - CHECK( msg1, msg); - CHECK( 0, fd_fifo_length(queue, &count) ); - CHECK( 2, count); - - /* Retrieve the second message using fd_fifo_timedget */ - CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); - ts.tv_sec += 1; /* Set the timeout to 1 second */ - CHECK( 0, fd_fifo_timedget(queue, &msg, &ts) ); - CHECK( msg2, msg); - CHECK( 0, fd_fifo_length(queue, &count) ); - CHECK( 1, count); - - /* Retrieve the third message using meq_tryget */ - CHECK( 0, fd_fifo_tryget(queue, &msg) ); - CHECK( msg3, msg); - CHECK( 0, fd_fifo_length(queue, &count) ); - CHECK( 0, count); - - /* Check that another meq_tryget does not block */ - CHECK( EWOULDBLOCK, fd_fifo_tryget(queue, &msg) ); - CHECK( 0, fd_fifo_length(queue, &count) ); - CHECK( 0, count); - - /* We're done for basic tests */ - CHECK( 0, fd_fifo_del(&queue) ); - } - - /* Test robustness, ensure no messages are lost */ - { -#define NBR_MSG 200 -#define NBR_THREADS 60 - struct fifo *queue = NULL; - pthread_barrier_t bar; - struct test_data td_1; - struct test_data td_2; - struct msg *msgs[NBR_MSG * NBR_THREADS * 2], *msg; - pthread_t thr [NBR_THREADS * 2]; - struct dict_object *dwr_model = NULL; - int count; - int i; - - /* Create the queue */ - CHECK( 0, fd_fifo_new(&queue) ); - - /* Create the barrier */ - CHECK( 0, pthread_barrier_init(&bar, NULL, NBR_THREADS * 2 + 1) ); - - /* Initialize the ts */ - CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); - ts.tv_sec += 2; /* Set the timeout to 2 second */ - - /* Create the messages */ - CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) ); - for (i = 0; i < NBR_MSG * NBR_THREADS * 2; i++) { - CHECK( 0, fd_msg_new ( dwr_model, 0, &msgs[i] ) ); - } - - /* Initialize the test data structures */ - td_1.queue = queue; - td_1.bar = &bar; - td_1.ts = &ts; - td_1.nbr = NBR_MSG; - td_2.queue = queue; - td_2.bar = &bar; - td_2.ts = NULL; - td_2.nbr = NBR_MSG; - - /* Create the threads */ - for (i=0; i < NBR_THREADS * 2; i++) { - CHECK( 0, pthread_create( &thr[i], NULL, test_fct, (i & 1) ? &td_1 : &td_2 ) ); - } - - /* Synchronize everyone */ - { - int ret = pthread_barrier_wait(&bar); - if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { - CHECK( 0, ret); - } else { - CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* for trace only */ - } - } - - /* Now post all the messages */ - for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) { - msg = msgs[i]; - CHECK( 0, fd_fifo_post(queue, &msg) ); - } - - /* Join all threads. This blocks if messages are lost... */ - for (i=0; i < NBR_THREADS * 2; i++) { - CHECK( 0, pthread_join( thr[i], NULL ) ); - } - - /* Check the count of the queue is back to 0 */ - CHECK( 0, fd_fifo_length(queue, &count) ); - CHECK( 0, count); - - /* Destroy this queue and the messages */ - CHECK( 0, fd_fifo_del(&queue) ); - for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) { - CHECK( 0, fd_msg_free( msgs[i] ) ); - } - } - - /* Test thread cancelation */ - { - struct fifo *queue = NULL; - pthread_barrier_t bar; - struct test_data td; - pthread_t th; - - /* Create the queue */ - CHECK( 0, fd_fifo_new(&queue) ); - - /* Create the barrier */ - CHECK( 0, pthread_barrier_init(&bar, NULL, 2) ); - - /* Initialize the ts */ - CHECK(0, clock_gettime(CLOCK_REALTIME, &ts)); - ts.tv_sec += 2; /* Set the timeout to 2 second */ - - /* Initialize the test data structures */ - td.queue = queue; - td.bar = &bar; - td.ts = &ts; - td.nbr = 1; - - /* Create the thread */ - CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) ); - - /* Wait for the thread to be running */ - { - int ret = pthread_barrier_wait(&bar); - if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { - CHECK( 0, ret); - } else { - CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret ); - } - } - - /* Now cancel the thread */ - CHECK( 0, pthread_cancel( th ) ); - - /* Join it */ - CHECK( 0, pthread_join( th, NULL ) ); - - /* Do the same with the other function */ - td.ts = NULL; - - /* Create the thread */ - CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) ); - - /* Wait for the thread to be running */ - { - int ret = pthread_barrier_wait(&bar); - if (ret != PTHREAD_BARRIER_SERIAL_THREAD) { - CHECK( 0, ret); - } else { - CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret ); - } - } - - /* Now cancel the thread */ - CHECK( 0, pthread_cancel( th ) ); - - /* Join it */ - CHECK( 0, pthread_join( th, NULL ) ); - - /* Destroy the queue */ - CHECK( 0, fd_fifo_del(&queue) ); - } - - /* Test the threashold function */ - { - struct fifo * queue = NULL; - int i; - struct msg * msg = NULL; - - /* Create the queue */ - CHECK( 0, fd_fifo_new(&queue) ); - - /* Prepare the test data */ - memset(&thrh_td, 0, sizeof(thrh_td)); - thrh_td.queue = queue; - - /* Set the thresholds for the queue */ - CHECK( 0, fd_fifo_setthrhd ( queue, NULL, 6, thrh_cb_h, 4, thrh_cb_l ) ); - - /* Post 5 messages, no cb must be called. */ - for (i=0; i<5; i++) { - msg = msg1; - CHECK( 0, fd_fifo_post(queue, &msg) ); - } /* 5 msg in queue */ - CHECK( 0, thrh_td.h_calls ); - CHECK( 0, thrh_td.l_calls ); - - /* Get all these messages, and check again */ - for (i=0; i<5; i++) { - CHECK( 0, fd_fifo_get(queue, &msg) ); - } /* 0 msg in queue */ - CHECK( 0, thrh_td.h_calls ); - CHECK( 0, thrh_td.l_calls ); - - /* Now, post 6 messages, the high threashold */ - for (i=0; i<6; i++) { - msg = msg1; - CHECK( 0, fd_fifo_post(queue, &msg) ); - } /* 6 msg in queue */ - CHECK( 1, thrh_td.h_calls ); - CHECK( 0, thrh_td.l_calls ); - - /* Remove 2 messages, to reach the low threshold */ - for (i=0; i<2; i++) { - CHECK( 0, fd_fifo_get(queue, &msg) ); - } /* 4 msg in queue */ - CHECK( 1, thrh_td.h_calls ); - CHECK( 1, thrh_td.l_calls ); - - /* Come again at the high threshold */ - for (i=0; i<2; i++) { - msg = msg1; - CHECK( 0, fd_fifo_post(queue, &msg) ); - } /* 6 msg in queue */ - CHECK( 2, thrh_td.h_calls ); - CHECK( 1, thrh_td.l_calls ); - - /* Suppose the queue continues to grow */ - for (i=0; i<6; i++) { - msg = msg1; - CHECK( 0, fd_fifo_post(queue, &msg) ); - } /* 12 msg in queue */ - CHECK( 3, thrh_td.h_calls ); - CHECK( 1, thrh_td.l_calls ); - for (i=0; i<5; i++) { - msg = msg1; - CHECK( 0, fd_fifo_post(queue, &msg) ); - } /* 17 msg in queue */ - CHECK( 3, thrh_td.h_calls ); - CHECK( 1, thrh_td.l_calls ); - - /* Now the queue goes back to 0 messages */ - for (i=0; i<17; i++) { - CHECK( 0, fd_fifo_get(queue, &msg) ); - } /* 0 msg in queue */ - CHECK( 3, thrh_td.h_calls ); - CHECK( 3, thrh_td.l_calls ); - - /* We're done for this test */ - CHECK( 0, fd_fifo_del(&queue) ); - } - - /* Delete the messages */ - CHECK( 0, fd_msg_free( msg1 ) ); - CHECK( 0, fd_msg_free( msg2 ) ); - CHECK( 0, fd_msg_free( msg3 ) ); - - /* That's all for the tests yet */ - PASSTEST(); -} diff -r fc7c18867cf7 -r c5c99c73c2bf freeDiameter/tests/tests.h --- a/freeDiameter/tests/tests.h Thu Sep 24 14:01:48 2009 +0900 +++ b/freeDiameter/tests/tests.h Fri Sep 25 16:12:08 2009 +0900 @@ -103,7 +103,7 @@ CHECK( 0, fd_lib_init() ); \ fd_log_threadname(basename(__FILE__)); \ CHECK( 0, fd_conf_init() ); \ - CHECK( 0, fd_dict_base_protocol(fd_g_config->g_dict) ); \ + CHECK( 0, fd_dict_base_protocol(fd_g_config->cnf_dict) ); \ parse_cmdline(argc, argv); \ } diff -r fc7c18867cf7 -r c5c99c73c2bf include/freeDiameter/freeDiameter.h --- a/include/freeDiameter/freeDiameter.h Thu Sep 24 14:01:48 2009 +0900 +++ b/include/freeDiameter/freeDiameter.h Fri Sep 25 16:12:08 2009 +0900 @@ -42,54 +42,65 @@ /* Structure to hold the configuration of the freeDiameter daemon */ struct fd_config { - int eyec; /* Eye catcher: EYEC_CONFIG */ - char *conf_file; /* Configuration file to parse, default is DEFAULT_CONF_FILE */ + int cnf_eyec; /* Eye catcher: EYEC_CONFIG */ + #define EYEC_CONFIG 0xC011F16 + + char *cnf_file; /* Configuration file to parse, default is DEFAULT_CONF_FILE */ + + char *cnf_diamid; /* Diameter Identity of the local peer (FQDN -- UTF-8) */ + size_t cnf_diamid_len; /* length of the previous string */ + char *cnf_diamrlm; /* Diameter realm of the local peer, default to realm part of diam_id */ + size_t cnf_diamrlm_len;/* length of the previous string */ - char *diam_id; /* Diameter Identity of the local peer (FQDN -- UTF-8) */ - size_t diam_id_len; /* length of the previous string */ - char *diam_realm; /* Diameter realm of the local peer, default to realm part of diam_id */ - size_t diam_realm_len;/* length of the previous string */ + unsigned int cnf_timer_tc; /* The value in seconds of the default Tc timer */ + unsigned int cnf_timer_tw; /* The value in seconds of the default Tw timer */ - uint16_t loc_port; /* the local port for legacy Diameter (default: 3868) in host byte order */ - uint16_t loc_port_tls; /* the local port for Diameter/TLS (default: 3869) in host byte order */ - uint16_t loc_sctp_str; /* default max number of streams for SCTP associations (def: 30) */ - struct fd_list loc_endpoints; /* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all) */ + uint16_t cnf_port; /* the local port for legacy Diameter (default: 3868) in host byte order */ + uint16_t cnf_port_tls; /* the local port for Diameter/TLS (default: 3869) in host byte order */ + uint16_t cnf_sctp_str; /* default max number of streams for SCTP associations (def: 30) */ + struct fd_list cnf_endpoints; /* the local endpoints to bind the server to. list of struct fd_endpoint. default is empty (bind all) */ + struct fd_list cnf_apps; /* Applications locally supported (except relay, see flags). Use fd_disp_app_support to add one. list of struct fd_app. */ struct { + unsigned no_fwd : 1; /* the peer does not relay messages (0xffffff app id) */ unsigned no_ip4 : 1; /* disable IP */ unsigned no_ip6 : 1; /* disable IPv6 */ unsigned no_tcp : 1; /* disable use of TCP */ unsigned no_sctp: 1; /* disable the use of SCTP */ unsigned pr_tcp : 1; /* prefer TCP over SCTP */ unsigned tls_alg: 1; /* TLS algorithm for initiated cnx. 0: separate port. 1: inband-security (old) */ - unsigned no_fwd : 1; /* the peer does not relay messages (0xffffff app id) */ - } flags; - - unsigned int timer_tc; /* The value in seconds of the default Tc timer */ - unsigned int timer_tw; /* The value in seconds of the default Tw timer */ + } cnf_flags; - uint32_t or_state_id; /* The value to use in Origin-State-Id, default to random value */ - struct dictionary *g_dict; /* pointer to the global dictionary */ - struct fifo *g_fifo_main; /* FIFO queue of events in the daemon main (struct fd_event items) */ + uint32_t cnf_orstateid; /* The value to use in Origin-State-Id, default to random value */ + struct dictionary *cnf_dict; /* pointer to the global dictionary */ + struct fifo *cnf_main_ev; /* events for the daemon's main (struct fd_event items) */ }; - -#define EYEC_CONFIG 0xC011F16 - -/* The pointer to access the global configuration, initalized in main */ -extern struct fd_config *fd_g_config; +extern struct fd_config *fd_g_config; /* The pointer to access the global configuration, initalized in main */ /* Endpoints */ struct fd_endpoint { - struct fd_list chain; /* link in loc_endpoints list */ + struct fd_list chain; /* link in cnf_endpoints list */ sSS ss; /* the socket information. */ }; +/* Applications */ +struct fd_app { + struct fd_list chain; /* link in cnf_apps list. List ordered by appid. */ + struct { + unsigned auth : 1; + unsigned acct : 1; + unsigned common : 1; + } flags; + vendor_id_t vndid; /* if not 0, Vendor-Specific-App-Id AVP will be used */ + application_id_t appid; /* The identifier of the application */ +}; + + /* Events */ struct fd_event { int code; /* codespace depends on the queue */ void *data; }; -/* send an event */ static __inline__ int fd_event_send(struct fifo *queue, int code, void * data) { struct fd_event * ev; @@ -99,7 +110,6 @@ CHECK_FCT( fd_fifo_post(queue, &ev) ); return 0; } -/* receive an event */ static __inline__ int fd_event_get(struct fifo *queue, int *code, void ** data) { struct fd_event * ev; @@ -112,6 +122,98 @@ return 0; } +/* Events codespace for fd_g_config->cnf_main_ev */ +enum { + FDEV_TERMINATE = 1000, /* request to terminate */ + FDEV_DUMP_DICT, /* Dump the content of the dictionary */ + FDEV_DUMP_EXT, /* Dump state of extensions */ + FDEV_DUMP_QUEUES, /* Dump the message queues */ + FDEV_DUMP_CONFIG, /* Dump the configuration */ + FDEV_DUMP_PEERS /* Dump the list of peers */ +}; + + + +/***************************************/ +/* Peers information */ +/***************************************/ + +/* States of a peer */ +enum peer_state { + /* Stable states */ + STATE_DISABLED = 1, /* No connexion must be attempted / only this state means that the peer PSM thread is not running */ + STATE_OPEN, /* Connexion established */ + + /* Peer state machine */ + STATE_CLOSED, /* No connection established, will re-attempt after TcTimer. */ + STATE_CLOSING, /* the connection is being shutdown (DPR/DPA in progress) */ + STATE_WAITCNXACK, /* Attempting to establish transport-level connection */ + STATE_WAITCNXACK_ELEC, /* Received a CER from this same peer on an incoming connection (other peer object), while we were waiting for cnx ack */ + STATE_WAITCEA, /* Connection established, CER sent, waiting for CEA */ + /* STATE_WAITRETURNS_ELEC, */ /* This state is not stable and therefore deprecated: + We have sent a CER on our initiated connection, and received a CER from the remote peer on another connection. Election. + If we win the election, we must disconnect the initiated connection and send a CEA on the other => we go to OPEN state. + If we lose, we disconnect the other connection (receiver) and fallback to WAITCEA state. */ + + /* Failover state machine */ + STATE_SUSPECT, /* A DWR was sent and not answered within TwTime. Failover in progress. */ + STATE_REOPEN /* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */ +}; +extern char *peer_state_str[]; + +/* Information about a remote peer, used both for query and for creating a new entry */ +struct peer_info { + + /* This information is always there */ + char * pi_diamid; /* UTF-8, \0 terminated. The Diameter Identity of the remote peer */ + char * pi_realm; /* idem, its realm. */ + + /* Flags */ + struct { + #define PI_PROT_DEFAULT 0 /* Use the default algorithm configured for the host */ + #define PI_PROT_TCP 1 + #define PI_PROT_SCTP 2 + unsigned proto :2; + + #define PI_SEC_DEFAULT 0 /* The default behavior configured for the host */ + #define PI_SEC_NONE 1 /* Transparent security with this peer (IPsec) */ + #define PI_SEC_TLS_NEW 2 /* New TLS security (dedicated port protecting also CER/CEA) */ + #define PI_SEC_TLS_OLD 3 /* Old TLS security (inband on default port) */ + unsigned sec :2; + + #define PI_EXP_DEFAULT 0 + #define PI_EXP_NONE 1 /* the peer entry does not expire */ + #define PI_EXP_INACTIVE 2 /* the peer entry expires after pi_lft seconds without activity */ + #define PI_EXP_LIFETIME 3 /* the peer SA information is destroyed after lft seconds (example: DNS timeout) */ + unsigned exp :2; + + /* Following flags are read-only and received from remote peer */ + #define PI_INB_NONE 1 /* Remote peer advertised inband-sec-id 0 (None) */ + #define PI_INB_TLS 2 /* Remote peer advertised inband-sec-id 1 (TLS) */ + unsigned inband :2; /* This is only meaningful with pi_flags.sec == 3 */ + + unsigned relay :1; /* The remote peer advertized the relay application */ + } pi_flags; + + /* Additional parameters */ + uint32_t pi_lft; /* lifetime of entry without activity (except watchdogs) (see pi_flags.exp definition) */ + uint16_t pi_streams; /* number of streams for SCTP. 0 = default */ + uint16_t pi_port; /* port to connect to. 0: default. */ + int pi_tctimer; /* use this value for TcTimer instead of global, if != 0 */ + int pi_twtimer; /* use this value for TwTimer instead of global, if != 0 */ + + struct fd_list pi_endpoints; /* Endpoint(s) of the remote peer (discovered or advertized). list of struct fd_endpoint. DNS resolved if empty. */ + + /* The remaining information is read-only, not used for peer creation */ + enum peer_state pi_state; + uint32_t pi_vendorid; /* Content of the Vendor-Id AVP, or 0 by default */ + uint32_t pi_orstate; /* Origin-State-Id value */ + char * pi_prodname; /* copy of UTF-8 Product-Name AVP (\0 terminated) */ + uint32_t pi_firmrev; /* Content of the Firmware-Revision AVP */ + struct fd_list pi_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */ +}; + + /***************************************/ /* Sending a message on the network */ /***************************************/ @@ -157,7 +259,6 @@ * * PARAMETERS: * msg : A msg object -- it must be an answer. - * dict : dictionary to use for AVP definitions * rescode : The name of the returned error code (ex: "DIAMETER_INVALID_AVP") * errormsg : (optional) human-readable error message to put in Error-Message AVP * optavp : (optional) If provided, the content will be put inside a Failed-AVP @@ -172,10 +273,10 @@ * 0 : Operation complete. * !0 : an error occurred. */ -int fd_msg_rescode_set( struct msg * msg, struct dictionary * dict, char * rescode, char * errormsg, struct avp * optavp, int type_id ); +int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id ); -/* The following functions are used to achieve frequent operations on the messages */ -int fd_msg_add_origin ( struct msg * msg, struct dictionary * dict, int osi ); /* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */ +/* Add Origin-Host, Origin-Realm, (if osi) Origin-State-Id AVPS at the end of the message */ +int fd_msg_add_origin ( struct msg * msg, int osi ); @@ -183,17 +284,14 @@ /* Dispatch module, daemon's part */ /***************************************/ -enum { - DISP_APP_AUTH = 1, - DISP_APP_ACCT = 2 -}; /* * FUNCTION: fd_disp_app_support * * PARAMETERS: * app : The dictionary object corresponding to the Application. * vendor : (Optional) the dictionary object of a Vendor to claim support in Vendor-Specific-Application-Id - * flags : Combination of DISP_APP_* flags. + * auth : Support auth app part. + * acct : Support acct app part. * * DESCRIPTION: * Registers an application to be advertized in CER/CEA exchanges. @@ -204,7 +302,7 @@ * 0 : The application support is registered. * EINVAL : A parameter is invalid. */ -int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int flags ); +int fd_disp_app_support ( struct dict_object * app, struct dict_object * vendor, int auth, int acct ); /* Note: if we want to support capabilities updates, we'll have to add possibility to remove an app as well... */ diff -r fc7c18867cf7 -r c5c99c73c2bf include/freeDiameter/libfreeDiameter.h --- a/include/freeDiameter/libfreeDiameter.h Thu Sep 24 14:01:48 2009 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Fri Sep 25 16:12:08 2009 +0900 @@ -170,7 +170,7 @@ if ( TRACE_BOOL(level) ) { \ char __buf[25]; \ char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"); \ - fd_log_debug("\t | th:%-30s\t%s\tin %s@%s:%d\n" \ + fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n" \ "\t%s|%*s" format "\n", \ __thn, fd_log_time(__buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__, \ (level < FULL)?"@":" ",level, "", ## args); \ @@ -2455,4 +2455,7 @@ #define fd_fifo_timedget(queue, item, abstime) \ fd_fifo_timedget_int((queue), (void *)(item), (abstime)) +/* Dump a fifo list and optionally its inner elements -- beware of deadlocks! */ +void fd_fifo_dump(int level, char * name, struct fifo * queue, void (*dump_item)(int level, void * item)); + #endif /* _LIBFREEDIAMETER_H */ diff -r fc7c18867cf7 -r c5c99c73c2bf libfreeDiameter/CMakeLists.txt --- a/libfreeDiameter/CMakeLists.txt Thu Sep 24 14:01:48 2009 +0900 +++ b/libfreeDiameter/CMakeLists.txt Fri Sep 25 16:12:08 2009 +0900 @@ -6,11 +6,11 @@ libfD.h dictionary.c dispatch.c + fifo.c init.c lists.c log.c messages.c - queues.c sessions.c ) diff -r fc7c18867cf7 -r c5c99c73c2bf libfreeDiameter/fifo.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libfreeDiameter/fifo.c Fri Sep 25 16:12:08 2009 +0900 @@ -0,0 +1,430 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2008, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +/* FIFO queues module. + * + * The threads that call these functions must be in the cancellation state PTHREAD_CANCEL_ENABLE and type PTHREAD_CANCEL_DEFERRED. + * This is the default state and type on thread creation. + * + * In order to destroy properly a queue, the application must: + * -> shutdown any process that can add into the queue first. + * -> pthread_cancel any thread that could be waiting on the queue. + * -> consume any element that is in the queue, using fd_qu_tryget_int. + * -> then destroy the queue using fd_mq_del. + */ + +#include "libfD.h" + +/* Definition of a FIFO queue object */ +struct fifo { + int eyec; /* An eye catcher, also used to check a queue is valid. FIFO_EYEC */ + + pthread_mutex_t mtx; /* Mutex protecting this queue */ + pthread_cond_t cond; /* condition variable of the list */ + + struct fd_list list; /* sentinel for the list of elements */ + int count; /* number of objects in the list */ + int thrs; /* number of threads waiting for a new element (when count is 0) */ + + uint16_t high; /* High level threshold (see libfreeDiameter.h for details) */ + uint16_t low; /* Low level threshhold */ + void *data; /* Opaque pointer for threshold callbacks */ + void (*h_cb)(struct fifo *, void **); /* The callbacks */ + void (*l_cb)(struct fifo *, void **); + int highest;/* The highest count value for which h_cb has been called */ +}; + +/* The eye catcher value */ +#define FIFO_EYEC 0xe7ec1130 + +/* Macro to check a pointer */ +#define CHECK_FIFO( _queue ) (( (_queue) != NULL) && ( (_queue)->eyec == FIFO_EYEC) ) + + +/* Create a new queue */ +int fd_fifo_new ( struct fifo ** queue ) +{ + struct fifo * new; + + TRACE_ENTRY( "%p", queue ); + + CHECK_PARAMS( queue ); + + /* Create a new object */ + CHECK_MALLOC( new = malloc (sizeof (struct fifo) ) ); + + /* Initialize the content */ + memset(new, 0, sizeof(struct fifo)); + + new->eyec = FIFO_EYEC; + CHECK_POSIX( pthread_mutex_init(&new->mtx, NULL) ); + CHECK_POSIX( pthread_cond_init(&new->cond, NULL) ); + + fd_list_init(&new->list, NULL); + + /* We're done */ + *queue = new; + return 0; +} + +/* Dump the content of a queue */ +void fd_fifo_dump(int level, char * name, struct fifo * queue, void (*dump_item)(int level, void * item)) +{ + TRACE_ENTRY("%i %p %p %p", level, name, queue, dump_item); + + if (!TRACE_BOOL(level)) + return; + + fd_log_debug("Dumping queue '%s' (%p):\n", name ?: "?", queue); + if (!CHECK_FIFO( queue )) { + fd_log_debug(" Queue invalid!\n"); + if (queue) + fd_log_debug(" (%x != %x)\n", queue->eyec, FIFO_EYEC); + return; + } + + CHECK_POSIX_DO( pthread_mutex_lock( &queue->mtx ), /* continue */ ); + fd_log_debug(" %d elements in queue\n", queue->count); + fd_log_debug(" %d threads waiting\n", queue->thrs); + fd_log_debug(" thresholds: %d / %d, cb: %p / %p (%p), highest: %d\n", + queue->high, queue->low, + queue->h_cb, queue->l_cb, queue->data, + queue->highest); + + if (dump_item) { + struct fd_list * li; + int i = 0; + for (li = queue->list.next; li != &queue->list; li = li->next) { + fd_log_debug(" [%i] item %p in fifo %p:\n", i++, li->o, queue); + (*dump_item)(level, li->o); + } + } + CHECK_POSIX_DO( pthread_mutex_unlock( &queue->mtx ), /* continue */ ); + +} + +/* Delete a queue. It must be unused. */ +int fd_fifo_del ( struct fifo ** queue ) +{ + struct fifo * q; + + TRACE_ENTRY( "%p", queue ); + + CHECK_PARAMS( queue && CHECK_FIFO( *queue ) ); + + q = *queue; + + CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); + + if ((q->count != 0) || (q->thrs != 0) || (q->data != NULL)) { + TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %d, %p)", q->count, q->thrs, q->data); + CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* no fallback */ ); + return EINVAL; + } + + /* sanity check */ + ASSERT(FD_IS_LIST_EMPTY(&q->list)); + + /* Ok, now invalidate the queue */ + q->eyec = 0xdead; + + /* And destroy it */ + CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) ); + + CHECK_POSIX( pthread_cond_destroy( &q->cond ) ); + + CHECK_POSIX( pthread_mutex_destroy( &q->mtx ) ); + + free(q); + *queue = NULL; + + return 0; +} + +/* Get the length of the queue */ +int fd_fifo_length ( struct fifo * queue, int * length ) +{ + TRACE_ENTRY( "%p %p", queue, length ); + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && length ); + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + + /* Retrieve the count */ + *length = queue->count; + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Done */ + return 0; +} + +/* alternate version with no error checking */ +int fd_fifo_length_noerr ( struct fifo * queue ) +{ + if ( !CHECK_FIFO( queue ) ) + return 0; + + return queue->count; /* Let's hope it's read atomically, since we are not locking... */ +} + +/* Set the thresholds of the queue */ +int fd_fifo_setthrhd ( struct fifo * queue, void * data, uint16_t high, void (*h_cb)(struct fifo *, void **), uint16_t low, void (*l_cb)(struct fifo *, void **) ) +{ + TRACE_ENTRY( "%p %p %hu %p %hu %p", queue, data, high, h_cb, low, l_cb ); + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && (high > low) && (queue->data == NULL) ); + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + + /* Save the values */ + queue->high = high; + queue->low = low; + queue->data = data; + queue->h_cb = h_cb; + queue->l_cb = l_cb; + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Done */ + return 0; +} + +/* Post a new item in the queue */ +int fd_fifo_post_int ( struct fifo * queue, void ** item ) +{ + struct fd_list * new; + int call_cb = 0; + + TRACE_ENTRY( "%p %p", queue, item ); + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && item && *item ); + + /* Create a new list item */ + CHECK_MALLOC( new = malloc (sizeof (struct fd_list)) ); + + fd_list_init(new, *item); + *item = NULL; + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + + /* Add the new item at the end */ + fd_list_insert_before( &queue->list, new); + queue->count++; + if (queue->high && ((queue->count % queue->high) == 0)) { + call_cb = 1; + queue->highest = queue->count; + } + + /* Signal if threads are asleep */ + if (queue->thrs > 0) { + CHECK_POSIX( pthread_cond_signal(&queue->cond) ); + } + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Call high-watermark cb as needed */ + if (call_cb && queue->h_cb) + (*queue->h_cb)(queue, &queue->data); + + /* Done */ + return 0; +} + +/* Pop the first item from the queue */ +static void * mq_pop(struct fifo * queue) +{ + void * ret = NULL; + struct fd_list * li; + + ASSERT( ! FD_IS_LIST_EMPTY(&queue->list) ); + + fd_list_unlink(li = queue->list.next); + queue->count--; + ret = li->o; + free(li); + + return ret; +} + +/* Check if the low watermark callback must be called. */ +static __inline__ int test_l_cb(struct fifo * queue) +{ + if ((queue->high == 0) || (queue->low == 0) || (queue->l_cb == 0)) + return 0; + + if (((queue->count % queue->high) == queue->low) && (queue->highest > queue->count)) { + queue->highest -= queue->high; + return 1; + } + + return 0; +} + +/* Try poping an item */ +int fd_fifo_tryget_int ( struct fifo * queue, void ** item ) +{ + int wouldblock = 0; + int call_cb = 0; + + TRACE_ENTRY( "%p %p", queue, item ); + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && item ); + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + + /* Check queue status */ + if (queue->count > 0) { + /* There are elements in the queue, so pick the first one */ + *item = mq_pop(queue); + call_cb = test_l_cb(queue); + } else { + wouldblock = 1; + *item = NULL; + } + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Call low watermark callback as needed */ + if (call_cb) + (*queue->l_cb)(queue, &queue->data); + + /* Done */ + return wouldblock ? EWOULDBLOCK : 0; +} + +/* This handler is called when a thread is blocked on a queue, and cancelled */ +static void fifo_cleanup(void * queue) +{ + struct fifo * q = (struct fifo *)queue; + TRACE_ENTRY( "%p", queue ); + + /* Check the parameter */ + if ( ! CHECK_FIFO( q )) { + TRACE_DEBUG(INFO, "Invalid queue, skipping handler"); + return; + } + + /* The thread has been cancelled, therefore it does not wait on the queue anymore */ + q->thrs--; + + /* Now unlock the queue, and we're done */ + CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* nothing */ ); + + /* End of cleanup handler */ + return; +} + +/* The internal function for fd_fifo_timedget and fd_fifo_get */ +static int fifo_tget ( struct fifo * queue, void ** item, int istimed, const struct timespec *abstime) +{ + int timedout = 0; + int call_cb = 0; + + /* Check the parameters */ + CHECK_PARAMS( CHECK_FIFO( queue ) && item && (abstime || !istimed) ); + + /* Initialize the return value */ + *item = NULL; + + /* lock the queue */ + CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); + +awaken: + /* Check queue status */ + if (queue->count > 0) { + /* There are items in the queue, so pick the first one */ + *item = mq_pop(queue); + call_cb = test_l_cb(queue); + } else { + int ret = 0; + /* We have to wait for a new item */ + queue->thrs++ ; + pthread_cleanup_push( fifo_cleanup, queue); + if (istimed) { + ret = pthread_cond_timedwait( &queue->cond, &queue->mtx, abstime ); + } else { + ret = pthread_cond_wait( &queue->cond, &queue->mtx ); + } + pthread_cleanup_pop(0); + queue->thrs-- ; + if (ret == 0) + goto awaken; /* test for spurious wake-ups */ + + if (istimed && (ret == ETIMEDOUT)) { + timedout = 1; + } else { + /* Unexpected error condition (means we need to debug) */ + ASSERT( ret == 0 /* never true */ ); + } + } + + /* Unlock */ + CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); + + /* Call low watermark callback as needed */ + if (call_cb) + (*queue->l_cb)(queue, &queue->data); + + /* Done */ + return timedout ? ETIMEDOUT : 0; +} + +/* Get the next available item, block until there is one */ +int fd_fifo_get_int ( struct fifo * queue, void ** item ) +{ + TRACE_ENTRY( "%p %p", queue, item ); + return fifo_tget(queue, item, 0, NULL); +} + +/* Get the next available item, block until there is one, or the timeout expires */ +int fd_fifo_timedget_int ( struct fifo * queue, void ** item, const struct timespec *abstime ) +{ + TRACE_ENTRY( "%p %p %p", queue, item, abstime ); + return fifo_tget(queue, item, 1, abstime); +} + diff -r fc7c18867cf7 -r c5c99c73c2bf libfreeDiameter/queues.c --- a/libfreeDiameter/queues.c Thu Sep 24 14:01:48 2009 +0900 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -/********************************************************************************************************* -* Software License Agreement (BSD License) * -* Author: Sebastien Decugis * -* * -* Copyright (c) 2008, WIDE Project and NICT * -* All rights reserved. * -* * -* Redistribution and use of this software in source and binary forms, with or without modification, are * -* permitted provided that the following conditions are met: * -* * -* * Redistributions of source code must retain the above * -* copyright notice, this list of conditions and the * -* following disclaimer. * -* * -* * Redistributions in binary form must reproduce the above * -* copyright notice, this list of conditions and the * -* following disclaimer in the documentation and/or other * -* materials provided with the distribution. * -* * -* * Neither the name of the WIDE Project or NICT nor the * -* names of its contributors may be used to endorse or * -* promote products derived from this software without * -* specific prior written permission of WIDE Project and * -* NICT. * -* * -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * -* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * -* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * -* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * -* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * -* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * -* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * -* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * -*********************************************************************************************************/ - -/* FIFO queues module. - * - * The threads that call these functions must be in the cancellation state PTHREAD_CANCEL_ENABLE and type PTHREAD_CANCEL_DEFERRED. - * This is the default state and type on thread creation. - * - * In order to destroy properly a queue, the application must: - * -> shutdown any process that can add into the queue first. - * -> pthread_cancel any thread that could be waiting on the queue. - * -> consume any element that is in the queue, using fd_qu_tryget_int. - * -> then destroy the queue using fd_mq_del. - */ - -#include "libfD.h" - -/* Definition of a FIFO queue object */ -struct fifo { - int eyec; /* An eye catcher, also used to check a queue is valid. FIFO_EYEC */ - - pthread_mutex_t mtx; /* Mutex protecting this queue */ - pthread_cond_t cond; /* condition variable of the list */ - - struct fd_list list; /* sentinel for the list of elements */ - int count; /* number of objects in the list */ - int thrs; /* number of threads waiting for a new element (when count is 0) */ - - uint16_t high; /* High level threshold (see libfreeDiameter.h for details) */ - uint16_t low; /* Low level threshhold */ - void *data; /* Opaque pointer for threshold callbacks */ - void (*h_cb)(struct fifo *, void **); /* The callbacks */ - void (*l_cb)(struct fifo *, void **); - int highest;/* The highest count value for which h_cb has been called */ -}; - -/* The eye catcher value */ -#define FIFO_EYEC 0xe7ec1130 - -/* Macro to check a pointer */ -#define CHECK_FIFO( _queue ) (( (_queue) != NULL) && ( (_queue)->eyec == FIFO_EYEC) ) - - -/* Create a new queue */ -int fd_fifo_new ( struct fifo ** queue ) -{ - struct fifo * new; - - TRACE_ENTRY( "%p", queue ); - - CHECK_PARAMS( queue ); - - /* Create a new object */ - CHECK_MALLOC( new = malloc (sizeof (struct fifo) ) ); - - /* Initialize the content */ - memset(new, 0, sizeof(struct fifo)); - - new->eyec = FIFO_EYEC; - CHECK_POSIX( pthread_mutex_init(&new->mtx, NULL) ); - CHECK_POSIX( pthread_cond_init(&new->cond, NULL) ); - - fd_list_init(&new->list, NULL); - - /* We're done */ - *queue = new; - return 0; -} - -/* Delete a queue. It must be unused. */ -int fd_fifo_del ( struct fifo ** queue ) -{ - struct fifo * q; - - TRACE_ENTRY( "%p", queue ); - - CHECK_PARAMS( queue && CHECK_FIFO( *queue ) ); - - q = *queue; - - CHECK_POSIX( pthread_mutex_lock( &q->mtx ) ); - - if ((q->count != 0) || (q->thrs != 0) || (q->data != NULL)) { - TRACE_DEBUG(INFO, "The queue cannot be destroyed (%d, %d, %p)", q->count, q->thrs, q->data); - CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* no fallback */ ); - return EINVAL; - } - - /* sanity check */ - ASSERT(FD_IS_LIST_EMPTY(&q->list)); - - /* Ok, now invalidate the queue */ - q->eyec = 0xdead; - - /* And destroy it */ - CHECK_POSIX( pthread_mutex_unlock( &q->mtx ) ); - - CHECK_POSIX( pthread_cond_destroy( &q->cond ) ); - - CHECK_POSIX( pthread_mutex_destroy( &q->mtx ) ); - - free(q); - *queue = NULL; - - return 0; -} - -/* Get the length of the queue */ -int fd_fifo_length ( struct fifo * queue, int * length ) -{ - TRACE_ENTRY( "%p %p", queue, length ); - - /* Check the parameters */ - CHECK_PARAMS( CHECK_FIFO( queue ) && length ); - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - - /* Retrieve the count */ - *length = queue->count; - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Done */ - return 0; -} - -/* alternate version with no error checking */ -int fd_fifo_length_noerr ( struct fifo * queue ) -{ - if ( !CHECK_FIFO( queue ) ) - return 0; - - return queue->count; /* Let's hope it's read atomically, since we are not locking... */ -} - -/* Set the thresholds of the queue */ -int fd_fifo_setthrhd ( struct fifo * queue, void * data, uint16_t high, void (*h_cb)(struct fifo *, void **), uint16_t low, void (*l_cb)(struct fifo *, void **) ) -{ - TRACE_ENTRY( "%p %p %hu %p %hu %p", queue, data, high, h_cb, low, l_cb ); - - /* Check the parameters */ - CHECK_PARAMS( CHECK_FIFO( queue ) && (high > low) && (queue->data == NULL) ); - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - - /* Save the values */ - queue->high = high; - queue->low = low; - queue->data = data; - queue->h_cb = h_cb; - queue->l_cb = l_cb; - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Done */ - return 0; -} - -/* Post a new item in the queue */ -int fd_fifo_post_int ( struct fifo * queue, void ** item ) -{ - struct fd_list * new; - int call_cb = 0; - - TRACE_ENTRY( "%p %p", queue, item ); - - /* Check the parameters */ - CHECK_PARAMS( CHECK_FIFO( queue ) && item && *item ); - - /* Create a new list item */ - CHECK_MALLOC( new = malloc (sizeof (struct fd_list)) ); - - fd_list_init(new, *item); - *item = NULL; - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - - /* Add the new item at the end */ - fd_list_insert_before( &queue->list, new); - queue->count++; - if (queue->high && ((queue->count % queue->high) == 0)) { - call_cb = 1; - queue->highest = queue->count; - } - - /* Signal if threads are asleep */ - if (queue->thrs > 0) { - CHECK_POSIX( pthread_cond_signal(&queue->cond) ); - } - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Call high-watermark cb as needed */ - if (call_cb && queue->h_cb) - (*queue->h_cb)(queue, &queue->data); - - /* Done */ - return 0; -} - -/* Pop the first item from the queue */ -static void * mq_pop(struct fifo * queue) -{ - void * ret = NULL; - struct fd_list * li; - - ASSERT( ! FD_IS_LIST_EMPTY(&queue->list) ); - - fd_list_unlink(li = queue->list.next); - queue->count--; - ret = li->o; - free(li); - - return ret; -} - -/* Check if the low watermark callback must be called. */ -static __inline__ int test_l_cb(struct fifo * queue) -{ - if ((queue->high == 0) || (queue->low == 0) || (queue->l_cb == 0)) - return 0; - - if (((queue->count % queue->high) == queue->low) && (queue->highest > queue->count)) { - queue->highest -= queue->high; - return 1; - } - - return 0; -} - -/* Try poping an item */ -int fd_fifo_tryget_int ( struct fifo * queue, void ** item ) -{ - int wouldblock = 0; - int call_cb = 0; - - TRACE_ENTRY( "%p %p", queue, item ); - - /* Check the parameters */ - CHECK_PARAMS( CHECK_FIFO( queue ) && item ); - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - - /* Check queue status */ - if (queue->count > 0) { - /* There are elements in the queue, so pick the first one */ - *item = mq_pop(queue); - call_cb = test_l_cb(queue); - } else { - wouldblock = 1; - *item = NULL; - } - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Call low watermark callback as needed */ - if (call_cb) - (*queue->l_cb)(queue, &queue->data); - - /* Done */ - return wouldblock ? EWOULDBLOCK : 0; -} - -/* This handler is called when a thread is blocked on a queue, and cancelled */ -static void fifo_cleanup(void * queue) -{ - struct fifo * q = (struct fifo *)queue; - TRACE_ENTRY( "%p", queue ); - - /* Check the parameter */ - if ( ! CHECK_FIFO( q )) { - TRACE_DEBUG(INFO, "Invalid queue, skipping handler"); - return; - } - - /* The thread has been cancelled, therefore it does not wait on the queue anymore */ - q->thrs--; - - /* Now unlock the queue, and we're done */ - CHECK_POSIX_DO( pthread_mutex_unlock( &q->mtx ), /* nothing */ ); - - /* End of cleanup handler */ - return; -} - -/* The internal function for fd_fifo_timedget and fd_fifo_get */ -static int fifo_tget ( struct fifo * queue, void ** item, int istimed, const struct timespec *abstime) -{ - int timedout = 0; - int call_cb = 0; - - /* Check the parameters */ - CHECK_PARAMS( CHECK_FIFO( queue ) && item && (abstime || !istimed) ); - - /* Initialize the return value */ - *item = NULL; - - /* lock the queue */ - CHECK_POSIX( pthread_mutex_lock( &queue->mtx ) ); - -awaken: - /* Check queue status */ - if (queue->count > 0) { - /* There are items in the queue, so pick the first one */ - *item = mq_pop(queue); - call_cb = test_l_cb(queue); - } else { - int ret = 0; - /* We have to wait for a new item */ - queue->thrs++ ; - pthread_cleanup_push( fifo_cleanup, queue); - if (istimed) { - ret = pthread_cond_timedwait( &queue->cond, &queue->mtx, abstime ); - } else { - ret = pthread_cond_wait( &queue->cond, &queue->mtx ); - } - pthread_cleanup_pop(0); - queue->thrs-- ; - if (ret == 0) - goto awaken; /* test for spurious wake-ups */ - - if (istimed && (ret == ETIMEDOUT)) { - timedout = 1; - } else { - /* Unexpected error condition (means we need to debug) */ - ASSERT( ret == 0 /* never true */ ); - } - } - - /* Unlock */ - CHECK_POSIX( pthread_mutex_unlock( &queue->mtx ) ); - - /* Call low watermark callback as needed */ - if (call_cb) - (*queue->l_cb)(queue, &queue->data); - - /* Done */ - return timedout ? ETIMEDOUT : 0; -} - -/* Get the next available item, block until there is one */ -int fd_fifo_get_int ( struct fifo * queue, void ** item ) -{ - TRACE_ENTRY( "%p %p", queue, item ); - return fifo_tget(queue, item, 0, NULL); -} - -/* Get the next available item, block until there is one, or the timeout expires */ -int fd_fifo_timedget_int ( struct fifo * queue, void ** item, const struct timespec *abstime ) -{ - TRACE_ENTRY( "%p %p %p", queue, item, abstime ); - return fifo_tget(queue, item, 1, abstime); -} -