diff options
Diffstat (limited to 'lib')
351 files changed, 75179 insertions, 7981 deletions
diff --git a/lib/Makefile b/lib/Makefile index 5faf0c8714..7f4c309da9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -28,8 +28,9 @@ ifeq ($(findstring vxworks,$(TARGET)),vxworks) snmp otp_mibs appmon erl_interface os_mon tools runtime_tools ifdef BUILD_ALL OTHER_SUB_DIRECTORIES += mnesia jinterface ic asn1 debugger \ - inets mnesia_session orber pman tv observer cosTransactions cosEvent \ - cosTime cosNotification cosProperty cosFileTransfer cosEventDomain + inets mnesia_session diameter orber pman tv observer \ + cosTransactions cosEvent cosTime cosNotification cosProperty + cosFileTransfer cosEventDomain endif else ifeq ($(findstring ose,$(TARGET)),ose) @@ -57,7 +58,8 @@ else OTHER_SUB_DIRECTORIES += \ snmp otp_mibs appmon erl_interface asn1 jinterface gs wx inets ic \ mnesia crypto orber os_mon parsetools syntax_tools pman \ - public_key ssl toolbar tv observer debugger reltool odbc runtime_tools \ + public_key ssl toolbar tv observer debugger reltool odbc \ + runtime_tools diameter \ cosTransactions cosEvent cosTime cosNotification cosProperty \ cosFileTransfer cosEventDomain et megaco webtool \ xmerl edoc eunit ssh inviso typer docbuilder erl_docgen common_test percept @@ -68,7 +70,8 @@ else snmp otp_mibs appmon erl_interface asn1 jinterface wx debugger reltool gs inets \ ic mnesia crypto orber os_mon parsetools syntax_tools \ pman public_key ssl toolbar tv observer odbc \ - runtime_tools cosTransactions cosEvent cosTime cosNotification \ + runtime_tools diameter \ + cosTransactions cosEvent cosTime cosNotification \ cosProperty cosFileTransfer cosEventDomain et megaco webtool \ xmerl edoc eunit ssh inviso typer docbuilder erl_docgen common_test percept # dialyzer diff --git a/lib/asn1/c_src/asn1_erl_driver.c b/lib/asn1/c_src/asn1_erl_driver.c index 9dd3a0fd7d..18d4157941 100644 --- a/lib/asn1/c_src/asn1_erl_driver.c +++ b/lib/asn1/c_src/asn1_erl_driver.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2010. All Rights Reserved. + * Copyright Ericsson AB 2002-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -101,6 +101,8 @@ int insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *); int insert_octets_unaligned(int, unsigned char **, unsigned char **, int); +int realloc_decode_buf(ErlDrvBinary **,int); + int realloc_memory(ErlDrvBinary **,int,unsigned char **,unsigned char **); int decode_begin(ErlDrvBinary **,unsigned char *, int, unsigned int *); @@ -123,6 +125,8 @@ int skip_length_and_value(unsigned char *,int *,int); int get_tag(unsigned char *,int *,int); +int get_length(unsigned char *,int *,int *,int); + int get_value(char *,unsigned char *,int *,int); static ErlDrvEntry asn1_drv_entry = { @@ -185,12 +189,12 @@ static void asn1_drv_stop(ErlDrvData handle) int asn1_drv_control(ErlDrvData handle, unsigned int command, - char *buf, + char *buf, int buf_len, char **res_buf, int res_buf_len) { - char *complete_buf; + unsigned char *complete_buf; int complete_len, decode_len; ErlDrvBinary *drv_binary; ErlDrvBinary **drv_bin_ptr; @@ -216,8 +220,8 @@ int asn1_drv_control(ErlDrvData handle, set_port_control_flags(a_data->port, 0); return ASN1_MEMORY_ERROR; } - complete_buf = drv_binary->orig_bytes; - if ((complete_len = complete(&drv_binary,complete_buf,buf,buf_len)) == ASN1_ERROR) + complete_buf = (unsigned char*) drv_binary->orig_bytes; + if ((complete_len = complete(&drv_binary,complete_buf,(unsigned char*) buf,buf_len)) == ASN1_ERROR) { /* error handling due to failure in complete */ /* printf("error when running complete\n\r"); */ @@ -252,7 +256,7 @@ int asn1_drv_control(ErlDrvData handle, return ASN1_MEMORY_ERROR; } drv_bin_ptr = &drv_binary; - if ((decode_len = decode_begin(drv_bin_ptr,buf,buf_len,&err_pos)) <= ASN1_ERROR) + if ((decode_len = decode_begin(drv_bin_ptr,(unsigned char*)buf,buf_len,&err_pos)) <= ASN1_ERROR) { /* error handling due to failure in decode */ char tmp_res_buf[5]; @@ -301,7 +305,7 @@ int asn1_drv_control(ErlDrvData handle, return ASN1_MEMORY_ERROR; } drv_bin_ptr = &drv_binary; - if ((decode_len = decode_partial(drv_bin_ptr,buf,buf_len)) + if ((decode_len = decode_partial(drv_bin_ptr,(unsigned char*)buf,buf_len)) <= ASN1_ERROR) { /* error handling due to failure in decode */ driver_free_binary(*drv_bin_ptr); @@ -723,7 +727,7 @@ int realloc_memory(ErlDrvBinary **drv_binary, }else { i = *ptr - *complete_buf; *drv_binary=tmp_bin; - *complete_buf = (*drv_binary)->orig_bytes; + *complete_buf = (unsigned char*)(*drv_binary)->orig_bytes; *ptr = *complete_buf + i; } return ASN1_OK; @@ -1164,7 +1168,7 @@ int decode(ErlDrvBinary **drv_binary,int *ei_index,unsigned char *in_buf, if (ei_encode_tuple_header(decode_buf,ei_index,2) == ASN1_ERROR) return ASN1_ERROR; /* 2 bytes */ #ifdef ASN1_DEBUG - printf("decode 3:orig_size=%d, ei_index=%d, ib_index=%d\n\r",(*drv_binary)->orig_size,*ei_index,*ib_index); + printf("decode 3:orig_size=%ld, ei_index=%d, ib_index=%d\n\r",(*drv_binary)->orig_size,*ei_index,*ib_index); #endif /*buffer must hold at least two bytes*/ @@ -1275,7 +1279,8 @@ int decode_value(int *ei_index,unsigned char *in_buf, { int maybe_ret; char *decode_buf = (*drv_binary)->orig_bytes; - int len, lenoflen; + unsigned int len = 0; + unsigned int lenoflen = 0; int indef = 0; #ifdef ASN1_DEBUG @@ -1283,8 +1288,6 @@ int decode_value(int *ei_index,unsigned char *in_buf, #endif if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) { len = in_buf[*ib_index]; - if (len > (in_buf_len - (*ib_index + 1))) - return ASN1_LEN_ERROR; } else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH) indef = 1; @@ -1293,17 +1296,21 @@ int decode_value(int *ei_index,unsigned char *in_buf, #ifdef ASN1_DEBUG printf("decode_value,lenoflen:%d\r\n",lenoflen); #endif - len = 0; - while (lenoflen-- && (*ib_index <= in_buf_len)) { - (*ib_index)++; + if (lenoflen > (in_buf_len - (*ib_index+1))) + return ASN1_LEN_ERROR; + len = 0; + while (lenoflen-- ) { + (*ib_index)++; #ifdef ASN1_DEBUG - printf("decode_value1:ii=%d.\r\n",*ib_index); + printf("decode_value1:*ib_index=%d, byte = %d.\r\n",*ib_index,in_buf[*ib_index]); #endif - len = (len << 8) + in_buf[*ib_index]; - } - if (len > (in_buf_len - (*ib_index + 1))) - return ASN1_LEN_ERROR; + if (!(len < (1 << (sizeof(len)-1)*8))) + return ASN1_LEN_ERROR; /* length does not fit in 32 bits */ + len = (len << 8) + in_buf[*ib_index]; + } } + if (len > (in_buf_len - (*ib_index + 1))) + return ASN1_VALUE_ERROR; (*ib_index)++; #ifdef ASN1_DEBUG printf("decode_value2:ii=%d.\r\n",*ib_index); diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl index d6f23aca06..c1b6aa5713 100644 --- a/lib/asn1/src/asn1ct_constructed_per.erl +++ b/lib/asn1/src/asn1ct_constructed_per.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -255,7 +255,7 @@ gen_decode_constructed(Erules,Typename,D) when is_record(D,type) -> _ -> false end end, - case lists:any(F,CompList) of + case lists:any(F,flat_complist(CompList)) of true -> % when component relation constraint establish %% relation from a component to another components %% subtype component @@ -1493,6 +1493,11 @@ emit_extaddgroupTerms(VarSeries,[_|Rest]) -> emit_extaddgroupTerms(VarSeries,Rest); emit_extaddgroupTerms(_,[]) -> ok. + +flat_complist({Rl1,El,Rl2}) -> Rl1 ++ El ++ Rl2; +flat_complist({Rl,El}) -> Rl ++ El; +flat_complist(CompList) -> CompList. + wrap_compList({Root1,Ext,Root2}) -> {Root1,wrap_extensionAdditionGroups(Ext),Root2}; wrap_compList({Root1,Ext}) -> diff --git a/lib/asn1/src/asn1ct_value.erl b/lib/asn1/src/asn1ct_value.erl index d9a7e5374a..693e039a13 100644 --- a/lib/asn1/src/asn1ct_value.erl +++ b/lib/asn1/src/asn1ct_value.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -443,7 +443,7 @@ open_type_value(ber_bin_v2) -> open_type_value(per) -> "\n\topen_type"; %octet string value "open_type" open_type_value(per_bin) -> - "\n\topen_type"; + <<"\n\topen_type">>; % <<10,9,111,112,101,110,95,116,121,112,101>>; open_type_value(_) -> [4,9,111,112,101,110,95,116,121,112,101]. diff --git a/lib/asn1/src/asn1rt_check.erl b/lib/asn1/src/asn1rt_check.erl index 59a74a7078..24a2a3802d 100644 --- a/lib/asn1/src/asn1rt_check.erl +++ b/lib/asn1/src/asn1rt_check.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2009. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -311,7 +311,7 @@ transform_to_EXTERNAL1990([Data_val_desc,Data_value],Acc) when is_list(Data_valu Data_val_desc|Acc])); transform_to_EXTERNAL1990([Data_val_desc,Data_value],Acc) when is_binary(Data_value)-> - list_to_tuple(lists:reverse([{'octet-aligned',binary_to_list(Data_value)}, + list_to_tuple(lists:reverse([{'single-ASN1-type',Data_value}, Data_val_desc|Acc])); transform_to_EXTERNAL1990([Data_value],Acc) when is_list(Data_value)-> list_to_tuple(lists:reverse([{'octet-aligned',Data_value}|Acc])). diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl deleted file mode 100644 index d050d8c84b..0000000000 --- a/lib/asn1/test/asn1_SUITE.erl +++ /dev/null @@ -1,2489 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% -%%% Purpose : Test suite for the ASN.1 application - --module(asn1_SUITE). --define(PER,'per'). --define(BER,'ber'). --define(ber_driver(Erule,Func), - case Erule of - ber_bin_v2 -> - Func; - _ -> ok - end). --define(per_optimize(Erule), - case Erule of - ber_bin_v2 ->[optimize]; - _ -> [] - end). --define(per_bit_opt(FuncCall), - case ?BER of - ber_bin_v2 -> FuncCall; -% _ -> {skip,"only for bit optimized per_bin"} - _ -> ok - end). --define(uper_bin(FuncCall), - case ?PER of - per -> FuncCall; - _ -> ok - end). - --compile(export_all). -%%-export([Function/Arity, ...]). - --include_lib("test_server/include/test_server.hrl"). - -%% records used by test-case default --record('Def1',{ bool0, - bool1 = asn1_DEFAULT, - bool2 = asn1_DEFAULT, - bool3 = asn1_DEFAULT}). - -%-record('Def2',{ -%bool10, bool11 = asn1_DEFAULT, bool12 = asn1_DEFAULT, bool13}). - -%-record('Def3',{ -%bool30 = asn1_DEFAULT, bool31 = asn1_DEFAULT, bool32 = asn1_DEFAULT, bool33 = asn1_DEFAULT}). - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [{group, compile}, parse, default_per, default_ber, - default_per_opt, per, {group, ber}, testPrim, - testPrimStrings, testPrimExternal, testChoPrim, - testChoExtension, testChoExternal, testChoOptional, - testChoOptionalImplicitTag, testChoRecursive, - testChoTypeRefCho, testChoTypeRefPrim, - testChoTypeRefSeq, testChoTypeRefSet, testDef, testOpt, - testSeqDefault, testSeqExtension, testSeqExternal, - testSeqOptional, testSeqPrim, testSeqTag, - testSeqTypeRefCho, testSeqTypeRefPrim, - testSeqTypeRefSeq, testSeqTypeRefSet, testSeqOf, - testSeqOfIndefinite, testSeqOfCho, testSeqOfExternal, - testSetDefault, testSetExtension, - testExtensionAdditionGroup, testSetExternal, - testSeqOfTag, testSetOptional, testSetPrim, testSetTag, - testSetTypeRefCho, testSetTypeRefPrim, - testSetTypeRefSeq, testSetTypeRefSet, testSetOf, - testSetOfCho, testSetOfExternal, testSetOfTag, - testEnumExt, value_test, testSeq2738, constructed, - ber_decode_error, h323test, testSeqIndefinite, - testSetIndefinite, testChoiceIndefinite, - per_GeneralString, per_open_type, testInfObjectClass, - testParameterizedInfObj, testMergeCompile, testobj, - testDeepTConstr, testConstraints, testInvokeMod, - testExport, testImport, testCompactBitString, - testMegaco, testParamBasic, testMvrasn6, - testContextSwitchingTypes, testTypeValueNotation, - testOpenTypeImplicitTag, duplicate_tags, rtUI, testROSE, - testINSTANCE_OF, testTCAP, testDER, specialized_decodes, - special_decode_performance, test_driver_load, - test_ParamTypeInfObj, test_WS_ParamClass, - test_Defed_ObjectIdentifier, testSelectionType, - testSSLspecs, testNortel, test_undecoded_rest, - test_inline, testTcapsystem, testNBAPsystem, - test_compile_options, testDoubleEllipses, - test_modified_x420, testX420, test_x691, ticket_6143, - testExtensionAdditionGroup] ++ common() ++ particular(). - -groups() -> - [{option_tests, [], - [test_compile_options, ticket_6143]}, - {infobj, [], - [testInfObjectClass, testParameterizedInfObj, - testMergeCompile, testobj, testDeepTConstr]}, - {performance, [], - [testTimer_ber, testTimer_ber_opt_driver, testTimer_per, - testTimer_per_opt, testTimer_uper_bin]}, - {bugs, [], - [test_ParamTypeInfObj, test_WS_ParamClass, - test_Defed_ObjectIdentifier]}, - {compile, [], - [c_syntax, c_string_per, c_string_ber, - c_implicit_before_choice]}, - {ber, [], - [ber_choiceinseq, ber_optional, ber_optional_keyed_list, - ber_other]}, - {app_test, [], [{asn1_app_test, all}]}, - {appup_test, [], [{asn1_appup_test, all}]}]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - - -%all(suite) -> [test_inline,testNBAPsystem,test_compile_options,ticket_6143]. - - -init_per_testcase(Func,Config) -> - %%?line test_server:format("Func: ~p~n",[Func]), - ?line {ok, _} = file:read_file_info(filename:join([?config(priv_dir,Config)])), - ?line code:add_patha(?config(priv_dir,Config)), - Dog= - case Func of - testX420 -> - test_server:timetrap({minutes,60}); % 60 minutes - _ -> - test_server:timetrap({minutes,30}) % 60 minutes - end, -%% Dog=test_server:timetrap(1800000), % 30 minutes - [{watchdog, Dog}|Config]. - -end_per_testcase(_Func,Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog). - - -testPrim(suite) -> []; -testPrim(Config) -> - ?line testPrim:compile(Config,?BER,[]), - ?line testPrim_cases(?BER), - ?line ?ber_driver(?BER,testPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrim_cases(?BER)), - ?line testPrim:compile(Config,?PER,[]), - ?line testPrim_cases(?PER), - ?line ?per_bit_opt(testPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrim_cases(?PER)), - ?line ?uper_bin(testPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrim_cases(uper_bin)), - ?line testPrim:compile(Config,?PER,[optimize]), - ?line testPrim_cases(?PER). - -testPrim_cases(Rules) -> - ?line testPrim:bool(Rules), - ?line testPrim:int(Rules), - ?line testPrim:enum(Rules), - ?line testPrim:obj_id(Rules), - ?line testPrim:rel_oid(Rules), - ?line testPrim:null(Rules), - ?line testPrim:real(Rules). - - -testCompactBitString(suite) -> []; -testCompactBitString(Config) -> - - ?line testCompactBitString:compile(Config,?BER,[compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?BER), - - ?line ?ber_driver(?BER,testCompactBitString:compile(Config,?BER,[compact_bit_string,driver])), - ?line ?ber_driver(?BER,testCompactBitString:compact_bit_string(?BER)), - - ?line testCompactBitString:compile(Config,?PER,[compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?PER), - ?line testCompactBitString:bit_string_unnamed(?PER), - - ?line ?per_bit_opt(testCompactBitString:compile(Config,?PER, - [compact_bit_string,optimize])), - ?line ?per_bit_opt(testCompactBitString:compact_bit_string(?PER)), - ?line ?per_bit_opt(testCompactBitString:bit_string_unnamed(?PER)), - ?line ?per_bit_opt(testCompactBitString:ticket_7734(?PER)), - - ?line ?uper_bin(testCompactBitString:compile(Config,uper_bin, - [compact_bit_string])), - ?line ?uper_bin(testCompactBitString:compact_bit_string(uper_bin)), - ?line ?uper_bin(testCompactBitString:bit_string_unnamed(uper_bin)), - - ?line testCompactBitString:compile(Config,?PER,[optimize,compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?PER), - ?line testCompactBitString:bit_string_unnamed(?PER), - - ?line testCompactBitString:otp_4869(?PER). - - -testPrimStrings(suite) -> []; -testPrimStrings(Config) -> - - ?line testPrimStrings:compile(Config,?BER,[]), - ?line testPrimStrings_cases(?BER), - ?line testPrimStrings:more_strings(?BER), %% these are not implemented in per yet - ?line ?ber_driver(?BER,testPrimStrings:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimStrings_cases(?BER)), - ?line ?ber_driver(?BER,testPrimStrings:more_strings(?BER)), - - ?line testPrimStrings:compile(Config,?PER,[]), - ?line testPrimStrings_cases(?PER), - - ?line ?per_bit_opt(testPrimStrings:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimStrings_cases(?PER)), - - ?line ?uper_bin(testPrimStrings:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimStrings_cases(uper_bin)), - - ?line testPrimStrings:compile(Config,?PER,[optimize]), - ?line testPrimStrings_cases(?PER). - -testPrimStrings_cases(Rules) -> - ?line testPrimStrings:bit_string(Rules), - ?line testPrimStrings:bit_string_unnamed(Rules), - ?line testPrimStrings:octet_string(Rules), - ?line testPrimStrings:numeric_string(Rules), - ?line testPrimStrings:other_strings(Rules), - ?line testPrimStrings:universal_string(Rules), - ?line testPrimStrings:bmp_string(Rules), - ?line testPrimStrings:times(Rules), - ?line testPrimStrings:utf8_string(Rules). - - - -testPrimExternal(suite) -> []; -testPrimExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testPrimExternal:compile(Config,?BER,[]), - ?line testPrimExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testPrimExternal:compile(Config,?PER,[]), - ?line testPrimExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testPrimExternal:compile(Config,?PER,[optimize]), - ?line testPrimExternal_cases(?PER). - -testPrimExternal_cases(Rules) -> - ?line testPrimExternal:external(Rules). - - - - -testChoPrim(suite) -> []; -testChoPrim(Config) -> - - ?line testChoPrim:compile(Config,?BER,[]), - ?line testChoPrim_cases(?BER), - - ?line ?ber_driver(?BER,testChoPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoPrim_cases(?BER)), - - ?line testChoPrim:compile(Config,?PER,[]), - ?line testChoPrim_cases(?PER), - - ?line ?per_bit_opt(testChoPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoPrim_cases(?PER)), - - ?line ?uper_bin(testChoPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoPrim_cases(uper_bin)), - - ?line testChoPrim:compile(Config,?PER,[optimize]), - ?line testChoPrim_cases(?PER). - -testChoPrim_cases(Rules) -> - ?line testChoPrim:bool(Rules), - ?line testChoPrim:int(Rules). - - - -testChoExtension(suite) -> []; -testChoExtension(Config) -> - - ?line testChoExtension:compile(Config,?BER,[]), - ?line testChoExtension_cases(?BER), - - ?line ?ber_driver(?BER,testChoExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExtension_cases(?BER)), - - ?line testChoExtension:compile(Config,?PER,[]), - ?line testChoExtension_cases(?PER), - - ?line ?per_bit_opt(testChoExtension:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExtension_cases(?PER)), - - ?line ?uper_bin(testChoExtension:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExtension_cases(uper_bin)), - - ?line testChoExtension:compile(Config,?PER,[optimize]), - ?line testChoExtension_cases(?PER). - -testChoExtension_cases(Rules) -> - ?line testChoExtension:extension(Rules). - - - -testChoExternal(suite) -> []; -testChoExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testChoExternal:compile(Config,?BER,[]), - ?line testChoExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testChoExternal:compile(Config,?PER,[]), - ?line testChoExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testChoExternal:compile(Config,?PER,[optimize]), - ?line testChoExternal_cases(?PER). - - -testChoExternal_cases(Rules) -> - ?line testChoExternal:external(Rules). - - - -testChoOptional(suite) -> []; -testChoOptional(Config) -> - - ?line testChoOptional:compile(Config,?BER,[]), - ?line testChoOptional_cases(?BER), - - ?line ?ber_driver(?BER,testChoOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoOptional_cases(?BER)), - - ?line testChoOptional:compile(Config,?PER,[]), - ?line testChoOptional_cases(?PER), - - ?line ?per_bit_opt(testChoOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoOptional_cases(?PER)), - - ?line ?uper_bin(testChoOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoOptional_cases(uper_bin)), - - ?line testChoOptional:compile(Config,?PER,[optimize]), - ?line testChoOptional_cases(?PER). - -testChoOptional_cases(Rules) -> - ?line testChoOptional:optional(Rules). - -testChoOptionalImplicitTag(suite) -> []; -testChoOptionalImplicitTag(Config) -> - %% Only meaningful for ?BER - ?line testChoOptionalImplicitTag:compile(Config,?BER), - ?line testChoOptionalImplicitTag:optional(?BER). - - -testChoRecursive(suite) -> []; -testChoRecursive(Config) -> - - ?line testChoRecursive:compile(Config,?BER,[]), - ?line testChoRecursive_cases(?BER), - - ?line ?ber_driver(?BER,testChoRecursive:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoRecursive_cases(?BER)), - - ?line testChoRecursive:compile(Config,?PER,[]), - ?line testChoRecursive_cases(?PER), - - ?line ?per_bit_opt(testChoRecursive:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoRecursive_cases(?PER)), - - ?line ?uper_bin(testChoRecursive:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoRecursive_cases(uper_bin)), - - ?line testChoRecursive:compile(Config,?PER,[optimize]), - ?line testChoRecursive_cases(?PER). - -testChoRecursive_cases(Rules) -> - ?line testChoRecursive:recursive(Rules). - - - -testChoTypeRefCho(suite) -> []; -testChoTypeRefCho(Config) -> - - ?line testChoTypeRefCho:compile(Config,?BER,[]), - ?line testChoTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefCho_cases(?BER)), - - ?line testChoTypeRefCho:compile(Config,?PER,[]), - ?line testChoTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefCho_cases(uper_bin)), - - ?line testChoTypeRefCho:compile(Config,?PER,[optimize]), - ?line testChoTypeRefCho_cases(?PER). - -testChoTypeRefCho_cases(Rules) -> - ?line testChoTypeRefCho:choice(Rules). - - - -testChoTypeRefPrim(suite) -> []; -testChoTypeRefPrim(Config) -> - - ?line testChoTypeRefPrim:compile(Config,?BER,[]), - ?line testChoTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefPrim_cases(?BER)), - - ?line testChoTypeRefPrim:compile(Config,?PER,[]), - ?line testChoTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefPrim_cases(uper_bin)), - - ?line testChoTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testChoTypeRefPrim_cases(?PER). - -testChoTypeRefPrim_cases(Rules) -> - ?line testChoTypeRefPrim:prim(Rules). - - - -testChoTypeRefSeq(suite) -> []; -testChoTypeRefSeq(Config) -> - - ?line testChoTypeRefSeq:compile(Config,?BER,[]), - ?line testChoTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefSeq_cases(?BER)), - - ?line testChoTypeRefSeq:compile(Config,?PER,[]), - ?line testChoTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefSeq_cases(uper_bin)), - - ?line testChoTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testChoTypeRefSeq_cases(?PER). - -testChoTypeRefSeq_cases(Rules) -> - ?line testChoTypeRefSeq:seq(Rules). - - - -testChoTypeRefSet(suite) -> []; -testChoTypeRefSet(Config) -> - - ?line testChoTypeRefSet:compile(Config,?BER,[]), - ?line testChoTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefSet_cases(?BER)), - - ?line testChoTypeRefSet:compile(Config,?PER,[]), - ?line testChoTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefSet_cases(uper_bin)), - - ?line testChoTypeRefSet:compile(Config,?PER,[optimize]), - ?line testChoTypeRefSet_cases(?PER). - -testChoTypeRefSet_cases(Rules) -> - ?line testChoTypeRefSet:set(Rules). - - - -testDef(suite) -> []; -testDef(Config) -> - - ?line testDef:compile(Config,?BER,[]), - ?line testDef_cases(?BER), - - ?line ?ber_driver(?BER,testDef:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDef_cases(?BER)), - - ?line testDef:compile(Config,?PER,[]), - ?line testDef_cases(?PER), - - ?line ?per_bit_opt(testDef:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDef_cases(?PER)), - - ?line ?uper_bin(testDef:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDef_cases(uper_bin)), - - ?line testDef:compile(Config,?PER,[optimize]), - ?line testDef_cases(?PER). - -testDef_cases(Rules) -> - ?line testDef:main(Rules). - - - -testOpt(suite) -> []; -testOpt(Config) -> - - ?line testOpt:compile(Config,?BER), - ?line testOpt_cases(?BER), - - ?line testOpt:compile(Config,?PER), - ?line testOpt_cases(?PER). - -testOpt_cases(Rules) -> - ?line testOpt:main(Rules). - - -testEnumExt(suite) -> []; -testEnumExt(Config) -> - - ?line testEnumExt:compile(Config,?BER,[]), - ?line testEnumExt:main(?BER), - - ?line ?ber_driver(?BER,testEnumExt:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testEnumExt:main(?BER)), - - ?line testEnumExt:compile(Config,?PER,[]), - ?line testEnumExt:main(?PER), - - ?line ?per_bit_opt(testEnumExt:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testEnumExt:main(?PER)), - - ?line ?uper_bin(testEnumExt:compile(Config,uper_bin,[])), - ?line ?uper_bin(testEnumExt:main(uper_bin)), - - ?line testEnumExt:compile(Config,?PER,[optimize]), - ?line testEnumExt:main(?PER). - -testSeqDefault(doc) -> ["Test of OTP-2523 ENUMERATED with extensionmark."]; -testSeqDefault(suite) -> []; -testSeqDefault(Config) -> - - ?line testSeqDefault:compile(Config,?BER,[]), - ?line testSeqDefault_cases(?BER), - - ?line ?ber_driver(?BER,testSeqDefault:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqDefault_cases(?BER)), - - ?line testSeqDefault:compile(Config,?PER,[]), - ?line testSeqDefault_cases(?PER), - - ?line ?per_bit_opt(testSeqDefault:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqDefault_cases(?PER)), - - ?line ?uper_bin(testSeqDefault:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqDefault_cases(uper_bin)), - - ?line testSeqDefault:compile(Config,?PER,[optimize]), - ?line testSeqDefault_cases(?PER). - -testSeqDefault_cases(Rules) -> - ?line testSeqDefault:main(Rules). - - - -testSeqExtension(suite) -> []; -testSeqExtension(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqExtension:compile(Config,?BER,[]), - ?line testSeqExtension_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExtension_cases(?BER)). - -testSeqExtension_cases(Rules) -> - ?line testSeqExtension:main(Rules). - - - -testSeqExternal(suite) -> []; -testSeqExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqExternal:compile(Config,?BER,[]), - ?line testSeqExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExternal_cases(?BER)). - -testSeqExternal_cases(Rules) -> - ?line testSeqExternal:main(Rules). - - -testSeqOptional(suite) -> []; -testSeqOptional(Config) -> - - ?line testSeqOptional:compile(Config,?BER,[]), - ?line testSeqOptional_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOptional_cases(?BER)), - - ?line testSeqOptional:compile(Config,?PER,[]), - ?line testSeqOptional_cases(?PER), - - ?line ?per_bit_opt(testSeqOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOptional_cases(?PER)), - - ?line ?uper_bin(testSeqOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOptional_cases(uper_bin)), - - ?line testSeqOptional:compile(Config,?PER,[optimize]), - ?line testSeqOptional_cases(?PER). - -testSeqOptional_cases(Rules) -> - ?line testSeqOptional:main(Rules). - - - -testSeqPrim(suite) -> []; -testSeqPrim(Config) -> - - ?line testSeqPrim:compile(Config,?BER,[]), - ?line testSeqPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSeqPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqPrim_cases(?BER)), - - ?line testSeqPrim:compile(Config,?PER,[]), - ?line testSeqPrim_cases(?PER), - - ?line ?per_bit_opt(testSeqPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqPrim_cases(?PER)), - - ?line ?uper_bin(testSeqPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqPrim_cases(uper_bin)), - - ?line testSeqPrim:compile(Config,?PER,[optimize]), - ?line testSeqPrim_cases(?PER). - -testSeqPrim_cases(Rules) -> - ?line testSeqPrim:main(Rules). - - -testSeq2738(doc) -> ["Test of OTP-2738 Detect corrupt optional component."]; -testSeq2738(suite) -> []; -testSeq2738(Config) -> - - ?line testSeq2738:compile(Config,?BER,[]), - ?line testSeq2738_cases(?BER), - - ?line ?ber_driver(?BER,testSeq2738:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeq2738_cases(?BER)), - - ?line testSeq2738:compile(Config,?PER,[]), - ?line testSeq2738_cases(?PER), - - ?line ?per_bit_opt(testSeq2738:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeq2738_cases(?PER)), - - ?line ?uper_bin(testSeq2738:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeq2738_cases(uper_bin)), - - ?line testSeq2738:compile(Config,?PER,[optimize]), - ?line testSeq2738_cases(?PER). - -testSeq2738_cases(Rules) -> - ?line testSeq2738:main(Rules). - - -testSeqTag(suite) -> []; -testSeqTag(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqTag:compile(Config,?BER,[]), - ?line testSeqTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqTag:compile(Config,?PER,[]), - ?line testSeqTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqTag:compile(Config,?PER,[optimize]), - ?line testSeqTag_cases(?PER). - -testSeqTag_cases(Rules) -> - ?line testSeqTag:main(Rules). - - - - -testSeqTypeRefCho(suite) -> []; -testSeqTypeRefCho(Config) -> - - ?line testSeqTypeRefCho:compile(Config,?BER,[]), - ?line testSeqTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefCho_cases(?BER)), - - ?line testSeqTypeRefCho:compile(Config,?PER,[]), - ?line testSeqTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefCho_cases(uper_bin)), - - ?line testSeqTypeRefCho:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefCho_cases(?PER). - -testSeqTypeRefCho_cases(Rules) -> - ?line testSeqTypeRefCho:main(Rules). - - - -testSeqTypeRefPrim(suite) -> []; -testSeqTypeRefPrim(Config) -> - - ?line testSeqTypeRefPrim:compile(Config,?BER,[]), - ?line testSeqTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefPrim_cases(?BER)), - - ?line testSeqTypeRefPrim:compile(Config,?PER,[]), - ?line testSeqTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefPrim_cases(uper_bin)), - - ?line testSeqTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefPrim_cases(?PER). - -testSeqTypeRefPrim_cases(Rules) -> - ?line testSeqTypeRefPrim:main(Rules). - - - -testSeqTypeRefSeq(suite) -> []; -testSeqTypeRefSeq(Config) -> - - ?line testSeqTypeRefSeq:compile(Config,?BER,[]), - ?line testSeqTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefSeq_cases(?BER)), - - ?line testSeqTypeRefSeq:compile(Config,?PER,[]), - ?line testSeqTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefSeq_cases(uper_bin)), - - ?line testSeqTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefSeq_cases(?PER). - -testSeqTypeRefSeq_cases(Rules) -> - ?line testSeqTypeRefSeq:main(Rules). - - - -testSeqTypeRefSet(suite) -> []; -testSeqTypeRefSet(Config) -> - - ?line testSeqTypeRefSet:compile(Config,?BER,[]), - ?line testSeqTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefSet_cases(?BER)), - - ?line testSeqTypeRefSet:compile(Config,?PER,[]), - ?line testSeqTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefSet_cases(uper_bin)), - - ?line testSeqTypeRefSet:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefSet_cases(?PER). - -testSeqTypeRefSet_cases(Rules) -> - ?line testSeqTypeRefSet:main(Rules). - - - - -testSeqOf(suite) -> []; -testSeqOf(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOf:compile(Config,?BER,[]), - ?line testSeqOf_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOf:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOf_cases(?BER)), - - ?line testSeqOf:compile(Config,?PER,[]), - ?line testSeqOf_cases(?PER), - - ?line ?per_bit_opt(testSeqOf:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOf_cases(?PER)), - - ?line ?uper_bin(testSeqOf:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOf_cases(uper_bin)), - - ?line testSeqOf:compile(Config,?PER,[optimize]), - ?line testSeqOf_cases(?PER). - -testSeqOf_cases(Rules) -> - ?line testSeqOf:main(Rules). - - - - -testSeqOfCho(suite) -> []; -testSeqOfCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOfCho:compile(Config,?BER,[]), - ?line testSeqOfCho_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOfCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfCho_cases(?BER)), - - ?line testSeqOfCho:compile(Config,?PER,[]), - ?line testSeqOfCho_cases(?PER), - - ?line ?per_bit_opt(testSeqOfCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfCho_cases(?PER)), - - ?line ?uper_bin(testSeqOfCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfCho_cases(uper_bin)), - - ?line testSeqOfCho:compile(Config,?PER,[optimize]), - ?line testSeqOfCho_cases(?PER). - -testSeqOfIndefinite(suite) -> []; -testSeqOfIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOfIndefinite:compile(Config,?BER,[]), - ?line testSeqOfIndefinite:main(), - - ?line ?ber_driver(?BER,testSeqOfIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfIndefinite:main()). - -testSeqOfCho_cases(Rules) -> - ?line testSeqOfCho:main(Rules). - - -testSeqOfExternal(suite) -> []; -testSeqOfExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqOfExternal:compile(Config,?BER,[]), - ?line testSeqOfExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqOfExternal:compile(Config,?PER,[]), - ?line testSeqOfExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfExternal_cases(?PER). - -testSeqOfExternal_cases(Rules) -> - ?line testSeqOfExternal:main(Rules). - - - -testSeqOfTag(suite) -> []; -testSeqOfTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqOfTag:compile(Config,?BER,[]), - ?line testSeqOfTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqOfTag:compile(Config,?PER,[]), - ?line testSeqOfTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfTag:compile(Config,?PER,[optimize]), - ?line testSeqOfTag_cases(?PER). - -testSeqOfTag_cases(Rules) -> - ?line testSeqOfTag:main(Rules). - - - - -testSetDefault(suite) -> []; -testSetDefault(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetDefault:compile(Config,?BER,[]), - ?line testSetDefault_cases(?BER), - - ?line ?ber_driver(?BER,testSetDefault:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetDefault_cases(?BER)), - - ?line testSetDefault:compile(Config,?PER,[]), - ?line testSetDefault_cases(?PER), - - ?line ?per_bit_opt(testSetDefault:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetDefault_cases(?PER)), - - ?line ?uper_bin(testSetDefault:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetDefault_cases(uper_bin)), - - ?line testSetDefault:compile(Config,?PER,[optimize]), - ?line testSetDefault_cases(?PER). - -testSetDefault_cases(Rules) -> - ?line testSetDefault:main(Rules). - - -testParamBasic(suite) -> []; -testParamBasic(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testParamBasic:compile(Config,?BER,[]), - ?line testParamBasic_cases(?BER), - - ?line ?ber_driver(?BER,testParamBasic:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testParamBasic_cases(?BER)), - - ?line testParamBasic:compile(Config,?PER,[]), - ?line testParamBasic_cases(?PER), - - ?line ?per_bit_opt(testParamBasic:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testParamBasic_cases(?PER)), - - ?line ?uper_bin(testParamBasic:compile(Config,uper_bin,[])), - ?line ?uper_bin(testParamBasic_cases(uper_bin)), - - ?line testParamBasic:compile(Config,?PER,[optimize]), - ?line testParamBasic_cases(?PER). - - -testParamBasic_cases(Rules) -> - ?line testParamBasic:main(Rules). - -testSetExtension(suite) -> []; -testSetExtension(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetExtension:compile(Config,?BER,[]), - ?line testSetExtension_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExtension_cases(?BER)). - -testSetExtension_cases(Rules) -> - ?line testSetExtension:main(Rules). - - -testSetExternal(suite) -> []; -testSetExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetExternal:compile(Config,?BER,[]), - ?line testSetExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExternal_cases(?BER)). - -testSetExternal_cases(Rules) -> - ?line testSetExternal:main(Rules). - - -testSetOptional(suite) -> []; -testSetOptional(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOptional:compile(Config,?BER,[]), - ?line testSetOptional_cases(?BER), - - ?line ?ber_driver(?BER,testSetOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOptional_cases(?BER)), - - ?line testSetOptional:compile(Config,?PER,[]), - ?line testSetOptional_cases(?PER), - - ?line ?per_bit_opt(testSetOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOptional_cases(?PER)), - - ?line ?uper_bin(testSetOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOptional_cases(uper_bin)), - - ?line testSetOptional:compile(Config,?PER,[optimize]), - ?line testSetOptional_cases(?PER). - -testSetOptional_cases(Rules) -> - ?line ok = testSetOptional:ticket_7533(Rules), - ?line ok = testSetOptional:main(Rules). - - - - -testSetPrim(suite) -> []; -testSetPrim(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetPrim:compile(Config,?BER,[]), - ?line testSetPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSetPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetPrim_cases(?BER)), - - ?line testSetPrim:compile(Config,?PER,[]), - ?line testSetPrim_cases(?PER), - - ?line ?per_bit_opt(testSetPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetPrim_cases(?PER)), - - ?line ?uper_bin(testSetPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetPrim_cases(uper_bin)), - - ?line testSetPrim:compile(Config,?PER,[optimize]), - ?line testSetPrim_cases(?PER). - -testSetPrim_cases(Rules) -> - ?line testSetPrim:main(Rules). - - - -testSetTag(suite) -> []; -testSetTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetTag:compile(Config,?BER,[]), - ?line testSetTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetTag:compile(Config,?PER,[]), - ?line testSetTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetTag:compile(Config,?PER,[optimize]), - ?line testSetTag_cases(?PER). - -testSetTag_cases(Rules) -> - ?line testSetTag:main(Rules). - - - -testSetTypeRefCho(suite) -> []; -testSetTypeRefCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefCho:compile(Config,?BER,[]), - ?line testSetTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefCho_cases(?BER)), - - ?line testSetTypeRefCho:compile(Config,?PER,[]), - ?line testSetTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefCho_cases(uper_bin)), - - ?line testSetTypeRefCho:compile(Config,?PER,[optimize]), - ?line testSetTypeRefCho_cases(?PER). - -testSetTypeRefCho_cases(Rules) -> - ?line testSetTypeRefCho:main(Rules). - - - -testSetTypeRefPrim(suite) -> []; -testSetTypeRefPrim(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefPrim:compile(Config,?BER,[]), - ?line testSetTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefPrim_cases(?BER)), - - ?line testSetTypeRefPrim:compile(Config,?PER,[]), - ?line testSetTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefPrim_cases(uper_bin)), - - ?line testSetTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testSetTypeRefPrim_cases(?PER). - -testSetTypeRefPrim_cases(Rules) -> - ?line testSetTypeRefPrim:main(Rules). - - - -testSetTypeRefSeq(suite) -> []; -testSetTypeRefSeq(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefSeq:compile(Config,?BER,[]), - ?line testSetTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefSeq_cases(?BER)), - - ?line testSetTypeRefSeq:compile(Config,?PER,[]), - ?line testSetTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefSeq_cases(uper_bin)), - - ?line testSetTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testSetTypeRefSeq_cases(?PER). - -testSetTypeRefSeq_cases(Rules) -> - ?line testSetTypeRefSeq:main(Rules). - - - -testSetTypeRefSet(suite) -> []; -testSetTypeRefSet(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefSet:compile(Config,?BER,[]), - ?line testSetTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefSet_cases(?BER)), - - ?line testSetTypeRefSet:compile(Config,?PER,[]), - ?line testSetTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefSet_cases(uper_bin)), - - ?line testSetTypeRefSet:compile(Config,?PER,[optimize]), - ?line testSetTypeRefSet_cases(?PER). - -testSetTypeRefSet_cases(Rules) -> - ?line testSetTypeRefSet:main(Rules). - - - -testSetOf(suite) -> []; -testSetOf(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOf:compile(Config,?BER,[]), - ?line testSetOf_cases(?BER), - - ?line ?ber_driver(?BER,testSetOf:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOf_cases(?BER)), - - ?line testSetOf:compile(Config,?PER,[]), - ?line testSetOf_cases(?PER), - - ?line ?per_bit_opt(testSetOf:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOf_cases(?PER)), - - ?line ?uper_bin(testSetOf:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOf_cases(uper_bin)), - - ?line testSetOf:compile(Config,?PER,[optimize]), - ?line testSetOf_cases(?PER). - -testSetOf_cases(Rules) -> - ?line testSetOf:main(Rules). - - - -testSetOfCho(suite) -> []; -testSetOfCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOfCho:compile(Config,?BER,[]), - ?line testSetOfCho_cases(?BER), - - ?line ?ber_driver(?BER,testSetOfCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfCho_cases(?BER)), - - ?line testSetOfCho:compile(Config,?PER,[]), - ?line testSetOfCho_cases(?PER), - - ?line ?per_bit_opt(testSetOfCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfCho_cases(?PER)), - - ?line ?uper_bin(testSetOfCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfCho_cases(uper_bin)), - - ?line testSetOfCho:compile(Config,?PER,[optimize]), - ?line testSetOfCho_cases(?PER). - -testSetOfCho_cases(Rules) -> - ?line testSetOfCho:main(Rules). - - -testSetOfExternal(suite) -> []; -testSetOfExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetOfExternal:compile(Config,?BER,[]), - ?line testSetOfExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetOfExternal:compile(Config,?PER,[]), - ?line testSetOfExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetOfExternal:compile(Config,?PER,[optimize]), - ?line testSetOfExternal_cases(?PER). - -testSetOfExternal_cases(Rules) -> - ?line testSetOfExternal:main(Rules). - - - - -testSetOfTag(suite) -> []; -testSetOfTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetOfTag:compile(Config,?BER,[]), - ?line testSetOfTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetOfTag:compile(Config,?PER,[]), - ?line testSetOfTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetOfTag:compile(Config,?PER,[optimize]), - ?line testSetOfTag_cases(?PER). - -testSetOfTag_cases(Rules) -> - ?line testSetOfTag:main(Rules). - - -c_syntax(suite) -> []; -c_syntax(Config) -> - ?line DataDir% ?line testExternal:compile(Config,?PER), -% ?line testPrimExternal:compile(Config,?PER), -% ?line testPrimExternal_cases(?PER). - = ?config(data_dir,Config), - ?line _TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line {error,_R1} = asn1ct:compile(filename:join(DataDir,"Syntax")), - ?line {error,_R2} = asn1ct:compile(filename:join(DataDir,"BadTypeEnding")), - ?line {error,_R3} = asn1ct:compile(filename:join(DataDir, - "BadValueAssignment1")), - ?line {error,_R4} = asn1ct:compile(filename:join(DataDir, - "BadValueAssignment2")), - ?line {error,_R5} = asn1ct:compile(filename:join(DataDir, - "BadValueSet")), - ?line {error,_R6} = asn1ct:compile(filename:join(DataDir, - "ChoiceBadExtension")), - ?line {error,_R7} = asn1ct:compile(filename:join(DataDir, - "EnumerationBadExtension")), - ?line {error,_R8} = asn1ct:compile(filename:join(DataDir, - "Example")), - ?line {error,_R9} = asn1ct:compile(filename:join(DataDir, - "Export1")), - ?line {error,_R10} = asn1ct:compile(filename:join(DataDir, - "MissingEnd")), - ?line {error,_R11} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComma")), - ?line {error,_R12} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComponentName")), - ?line {error,_R13} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComponentType")), - ?line {error,_R14} = asn1ct:compile(filename:join(DataDir, - "SeqBadComma")). - - -c_string_per(suite) -> []; -c_string_per(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"String"),[?PER,{outdir,TempDir}]). - -c_string_ber(suite) -> []; -c_string_ber(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"String"),[?BER,{outdir,TempDir}]). - - -c_implicit_before_choice(suite) -> []; -c_implicit_before_choice(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line {error,_R2} = asn1ct:compile(filename:join(DataDir,"CCSNARG3"),[?BER,{outdir,TempDir}]). - -parse(suite) -> []; -parse(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - M1 = test_modules(), -% M2 = parse_modules(), - ?line ok = parse1(M1,DataDir,OutDir). - -parse1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[abs,{outdir,OutDir}]), - parse1(T,DataDir,OutDir); -parse1([],_,_) -> - ok. - -per(suite) -> []; -per(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = per1(per_modules(),DataDir,OutDir), - ?line ?per_bit_opt(per1_bit_opt(per_modules(),DataDir,OutDir)), - ?line ok = per1_opt(per_modules(),DataDir,OutDir). - - -per1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1(T,DataDir,OutDir); -per1([],_,_) -> - ok. - -per1_bit_opt([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,optimize,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1_bit_opt(T,DataDir,OutDir); -per1_bit_opt([],_,_) -> - ok. - -per1_opt([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,optimized,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1_opt(T,DataDir,OutDir); -per1_opt([],_,_) -> - ok. - - -ber_choiceinseq(suite) ->[]; -ber_choiceinseq(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"ChoiceInSeq"),[?BER,{outdir,OutDir}]). - -ber_optional(suite) ->[]; -ber_optional(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"SOpttest"),[?BER,{outdir,OutDir}]), - ?line V = {'S',{'A',10,asn1_NOVALUE,asn1_NOVALUE}, - {'B',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}, - {'C',asn1_NOVALUE,111,asn1_NOVALUE}}, - ?line {ok,B} = asn1_wrapper:encode('SOpttest','S',V), - ?line Bytes = lists:flatten(B), - ?line V2 = asn1_wrapper:decode('SOpttest','S',Bytes), - ?line ok = eq(V,element(2,V2)). - -ber_optional_keyed_list(suite) ->[]; -ber_optional_keyed_list(Config) -> - case ?BER of - ber_bin_v2 -> ok; - _ -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"SOpttest"), - [?BER,keyed_list,{outdir,OutDir}]), - ?line Vrecord = {'S',{'A',10,asn1_NOVALUE,asn1_NOVALUE}, - {'B',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}, - {'C',asn1_NOVALUE,111,asn1_NOVALUE}}, - ?line V = [ {a,[{scriptKey,10}]}, - {b,[]}, - {c,[{callingPartysCategory,111}]} ], - ?line {ok,B} = asn1_wrapper:encode('SOpttest','S',V), - ?line Bytes = lists:flatten(B), - ?line V2 = asn1_wrapper:decode('SOpttest','S',Bytes), - ?line ok = eq(Vrecord,element(2,V2)) - end. - - -eq(V,V) -> - ok. - - -ber_other(suite) ->[]; -ber_other(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = ber1(ber_modules(),DataDir,OutDir). - - -ber1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?BER,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - ber1(T,DataDir,OutDir); -ber1([],_,_) -> - ok. - -default_per(suite) ->[]; -default_per(Config) -> - default1(?PER,Config,[]). - -default_per_opt(suite) -> []; -default_per_opt(Config) -> - ?per_bit_opt(default1(?PER,Config,[optimize])), - default1(?PER,Config,[optimize]). - -default_ber(suite) ->[]; -default_ber(Config) -> - default1(?BER,Config,[]). - -default1(Rule,Config,Options) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "Def",[Rule,{outdir,OutDir}]++Options), - ?line {ok,Bytes1} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true, - bool1 = true, - bool2 = true, - bool3 = true}), - ?line {ok,{'Def1',true,true,true,true}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes1)), - - ?line {ok,Bytes2} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true}), - ?line {ok,{'Def1',true,false,false,false}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes2)), - - ?line {ok,Bytes3} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true,bool2=false}), - ?line {ok,{'Def1',true,false,false,false}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes3)). - - -value_test(suite) ->[]; -value_test(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "ObjIdValues",[?BER,{outdir,OutDir}]), - ?line {ok,_} = asn1_wrapper:encode('ObjIdValues','ObjIdType','ObjIdValues':'mobileDomainId'()), - ?line ok = asn1ct:compile(DataDir ++ "ObjIdValues",[?PER,{outdir,OutDir}]), - ?line {ok,_} = asn1_wrapper:encode('ObjIdValues','ObjIdType','ObjIdValues':'mobileDomainId'()), - ?line ok = test_bad_values:tests(Config), - ok. - - -constructed(suite) -> - []; -constructed(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "Constructed",[?BER,{outdir,OutDir}]), - ?line {ok,B} = asn1_wrapper:encode('Constructed','S',{'S',false}), - ?line [40,3,1,1,0] = lists:flatten(B), - ?line {ok,B1} = asn1_wrapper:encode('Constructed','S2',{'S2',false}), - ?line [40,5,48,3,1,1,0] = lists:flatten(B1), - ?line {ok,B2} = asn1_wrapper:encode('Constructed','I',10), - ?line [136,1,10] = lists:flatten(B2), - ok. - -ber_decode_error(suite) -> []; -ber_decode_error(Config) -> - ?line ok = ber_decode_error:compile(Config,?BER,[]), - ?line ok = ber_decode_error:run([]), - - ?line ok = ?ber_driver(?BER,ber_decode_error:compile(Config,?BER,[driver])), - ?line ok = ?ber_driver(?BER,ber_decode_error:run([driver])), - ok. - -h323test(suite) -> - []; -h323test(Config) -> - ?line ok = h323test:compile(Config,?PER,[]), - ?line ok = h323test:run(?PER), - ?line ?per_bit_opt(h323test:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(h323test:run(?PER)), - ?line ?uper_bin(h323test:compile(Config,uper_bin,[])), - ?line ?uper_bin(h323test:run(uper_bin)), - ?line ok = h323test:compile(Config,?PER,[optimize]), - ?line ok = h323test:run(?PER), - ok. - -per_GeneralString(suite) -> - []; -per_GeneralString(Config) -> - case erlang:module_loaded('MULTIMEDIA-SYSTEM-CONTROL') of - true -> - ok; - false -> - h323test:compile(Config,?PER,[]) - end, - UI = [109,64,1,57], - ?line {ok,_V} = asn1_wrapper:decode('MULTIMEDIA-SYSTEM-CONTROL', - 'MultimediaSystemControlMessage',UI). - -per_open_type(suite) -> - []; -per_open_type(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line ok = asn1ct:compile(DataDir ++ "OpenType",[?PER,{outdir,OutDir}]), - Stype = {'Stype',10,true}, - ?line {ok,Bytes} = asn1_wrapper:encode('OpenType','Ot',Stype), - ?line {ok,Stype} = asn1_wrapper:decode('OpenType','Ot',Bytes), - - ?line ?per_bit_opt(ok = asn1ct:compile(DataDir ++ "OpenType", - [?PER,optimize,{outdir,OutDir}])), - ?line ?per_bit_opt({ok,Bytes}=asn1_wrapper:encode('OpenType','Ot',Stype)), - ?line ?per_bit_opt({ok,Stype}=asn1_wrapper:decode('OpenType','Ot',Bytes)), - - ?line ?uper_bin(ok = asn1ct:compile(DataDir ++ "OpenType", - [uper_bin,{outdir,OutDir}])), - ?line ?uper_bin({ok,Bytes}=asn1_wrapper:encode('OpenType','Ot',Stype)), - ?line ?uper_bin({ok,Stype}=asn1_wrapper:decode('OpenType','Ot',Bytes)), - - ?line ok = asn1ct:compile(DataDir ++ "OpenType", - [?PER,optimize,{outdir,OutDir}]), - ?line {ok,Bytes} = asn1_wrapper:encode('OpenType','Ot',Stype), - ?line {ok,Stype} = asn1_wrapper:decode('OpenType','Ot',Bytes). - -testConstraints(suite) -> - []; -testConstraints(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testConstraints:compile(Config,?BER,[]), - ?line testConstraints:int_constraints(?BER), - - ?line ?ber_driver(?BER,testConstraints:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testConstraints:int_constraints(?BER)), - - ?line testConstraints:compile(Config,?PER,[]), - ?line testConstraints:int_constraints(?PER), - ?line testConstraints:refed_NNL_name(?PER), - - ?line ?per_bit_opt(testConstraints:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testConstraints:int_constraints(?PER)), - ?line ?per_bit_opt(testConstraints:refed_NNL_name(?PER)), - - ?line ?uper_bin(testConstraints:compile(Config,uper_bin,[])), - ?line ?uper_bin(testConstraints:int_constraints(uper_bin)), - ?line ?uper_bin(testConstraints:refed_NNL_name(uper_bin)), - - ?line testConstraints:compile(Config,?PER,[optimize]), - ?line testConstraints:int_constraints(?PER), - ?line testConstraints:refed_NNL_name(?PER). - -testSeqIndefinite(suite) -> []; -testSeqIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqIndefinite:compile(Config,?BER,[]), - ?line testSeqIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testSeqIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqIndefinite:main(?BER)). - -testSetIndefinite(suite) -> []; -testSetIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetIndefinite:compile(Config,?BER,[]), - ?line testSetIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testSetIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetIndefinite:main(?BER)). - -testChoiceIndefinite(suite) -> []; -testChoiceIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testChoiceIndefinite:compile(Config,?BER,[]), - ?line testChoiceIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testChoiceIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoiceIndefinite:main(?BER)). - -testInfObjectClass(suite) -> - []; -testInfObjectClass(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testInfObjectClass:compile(Config,?PER,[]), - ?line testInfObjectClass:main(?PER), - ?line testInfObj:compile(Config,?PER,[]), - ?line testInfObj:main(?PER), - - ?line ?per_bit_opt(testInfObjectClass:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testInfObjectClass:main(?PER)), - ?line ?per_bit_opt(testInfObj:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testInfObj:main(?PER)), - - ?line ?uper_bin(testInfObjectClass:compile(Config,uper_bin,[])), - ?line ?uper_bin(testInfObjectClass:main(uper_bin)), - ?line ?uper_bin(testInfObj:compile(Config,uper_bin,[])), - ?line ?uper_bin(testInfObj:main(uper_bin)), - - ?line testInfObjectClass:compile(Config,?PER,[optimize]), - ?line testInfObjectClass:main(?PER), - ?line testInfObj:compile(Config,?PER,[optimize]), - ?line testInfObj:main(?PER), - - ?line testInfObjectClass:compile(Config,?BER,[]), - ?line testInfObjectClass:main(?BER), - ?line testInfObj:compile(Config,?BER,[]), - ?line testInfObj:main(?BER), - - ?line ?ber_driver(?BER,testInfObjectClass:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testInfObjectClass:main(?BER)), - ?line ?ber_driver(?BER,testInfObj:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testInfObj:main(?BER)), - - ?line testInfObj:compile_RANAPfiles(Config,?PER,[]), - - ?line ?per_bit_opt(testInfObj:compile_RANAPfiles(Config,?PER,[optimize])), - - ?line ?uper_bin(testInfObj:compile_RANAPfiles(Config,uper_bin,[])), - - ?line testInfObj:compile_RANAPfiles(Config,?PER,[optimize]), - - ?line testInfObj:compile_RANAPfiles(Config,?BER,[]). - -testParameterizedInfObj(suite) -> - []; -testParameterizedInfObj(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testParameterizedInfObj:compile(Config,?PER,[]), - ?line testParameterizedInfObj:main(?PER), - - ?line ?per_bit_opt(testParameterizedInfObj:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testParameterizedInfObj:main(?PER)), - - ?line ?uper_bin(testParameterizedInfObj:compile(Config,uper_bin,[])), - ?line ?uper_bin(testParameterizedInfObj:main(uper_bin)), - - ?line testParameterizedInfObj:compile(Config,?PER,[optimize]), - ?line testParameterizedInfObj:main(?PER), - - ?line testParameterizedInfObj:compile(Config,?BER,[]), - ?line testParameterizedInfObj:main(?BER), - - ?line ?ber_driver(?BER,testParameterizedInfObj:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testParameterizedInfObj:main(?BER)). - -testMergeCompile(suite) -> - []; -testMergeCompile(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testMergeCompile:compile(Config,?PER,[]), - ?line testMergeCompile:main(?PER), - ?line testMergeCompile:mvrasn(?PER), - - ?line ?per_bit_opt(testMergeCompile:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testMergeCompile:main(?PER)), - ?line ?per_bit_opt(testMergeCompile:mvrasn(?PER)), - - ?line ?uper_bin(testMergeCompile:compile(Config,uper_bin,[])), - ?line ?uper_bin(testMergeCompile:main(uper_bin)), - ?line ?uper_bin(testMergeCompile:mvrasn(uper_bin)), - - ?line testMergeCompile:compile(Config,?BER,[]), - ?line testMergeCompile:main(?BER), - ?line testMergeCompile:mvrasn(?BER), - - ?line ?ber_driver(?BER,testMergeCompile:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testMergeCompile:main(?BER)), - ?line ?ber_driver(?BER,testMergeCompile:mvrasn(?BER)). - -testobj(suite) -> - []; -testobj(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line ok = testRANAP:compile(Config,?PER,[]), - ?line ok = testRANAP:testobj(?PER), - ?line ok = testParameterizedInfObj:ranap(?PER), - - ?line ?per_bit_opt(ok = testRANAP:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(ok = testRANAP:testobj(?PER)), - ?line ?per_bit_opt(ok = testParameterizedInfObj:ranap(?PER)), - - ?line ?uper_bin(ok = testRANAP:compile(Config,uper_bin,[])), - ?line ?uper_bin(ok = testRANAP:testobj(uper_bin)), - ?line ?uper_bin(ok = testParameterizedInfObj:ranap(uper_bin)), - - ?line ok = testRANAP:compile(Config,?PER,[optimize]), - ?line ok = testRANAP:testobj(?PER), - ?line ok = testParameterizedInfObj:ranap(?PER), - - ?line ok = testRANAP:compile(Config,?BER,[]), - ?line ok = testRANAP:testobj(?BER), - ?line ok = testParameterizedInfObj:ranap(?BER), - - ?line ?ber_driver(?BER,testRANAP:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testRANAP:testobj(?BER)), - ?line ?ber_driver(?BER,testParameterizedInfObj:ranap(?BER)). - - -testDeepTConstr(suite) -> - []; -testDeepTConstr(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testDeepTConstr:compile(Config,?PER,[]), - ?line testDeepTConstr:main(?PER), - - ?line ?per_bit_opt(testDeepTConstr:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDeepTConstr:main(?PER)), - - ?line ?uper_bin(testDeepTConstr:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDeepTConstr:main(uper_bin)), - - ?line testDeepTConstr:compile(Config,?PER,[optimize]), - ?line testDeepTConstr:main(?PER), - - ?line testDeepTConstr:compile(Config,?BER,[]), - ?line testDeepTConstr:main(?BER), - - ?line ?ber_driver(?BER,testDeepTConstr:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDeepTConstr:main(?BER)). - -testInvokeMod(suite) -> - []; -testInvokeMod(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line ok = asn1ct:compile(filename:join(DataDir,"PrimStrings"),[{outdir,OutDir}]), - ?line {ok,_Result1} = 'PrimStrings':encode('Bs1',[1,0,1,0]), - ?line ok = asn1ct:compile(filename:join(DataDir,"PrimStrings"),[?PER,{outdir,OutDir}]), - ?line {ok,_Result2} = 'PrimStrings':encode('Bs1',[1,0,1,0]). - -testExport(suite) -> - []; -testExport(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line {error,{asn1,_Reason}} = asn1ct:compile(filename:join(DataDir,"IllegalExport"),[{outdir,OutDir}]). - -testImport(suite) -> - []; -testImport(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line _OutDir = ?config(priv_dir,Config), - ?line {error,_} = asn1ct:compile(filename:join(DataDir,"ImportsFrom"),[?BER]), - ok. - -testMegaco(suite) -> - []; -testMegaco(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - io:format("Config: ~p~n",[Config]), - ?line {ok,ModuleName1,ModuleName2} = testMegaco:compile(Config,?BER,[]), - ?line ok = testMegaco:main(ModuleName1,Config), - ?line ok = testMegaco:main(ModuleName2,Config), - - case ?BER of - ber_bin_v2 -> - ?line {ok,ModuleName3,ModuleName4} = testMegaco:compile(Config,?BER,[driver]), - ?line ok = testMegaco:main(ModuleName3,Config), - ?line ok = testMegaco:main(ModuleName4,Config); - _-> ok - end, - - ?line {ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,?PER,[]), - ?line ok = testMegaco:main(ModuleName5,Config), - ?line ok = testMegaco:main(ModuleName6,Config), - - ?line ?per_bit_opt({ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(ok = testMegaco:main(ModuleName5,Config)), - ?line ?per_bit_opt(ok = testMegaco:main(ModuleName6,Config)), - - ?line ?uper_bin({ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,uper_bin,[])), - ?line ?uper_bin(ok = testMegaco:main(ModuleName5,Config)), - ?line ?uper_bin(ok = testMegaco:main(ModuleName6,Config)), - - ?line {ok,ModuleName7,ModuleName8} = testMegaco:compile(Config,?PER,[optimize]), - ?line ok = testMegaco:main(ModuleName7,Config), - ?line ok = testMegaco:main(ModuleName8,Config). - - -testMvrasn6(suite) -> []; -testMvrasn6(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testMvrasn6:compile(Config,?BER), - ?line testMvrasn6:main(). - -testContextSwitchingTypes(suite) -> []; -testContextSwitchingTypes(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testContextSwitchingTypes:compile(Config,?BER,[]), - ?line testContextSwitchingTypes:test(), - - ?line ?ber_driver(?BER,testContextSwitchingTypes:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testContextSwitchingTypes:test()), - - ?line testContextSwitchingTypes:compile(Config,?PER,[]), - ?line testContextSwitchingTypes:test(), - - ?line ?per_bit_opt(testContextSwitchingTypes:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testContextSwitchingTypes:test()), - - ?line ?uper_bin(testContextSwitchingTypes:compile(Config,uper_bin,[])), - ?line ?uper_bin(testContextSwitchingTypes:test()), - - ?line testContextSwitchingTypes:compile(Config,?PER,[optimize]), - ?line testContextSwitchingTypes:test(). - -testTypeValueNotation(suite) -> []; -testTypeValueNotation(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - case ?BER of - Ber when Ber == ber; Ber == ber_bin -> - ?line testTypeValueNotation:compile(Config,?BER,[]), - ?line testTypeValueNotation:main(?BER,dummy); - _ -> - ok - end, - - ?line ?ber_driver(?BER,testTypeValueNotation:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testTypeValueNotation:main(?BER,optimize)), - - case ?BER of - Ber2 when Ber2 == ber; Ber2 == ber_bin -> - ?line testTypeValueNotation:compile(Config,?PER,[]), - ?line testTypeValueNotation:main(?PER,dummy); - _ -> - ok - end, - - ?line ?per_bit_opt(testTypeValueNotation:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testTypeValueNotation:main(?PER,optimize)), - - ?line ?uper_bin(testTypeValueNotation:compile(Config,uper_bin,[])), - ?line ?uper_bin(testTypeValueNotation:main(uper_bin,optimize)), - case ?BER of - Ber3 when Ber3 == ber; Ber3 == ber_bin -> - ?line testTypeValueNotation:compile(Config,?PER,[optimize]), - ?line testTypeValueNotation:main(?PER,optimize); - _ -> - ok - end. - -testOpenTypeImplicitTag(suite) -> []; -testOpenTypeImplicitTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testOpenTypeImplicitTag:compile(Config,?BER,[]), - ?line testOpenTypeImplicitTag:main(?BER), - - ?line ?ber_driver(?BER,testOpenTypeImplicitTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testOpenTypeImplicitTag:main(?BER)), - - ?line testOpenTypeImplicitTag:compile(Config,?PER,[]), - ?line testOpenTypeImplicitTag:main(?PER), - - ?line ?per_bit_opt(testOpenTypeImplicitTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testOpenTypeImplicitTag:main(?PER)), - - ?line ?uper_bin(testOpenTypeImplicitTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testOpenTypeImplicitTag:main(uper_bin)), - - ?line testOpenTypeImplicitTag:compile(Config,?PER,[optimize]), - ?line testOpenTypeImplicitTag:main(?PER). - -duplicate_tags(suite) -> []; -duplicate_tags(Config) -> - ?line DataDir = ?config(data_dir,Config), - {error,{asn1,[{error,{type,_,_,'SeqOpt1Imp',{asn1,{duplicates_of_the_tags,_}}}}]}} = - asn1ct:compile(filename:join(DataDir,"SeqOptional2"),[abs]), - ok. - -rtUI(suite) -> []; -rtUI(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"Prim"),[?BER]), - ?line {ok,_} = asn1rt:info('Prim'), - - ?line ok = asn1ct:compile(filename:join(DataDir,"Prim"),[?PER]), - ?line {ok,_} = asn1rt:info('Prim'), - - ?line ok = asn1rt:load_driver(), - ?line ok = asn1rt:load_driver(), - ?line ok = asn1rt:unload_driver(). - -testROSE(suite) -> []; -testROSE(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testROSE:compile(Config,?BER,[]), - - ?line testROSE:compile(Config,?PER,[]), - ?line ?per_bit_opt(testROSE:compile(Config,?PER,[optimize])), - ?line ?uper_bin(testROSE:compile(Config,uper_bin,[])), - ?line testROSE:compile(Config,?PER,[optimize]). - -testINSTANCE_OF(suite) -> []; -testINSTANCE_OF(Config) -> - ?line testINSTANCE_OF:compile(Config,?BER,[]), - ?line testINSTANCE_OF:main(?BER), - - ?line ?ber_driver(?BER,testINSTANCE_OF:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testINSTANCE_OF:main(?BER)), - - ?line testINSTANCE_OF:compile(Config,?PER,[]), - ?line testINSTANCE_OF:main(?PER), - - ?line ?per_bit_opt(testINSTANCE_OF:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testINSTANCE_OF:main(?PER)), - - ?line ?uper_bin(testINSTANCE_OF:compile(Config,uper_bin,[])), - ?line ?uper_bin(testINSTANCE_OF:main(uper_bin)), - - ?line testINSTANCE_OF:compile(Config,?PER,[optimize]), - ?line testINSTANCE_OF:main(?PER). - -testTCAP(suite) -> []; -testTCAP(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testTCAP:compile(Config,?BER,[]), - ?line testTCAP:test(?BER,Config), - - ?line ?ber_driver(?BER,testTCAP:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testTCAP:test(?BER,Config)), - - ?line ?ber_driver(?BER,testTCAP:compile_asn1config(Config,?BER,[asn1config])), - ?line ?ber_driver(?BER,testTCAP:test_asn1config()). - -testDER(suite) ->[]; -testDER(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testDER:compile(Config,?BER,[]), - ?line testDER:test(), - - ?line ?ber_driver(?BER,testDER:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDER:test()), - - ?line testParamBasic:compile_der(Config,?BER), - ?line testParamBasic_cases(der), - - - ?line testSeqSetDefaultVal:compile(Config,?BER), - ?line testSeqSetDefaultVal_cases(?BER). - -testSeqSetDefaultVal_cases(?BER) -> - ?line testSeqSetDefaultVal:main(?BER). - - -specialized_decodes(suite) -> []; -specialized_decodes(Config) -> - ?line test_partial_incomplete_decode:compile(Config,?BER,[optimize]), - ?line test_partial_incomplete_decode:test(?BER,Config), - ?line test_selective_decode:test(?BER,Config). - -special_decode_performance(suite) ->[]; -special_decode_performance(Config) -> - ?line ?ber_driver(?BER,test_special_decode_performance:compile(Config,?BER)), - ?line ?ber_driver(?BER,test_special_decode_performance:go(all)). - - -test_driver_load(suite) -> []; -test_driver_load(Config) -> - ?line test_driver_load:compile(Config,?PER), - ?line test_driver_load:test(?PER,5). - -test_ParamTypeInfObj(suite) -> []; -test_ParamTypeInfObj(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"IN-CS-1-Datatypes"),[ber_bin]). - -test_WS_ParamClass(suite) -> []; -test_WS_ParamClass(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"InformationFramework"), - [ber_bin]). - -test_Defed_ObjectIdentifier(suite) -> []; -test_Defed_ObjectIdentifier(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"UsefulDefinitions"), - [ber_bin]). - -testSelectionType(suite) -> []; -testSelectionType(Config) -> - - ?line ok = testSelectionTypes:compile(Config,?BER,[]), - ?line {ok,_} = testSelectionTypes:test(), - - ?line ok = testSelectionTypes:compile(Config,?PER,[]), - ?line {ok,_} = testSelectionTypes:test(). - -testSSLspecs(suite) -> []; -testSSLspecs(Config) -> - - ?line ok = testSSLspecs:compile(Config,?BER, - [optimize,compact_bit_string,der]), - ?line testSSLspecs:run(?BER), - - case code:which(asn1ct) of - cover_compiled -> - ok; - _ -> - ?line ok = testSSLspecs:compile_inline(Config,?BER), - ?line ok = testSSLspecs:run_inline(?BER) - end. - -testNortel(suite) -> []; -testNortel(Config) -> - ?line DataDir = ?config(data_dir,Config), - - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[?BER]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?BER,optimize]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?BER,optimize,driver]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[?PER]), - ?line ?per_bit_opt(ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?PER,optimize])), - ?line ?uper_bin(ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[uper_bin])), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?PER,optimize]). -test_undecoded_rest(suite) -> []; -test_undecoded_rest(Config) -> - - ?line ok = test_undecoded_rest:compile(Config,?BER,[]), - ?line ok = test_undecoded_rest:test([]), - - ?line ok = test_undecoded_rest:compile(Config,?BER,[undec_rest]), - ?line ok = test_undecoded_rest:test(undec_rest), - - ?line ok = test_undecoded_rest:compile(Config,?PER,[]), - ?line ok = test_undecoded_rest:test([]), - - ?line ?per_bit_opt(ok = test_undecoded_rest:compile(Config,?PER,[optimize,undec_rest])), - ?line ?per_bit_opt(ok = test_undecoded_rest:test(undec_rest)), - - ?line ?uper_bin(ok = test_undecoded_rest:compile(Config,uper_bin,[undec_rest])), - ?line ?uper_bin(ok = test_undecoded_rest:test(undec_rest)), - - ?line ok = test_undecoded_rest:compile(Config,?PER,[undec_rest]), - ?line ok = test_undecoded_rest:test(undec_rest). - -test_inline(suite) -> []; -test_inline(Config) -> - case code:which(asn1ct) of - cover_compiled -> - {skip,"Not runnable when cover compiled"}; - _ -> - ?line ok=test_inline:compile(Config,?BER,[]), - ?line test_inline:main(?BER), - ?line test_inline:inline1(Config,?BER,[]), - ?line test_inline:performance2() - end. - -%test_inline_prf(suite) -> []; -%test_inline_prf(Config) -> -% ?line test_inline:performance(Config). - -testTcapsystem(suite) -> []; -testTcapsystem(Config) -> - ?line ok=testTcapsystem:compile(Config,?BER,[]). - -testNBAPsystem(suite) -> []; -testNBAPsystem(Config) -> - ?line ok=testNBAPsystem:compile(Config,?PER,?per_optimize(?BER)), - ?line ok=testNBAPsystem:test(?PER,Config). - -test_compile_options(suite) -> []; -test_compile_options(Config) -> - case code:which(asn1ct) of - cover_compiled -> - {skip,"Not runnable when cover compiled"}; - _ -> - ?line ok = test_compile_options:wrong_path(Config), - ?line ok = test_compile_options:path(Config), - ?line ok = test_compile_options:noobj(Config), - ?line ok = test_compile_options:record_name_prefix(Config), - ?line ok = test_compile_options:verbose(Config) - end. -testDoubleEllipses(suite) -> []; -testDoubleEllipses(Config) -> - ?line testDoubleEllipses:compile(Config,?BER,[]), - ?line testDoubleEllipses:main(?BER), - ?line ?ber_driver(?BER,testDoubleEllipses:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDoubleEllipses:main(?BER)), - ?line ?per_bit_opt(testDoubleEllipses:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDoubleEllipses:main(?PER)), - ?line ?uper_bin(testDoubleEllipses:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDoubleEllipses:main(uper_bin)), - ?line testDoubleEllipses:compile(Config,?PER,?per_optimize(?BER)), - ?line testDoubleEllipses:main(?PER). - -test_modified_x420(suite) -> []; -test_modified_x420(Config) -> - ?line test_modified_x420:compile(Config), - ?line test_modified_x420:test_io(Config). - -testX420(suite) -> []; -testX420(Config) -> - ?line testX420:compile(?BER,[der],Config), - ?line ok = testX420:ticket7759(?BER,Config), - ?line testX420:compile(?PER,[],Config). - -test_x691(suite) -> []; -test_x691(Config) -> - case ?PER of - per -> - ?line ok = test_x691:compile(Config,uper_bin,[]), - ?line true = test_x691:cases(uper_bin,unaligned), - ?line ok = test_x691:compile(Config,?PER,[]), - ?line true = test_x691:cases(?PER,aligned), -%% ?line ok = asn1_test_lib:ticket_7678(Config,[]), - ?line ok = asn1_test_lib:ticket_7708(Config,[]), - ?line ok = asn1_test_lib:ticket_7763(Config); - _ -> - ?line ok = test_x691:compile(Config,?PER,?per_optimize(?BER)), - ?line true = test_x691:cases(?PER,aligned) - end. -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[compact_bit_string]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[optimize]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[optimize,compact_bit_string]). - - -ticket_6143(suite) -> []; -ticket_6143(Config) -> - ?line ok = test_compile_options:ticket_6143(Config). - -testExtensionAdditionGroup(suite) -> []; -testExtensionAdditionGroup(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line PrivDir = ?config(priv_dir,Config), - ?line Path = code:get_path(), - ?line code:add_patha(PrivDir), - DoIt = fun(Erule) -> - ?line ok = asn1ct:compile(filename:join(DataDir,"Extension-Addition-Group"),[Erule,{outdir,PrivDir}]), - ?line {ok,_M} = compile:file(filename:join(DataDir,"extensionAdditionGroup"),[{i,PrivDir},{outdir,PrivDir},debug_info]), - ?line ok = extensionAdditionGroup:run(Erule) - end, - ?line [DoIt(Rule)|| Rule <- [per_bin,uper_bin,ber_bin]], - ?line code:set_path(Path). - - - -% parse_modules() -> -% ["ImportsFrom"]. - -per_modules() -> - [X || X <- test_modules()]. -ber_modules() -> - [X || X <- test_modules(), - X =/= "CommonDataTypes", - X =/= "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath", - X =/= "H323-MESSAGES", - X =/= "H235-SECURITY-MESSAGES", - X =/= "MULTIMEDIA-SYSTEM-CONTROL"]. -test_modules() -> - _Modules = [ - "BitStr", - "CommonDataTypes", - "Constraints", - "ContextSwitchingTypes", - "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath", - "Enum", - "From", - "H235-SECURITY-MESSAGES", - "H323-MESSAGES", - %%"MULTIMEDIA-SYSTEM-CONTROL", recursive type , problem for asn1ct:value - "Import", - "Int", - "MAP-commonDataTypes", -% ambigous tags "MAP-insertSubscriberData-def", - "Null", - "Octetstr", - "One", - "P-Record", - "P", -% "PDUs", - "Person", - "PrimStrings", - "Real", - "XSeq", - "XSeqOf", - "XSet", - "XSetOf", - "String", - "SwCDR", -% "Syntax", - "Time" -% ANY "Tst", -% "Two", -% errors that should be detected "UndefType" -] ++ - [ - "SeqSetLib", % must be compiled before Seq and Set - "Seq", - "Set", - "SetOf", - "SeqOf", - "Prim", - "Cho", - "Def", - "Opt", - "ELDAPv3", - "LDAP" - ]. - - -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% - -common() -> -[{group, app_test}, {group, appup_test}, testTimer_ber, - testTimer_ber_bin, testTimer_ber_bin_opt, - testTimer_ber_bin_opt_driver, testTimer_per, - testTimer_per_bin, testTimer_per_bin_opt, - testTimer_uper_bin, testComment, testName2Number]. - - - -testTimer_ber(suite) -> []; -testTimer_ber(Config) -> - ?line testTimer:compile(Config,ber,[]), - ?line testTimer:go(Config,ber). - -testTimer_ber_bin(suite) -> []; -testTimer_ber_bin(Config) -> - ?line testTimer:compile(Config,ber_bin,[]), - ?line testTimer:go(Config,ber_bin). - -testTimer_ber_bin_opt(suite) -> []; -testTimer_ber_bin_opt(Config) -> - ?line testTimer:compile(Config,ber_bin,[optimize]), - ?line testTimer:go(Config,ber_bin). - -testTimer_ber_bin_opt_driver(suite) -> []; -testTimer_ber_bin_opt_driver(Config) -> - ?line testTimer:compile(Config,ber_bin,[optimize,driver]), - ?line testTimer:go(Config,ber_bin). - -testTimer_per(suite) -> []; -testTimer_per(Config) -> - ?line testTimer:compile(Config,per,[]), - ?line testTimer:go(Config,per). - -testTimer_per_bin(suite) -> []; -testTimer_per_bin(Config) -> - ?line testTimer:compile(Config,per_bin,[]), - ?line testTimer:go(Config,per_bin). - -testTimer_per_bin_opt(suite) -> []; -testTimer_per_bin_opt(Config) -> - ?line testTimer:compile(Config,per_bin,[optimize]), - ?line testTimer:go(Config,per_bin). - - -testTimer_uper_bin(suite) -> []; -testTimer_uper_bin(Config) -> - ?line ok=testTimer:compile(Config,uper_bin,[]), - ?line {comment,_} = testTimer:go(Config,uper_bin). - -%% Test of multiple-line comment, OTP-8043 -testComment(suite) -> []; -testComment(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - - ?line ok = asn1ct:compile(DataDir ++ "Comment",[{outdir,OutDir}]), - - ?line {ok,Enc} = asn1_wrapper:encode('Comment','Seq',{'Seq',12,true}), - ?line {ok,{'Seq',12,true}} = asn1_wrapper:decode('Comment','Seq',Enc), - ok. - -testName2Number(suite) -> []; -testName2Number(Config) -> - DataDir = ?config(data_dir,Config), - OutDir = ?config(priv_dir,Config), - N2NOptions = [{n2n,Type}|| Type <- - ['CauseMisc','CauseProtocol', - %% 'CauseNetwork', - 'CauseRadioNetwork', - 'CauseTransport','CauseNas']], - ?line ok = asn1ct:compile(DataDir ++ "S1AP-IEs",[{outdir,OutDir}]++N2NOptions), - ?line true = code:add_patha(OutDir), - - ?line 0 = 'S1AP-IEs':name2num_CauseMisc('control-processing-overload'), - ?line 'unknown-PLMN' = 'S1AP-IEs':num2name_CauseMisc(5), - ok. - - -particular() -> - [ticket_7407]. - -ticket_7407(suite) -> []; -ticket_7407(Config) -> - ?line ok = asn1_test_lib:ticket_7407_compile(Config,[]), - ?line ok = asn1_test_lib:ticket_7407_code(true), - - ?line ok = asn1_test_lib:ticket_7407_compile(Config,[no_final_padding]), - ?line ok = asn1_test_lib:ticket_7407_code(false). diff --git a/lib/asn1/test/asn1_SUITE.erl.src b/lib/asn1/test/asn1_SUITE.erl.src index 7201365ea3..582ccd877c 100644 --- a/lib/asn1/test/asn1_SUITE.erl.src +++ b/lib/asn1/test/asn1_SUITE.erl.src @@ -60,10 +60,10 @@ bool0, bool1 = asn1_DEFAULT, bool2 = asn1_DEFAULT, bool3 = asn1_DEFAULT}). %-record('Def3',{ %bool30 = asn1_DEFAULT, bool31 = asn1_DEFAULT, bool32 = asn1_DEFAULT, bool33 = asn1_DEFAULT}). +suite() -> [{ct_hooks,[ts_install_cth]}]. - -all(suite) -> [compile,parse,default_per,default_ber,default_per_opt,per, - ber,testPrim, +all() -> [{group,compile},parse,default_per,default_ber,default_per_opt,per, + {group,ber},testPrim, testPrimStrings, testPrimExternal, testChoPrim, testChoExtension, testChoExternal, testChoOptional, testChoOptionalImplicitTag, testChoRecursive, @@ -99,21 +99,34 @@ all(suite) -> [compile,parse,default_per,default_ber,default_per_opt,per, testX420, test_x691,ticket_6143, testExtensionAdditionGroup ] ++ common() ++ particular(). -%all(suite) -> [test_inline,testNBAPsystem,test_compile_options,ticket_6143]. +groups() -> + [ + {compile, [], + [c_syntax, c_string_per, c_string_ber, + c_implicit_before_choice]}, + {ber, [], + [ber_choiceinseq, ber_optional, ber_optional_keyed_list, + ber_other]}, + {app_test, [], [{asn1_app_test, all}]}, + {appup_test, [], [{asn1_appup_test, all}]} + ]. + +init_per_suite(Config) -> + io:format("code:lib_dir(asn1) = ~p~n",[code:lib_dir(asn1)]), + Config. + +end_per_suite(_Config) -> + ok. -option_tests(suite) -> - [test_compile_options,ticket_6143]. +init_per_group(_GroupName, Config) -> + Config. -infobj(suite) -> - [testInfObjectClass, testParameterizedInfObj, testMergeCompile, - testobj, testDeepTConstr]. +end_per_group(_GroupName, Config) -> + Config. -performance(suite) -> - [testTimer_ber, testTimer_ber_opt_driver, - testTimer_per, testTimer_per_opt, testTimer_uper_bin]. -bugs(suite) -> - [test_ParamTypeInfObj, test_WS_ParamClass,test_Defed_ObjectIdentifier]. +%all(suite) -> [test_inline,testNBAPsystem,test_compile_options,ticket_6143]. + init_per_testcase(Func,Config) -> %%?line test_server:format("Func: ~p~n",[Func]), @@ -129,7 +142,7 @@ init_per_testcase(Func,Config) -> %% Dog=test_server:timetrap(1800000), % 30 minutes [{watchdog, Dog}|Config]. -fin_per_testcase(_Func,Config) -> +end_per_testcase(_Func,Config) -> Dog=?config(watchdog, Config), test_server:timetrap_cancel(Dog). @@ -1371,22 +1384,6 @@ testSetOfTag_cases(Rules) -> sequence(suite) -> [{sequence,all}]. -compile(suite) -> [c_syntax,c_string_per,c_string_ber,c_implicit_before_choice]; -compile(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line True = lists:member(TempDir,code:get_path()), - ?line test_server:format("~p~n",[True]), - ?line test_server:format("~p~n",[code:get_path()]), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line {error,_R1} = asn1ct:compile(filename:join(DataDir,"Syntax")), - ?line ok = asn1ct:compile(filename:join(DataDir,"String"),[?PER,{outdir,TempDir}]), - test_server:format("first String ok~n"), - ?line ok = asn1ct:compile(filename:join(DataDir,"String"),[?BER,{outdir,TempDir}]), - ?line {error,_R2} = asn1ct:compile(filename:join(DataDir,"CCSNARG3"),[?BER,{outdir,TempDir}]), - ?line {error,_} = asn1ct:compile(filename:join(DataDir,"ImportsFrom"),[?BER,{outdir,TempDir}]), - ok. - c_syntax(suite) -> []; c_syntax(Config) -> ?line DataDir% ?line testExternal:compile(Config,?PER), @@ -1490,8 +1487,6 @@ per1_opt([M|T],DataDir,OutDir) -> per1_opt([],_,_) -> ok. -ber(suite) -> [ber_choiceinseq,ber_optional,ber_optional_keyed_list,ber_other]. - ber_choiceinseq(suite) ->[]; ber_choiceinseq(Config) -> ?line DataDir = ?config(data_dir,Config), diff --git a/lib/asn1/test/asn1_bin_SUITE.erl b/lib/asn1/test/asn1_bin_SUITE.erl deleted file mode 100644 index a924aee0db..0000000000 --- a/lib/asn1/test/asn1_bin_SUITE.erl +++ /dev/null @@ -1,2382 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% -%%% Purpose : Test suite for the ASN.1 application - --module(asn1_bin_SUITE). --define(PER,'per_bin'). --define(BER,'ber_bin'). --define(ber_driver(Erule,Func), - case Erule of - ber_bin_v2 -> - Func; - _ -> ok - end). --define(per_optimize(Erule), - case Erule of - ber_bin_v2 ->[optimize]; - _ -> [] - end). --define(per_bit_opt(FuncCall), - case ?BER of - ber_bin_v2 -> FuncCall; -% _ -> {skip,"only for bit optimized per_bin"} - _ -> ok - end). --define(uper_bin(FuncCall), - case ?PER of - per -> FuncCall; - _ -> ok - end). - --compile(export_all). -%%-export([Function/Arity, ...]). - --include_lib("test_server/include/test_server.hrl"). - -%% records used by test-case default --record('Def1',{bool0, bool1 = asn1_DEFAULT, - bool2 = asn1_DEFAULT, - bool3 = asn1_DEFAULT}). - -%-record('Def2',{ -%bool10, bool11 = asn1_DEFAULT, bool12 = asn1_DEFAULT, bool13}). - -%-record('Def3',{ -%bool30 = asn1_DEFAULT, bool31 = asn1_DEFAULT, bool32 = asn1_DEFAULT, bool33 = asn1_DEFAULT}). - - - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [{group, compile}, parse, default_per, default_ber, - default_per_opt, per, {group, ber}, testPrim, - testPrimStrings, testPrimExternal, testChoPrim, - testChoExtension, testChoExternal, testChoOptional, - testChoOptionalImplicitTag, testChoRecursive, - testChoTypeRefCho, testChoTypeRefPrim, - testChoTypeRefSeq, testChoTypeRefSet, testDef, testOpt, - testSeqDefault, testSeqExtension, testSeqExternal, - testSeqOptional, testSeqPrim, testSeqTag, - testSeqTypeRefCho, testSeqTypeRefPrim, - testSeqTypeRefSeq, testSeqTypeRefSet, testSeqOf, - testSeqOfIndefinite, testSeqOfCho, testSeqOfExternal, - testSetDefault, testSetExtension, - testExtensionAdditionGroup, testSetExternal, - testSeqOfTag, testSetOptional, testSetPrim, testSetTag, - testSetTypeRefCho, testSetTypeRefPrim, - testSetTypeRefSeq, testSetTypeRefSet, testSetOf, - testSetOfCho, testSetOfExternal, testSetOfTag, - testEnumExt, value_test, testSeq2738, constructed, - ber_decode_error, h323test, testSeqIndefinite, - testSetIndefinite, testChoiceIndefinite, - per_GeneralString, per_open_type, testInfObjectClass, - testParameterizedInfObj, testMergeCompile, testobj, - testDeepTConstr, testConstraints, testInvokeMod, - testExport, testImport, testCompactBitString, - testMegaco, testParamBasic, testMvrasn6, - testContextSwitchingTypes, testTypeValueNotation, - testOpenTypeImplicitTag, duplicate_tags, rtUI, testROSE, - testINSTANCE_OF, testTCAP, testDER, specialized_decodes, - special_decode_performance, test_driver_load, - test_ParamTypeInfObj, test_WS_ParamClass, - test_Defed_ObjectIdentifier, testSelectionType, - testSSLspecs, testNortel, test_undecoded_rest, - test_inline, testTcapsystem, testNBAPsystem, - test_compile_options, testDoubleEllipses, - test_modified_x420, testX420, test_x691, ticket_6143, - testExtensionAdditionGroup] ++ common() ++ particular(). - -groups() -> - [{option_tests, [], - [test_compile_options, ticket_6143]}, - {infobj, [], - [testInfObjectClass, testParameterizedInfObj, - testMergeCompile, testobj, testDeepTConstr]}, - {performance, [], - [testTimer_ber, testTimer_ber_opt_driver, testTimer_per, - testTimer_per_opt, testTimer_uper_bin]}, - {bugs, [], - [test_ParamTypeInfObj, test_WS_ParamClass, - test_Defed_ObjectIdentifier]}, - {compile, [], - [c_syntax, c_string_per, c_string_ber, - c_implicit_before_choice]}, - {ber, [], - [ber_choiceinseq, ber_optional, ber_optional_keyed_list, - ber_other]}]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - -%all(suite) -> [test_inline,testNBAPsystem,test_compile_options,ticket_6143]. - -init_per_testcase(Func,Config) -> - %%?line test_server:format("Func: ~p~n",[Func]), - ?line {ok, _} = file:read_file_info(filename:join([?config(priv_dir,Config)])), - ?line code:add_patha(?config(priv_dir,Config)), - Dog= - case Func of - testX420 -> - test_server:timetrap({minutes,60}); % 60 minutes - _ -> - test_server:timetrap({minutes,30}) % 60 minutes - end, -%% Dog=test_server:timetrap(1800000), % 30 minutes - [{watchdog, Dog}|Config]. - -end_per_testcase(_Func,Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog). - - -testPrim(suite) -> []; -testPrim(Config) -> - ?line testPrim:compile(Config,?BER,[]), - ?line testPrim_cases(?BER), - ?line ?ber_driver(?BER,testPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrim_cases(?BER)), - ?line testPrim:compile(Config,?PER,[]), - ?line testPrim_cases(?PER), - ?line ?per_bit_opt(testPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrim_cases(?PER)), - ?line ?uper_bin(testPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrim_cases(uper_bin)), - ?line testPrim:compile(Config,?PER,[optimize]), - ?line testPrim_cases(?PER). - -testPrim_cases(Rules) -> - ?line testPrim:bool(Rules), - ?line testPrim:int(Rules), - ?line testPrim:enum(Rules), - ?line testPrim:obj_id(Rules), - ?line testPrim:rel_oid(Rules), - ?line testPrim:null(Rules), - ?line testPrim:real(Rules). - - -testCompactBitString(suite) -> []; -testCompactBitString(Config) -> - - ?line testCompactBitString:compile(Config,?BER,[compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?BER), - - ?line ?ber_driver(?BER,testCompactBitString:compile(Config,?BER,[compact_bit_string,driver])), - ?line ?ber_driver(?BER,testCompactBitString:compact_bit_string(?BER)), - - ?line testCompactBitString:compile(Config,?PER,[compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?PER), - ?line testCompactBitString:bit_string_unnamed(?PER), - - ?line ?per_bit_opt(testCompactBitString:compile(Config,?PER, - [compact_bit_string,optimize])), - ?line ?per_bit_opt(testCompactBitString:compact_bit_string(?PER)), - ?line ?per_bit_opt(testCompactBitString:bit_string_unnamed(?PER)), - ?line ?per_bit_opt(testCompactBitString:ticket_7734(?PER)), - - ?line ?uper_bin(testCompactBitString:compile(Config,uper_bin, - [compact_bit_string])), - ?line ?uper_bin(testCompactBitString:compact_bit_string(uper_bin)), - ?line ?uper_bin(testCompactBitString:bit_string_unnamed(uper_bin)), - - ?line testCompactBitString:compile(Config,?PER,[optimize,compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?PER), - ?line testCompactBitString:bit_string_unnamed(?PER), - - ?line testCompactBitString:otp_4869(?PER). - - -testPrimStrings(suite) -> []; -testPrimStrings(Config) -> - - ?line testPrimStrings:compile(Config,?BER,[]), - ?line testPrimStrings_cases(?BER), - ?line testPrimStrings:more_strings(?BER), %% these are not implemented in per yet - ?line ?ber_driver(?BER,testPrimStrings:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimStrings_cases(?BER)), - ?line ?ber_driver(?BER,testPrimStrings:more_strings(?BER)), - - ?line testPrimStrings:compile(Config,?PER,[]), - ?line testPrimStrings_cases(?PER), - - ?line ?per_bit_opt(testPrimStrings:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimStrings_cases(?PER)), - - ?line ?uper_bin(testPrimStrings:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimStrings_cases(uper_bin)), - - ?line testPrimStrings:compile(Config,?PER,[optimize]), - ?line testPrimStrings_cases(?PER). - -testPrimStrings_cases(Rules) -> - ?line testPrimStrings:bit_string(Rules), - ?line testPrimStrings:bit_string_unnamed(Rules), - ?line testPrimStrings:octet_string(Rules), - ?line testPrimStrings:numeric_string(Rules), - ?line testPrimStrings:other_strings(Rules), - ?line testPrimStrings:universal_string(Rules), - ?line testPrimStrings:bmp_string(Rules), - ?line testPrimStrings:times(Rules), - ?line testPrimStrings:utf8_string(Rules). - - - -testPrimExternal(suite) -> []; -testPrimExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testPrimExternal:compile(Config,?BER,[]), - ?line testPrimExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testPrimExternal:compile(Config,?PER,[]), - ?line testPrimExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testPrimExternal:compile(Config,?PER,[optimize]), - ?line testPrimExternal_cases(?PER). - -testPrimExternal_cases(Rules) -> - ?line testPrimExternal:external(Rules). - - - - -testChoPrim(suite) -> []; -testChoPrim(Config) -> - - ?line testChoPrim:compile(Config,?BER,[]), - ?line testChoPrim_cases(?BER), - - ?line ?ber_driver(?BER,testChoPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoPrim_cases(?BER)), - - ?line testChoPrim:compile(Config,?PER,[]), - ?line testChoPrim_cases(?PER), - - ?line ?per_bit_opt(testChoPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoPrim_cases(?PER)), - - ?line ?uper_bin(testChoPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoPrim_cases(uper_bin)), - - ?line testChoPrim:compile(Config,?PER,[optimize]), - ?line testChoPrim_cases(?PER). - -testChoPrim_cases(Rules) -> - ?line testChoPrim:bool(Rules), - ?line testChoPrim:int(Rules). - - - -testChoExtension(suite) -> []; -testChoExtension(Config) -> - - ?line testChoExtension:compile(Config,?BER,[]), - ?line testChoExtension_cases(?BER), - - ?line ?ber_driver(?BER,testChoExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExtension_cases(?BER)), - - ?line testChoExtension:compile(Config,?PER,[]), - ?line testChoExtension_cases(?PER), - - ?line ?per_bit_opt(testChoExtension:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExtension_cases(?PER)), - - ?line ?uper_bin(testChoExtension:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExtension_cases(uper_bin)), - - ?line testChoExtension:compile(Config,?PER,[optimize]), - ?line testChoExtension_cases(?PER). - -testChoExtension_cases(Rules) -> - ?line testChoExtension:extension(Rules). - - - -testChoExternal(suite) -> []; -testChoExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testChoExternal:compile(Config,?BER,[]), - ?line testChoExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testChoExternal:compile(Config,?PER,[]), - ?line testChoExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testChoExternal:compile(Config,?PER,[optimize]), - ?line testChoExternal_cases(?PER). - - -testChoExternal_cases(Rules) -> - ?line testChoExternal:external(Rules). - - - -testChoOptional(suite) -> []; -testChoOptional(Config) -> - - ?line testChoOptional:compile(Config,?BER,[]), - ?line testChoOptional_cases(?BER), - - ?line ?ber_driver(?BER,testChoOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoOptional_cases(?BER)), - - ?line testChoOptional:compile(Config,?PER,[]), - ?line testChoOptional_cases(?PER), - - ?line ?per_bit_opt(testChoOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoOptional_cases(?PER)), - - ?line ?uper_bin(testChoOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoOptional_cases(uper_bin)), - - ?line testChoOptional:compile(Config,?PER,[optimize]), - ?line testChoOptional_cases(?PER). - -testChoOptional_cases(Rules) -> - ?line testChoOptional:optional(Rules). - -testChoOptionalImplicitTag(suite) -> []; -testChoOptionalImplicitTag(Config) -> - %% Only meaningful for ?BER - ?line testChoOptionalImplicitTag:compile(Config,?BER), - ?line testChoOptionalImplicitTag:optional(?BER). - - -testChoRecursive(suite) -> []; -testChoRecursive(Config) -> - - ?line testChoRecursive:compile(Config,?BER,[]), - ?line testChoRecursive_cases(?BER), - - ?line ?ber_driver(?BER,testChoRecursive:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoRecursive_cases(?BER)), - - ?line testChoRecursive:compile(Config,?PER,[]), - ?line testChoRecursive_cases(?PER), - - ?line ?per_bit_opt(testChoRecursive:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoRecursive_cases(?PER)), - - ?line ?uper_bin(testChoRecursive:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoRecursive_cases(uper_bin)), - - ?line testChoRecursive:compile(Config,?PER,[optimize]), - ?line testChoRecursive_cases(?PER). - -testChoRecursive_cases(Rules) -> - ?line testChoRecursive:recursive(Rules). - - - -testChoTypeRefCho(suite) -> []; -testChoTypeRefCho(Config) -> - - ?line testChoTypeRefCho:compile(Config,?BER,[]), - ?line testChoTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefCho_cases(?BER)), - - ?line testChoTypeRefCho:compile(Config,?PER,[]), - ?line testChoTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefCho_cases(uper_bin)), - - ?line testChoTypeRefCho:compile(Config,?PER,[optimize]), - ?line testChoTypeRefCho_cases(?PER). - -testChoTypeRefCho_cases(Rules) -> - ?line testChoTypeRefCho:choice(Rules). - - - -testChoTypeRefPrim(suite) -> []; -testChoTypeRefPrim(Config) -> - - ?line testChoTypeRefPrim:compile(Config,?BER,[]), - ?line testChoTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefPrim_cases(?BER)), - - ?line testChoTypeRefPrim:compile(Config,?PER,[]), - ?line testChoTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefPrim_cases(uper_bin)), - - ?line testChoTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testChoTypeRefPrim_cases(?PER). - -testChoTypeRefPrim_cases(Rules) -> - ?line testChoTypeRefPrim:prim(Rules). - - - -testChoTypeRefSeq(suite) -> []; -testChoTypeRefSeq(Config) -> - - ?line testChoTypeRefSeq:compile(Config,?BER,[]), - ?line testChoTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefSeq_cases(?BER)), - - ?line testChoTypeRefSeq:compile(Config,?PER,[]), - ?line testChoTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefSeq_cases(uper_bin)), - - ?line testChoTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testChoTypeRefSeq_cases(?PER). - -testChoTypeRefSeq_cases(Rules) -> - ?line testChoTypeRefSeq:seq(Rules). - - - -testChoTypeRefSet(suite) -> []; -testChoTypeRefSet(Config) -> - - ?line testChoTypeRefSet:compile(Config,?BER,[]), - ?line testChoTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefSet_cases(?BER)), - - ?line testChoTypeRefSet:compile(Config,?PER,[]), - ?line testChoTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefSet_cases(uper_bin)), - - ?line testChoTypeRefSet:compile(Config,?PER,[optimize]), - ?line testChoTypeRefSet_cases(?PER). - -testChoTypeRefSet_cases(Rules) -> - ?line testChoTypeRefSet:set(Rules). - - - -testDef(suite) -> []; -testDef(Config) -> - - ?line testDef:compile(Config,?BER,[]), - ?line testDef_cases(?BER), - - ?line ?ber_driver(?BER,testDef:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDef_cases(?BER)), - - ?line testDef:compile(Config,?PER,[]), - ?line testDef_cases(?PER), - - ?line ?per_bit_opt(testDef:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDef_cases(?PER)), - - ?line ?uper_bin(testDef:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDef_cases(uper_bin)), - - ?line testDef:compile(Config,?PER,[optimize]), - ?line testDef_cases(?PER). - -testDef_cases(Rules) -> - ?line testDef:main(Rules). - - - -testOpt(suite) -> []; -testOpt(Config) -> - - ?line testOpt:compile(Config,?BER), - ?line testOpt_cases(?BER), - - ?line testOpt:compile(Config,?PER), - ?line testOpt_cases(?PER). - -testOpt_cases(Rules) -> - ?line testOpt:main(Rules). - - -testEnumExt(suite) -> []; -testEnumExt(Config) -> - - ?line testEnumExt:compile(Config,?BER,[]), - ?line testEnumExt:main(?BER), - - ?line ?ber_driver(?BER,testEnumExt:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testEnumExt:main(?BER)), - - ?line testEnumExt:compile(Config,?PER,[]), - ?line testEnumExt:main(?PER), - - ?line ?per_bit_opt(testEnumExt:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testEnumExt:main(?PER)), - - ?line ?uper_bin(testEnumExt:compile(Config,uper_bin,[])), - ?line ?uper_bin(testEnumExt:main(uper_bin)), - - ?line testEnumExt:compile(Config,?PER,[optimize]), - ?line testEnumExt:main(?PER). - -testSeqDefault(doc) -> ["Test of OTP-2523 ENUMERATED with extensionmark."]; -testSeqDefault(suite) -> []; -testSeqDefault(Config) -> - - ?line testSeqDefault:compile(Config,?BER,[]), - ?line testSeqDefault_cases(?BER), - - ?line ?ber_driver(?BER,testSeqDefault:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqDefault_cases(?BER)), - - ?line testSeqDefault:compile(Config,?PER,[]), - ?line testSeqDefault_cases(?PER), - - ?line ?per_bit_opt(testSeqDefault:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqDefault_cases(?PER)), - - ?line ?uper_bin(testSeqDefault:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqDefault_cases(uper_bin)), - - ?line testSeqDefault:compile(Config,?PER,[optimize]), - ?line testSeqDefault_cases(?PER). - -testSeqDefault_cases(Rules) -> - ?line testSeqDefault:main(Rules). - - - -testSeqExtension(suite) -> []; -testSeqExtension(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqExtension:compile(Config,?BER,[]), - ?line testSeqExtension_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExtension_cases(?BER)). - -testSeqExtension_cases(Rules) -> - ?line testSeqExtension:main(Rules). - - - -testSeqExternal(suite) -> []; -testSeqExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqExternal:compile(Config,?BER,[]), - ?line testSeqExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExternal_cases(?BER)). - -testSeqExternal_cases(Rules) -> - ?line testSeqExternal:main(Rules). - - -testSeqOptional(suite) -> []; -testSeqOptional(Config) -> - - ?line testSeqOptional:compile(Config,?BER,[]), - ?line testSeqOptional_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOptional_cases(?BER)), - - ?line testSeqOptional:compile(Config,?PER,[]), - ?line testSeqOptional_cases(?PER), - - ?line ?per_bit_opt(testSeqOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOptional_cases(?PER)), - - ?line ?uper_bin(testSeqOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOptional_cases(uper_bin)), - - ?line testSeqOptional:compile(Config,?PER,[optimize]), - ?line testSeqOptional_cases(?PER). - -testSeqOptional_cases(Rules) -> - ?line testSeqOptional:main(Rules). - - - -testSeqPrim(suite) -> []; -testSeqPrim(Config) -> - - ?line testSeqPrim:compile(Config,?BER,[]), - ?line testSeqPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSeqPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqPrim_cases(?BER)), - - ?line testSeqPrim:compile(Config,?PER,[]), - ?line testSeqPrim_cases(?PER), - - ?line ?per_bit_opt(testSeqPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqPrim_cases(?PER)), - - ?line ?uper_bin(testSeqPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqPrim_cases(uper_bin)), - - ?line testSeqPrim:compile(Config,?PER,[optimize]), - ?line testSeqPrim_cases(?PER). - -testSeqPrim_cases(Rules) -> - ?line testSeqPrim:main(Rules). - - -testSeq2738(doc) -> ["Test of OTP-2738 Detect corrupt optional component."]; -testSeq2738(suite) -> []; -testSeq2738(Config) -> - - ?line testSeq2738:compile(Config,?BER,[]), - ?line testSeq2738_cases(?BER), - - ?line ?ber_driver(?BER,testSeq2738:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeq2738_cases(?BER)), - - ?line testSeq2738:compile(Config,?PER,[]), - ?line testSeq2738_cases(?PER), - - ?line ?per_bit_opt(testSeq2738:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeq2738_cases(?PER)), - - ?line ?uper_bin(testSeq2738:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeq2738_cases(uper_bin)), - - ?line testSeq2738:compile(Config,?PER,[optimize]), - ?line testSeq2738_cases(?PER). - -testSeq2738_cases(Rules) -> - ?line testSeq2738:main(Rules). - - -testSeqTag(suite) -> []; -testSeqTag(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqTag:compile(Config,?BER,[]), - ?line testSeqTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqTag:compile(Config,?PER,[]), - ?line testSeqTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqTag:compile(Config,?PER,[optimize]), - ?line testSeqTag_cases(?PER). - -testSeqTag_cases(Rules) -> - ?line testSeqTag:main(Rules). - - - - -testSeqTypeRefCho(suite) -> []; -testSeqTypeRefCho(Config) -> - - ?line testSeqTypeRefCho:compile(Config,?BER,[]), - ?line testSeqTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefCho_cases(?BER)), - - ?line testSeqTypeRefCho:compile(Config,?PER,[]), - ?line testSeqTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefCho_cases(uper_bin)), - - ?line testSeqTypeRefCho:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefCho_cases(?PER). - -testSeqTypeRefCho_cases(Rules) -> - ?line testSeqTypeRefCho:main(Rules). - - - -testSeqTypeRefPrim(suite) -> []; -testSeqTypeRefPrim(Config) -> - - ?line testSeqTypeRefPrim:compile(Config,?BER,[]), - ?line testSeqTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefPrim_cases(?BER)), - - ?line testSeqTypeRefPrim:compile(Config,?PER,[]), - ?line testSeqTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefPrim_cases(uper_bin)), - - ?line testSeqTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefPrim_cases(?PER). - -testSeqTypeRefPrim_cases(Rules) -> - ?line testSeqTypeRefPrim:main(Rules). - - - -testSeqTypeRefSeq(suite) -> []; -testSeqTypeRefSeq(Config) -> - - ?line testSeqTypeRefSeq:compile(Config,?BER,[]), - ?line testSeqTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefSeq_cases(?BER)), - - ?line testSeqTypeRefSeq:compile(Config,?PER,[]), - ?line testSeqTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefSeq_cases(uper_bin)), - - ?line testSeqTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefSeq_cases(?PER). - -testSeqTypeRefSeq_cases(Rules) -> - ?line testSeqTypeRefSeq:main(Rules). - - - -testSeqTypeRefSet(suite) -> []; -testSeqTypeRefSet(Config) -> - - ?line testSeqTypeRefSet:compile(Config,?BER,[]), - ?line testSeqTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefSet_cases(?BER)), - - ?line testSeqTypeRefSet:compile(Config,?PER,[]), - ?line testSeqTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefSet_cases(uper_bin)), - - ?line testSeqTypeRefSet:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefSet_cases(?PER). - -testSeqTypeRefSet_cases(Rules) -> - ?line testSeqTypeRefSet:main(Rules). - - - - -testSeqOf(suite) -> []; -testSeqOf(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOf:compile(Config,?BER,[]), - ?line testSeqOf_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOf:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOf_cases(?BER)), - - ?line testSeqOf:compile(Config,?PER,[]), - ?line testSeqOf_cases(?PER), - - ?line ?per_bit_opt(testSeqOf:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOf_cases(?PER)), - - ?line ?uper_bin(testSeqOf:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOf_cases(uper_bin)), - - ?line testSeqOf:compile(Config,?PER,[optimize]), - ?line testSeqOf_cases(?PER). - -testSeqOf_cases(Rules) -> - ?line testSeqOf:main(Rules). - - - - -testSeqOfCho(suite) -> []; -testSeqOfCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOfCho:compile(Config,?BER,[]), - ?line testSeqOfCho_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOfCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfCho_cases(?BER)), - - ?line testSeqOfCho:compile(Config,?PER,[]), - ?line testSeqOfCho_cases(?PER), - - ?line ?per_bit_opt(testSeqOfCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfCho_cases(?PER)), - - ?line ?uper_bin(testSeqOfCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfCho_cases(uper_bin)), - - ?line testSeqOfCho:compile(Config,?PER,[optimize]), - ?line testSeqOfCho_cases(?PER). - -testSeqOfIndefinite(suite) -> []; -testSeqOfIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOfIndefinite:compile(Config,?BER,[]), - ?line testSeqOfIndefinite:main(), - - ?line ?ber_driver(?BER,testSeqOfIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfIndefinite:main()). - -testSeqOfCho_cases(Rules) -> - ?line testSeqOfCho:main(Rules). - - -testSeqOfExternal(suite) -> []; -testSeqOfExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqOfExternal:compile(Config,?BER,[]), - ?line testSeqOfExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqOfExternal:compile(Config,?PER,[]), - ?line testSeqOfExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfExternal_cases(?PER). - -testSeqOfExternal_cases(Rules) -> - ?line testSeqOfExternal:main(Rules). - - - -testSeqOfTag(suite) -> []; -testSeqOfTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqOfTag:compile(Config,?BER,[]), - ?line testSeqOfTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqOfTag:compile(Config,?PER,[]), - ?line testSeqOfTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfTag:compile(Config,?PER,[optimize]), - ?line testSeqOfTag_cases(?PER). - -testSeqOfTag_cases(Rules) -> - ?line testSeqOfTag:main(Rules). - - - - -testSetDefault(suite) -> []; -testSetDefault(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetDefault:compile(Config,?BER,[]), - ?line testSetDefault_cases(?BER), - - ?line ?ber_driver(?BER,testSetDefault:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetDefault_cases(?BER)), - - ?line testSetDefault:compile(Config,?PER,[]), - ?line testSetDefault_cases(?PER), - - ?line ?per_bit_opt(testSetDefault:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetDefault_cases(?PER)), - - ?line ?uper_bin(testSetDefault:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetDefault_cases(uper_bin)), - - ?line testSetDefault:compile(Config,?PER,[optimize]), - ?line testSetDefault_cases(?PER). - -testSetDefault_cases(Rules) -> - ?line testSetDefault:main(Rules). - - -testParamBasic(suite) -> []; -testParamBasic(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testParamBasic:compile(Config,?BER,[]), - ?line testParamBasic_cases(?BER), - - ?line ?ber_driver(?BER,testParamBasic:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testParamBasic_cases(?BER)), - - ?line testParamBasic:compile(Config,?PER,[]), - ?line testParamBasic_cases(?PER), - - ?line ?per_bit_opt(testParamBasic:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testParamBasic_cases(?PER)), - - ?line ?uper_bin(testParamBasic:compile(Config,uper_bin,[])), - ?line ?uper_bin(testParamBasic_cases(uper_bin)), - - ?line testParamBasic:compile(Config,?PER,[optimize]), - ?line testParamBasic_cases(?PER). - - -testParamBasic_cases(Rules) -> - ?line testParamBasic:main(Rules). - -testSetExtension(suite) -> []; -testSetExtension(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetExtension:compile(Config,?BER,[]), - ?line testSetExtension_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExtension_cases(?BER)). - -testSetExtension_cases(Rules) -> - ?line testSetExtension:main(Rules). - - -testSetExternal(suite) -> []; -testSetExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetExternal:compile(Config,?BER,[]), - ?line testSetExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExternal_cases(?BER)). - -testSetExternal_cases(Rules) -> - ?line testSetExternal:main(Rules). - - -testSetOptional(suite) -> []; -testSetOptional(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOptional:compile(Config,?BER,[]), - ?line testSetOptional_cases(?BER), - - ?line ?ber_driver(?BER,testSetOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOptional_cases(?BER)), - - ?line testSetOptional:compile(Config,?PER,[]), - ?line testSetOptional_cases(?PER), - - ?line ?per_bit_opt(testSetOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOptional_cases(?PER)), - - ?line ?uper_bin(testSetOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOptional_cases(uper_bin)), - - ?line testSetOptional:compile(Config,?PER,[optimize]), - ?line testSetOptional_cases(?PER). - -testSetOptional_cases(Rules) -> - ?line ok = testSetOptional:ticket_7533(Rules), - ?line ok = testSetOptional:main(Rules). - - - - -testSetPrim(suite) -> []; -testSetPrim(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetPrim:compile(Config,?BER,[]), - ?line testSetPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSetPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetPrim_cases(?BER)), - - ?line testSetPrim:compile(Config,?PER,[]), - ?line testSetPrim_cases(?PER), - - ?line ?per_bit_opt(testSetPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetPrim_cases(?PER)), - - ?line ?uper_bin(testSetPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetPrim_cases(uper_bin)), - - ?line testSetPrim:compile(Config,?PER,[optimize]), - ?line testSetPrim_cases(?PER). - -testSetPrim_cases(Rules) -> - ?line testSetPrim:main(Rules). - - - -testSetTag(suite) -> []; -testSetTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetTag:compile(Config,?BER,[]), - ?line testSetTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetTag:compile(Config,?PER,[]), - ?line testSetTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetTag:compile(Config,?PER,[optimize]), - ?line testSetTag_cases(?PER). - -testSetTag_cases(Rules) -> - ?line testSetTag:main(Rules). - - - -testSetTypeRefCho(suite) -> []; -testSetTypeRefCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefCho:compile(Config,?BER,[]), - ?line testSetTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefCho_cases(?BER)), - - ?line testSetTypeRefCho:compile(Config,?PER,[]), - ?line testSetTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefCho_cases(uper_bin)), - - ?line testSetTypeRefCho:compile(Config,?PER,[optimize]), - ?line testSetTypeRefCho_cases(?PER). - -testSetTypeRefCho_cases(Rules) -> - ?line testSetTypeRefCho:main(Rules). - - - -testSetTypeRefPrim(suite) -> []; -testSetTypeRefPrim(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefPrim:compile(Config,?BER,[]), - ?line testSetTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefPrim_cases(?BER)), - - ?line testSetTypeRefPrim:compile(Config,?PER,[]), - ?line testSetTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefPrim_cases(uper_bin)), - - ?line testSetTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testSetTypeRefPrim_cases(?PER). - -testSetTypeRefPrim_cases(Rules) -> - ?line testSetTypeRefPrim:main(Rules). - - - -testSetTypeRefSeq(suite) -> []; -testSetTypeRefSeq(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefSeq:compile(Config,?BER,[]), - ?line testSetTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefSeq_cases(?BER)), - - ?line testSetTypeRefSeq:compile(Config,?PER,[]), - ?line testSetTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefSeq_cases(uper_bin)), - - ?line testSetTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testSetTypeRefSeq_cases(?PER). - -testSetTypeRefSeq_cases(Rules) -> - ?line testSetTypeRefSeq:main(Rules). - - - -testSetTypeRefSet(suite) -> []; -testSetTypeRefSet(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefSet:compile(Config,?BER,[]), - ?line testSetTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefSet_cases(?BER)), - - ?line testSetTypeRefSet:compile(Config,?PER,[]), - ?line testSetTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefSet_cases(uper_bin)), - - ?line testSetTypeRefSet:compile(Config,?PER,[optimize]), - ?line testSetTypeRefSet_cases(?PER). - -testSetTypeRefSet_cases(Rules) -> - ?line testSetTypeRefSet:main(Rules). - - - -testSetOf(suite) -> []; -testSetOf(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOf:compile(Config,?BER,[]), - ?line testSetOf_cases(?BER), - - ?line ?ber_driver(?BER,testSetOf:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOf_cases(?BER)), - - ?line testSetOf:compile(Config,?PER,[]), - ?line testSetOf_cases(?PER), - - ?line ?per_bit_opt(testSetOf:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOf_cases(?PER)), - - ?line ?uper_bin(testSetOf:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOf_cases(uper_bin)), - - ?line testSetOf:compile(Config,?PER,[optimize]), - ?line testSetOf_cases(?PER). - -testSetOf_cases(Rules) -> - ?line testSetOf:main(Rules). - - - -testSetOfCho(suite) -> []; -testSetOfCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOfCho:compile(Config,?BER,[]), - ?line testSetOfCho_cases(?BER), - - ?line ?ber_driver(?BER,testSetOfCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfCho_cases(?BER)), - - ?line testSetOfCho:compile(Config,?PER,[]), - ?line testSetOfCho_cases(?PER), - - ?line ?per_bit_opt(testSetOfCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfCho_cases(?PER)), - - ?line ?uper_bin(testSetOfCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfCho_cases(uper_bin)), - - ?line testSetOfCho:compile(Config,?PER,[optimize]), - ?line testSetOfCho_cases(?PER). - -testSetOfCho_cases(Rules) -> - ?line testSetOfCho:main(Rules). - - -testSetOfExternal(suite) -> []; -testSetOfExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetOfExternal:compile(Config,?BER,[]), - ?line testSetOfExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetOfExternal:compile(Config,?PER,[]), - ?line testSetOfExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetOfExternal:compile(Config,?PER,[optimize]), - ?line testSetOfExternal_cases(?PER). - -testSetOfExternal_cases(Rules) -> - ?line testSetOfExternal:main(Rules). - - - - -testSetOfTag(suite) -> []; -testSetOfTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetOfTag:compile(Config,?BER,[]), - ?line testSetOfTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetOfTag:compile(Config,?PER,[]), - ?line testSetOfTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetOfTag:compile(Config,?PER,[optimize]), - ?line testSetOfTag_cases(?PER). - -testSetOfTag_cases(Rules) -> - ?line testSetOfTag:main(Rules). - - -c_syntax(suite) -> []; -c_syntax(Config) -> - ?line DataDir% ?line testExternal:compile(Config,?PER), -% ?line testPrimExternal:compile(Config,?PER), -% ?line testPrimExternal_cases(?PER). - = ?config(data_dir,Config), - ?line _TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line {error,_R1} = asn1ct:compile(filename:join(DataDir,"Syntax")), - ?line {error,_R2} = asn1ct:compile(filename:join(DataDir,"BadTypeEnding")), - ?line {error,_R3} = asn1ct:compile(filename:join(DataDir, - "BadValueAssignment1")), - ?line {error,_R4} = asn1ct:compile(filename:join(DataDir, - "BadValueAssignment2")), - ?line {error,_R5} = asn1ct:compile(filename:join(DataDir, - "BadValueSet")), - ?line {error,_R6} = asn1ct:compile(filename:join(DataDir, - "ChoiceBadExtension")), - ?line {error,_R7} = asn1ct:compile(filename:join(DataDir, - "EnumerationBadExtension")), - ?line {error,_R8} = asn1ct:compile(filename:join(DataDir, - "Example")), - ?line {error,_R9} = asn1ct:compile(filename:join(DataDir, - "Export1")), - ?line {error,_R10} = asn1ct:compile(filename:join(DataDir, - "MissingEnd")), - ?line {error,_R11} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComma")), - ?line {error,_R12} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComponentName")), - ?line {error,_R13} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComponentType")), - ?line {error,_R14} = asn1ct:compile(filename:join(DataDir, - "SeqBadComma")). - - -c_string_per(suite) -> []; -c_string_per(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"String"),[?PER,{outdir,TempDir}]). - -c_string_ber(suite) -> []; -c_string_ber(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"String"),[?BER,{outdir,TempDir}]). - - -c_implicit_before_choice(suite) -> []; -c_implicit_before_choice(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line {error,_R2} = asn1ct:compile(filename:join(DataDir,"CCSNARG3"),[?BER,{outdir,TempDir}]). - -parse(suite) -> []; -parse(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - M1 = test_modules(), -% M2 = parse_modules(), - ?line ok = parse1(M1,DataDir,OutDir). - -parse1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[abs,{outdir,OutDir}]), - parse1(T,DataDir,OutDir); -parse1([],_,_) -> - ok. - -per(suite) -> []; -per(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = per1(per_modules(),DataDir,OutDir), - ?line ?per_bit_opt(per1_bit_opt(per_modules(),DataDir,OutDir)), - ?line ok = per1_opt(per_modules(),DataDir,OutDir). - - -per1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1(T,DataDir,OutDir); -per1([],_,_) -> - ok. - -per1_bit_opt([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,optimize,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1_bit_opt(T,DataDir,OutDir); -per1_bit_opt([],_,_) -> - ok. - -per1_opt([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,optimized,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1_opt(T,DataDir,OutDir); -per1_opt([],_,_) -> - ok. - - -ber_choiceinseq(suite) ->[]; -ber_choiceinseq(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"ChoiceInSeq"),[?BER,{outdir,OutDir}]). - -ber_optional(suite) ->[]; -ber_optional(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"SOpttest"),[?BER,{outdir,OutDir}]), - ?line V = {'S',{'A',10,asn1_NOVALUE,asn1_NOVALUE}, - {'B',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}, - {'C',asn1_NOVALUE,111,asn1_NOVALUE}}, - ?line {ok,B} = asn1_wrapper:encode('SOpttest','S',V), - ?line Bytes = lists:flatten(B), - ?line V2 = asn1_wrapper:decode('SOpttest','S',Bytes), - ?line ok = eq(V,element(2,V2)). - -ber_optional_keyed_list(suite) ->[]; -ber_optional_keyed_list(Config) -> - case ?BER of - ber_bin_v2 -> ok; - _ -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"SOpttest"), - [?BER,keyed_list,{outdir,OutDir}]), - ?line Vrecord = {'S',{'A',10,asn1_NOVALUE,asn1_NOVALUE}, - {'B',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}, - {'C',asn1_NOVALUE,111,asn1_NOVALUE}}, - ?line V = [ {a,[{scriptKey,10}]}, - {b,[]}, - {c,[{callingPartysCategory,111}]} ], - ?line {ok,B} = asn1_wrapper:encode('SOpttest','S',V), - ?line Bytes = lists:flatten(B), - ?line V2 = asn1_wrapper:decode('SOpttest','S',Bytes), - ?line ok = eq(Vrecord,element(2,V2)) - end. - - -eq(V,V) -> - ok. - - -ber_other(suite) ->[]; -ber_other(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = ber1(ber_modules(),DataDir,OutDir). - - -ber1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?BER,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - ber1(T,DataDir,OutDir); -ber1([],_,_) -> - ok. - -default_per(suite) ->[]; -default_per(Config) -> - default1(?PER,Config,[]). - -default_per_opt(suite) -> []; -default_per_opt(Config) -> - ?per_bit_opt(default1(?PER,Config,[optimize])), - default1(?PER,Config,[optimize]). - -default_ber(suite) ->[]; -default_ber(Config) -> - default1(?BER,Config,[]). - -default1(Rule,Config,Options) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "Def",[Rule,{outdir,OutDir}]++Options), - ?line {ok,Bytes1} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true, - bool1 = true, - bool2 = true, - bool3 = true}), - ?line {ok,{'Def1',true,true,true,true}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes1)), - - ?line {ok,Bytes2} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true}), - ?line {ok,{'Def1',true,false,false,false}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes2)), - - ?line {ok,Bytes3} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true,bool2=false}), - ?line {ok,{'Def1',true,false,false,false}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes3)). - - -value_test(suite) ->[]; -value_test(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "ObjIdValues",[?BER,{outdir,OutDir}]), - ?line {ok,_} = asn1_wrapper:encode('ObjIdValues','ObjIdType','ObjIdValues':'mobileDomainId'()), - ?line ok = asn1ct:compile(DataDir ++ "ObjIdValues",[?PER,{outdir,OutDir}]), - ?line {ok,_} = asn1_wrapper:encode('ObjIdValues','ObjIdType','ObjIdValues':'mobileDomainId'()), - ?line ok = test_bad_values:tests(Config), - ok. - - -constructed(suite) -> - []; -constructed(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "Constructed",[?BER,{outdir,OutDir}]), - ?line {ok,B} = asn1_wrapper:encode('Constructed','S',{'S',false}), - ?line [40,3,1,1,0] = lists:flatten(B), - ?line {ok,B1} = asn1_wrapper:encode('Constructed','S2',{'S2',false}), - ?line [40,5,48,3,1,1,0] = lists:flatten(B1), - ?line {ok,B2} = asn1_wrapper:encode('Constructed','I',10), - ?line [136,1,10] = lists:flatten(B2), - ok. - -ber_decode_error(suite) -> []; -ber_decode_error(Config) -> - ?line ok = ber_decode_error:compile(Config,?BER,[]), - ?line ok = ber_decode_error:run([]), - - ?line ok = ?ber_driver(?BER,ber_decode_error:compile(Config,?BER,[driver])), - ?line ok = ?ber_driver(?BER,ber_decode_error:run([driver])), - ok. - -h323test(suite) -> - []; -h323test(Config) -> - ?line ok = h323test:compile(Config,?PER,[]), - ?line ok = h323test:run(?PER), - ?line ?per_bit_opt(h323test:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(h323test:run(?PER)), - ?line ?uper_bin(h323test:compile(Config,uper_bin,[])), - ?line ?uper_bin(h323test:run(uper_bin)), - ?line ok = h323test:compile(Config,?PER,[optimize]), - ?line ok = h323test:run(?PER), - ok. - -per_GeneralString(suite) -> - []; -per_GeneralString(Config) -> - case erlang:module_loaded('MULTIMEDIA-SYSTEM-CONTROL') of - true -> - ok; - false -> - h323test:compile(Config,?PER,[]) - end, - UI = [109,64,1,57], - ?line {ok,_V} = asn1_wrapper:decode('MULTIMEDIA-SYSTEM-CONTROL', - 'MultimediaSystemControlMessage',UI). - -per_open_type(suite) -> - []; -per_open_type(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line ok = asn1ct:compile(DataDir ++ "OpenType",[?PER,{outdir,OutDir}]), - Stype = {'Stype',10,true}, - ?line {ok,Bytes} = asn1_wrapper:encode('OpenType','Ot',Stype), - ?line {ok,Stype} = asn1_wrapper:decode('OpenType','Ot',Bytes), - - ?line ?per_bit_opt(ok = asn1ct:compile(DataDir ++ "OpenType", - [?PER,optimize,{outdir,OutDir}])), - ?line ?per_bit_opt({ok,Bytes}=asn1_wrapper:encode('OpenType','Ot',Stype)), - ?line ?per_bit_opt({ok,Stype}=asn1_wrapper:decode('OpenType','Ot',Bytes)), - - ?line ?uper_bin(ok = asn1ct:compile(DataDir ++ "OpenType", - [uper_bin,{outdir,OutDir}])), - ?line ?uper_bin({ok,Bytes}=asn1_wrapper:encode('OpenType','Ot',Stype)), - ?line ?uper_bin({ok,Stype}=asn1_wrapper:decode('OpenType','Ot',Bytes)), - - ?line ok = asn1ct:compile(DataDir ++ "OpenType", - [?PER,optimize,{outdir,OutDir}]), - ?line {ok,Bytes} = asn1_wrapper:encode('OpenType','Ot',Stype), - ?line {ok,Stype} = asn1_wrapper:decode('OpenType','Ot',Bytes). - -testConstraints(suite) -> - []; -testConstraints(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testConstraints:compile(Config,?BER,[]), - ?line testConstraints:int_constraints(?BER), - - ?line ?ber_driver(?BER,testConstraints:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testConstraints:int_constraints(?BER)), - - ?line testConstraints:compile(Config,?PER,[]), - ?line testConstraints:int_constraints(?PER), - ?line testConstraints:refed_NNL_name(?PER), - - ?line ?per_bit_opt(testConstraints:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testConstraints:int_constraints(?PER)), - ?line ?per_bit_opt(testConstraints:refed_NNL_name(?PER)), - - ?line ?uper_bin(testConstraints:compile(Config,uper_bin,[])), - ?line ?uper_bin(testConstraints:int_constraints(uper_bin)), - ?line ?uper_bin(testConstraints:refed_NNL_name(uper_bin)), - - ?line testConstraints:compile(Config,?PER,[optimize]), - ?line testConstraints:int_constraints(?PER), - ?line testConstraints:refed_NNL_name(?PER). - -testSeqIndefinite(suite) -> []; -testSeqIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqIndefinite:compile(Config,?BER,[]), - ?line testSeqIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testSeqIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqIndefinite:main(?BER)). - -testSetIndefinite(suite) -> []; -testSetIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetIndefinite:compile(Config,?BER,[]), - ?line testSetIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testSetIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetIndefinite:main(?BER)). - -testChoiceIndefinite(suite) -> []; -testChoiceIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testChoiceIndefinite:compile(Config,?BER,[]), - ?line testChoiceIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testChoiceIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoiceIndefinite:main(?BER)). - -testInfObjectClass(suite) -> - []; -testInfObjectClass(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testInfObjectClass:compile(Config,?PER,[]), - ?line testInfObjectClass:main(?PER), - ?line testInfObj:compile(Config,?PER,[]), - ?line testInfObj:main(?PER), - - ?line ?per_bit_opt(testInfObjectClass:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testInfObjectClass:main(?PER)), - ?line ?per_bit_opt(testInfObj:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testInfObj:main(?PER)), - - ?line ?uper_bin(testInfObjectClass:compile(Config,uper_bin,[])), - ?line ?uper_bin(testInfObjectClass:main(uper_bin)), - ?line ?uper_bin(testInfObj:compile(Config,uper_bin,[])), - ?line ?uper_bin(testInfObj:main(uper_bin)), - - ?line testInfObjectClass:compile(Config,?PER,[optimize]), - ?line testInfObjectClass:main(?PER), - ?line testInfObj:compile(Config,?PER,[optimize]), - ?line testInfObj:main(?PER), - - ?line testInfObjectClass:compile(Config,?BER,[]), - ?line testInfObjectClass:main(?BER), - ?line testInfObj:compile(Config,?BER,[]), - ?line testInfObj:main(?BER), - - ?line ?ber_driver(?BER,testInfObjectClass:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testInfObjectClass:main(?BER)), - ?line ?ber_driver(?BER,testInfObj:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testInfObj:main(?BER)), - - ?line testInfObj:compile_RANAPfiles(Config,?PER,[]), - - ?line ?per_bit_opt(testInfObj:compile_RANAPfiles(Config,?PER,[optimize])), - - ?line ?uper_bin(testInfObj:compile_RANAPfiles(Config,uper_bin,[])), - - ?line testInfObj:compile_RANAPfiles(Config,?PER,[optimize]), - - ?line testInfObj:compile_RANAPfiles(Config,?BER,[]). - -testParameterizedInfObj(suite) -> - []; -testParameterizedInfObj(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testParameterizedInfObj:compile(Config,?PER,[]), - ?line testParameterizedInfObj:main(?PER), - - ?line ?per_bit_opt(testParameterizedInfObj:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testParameterizedInfObj:main(?PER)), - - ?line ?uper_bin(testParameterizedInfObj:compile(Config,uper_bin,[])), - ?line ?uper_bin(testParameterizedInfObj:main(uper_bin)), - - ?line testParameterizedInfObj:compile(Config,?PER,[optimize]), - ?line testParameterizedInfObj:main(?PER), - - ?line testParameterizedInfObj:compile(Config,?BER,[]), - ?line testParameterizedInfObj:main(?BER), - - ?line ?ber_driver(?BER,testParameterizedInfObj:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testParameterizedInfObj:main(?BER)). - -testMergeCompile(suite) -> - []; -testMergeCompile(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testMergeCompile:compile(Config,?PER,[]), - ?line testMergeCompile:main(?PER), - ?line testMergeCompile:mvrasn(?PER), - - ?line ?per_bit_opt(testMergeCompile:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testMergeCompile:main(?PER)), - ?line ?per_bit_opt(testMergeCompile:mvrasn(?PER)), - - ?line ?uper_bin(testMergeCompile:compile(Config,uper_bin,[])), - ?line ?uper_bin(testMergeCompile:main(uper_bin)), - ?line ?uper_bin(testMergeCompile:mvrasn(uper_bin)), - - ?line testMergeCompile:compile(Config,?BER,[]), - ?line testMergeCompile:main(?BER), - ?line testMergeCompile:mvrasn(?BER), - - ?line ?ber_driver(?BER,testMergeCompile:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testMergeCompile:main(?BER)), - ?line ?ber_driver(?BER,testMergeCompile:mvrasn(?BER)). - -testobj(suite) -> - []; -testobj(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line ok = testRANAP:compile(Config,?PER,[]), - ?line ok = testRANAP:testobj(?PER), - ?line ok = testParameterizedInfObj:ranap(?PER), - - ?line ?per_bit_opt(ok = testRANAP:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(ok = testRANAP:testobj(?PER)), - ?line ?per_bit_opt(ok = testParameterizedInfObj:ranap(?PER)), - - ?line ?uper_bin(ok = testRANAP:compile(Config,uper_bin,[])), - ?line ?uper_bin(ok = testRANAP:testobj(uper_bin)), - ?line ?uper_bin(ok = testParameterizedInfObj:ranap(uper_bin)), - - ?line ok = testRANAP:compile(Config,?PER,[optimize]), - ?line ok = testRANAP:testobj(?PER), - ?line ok = testParameterizedInfObj:ranap(?PER), - - ?line ok = testRANAP:compile(Config,?BER,[]), - ?line ok = testRANAP:testobj(?BER), - ?line ok = testParameterizedInfObj:ranap(?BER), - - ?line ?ber_driver(?BER,testRANAP:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testRANAP:testobj(?BER)), - ?line ?ber_driver(?BER,testParameterizedInfObj:ranap(?BER)). - - -testDeepTConstr(suite) -> - []; -testDeepTConstr(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testDeepTConstr:compile(Config,?PER,[]), - ?line testDeepTConstr:main(?PER), - - ?line ?per_bit_opt(testDeepTConstr:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDeepTConstr:main(?PER)), - - ?line ?uper_bin(testDeepTConstr:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDeepTConstr:main(uper_bin)), - - ?line testDeepTConstr:compile(Config,?PER,[optimize]), - ?line testDeepTConstr:main(?PER), - - ?line testDeepTConstr:compile(Config,?BER,[]), - ?line testDeepTConstr:main(?BER), - - ?line ?ber_driver(?BER,testDeepTConstr:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDeepTConstr:main(?BER)). - -testInvokeMod(suite) -> - []; -testInvokeMod(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line ok = asn1ct:compile(filename:join(DataDir,"PrimStrings"),[{outdir,OutDir}]), - ?line {ok,_Result1} = 'PrimStrings':encode('Bs1',[1,0,1,0]), - ?line ok = asn1ct:compile(filename:join(DataDir,"PrimStrings"),[?PER,{outdir,OutDir}]), - ?line {ok,_Result2} = 'PrimStrings':encode('Bs1',[1,0,1,0]). - -testExport(suite) -> - []; -testExport(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line {error,{asn1,_Reason}} = asn1ct:compile(filename:join(DataDir,"IllegalExport"),[{outdir,OutDir}]). - -testImport(suite) -> - []; -testImport(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line _OutDir = ?config(priv_dir,Config), - ?line {error,_} = asn1ct:compile(filename:join(DataDir,"ImportsFrom"),[?BER]), - ok. - -testMegaco(suite) -> - []; -testMegaco(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - io:format("Config: ~p~n",[Config]), - ?line {ok,ModuleName1,ModuleName2} = testMegaco:compile(Config,?BER,[]), - ?line ok = testMegaco:main(ModuleName1,Config), - ?line ok = testMegaco:main(ModuleName2,Config), - - case ?BER of - ber_bin_v2 -> - ?line {ok,ModuleName3,ModuleName4} = testMegaco:compile(Config,?BER,[driver]), - ?line ok = testMegaco:main(ModuleName3,Config), - ?line ok = testMegaco:main(ModuleName4,Config); - _-> ok - end, - - ?line {ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,?PER,[]), - ?line ok = testMegaco:main(ModuleName5,Config), - ?line ok = testMegaco:main(ModuleName6,Config), - - ?line ?per_bit_opt({ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(ok = testMegaco:main(ModuleName5,Config)), - ?line ?per_bit_opt(ok = testMegaco:main(ModuleName6,Config)), - - ?line ?uper_bin({ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,uper_bin,[])), - ?line ?uper_bin(ok = testMegaco:main(ModuleName5,Config)), - ?line ?uper_bin(ok = testMegaco:main(ModuleName6,Config)), - - ?line {ok,ModuleName7,ModuleName8} = testMegaco:compile(Config,?PER,[optimize]), - ?line ok = testMegaco:main(ModuleName7,Config), - ?line ok = testMegaco:main(ModuleName8,Config). - - -testMvrasn6(suite) -> []; -testMvrasn6(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testMvrasn6:compile(Config,?BER), - ?line testMvrasn6:main(). - -testContextSwitchingTypes(suite) -> []; -testContextSwitchingTypes(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testContextSwitchingTypes:compile(Config,?BER,[]), - ?line testContextSwitchingTypes:test(), - - ?line ?ber_driver(?BER,testContextSwitchingTypes:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testContextSwitchingTypes:test()), - - ?line testContextSwitchingTypes:compile(Config,?PER,[]), - ?line testContextSwitchingTypes:test(), - - ?line ?per_bit_opt(testContextSwitchingTypes:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testContextSwitchingTypes:test()), - - ?line ?uper_bin(testContextSwitchingTypes:compile(Config,uper_bin,[])), - ?line ?uper_bin(testContextSwitchingTypes:test()), - - ?line testContextSwitchingTypes:compile(Config,?PER,[optimize]), - ?line testContextSwitchingTypes:test(). - -testTypeValueNotation(suite) -> []; -testTypeValueNotation(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - case ?BER of - Ber when Ber == ber; Ber == ber_bin -> - ?line testTypeValueNotation:compile(Config,?BER,[]), - ?line testTypeValueNotation:main(?BER,dummy); - _ -> - ok - end, - - ?line ?ber_driver(?BER,testTypeValueNotation:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testTypeValueNotation:main(?BER,optimize)), - - case ?BER of - Ber2 when Ber2 == ber; Ber2 == ber_bin -> - ?line testTypeValueNotation:compile(Config,?PER,[]), - ?line testTypeValueNotation:main(?PER,dummy); - _ -> - ok - end, - - ?line ?per_bit_opt(testTypeValueNotation:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testTypeValueNotation:main(?PER,optimize)), - - ?line ?uper_bin(testTypeValueNotation:compile(Config,uper_bin,[])), - ?line ?uper_bin(testTypeValueNotation:main(uper_bin,optimize)), - case ?BER of - Ber3 when Ber3 == ber; Ber3 == ber_bin -> - ?line testTypeValueNotation:compile(Config,?PER,[optimize]), - ?line testTypeValueNotation:main(?PER,optimize); - _ -> - ok - end. - -testOpenTypeImplicitTag(suite) -> []; -testOpenTypeImplicitTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testOpenTypeImplicitTag:compile(Config,?BER,[]), - ?line testOpenTypeImplicitTag:main(?BER), - - ?line ?ber_driver(?BER,testOpenTypeImplicitTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testOpenTypeImplicitTag:main(?BER)), - - ?line testOpenTypeImplicitTag:compile(Config,?PER,[]), - ?line testOpenTypeImplicitTag:main(?PER), - - ?line ?per_bit_opt(testOpenTypeImplicitTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testOpenTypeImplicitTag:main(?PER)), - - ?line ?uper_bin(testOpenTypeImplicitTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testOpenTypeImplicitTag:main(uper_bin)), - - ?line testOpenTypeImplicitTag:compile(Config,?PER,[optimize]), - ?line testOpenTypeImplicitTag:main(?PER). - -duplicate_tags(suite) -> []; -duplicate_tags(Config) -> - ?line DataDir = ?config(data_dir,Config), - {error,{asn1,[{error,{type,_,_,'SeqOpt1Imp',{asn1,{duplicates_of_the_tags,_}}}}]}} = - asn1ct:compile(filename:join(DataDir,"SeqOptional2"),[abs]), - ok. - -rtUI(suite) -> []; -rtUI(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"Prim"),[?BER]), - ?line {ok,_} = asn1rt:info('Prim'), - - ?line ok = asn1ct:compile(filename:join(DataDir,"Prim"),[?PER]), - ?line {ok,_} = asn1rt:info('Prim'), - - ?line ok = asn1rt:load_driver(), - ?line ok = asn1rt:load_driver(), - ?line ok = asn1rt:unload_driver(). - -testROSE(suite) -> []; -testROSE(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testROSE:compile(Config,?BER,[]), - - ?line testROSE:compile(Config,?PER,[]), - ?line ?per_bit_opt(testROSE:compile(Config,?PER,[optimize])), - ?line ?uper_bin(testROSE:compile(Config,uper_bin,[])), - ?line testROSE:compile(Config,?PER,[optimize]). - -testINSTANCE_OF(suite) -> []; -testINSTANCE_OF(Config) -> - ?line testINSTANCE_OF:compile(Config,?BER,[]), - ?line testINSTANCE_OF:main(?BER), - - ?line ?ber_driver(?BER,testINSTANCE_OF:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testINSTANCE_OF:main(?BER)), - - ?line testINSTANCE_OF:compile(Config,?PER,[]), - ?line testINSTANCE_OF:main(?PER), - - ?line ?per_bit_opt(testINSTANCE_OF:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testINSTANCE_OF:main(?PER)), - - ?line ?uper_bin(testINSTANCE_OF:compile(Config,uper_bin,[])), - ?line ?uper_bin(testINSTANCE_OF:main(uper_bin)), - - ?line testINSTANCE_OF:compile(Config,?PER,[optimize]), - ?line testINSTANCE_OF:main(?PER). - -testTCAP(suite) -> []; -testTCAP(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testTCAP:compile(Config,?BER,[]), - ?line testTCAP:test(?BER,Config), - - ?line ?ber_driver(?BER,testTCAP:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testTCAP:test(?BER,Config)), - - ?line ?ber_driver(?BER,testTCAP:compile_asn1config(Config,?BER,[asn1config])), - ?line ?ber_driver(?BER,testTCAP:test_asn1config()). - -testDER(suite) ->[]; -testDER(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testDER:compile(Config,?BER,[]), - ?line testDER:test(), - - ?line ?ber_driver(?BER,testDER:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDER:test()), - - ?line testParamBasic:compile_der(Config,?BER), - ?line testParamBasic_cases(der), - - - ?line testSeqSetDefaultVal:compile(Config,?BER), - ?line testSeqSetDefaultVal_cases(?BER). - -testSeqSetDefaultVal_cases(?BER) -> - ?line testSeqSetDefaultVal:main(?BER). - - -specialized_decodes(suite) -> []; -specialized_decodes(Config) -> - ?line test_partial_incomplete_decode:compile(Config,?BER,[optimize]), - ?line test_partial_incomplete_decode:test(?BER,Config), - ?line test_selective_decode:test(?BER,Config). - -special_decode_performance(suite) ->[]; -special_decode_performance(Config) -> - ?line ?ber_driver(?BER,test_special_decode_performance:compile(Config,?BER)), - ?line ?ber_driver(?BER,test_special_decode_performance:go(all)). - - -test_driver_load(suite) -> []; -test_driver_load(Config) -> - ?line test_driver_load:compile(Config,?PER), - ?line test_driver_load:test(?PER,5). - -test_ParamTypeInfObj(suite) -> []; -test_ParamTypeInfObj(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"IN-CS-1-Datatypes"),[ber_bin]). - -test_WS_ParamClass(suite) -> []; -test_WS_ParamClass(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"InformationFramework"), - [ber_bin]). - -test_Defed_ObjectIdentifier(suite) -> []; -test_Defed_ObjectIdentifier(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"UsefulDefinitions"), - [ber_bin]). - -testSelectionType(suite) -> []; -testSelectionType(Config) -> - - ?line ok = testSelectionTypes:compile(Config,?BER,[]), - ?line {ok,_} = testSelectionTypes:test(), - - ?line ok = testSelectionTypes:compile(Config,?PER,[]), - ?line {ok,_} = testSelectionTypes:test(). - -testSSLspecs(suite) -> []; -testSSLspecs(Config) -> - - ?line ok = testSSLspecs:compile(Config,?BER, - [optimize,compact_bit_string,der]), - ?line testSSLspecs:run(?BER), - - case code:which(asn1ct) of - cover_compiled -> - ok; - _ -> - ?line ok = testSSLspecs:compile_inline(Config,?BER), - ?line ok = testSSLspecs:run_inline(?BER) - end. - -testNortel(suite) -> []; -testNortel(Config) -> - ?line DataDir = ?config(data_dir,Config), - - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[?BER]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?BER,optimize]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?BER,optimize,driver]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[?PER]), - ?line ?per_bit_opt(ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?PER,optimize])), - ?line ?uper_bin(ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[uper_bin])), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?PER,optimize]). -test_undecoded_rest(suite) -> []; -test_undecoded_rest(Config) -> - - ?line ok = test_undecoded_rest:compile(Config,?BER,[]), - ?line ok = test_undecoded_rest:test([]), - - ?line ok = test_undecoded_rest:compile(Config,?BER,[undec_rest]), - ?line ok = test_undecoded_rest:test(undec_rest), - - ?line ok = test_undecoded_rest:compile(Config,?PER,[]), - ?line ok = test_undecoded_rest:test([]), - - ?line ?per_bit_opt(ok = test_undecoded_rest:compile(Config,?PER,[optimize,undec_rest])), - ?line ?per_bit_opt(ok = test_undecoded_rest:test(undec_rest)), - - ?line ?uper_bin(ok = test_undecoded_rest:compile(Config,uper_bin,[undec_rest])), - ?line ?uper_bin(ok = test_undecoded_rest:test(undec_rest)), - - ?line ok = test_undecoded_rest:compile(Config,?PER,[undec_rest]), - ?line ok = test_undecoded_rest:test(undec_rest). - -test_inline(suite) -> []; -test_inline(Config) -> - case code:which(asn1ct) of - cover_compiled -> - {skip,"Not runnable when cover compiled"}; - _ -> - ?line ok=test_inline:compile(Config,?BER,[]), - ?line test_inline:main(?BER), - ?line test_inline:inline1(Config,?BER,[]), - ?line test_inline:performance2() - end. - -%test_inline_prf(suite) -> []; -%test_inline_prf(Config) -> -% ?line test_inline:performance(Config). - -testTcapsystem(suite) -> []; -testTcapsystem(Config) -> - ?line ok=testTcapsystem:compile(Config,?BER,[]). - -testNBAPsystem(suite) -> []; -testNBAPsystem(Config) -> - ?line ok=testNBAPsystem:compile(Config,?PER,?per_optimize(?BER)), - ?line ok=testNBAPsystem:test(?PER,Config). - -test_compile_options(suite) -> []; -test_compile_options(Config) -> - case code:which(asn1ct) of - cover_compiled -> - {skip,"Not runnable when cover compiled"}; - _ -> - ?line ok = test_compile_options:wrong_path(Config), - ?line ok = test_compile_options:path(Config), - ?line ok = test_compile_options:noobj(Config), - ?line ok = test_compile_options:record_name_prefix(Config), - ?line ok = test_compile_options:verbose(Config) - end. -testDoubleEllipses(suite) -> []; -testDoubleEllipses(Config) -> - ?line testDoubleEllipses:compile(Config,?BER,[]), - ?line testDoubleEllipses:main(?BER), - ?line ?ber_driver(?BER,testDoubleEllipses:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDoubleEllipses:main(?BER)), - ?line ?per_bit_opt(testDoubleEllipses:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDoubleEllipses:main(?PER)), - ?line ?uper_bin(testDoubleEllipses:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDoubleEllipses:main(uper_bin)), - ?line testDoubleEllipses:compile(Config,?PER,?per_optimize(?BER)), - ?line testDoubleEllipses:main(?PER). - -test_modified_x420(suite) -> []; -test_modified_x420(Config) -> - ?line test_modified_x420:compile(Config), - ?line test_modified_x420:test_io(Config). - -testX420(suite) -> []; -testX420(Config) -> - ?line testX420:compile(?BER,[der],Config), - ?line ok = testX420:ticket7759(?BER,Config), - ?line testX420:compile(?PER,[],Config). - -test_x691(suite) -> []; -test_x691(Config) -> - case ?PER of - per -> - ?line ok = test_x691:compile(Config,uper_bin,[]), - ?line true = test_x691:cases(uper_bin,unaligned), - ?line ok = test_x691:compile(Config,?PER,[]), - ?line true = test_x691:cases(?PER,aligned), -%% ?line ok = asn1_test_lib:ticket_7678(Config,[]), - ?line ok = asn1_test_lib:ticket_7708(Config,[]), - ?line ok = asn1_test_lib:ticket_7763(Config); - _ -> - ?line ok = test_x691:compile(Config,?PER,?per_optimize(?BER)), - ?line true = test_x691:cases(?PER,aligned) - end. -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[compact_bit_string]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[optimize]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[optimize,compact_bit_string]). - - -ticket_6143(suite) -> []; -ticket_6143(Config) -> - ?line ok = test_compile_options:ticket_6143(Config). - -testExtensionAdditionGroup(suite) -> []; -testExtensionAdditionGroup(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line PrivDir = ?config(priv_dir,Config), - ?line Path = code:get_path(), - ?line code:add_patha(PrivDir), - DoIt = fun(Erule) -> - ?line ok = asn1ct:compile(filename:join(DataDir,"Extension-Addition-Group"),[Erule,{outdir,PrivDir}]), - ?line {ok,_M} = compile:file(filename:join(DataDir,"extensionAdditionGroup"),[{i,PrivDir},{outdir,PrivDir},debug_info]), - ?line ok = extensionAdditionGroup:run(Erule) - end, - ?line [DoIt(Rule)|| Rule <- [per_bin,uper_bin,ber_bin]], - ?line code:set_path(Path). - - - -% parse_modules() -> -% ["ImportsFrom"]. - -per_modules() -> - [X || X <- test_modules()]. -ber_modules() -> - [X || X <- test_modules(), - X =/= "CommonDataTypes", - X =/= "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath", - X =/= "H323-MESSAGES", - X =/= "H235-SECURITY-MESSAGES", - X =/= "MULTIMEDIA-SYSTEM-CONTROL"]. -test_modules() -> - _Modules = [ - "BitStr", - "CommonDataTypes", - "Constraints", - "ContextSwitchingTypes", - "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath", - "Enum", - "From", - "H235-SECURITY-MESSAGES", - "H323-MESSAGES", - %%"MULTIMEDIA-SYSTEM-CONTROL", recursive type , problem for asn1ct:value - "Import", - "Int", - "MAP-commonDataTypes", -% ambigous tags "MAP-insertSubscriberData-def", - "Null", - "Octetstr", - "One", - "P-Record", - "P", -% "PDUs", - "Person", - "PrimStrings", - "Real", - "XSeq", - "XSeqOf", - "XSet", - "XSetOf", - "String", - "SwCDR", -% "Syntax", - "Time" -% ANY "Tst", -% "Two", -% errors that should be detected "UndefType" -] ++ - [ - "SeqSetLib", % must be compiled before Seq and Set - "Seq", - "Set", - "SetOf", - "SeqOf", - "Prim", - "Cho", - "Def", - "Opt", - "ELDAPv3", - "LDAP" - ]. - - -common() -> -[]. - -particular() -> -[]. diff --git a/lib/asn1/test/asn1_bin_v2_SUITE.erl b/lib/asn1/test/asn1_bin_v2_SUITE.erl deleted file mode 100644 index 2273ca9918..0000000000 --- a/lib/asn1/test/asn1_bin_v2_SUITE.erl +++ /dev/null @@ -1,2474 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2001-2011. All Rights Reserved. -%% -%% The contents of this file are subject to the Erlang Public License, -%% Version 1.1, (the "License"); you may not use this file except in -%% compliance with the License. You should have received a copy of the -%% Erlang Public License along with this software. If not, it can be -%% retrieved online at http://www.erlang.org/. -%% -%% Software distributed under the License is distributed on an "AS IS" -%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -%% the License for the specific language governing rights and limitations -%% under the License. -%% -%% %CopyrightEnd% -%% -%% -%%% Purpose : Test suite for the ASN.1 application - --module(asn1_bin_v2_SUITE). --define(PER,'per_bin'). --define(BER,'ber_bin_v2'). --define(ber_driver(Erule,Func), - case Erule of - ber_bin_v2 -> - Func; - _ -> ok - end). --define(per_optimize(Erule), - case Erule of - ber_bin_v2 ->[optimize]; - _ -> [] - end). --define(per_bit_opt(FuncCall), - case ?BER of - ber_bin_v2 -> FuncCall; -% _ -> {skip,"only for bit optimized per_bin"} - _ -> ok - end). --define(uper_bin(FuncCall), - case ?PER of - per -> FuncCall; - _ -> ok - end). - --compile(export_all). -%%-export([Function/Arity, ...]). - --include_lib("test_server/include/test_server.hrl"). - -%% records used by test-case default --record('Def1',{ -bool0, bool1 = asn1_DEFAULT, bool2 = asn1_DEFAULT, bool3 = asn1_DEFAULT}). - -%-record('Def2',{ -%bool10, bool11 = asn1_DEFAULT, bool12 = asn1_DEFAULT, bool13}). - -%-record('Def3',{ -%bool30 = asn1_DEFAULT, bool31 = asn1_DEFAULT, bool32 = asn1_DEFAULT, bool33 = asn1_DEFAULT}). - - - -suite() -> [{ct_hooks,[ts_install_cth]}]. - -all() -> - [{group, compile}, parse, default_per, default_ber, - default_per_opt, per, {group, ber}, testPrim, - testPrimStrings, testPrimExternal, testChoPrim, - testChoExtension, testChoExternal, testChoOptional, - testChoOptionalImplicitTag, testChoRecursive, - testChoTypeRefCho, testChoTypeRefPrim, - testChoTypeRefSeq, testChoTypeRefSet, testDef, testOpt, - testSeqDefault, testSeqExtension, testSeqExternal, - testSeqOptional, testSeqPrim, testSeqTag, - testSeqTypeRefCho, testSeqTypeRefPrim, - testSeqTypeRefSeq, testSeqTypeRefSet, testSeqOf, - testSeqOfIndefinite, testSeqOfCho, testSeqOfExternal, - testSetDefault, testSetExtension, - testExtensionAdditionGroup, testSetExternal, - testSeqOfTag, testSetOptional, testSetPrim, testSetTag, - testSetTypeRefCho, testSetTypeRefPrim, - testSetTypeRefSeq, testSetTypeRefSet, testSetOf, - testSetOfCho, testSetOfExternal, testSetOfTag, - testEnumExt, value_test, testSeq2738, constructed, - ber_decode_error, h323test, testSeqIndefinite, - testSetIndefinite, testChoiceIndefinite, - per_GeneralString, per_open_type, testInfObjectClass, - testParameterizedInfObj, testMergeCompile, testobj, - testDeepTConstr, testConstraints, testInvokeMod, - testExport, testImport, testCompactBitString, - testMegaco, testParamBasic, testMvrasn6, - testContextSwitchingTypes, testTypeValueNotation, - testOpenTypeImplicitTag, duplicate_tags, rtUI, testROSE, - testINSTANCE_OF, testTCAP, testDER, specialized_decodes, - special_decode_performance, test_driver_load, - test_ParamTypeInfObj, test_WS_ParamClass, - test_Defed_ObjectIdentifier, testSelectionType, - testSSLspecs, testNortel, test_undecoded_rest, - test_inline, testTcapsystem, testNBAPsystem, - test_compile_options, testDoubleEllipses, - test_modified_x420, testX420, test_x691, ticket_6143, - testExtensionAdditionGroup] ++ common() ++ particular(). - -groups() -> - [{option_tests, [], - [test_compile_options, ticket_6143]}, - {infobj, [], - [testInfObjectClass, testParameterizedInfObj, - testMergeCompile, testobj, testDeepTConstr]}, - {performance, [], - [testTimer_ber, testTimer_ber_opt_driver, testTimer_per, - testTimer_per_opt, testTimer_uper_bin]}, - {bugs, [], - [test_ParamTypeInfObj, test_WS_ParamClass, - test_Defed_ObjectIdentifier]}, - {compile, [], - [c_syntax, c_string_per, c_string_ber, - c_implicit_before_choice]}, - {ber, [], - [ber_choiceinseq, ber_optional, ber_optional_keyed_list, - ber_other]}]. - -init_per_suite(Config) -> - Config. - -end_per_suite(_Config) -> - ok. - -init_per_group(_GroupName, Config) -> - Config. - -end_per_group(_GroupName, Config) -> - Config. - -%all(suite) -> [test_inline,testNBAPsystem,test_compile_options,ticket_6143]. - -init_per_testcase(Func,Config) -> - %%?line test_server:format("Func: ~p~n",[Func]), - ?line {ok, _} = file:read_file_info(filename:join([?config(priv_dir,Config)])), - ?line code:add_patha(?config(priv_dir,Config)), - Dog= - case Func of - testX420 -> - test_server:timetrap({minutes,60}); % 60 minutes - _ -> - test_server:timetrap({minutes,30}) % 60 minutes - end, - %% Dog=test_server:timetrap(1800000), % 30 minutes - [{watchdog, Dog}|Config]. - -end_per_testcase(_Func,Config) -> - Dog=?config(watchdog, Config), - test_server:timetrap_cancel(Dog). - - -testPrim(suite) -> []; -testPrim(Config) -> - ?line testPrim:compile(Config,?BER,[]), - ?line testPrim_cases(?BER), - ?line ?ber_driver(?BER,testPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrim_cases(?BER)), - ?line testPrim:compile(Config,?PER,[]), - ?line testPrim_cases(?PER), - ?line ?per_bit_opt(testPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrim_cases(?PER)), - ?line ?uper_bin(testPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrim_cases(uper_bin)), - ?line testPrim:compile(Config,?PER,[optimize]), - ?line testPrim_cases(?PER). - -testPrim_cases(Rules) -> - ?line testPrim:bool(Rules), - ?line testPrim:int(Rules), - ?line testPrim:enum(Rules), - ?line testPrim:obj_id(Rules), - ?line testPrim:rel_oid(Rules), - ?line testPrim:null(Rules), - ?line testPrim:real(Rules). - - -testCompactBitString(suite) -> []; -testCompactBitString(Config) -> - - ?line testCompactBitString:compile(Config,?BER,[compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?BER), - - ?line ?ber_driver(?BER,testCompactBitString:compile(Config,?BER,[compact_bit_string,driver])), - ?line ?ber_driver(?BER,testCompactBitString:compact_bit_string(?BER)), - - ?line testCompactBitString:compile(Config,?PER,[compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?PER), - ?line testCompactBitString:bit_string_unnamed(?PER), - - ?line ?per_bit_opt(testCompactBitString:compile(Config,?PER, - [compact_bit_string,optimize])), - ?line ?per_bit_opt(testCompactBitString:compact_bit_string(?PER)), - ?line ?per_bit_opt(testCompactBitString:bit_string_unnamed(?PER)), - ?line ?per_bit_opt(testCompactBitString:ticket_7734(?PER)), - - ?line ?uper_bin(testCompactBitString:compile(Config,uper_bin, - [compact_bit_string])), - ?line ?uper_bin(testCompactBitString:compact_bit_string(uper_bin)), - ?line ?uper_bin(testCompactBitString:bit_string_unnamed(uper_bin)), - - ?line testCompactBitString:compile(Config,?PER,[optimize,compact_bit_string]), - ?line testCompactBitString:compact_bit_string(?PER), - ?line testCompactBitString:bit_string_unnamed(?PER), - - ?line testCompactBitString:otp_4869(?PER). - - -testPrimStrings(suite) -> []; -testPrimStrings(Config) -> - - ?line testPrimStrings:compile(Config,?BER,[]), - ?line testPrimStrings_cases(?BER), - ?line testPrimStrings:more_strings(?BER), %% these are not implemented in per yet - ?line ?ber_driver(?BER,testPrimStrings:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimStrings_cases(?BER)), - ?line ?ber_driver(?BER,testPrimStrings:more_strings(?BER)), - - ?line testPrimStrings:compile(Config,?PER,[]), - ?line testPrimStrings_cases(?PER), - - ?line ?per_bit_opt(testPrimStrings:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimStrings_cases(?PER)), - - ?line ?uper_bin(testPrimStrings:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimStrings_cases(uper_bin)), - - ?line testPrimStrings:compile(Config,?PER,[optimize]), - ?line testPrimStrings_cases(?PER). - -testPrimStrings_cases(Rules) -> - ?line testPrimStrings:bit_string(Rules), - ?line testPrimStrings:bit_string_unnamed(Rules), - ?line testPrimStrings:octet_string(Rules), - ?line testPrimStrings:numeric_string(Rules), - ?line testPrimStrings:other_strings(Rules), - ?line testPrimStrings:universal_string(Rules), - ?line testPrimStrings:bmp_string(Rules), - ?line testPrimStrings:times(Rules), - ?line testPrimStrings:utf8_string(Rules). - - - -testPrimExternal(suite) -> []; -testPrimExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testPrimExternal:compile(Config,?BER,[]), - ?line testPrimExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testPrimExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testPrimExternal:compile(Config,?PER,[]), - ?line testPrimExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testPrimExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testPrimExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testPrimExternal:compile(Config,?PER,[optimize]), - ?line testPrimExternal_cases(?PER). - -testPrimExternal_cases(Rules) -> - ?line testPrimExternal:external(Rules). - - - - -testChoPrim(suite) -> []; -testChoPrim(Config) -> - - ?line testChoPrim:compile(Config,?BER,[]), - ?line testChoPrim_cases(?BER), - - ?line ?ber_driver(?BER,testChoPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoPrim_cases(?BER)), - - ?line testChoPrim:compile(Config,?PER,[]), - ?line testChoPrim_cases(?PER), - - ?line ?per_bit_opt(testChoPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoPrim_cases(?PER)), - - ?line ?uper_bin(testChoPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoPrim_cases(uper_bin)), - - ?line testChoPrim:compile(Config,?PER,[optimize]), - ?line testChoPrim_cases(?PER). - -testChoPrim_cases(Rules) -> - ?line testChoPrim:bool(Rules), - ?line testChoPrim:int(Rules). - - - -testChoExtension(suite) -> []; -testChoExtension(Config) -> - - ?line testChoExtension:compile(Config,?BER,[]), - ?line testChoExtension_cases(?BER), - - ?line ?ber_driver(?BER,testChoExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExtension_cases(?BER)), - - ?line testChoExtension:compile(Config,?PER,[]), - ?line testChoExtension_cases(?PER), - - ?line ?per_bit_opt(testChoExtension:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExtension_cases(?PER)), - - ?line ?uper_bin(testChoExtension:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExtension_cases(uper_bin)), - - ?line testChoExtension:compile(Config,?PER,[optimize]), - ?line testChoExtension_cases(?PER). - -testChoExtension_cases(Rules) -> - ?line testChoExtension:extension(Rules). - - - -testChoExternal(suite) -> []; -testChoExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testChoExternal:compile(Config,?BER,[]), - ?line testChoExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testChoExternal:compile(Config,?PER,[]), - ?line testChoExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testChoExternal:compile(Config,?PER,[optimize]), - ?line testChoExternal_cases(?PER). - - -testChoExternal_cases(Rules) -> - ?line testChoExternal:external(Rules). - - - -testChoOptional(suite) -> []; -testChoOptional(Config) -> - - ?line testChoOptional:compile(Config,?BER,[]), - ?line testChoOptional_cases(?BER), - - ?line ?ber_driver(?BER,testChoOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoOptional_cases(?BER)), - - ?line testChoOptional:compile(Config,?PER,[]), - ?line testChoOptional_cases(?PER), - - ?line ?per_bit_opt(testChoOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoOptional_cases(?PER)), - - ?line ?uper_bin(testChoOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoOptional_cases(uper_bin)), - - ?line testChoOptional:compile(Config,?PER,[optimize]), - ?line testChoOptional_cases(?PER). - -testChoOptional_cases(Rules) -> - ?line testChoOptional:optional(Rules). - -testChoOptionalImplicitTag(suite) -> []; -testChoOptionalImplicitTag(Config) -> - %% Only meaningful for ?BER - ?line testChoOptionalImplicitTag:compile(Config,?BER), - ?line testChoOptionalImplicitTag:optional(?BER). - - -testChoRecursive(suite) -> []; -testChoRecursive(Config) -> - - ?line testChoRecursive:compile(Config,?BER,[]), - ?line testChoRecursive_cases(?BER), - - ?line ?ber_driver(?BER,testChoRecursive:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoRecursive_cases(?BER)), - - ?line testChoRecursive:compile(Config,?PER,[]), - ?line testChoRecursive_cases(?PER), - - ?line ?per_bit_opt(testChoRecursive:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoRecursive_cases(?PER)), - - ?line ?uper_bin(testChoRecursive:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoRecursive_cases(uper_bin)), - - ?line testChoRecursive:compile(Config,?PER,[optimize]), - ?line testChoRecursive_cases(?PER). - -testChoRecursive_cases(Rules) -> - ?line testChoRecursive:recursive(Rules). - - - -testChoTypeRefCho(suite) -> []; -testChoTypeRefCho(Config) -> - - ?line testChoTypeRefCho:compile(Config,?BER,[]), - ?line testChoTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefCho_cases(?BER)), - - ?line testChoTypeRefCho:compile(Config,?PER,[]), - ?line testChoTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefCho_cases(uper_bin)), - - ?line testChoTypeRefCho:compile(Config,?PER,[optimize]), - ?line testChoTypeRefCho_cases(?PER). - -testChoTypeRefCho_cases(Rules) -> - ?line testChoTypeRefCho:choice(Rules). - - - -testChoTypeRefPrim(suite) -> []; -testChoTypeRefPrim(Config) -> - - ?line testChoTypeRefPrim:compile(Config,?BER,[]), - ?line testChoTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefPrim_cases(?BER)), - - ?line testChoTypeRefPrim:compile(Config,?PER,[]), - ?line testChoTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefPrim_cases(uper_bin)), - - ?line testChoTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testChoTypeRefPrim_cases(?PER). - -testChoTypeRefPrim_cases(Rules) -> - ?line testChoTypeRefPrim:prim(Rules). - - - -testChoTypeRefSeq(suite) -> []; -testChoTypeRefSeq(Config) -> - - ?line testChoTypeRefSeq:compile(Config,?BER,[]), - ?line testChoTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefSeq_cases(?BER)), - - ?line testChoTypeRefSeq:compile(Config,?PER,[]), - ?line testChoTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefSeq_cases(uper_bin)), - - ?line testChoTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testChoTypeRefSeq_cases(?PER). - -testChoTypeRefSeq_cases(Rules) -> - ?line testChoTypeRefSeq:seq(Rules). - - - -testChoTypeRefSet(suite) -> []; -testChoTypeRefSet(Config) -> - - ?line testChoTypeRefSet:compile(Config,?BER,[]), - ?line testChoTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testChoTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoTypeRefSet_cases(?BER)), - - ?line testChoTypeRefSet:compile(Config,?PER,[]), - ?line testChoTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testChoTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testChoTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testChoTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testChoTypeRefSet_cases(uper_bin)), - - ?line testChoTypeRefSet:compile(Config,?PER,[optimize]), - ?line testChoTypeRefSet_cases(?PER). - -testChoTypeRefSet_cases(Rules) -> - ?line testChoTypeRefSet:set(Rules). - - - -testDef(suite) -> []; -testDef(Config) -> - - ?line testDef:compile(Config,?BER,[]), - ?line testDef_cases(?BER), - - ?line ?ber_driver(?BER,testDef:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDef_cases(?BER)), - - ?line testDef:compile(Config,?PER,[]), - ?line testDef_cases(?PER), - - ?line ?per_bit_opt(testDef:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDef_cases(?PER)), - - ?line ?uper_bin(testDef:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDef_cases(uper_bin)), - - ?line testDef:compile(Config,?PER,[optimize]), - ?line testDef_cases(?PER). - -testDef_cases(Rules) -> - ?line testDef:main(Rules). - - - -testOpt(suite) -> []; -testOpt(Config) -> - - ?line testOpt:compile(Config,?BER), - ?line testOpt_cases(?BER), - - ?line testOpt:compile(Config,?PER), - ?line testOpt_cases(?PER). - -testOpt_cases(Rules) -> - ?line testOpt:main(Rules). - - -testEnumExt(suite) -> []; -testEnumExt(Config) -> - - ?line testEnumExt:compile(Config,?BER,[]), - ?line testEnumExt:main(?BER), - - ?line ?ber_driver(?BER,testEnumExt:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testEnumExt:main(?BER)), - - ?line testEnumExt:compile(Config,?PER,[]), - ?line testEnumExt:main(?PER), - - ?line ?per_bit_opt(testEnumExt:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testEnumExt:main(?PER)), - - ?line ?uper_bin(testEnumExt:compile(Config,uper_bin,[])), - ?line ?uper_bin(testEnumExt:main(uper_bin)), - - ?line testEnumExt:compile(Config,?PER,[optimize]), - ?line testEnumExt:main(?PER). - -testSeqDefault(doc) -> ["Test of OTP-2523 ENUMERATED with extensionmark."]; -testSeqDefault(suite) -> []; -testSeqDefault(Config) -> - - ?line testSeqDefault:compile(Config,?BER,[]), - ?line testSeqDefault_cases(?BER), - - ?line ?ber_driver(?BER,testSeqDefault:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqDefault_cases(?BER)), - - ?line testSeqDefault:compile(Config,?PER,[]), - ?line testSeqDefault_cases(?PER), - - ?line ?per_bit_opt(testSeqDefault:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqDefault_cases(?PER)), - - ?line ?uper_bin(testSeqDefault:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqDefault_cases(uper_bin)), - - ?line testSeqDefault:compile(Config,?PER,[optimize]), - ?line testSeqDefault_cases(?PER). - -testSeqDefault_cases(Rules) -> - ?line testSeqDefault:main(Rules). - - - -testSeqExtension(suite) -> []; -testSeqExtension(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqExtension:compile(Config,?BER,[]), - ?line testSeqExtension_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExtension_cases(?BER)). - -testSeqExtension_cases(Rules) -> - ?line testSeqExtension:main(Rules). - - - -testSeqExternal(suite) -> []; -testSeqExternal(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqExternal:compile(Config,?BER,[]), - ?line testSeqExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqExternal_cases(?BER)). - -testSeqExternal_cases(Rules) -> - ?line testSeqExternal:main(Rules). - - -testSeqOptional(suite) -> []; -testSeqOptional(Config) -> - - ?line testSeqOptional:compile(Config,?BER,[]), - ?line testSeqOptional_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOptional_cases(?BER)), - - ?line testSeqOptional:compile(Config,?PER,[]), - ?line testSeqOptional_cases(?PER), - - ?line ?per_bit_opt(testSeqOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOptional_cases(?PER)), - - ?line ?uper_bin(testSeqOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOptional_cases(uper_bin)), - - ?line testSeqOptional:compile(Config,?PER,[optimize]), - ?line testSeqOptional_cases(?PER). - -testSeqOptional_cases(Rules) -> - ?line testSeqOptional:main(Rules). - - - -testSeqPrim(suite) -> []; -testSeqPrim(Config) -> - - ?line testSeqPrim:compile(Config,?BER,[]), - ?line testSeqPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSeqPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqPrim_cases(?BER)), - - ?line testSeqPrim:compile(Config,?PER,[]), - ?line testSeqPrim_cases(?PER), - - ?line ?per_bit_opt(testSeqPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqPrim_cases(?PER)), - - ?line ?uper_bin(testSeqPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqPrim_cases(uper_bin)), - - ?line testSeqPrim:compile(Config,?PER,[optimize]), - ?line testSeqPrim_cases(?PER). - -testSeqPrim_cases(Rules) -> - ?line testSeqPrim:main(Rules). - - -testSeq2738(doc) -> ["Test of OTP-2738 Detect corrupt optional component."]; -testSeq2738(suite) -> []; -testSeq2738(Config) -> - - ?line testSeq2738:compile(Config,?BER,[]), - ?line testSeq2738_cases(?BER), - - ?line ?ber_driver(?BER,testSeq2738:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeq2738_cases(?BER)), - - ?line testSeq2738:compile(Config,?PER,[]), - ?line testSeq2738_cases(?PER), - - ?line ?per_bit_opt(testSeq2738:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeq2738_cases(?PER)), - - ?line ?uper_bin(testSeq2738:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeq2738_cases(uper_bin)), - - ?line testSeq2738:compile(Config,?PER,[optimize]), - ?line testSeq2738_cases(?PER). - -testSeq2738_cases(Rules) -> - ?line testSeq2738:main(Rules). - - -testSeqTag(suite) -> []; -testSeqTag(Config) -> - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqTag:compile(Config,?BER,[]), - ?line testSeqTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqTag:compile(Config,?PER,[]), - ?line testSeqTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqTag:compile(Config,?PER,[optimize]), - ?line testSeqTag_cases(?PER). - -testSeqTag_cases(Rules) -> - ?line testSeqTag:main(Rules). - - - - -testSeqTypeRefCho(suite) -> []; -testSeqTypeRefCho(Config) -> - - ?line testSeqTypeRefCho:compile(Config,?BER,[]), - ?line testSeqTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefCho_cases(?BER)), - - ?line testSeqTypeRefCho:compile(Config,?PER,[]), - ?line testSeqTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefCho_cases(uper_bin)), - - ?line testSeqTypeRefCho:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefCho_cases(?PER). - -testSeqTypeRefCho_cases(Rules) -> - ?line testSeqTypeRefCho:main(Rules). - - - -testSeqTypeRefPrim(suite) -> []; -testSeqTypeRefPrim(Config) -> - - ?line testSeqTypeRefPrim:compile(Config,?BER,[]), - ?line testSeqTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefPrim_cases(?BER)), - - ?line testSeqTypeRefPrim:compile(Config,?PER,[]), - ?line testSeqTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefPrim_cases(uper_bin)), - - ?line testSeqTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefPrim_cases(?PER). - -testSeqTypeRefPrim_cases(Rules) -> - ?line testSeqTypeRefPrim:main(Rules). - - - -testSeqTypeRefSeq(suite) -> []; -testSeqTypeRefSeq(Config) -> - - ?line testSeqTypeRefSeq:compile(Config,?BER,[]), - ?line testSeqTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefSeq_cases(?BER)), - - ?line testSeqTypeRefSeq:compile(Config,?PER,[]), - ?line testSeqTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefSeq_cases(uper_bin)), - - ?line testSeqTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefSeq_cases(?PER). - -testSeqTypeRefSeq_cases(Rules) -> - ?line testSeqTypeRefSeq:main(Rules). - - - -testSeqTypeRefSet(suite) -> []; -testSeqTypeRefSet(Config) -> - - ?line testSeqTypeRefSet:compile(Config,?BER,[]), - ?line testSeqTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testSeqTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqTypeRefSet_cases(?BER)), - - ?line testSeqTypeRefSet:compile(Config,?PER,[]), - ?line testSeqTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testSeqTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testSeqTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqTypeRefSet_cases(uper_bin)), - - ?line testSeqTypeRefSet:compile(Config,?PER,[optimize]), - ?line testSeqTypeRefSet_cases(?PER). - -testSeqTypeRefSet_cases(Rules) -> - ?line testSeqTypeRefSet:main(Rules). - - - - -testSeqOf(suite) -> []; -testSeqOf(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOf:compile(Config,?BER,[]), - ?line testSeqOf_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOf:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOf_cases(?BER)), - - ?line testSeqOf:compile(Config,?PER,[]), - ?line testSeqOf_cases(?PER), - - ?line ?per_bit_opt(testSeqOf:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOf_cases(?PER)), - - ?line ?uper_bin(testSeqOf:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOf_cases(uper_bin)), - - ?line testSeqOf:compile(Config,?PER,[optimize]), - ?line testSeqOf_cases(?PER). - -testSeqOf_cases(Rules) -> - ?line testSeqOf:main(Rules). - - - - -testSeqOfCho(suite) -> []; -testSeqOfCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOfCho:compile(Config,?BER,[]), - ?line testSeqOfCho_cases(?BER), - - ?line ?ber_driver(?BER,testSeqOfCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfCho_cases(?BER)), - - ?line testSeqOfCho:compile(Config,?PER,[]), - ?line testSeqOfCho_cases(?PER), - - ?line ?per_bit_opt(testSeqOfCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfCho_cases(?PER)), - - ?line ?uper_bin(testSeqOfCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfCho_cases(uper_bin)), - - ?line testSeqOfCho:compile(Config,?PER,[optimize]), - ?line testSeqOfCho_cases(?PER). - -testSeqOfIndefinite(suite) -> []; -testSeqOfIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqOfIndefinite:compile(Config,?BER,[]), - ?line testSeqOfIndefinite:main(), - - ?line ?ber_driver(?BER,testSeqOfIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfIndefinite:main()). - -testSeqOfCho_cases(Rules) -> - ?line testSeqOfCho:main(Rules). - - -testSeqOfExternal(suite) -> []; -testSeqOfExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqOfExternal:compile(Config,?BER,[]), - ?line testSeqOfExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqOfExternal:compile(Config,?PER,[]), - ?line testSeqOfExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfExternal_cases(?PER). - -testSeqOfExternal_cases(Rules) -> - ?line testSeqOfExternal:main(Rules). - - - -testSeqOfTag(suite) -> []; -testSeqOfTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSeqOfTag:compile(Config,?BER,[]), - ?line testSeqOfTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqOfTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSeqOfTag:compile(Config,?PER,[]), - ?line testSeqOfTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSeqOfTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSeqOfTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSeqOfTag:compile(Config,?PER,[optimize]), - ?line testSeqOfTag_cases(?PER). - -testSeqOfTag_cases(Rules) -> - ?line testSeqOfTag:main(Rules). - - - - -testSetDefault(suite) -> []; -testSetDefault(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetDefault:compile(Config,?BER,[]), - ?line testSetDefault_cases(?BER), - - ?line ?ber_driver(?BER,testSetDefault:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetDefault_cases(?BER)), - - ?line testSetDefault:compile(Config,?PER,[]), - ?line testSetDefault_cases(?PER), - - ?line ?per_bit_opt(testSetDefault:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetDefault_cases(?PER)), - - ?line ?uper_bin(testSetDefault:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetDefault_cases(uper_bin)), - - ?line testSetDefault:compile(Config,?PER,[optimize]), - ?line testSetDefault_cases(?PER). - -testSetDefault_cases(Rules) -> - ?line testSetDefault:main(Rules). - - -testParamBasic(suite) -> []; -testParamBasic(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testParamBasic:compile(Config,?BER,[]), - ?line testParamBasic_cases(?BER), - - ?line ?ber_driver(?BER,testParamBasic:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testParamBasic_cases(?BER)), - - ?line testParamBasic:compile(Config,?PER,[]), - ?line testParamBasic_cases(?PER), - - ?line ?per_bit_opt(testParamBasic:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testParamBasic_cases(?PER)), - - ?line ?uper_bin(testParamBasic:compile(Config,uper_bin,[])), - ?line ?uper_bin(testParamBasic_cases(uper_bin)), - - ?line testParamBasic:compile(Config,?PER,[optimize]), - ?line testParamBasic_cases(?PER). - - -testParamBasic_cases(Rules) -> - ?line testParamBasic:main(Rules). - -testSetExtension(suite) -> []; -testSetExtension(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetExtension:compile(Config,?BER,[]), - ?line testSetExtension_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExtension:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExtension_cases(?BER)). - -testSetExtension_cases(Rules) -> - ?line testSetExtension:main(Rules). - - -testSetExternal(suite) -> []; -testSetExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetExternal:compile(Config,?BER,[]), - ?line testSetExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetExternal_cases(?BER)). - -testSetExternal_cases(Rules) -> - ?line testSetExternal:main(Rules). - - -testSetOptional(suite) -> []; -testSetOptional(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOptional:compile(Config,?BER,[]), - ?line testSetOptional_cases(?BER), - - ?line ?ber_driver(?BER,testSetOptional:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOptional_cases(?BER)), - - ?line testSetOptional:compile(Config,?PER,[]), - ?line testSetOptional_cases(?PER), - - ?line ?per_bit_opt(testSetOptional:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOptional_cases(?PER)), - - ?line ?uper_bin(testSetOptional:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOptional_cases(uper_bin)), - - ?line testSetOptional:compile(Config,?PER,[optimize]), - ?line testSetOptional_cases(?PER). - -testSetOptional_cases(Rules) -> - ?line ok = testSetOptional:ticket_7533(Rules), - ?line ok = testSetOptional:main(Rules). - - - - -testSetPrim(suite) -> []; -testSetPrim(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetPrim:compile(Config,?BER,[]), - ?line testSetPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSetPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetPrim_cases(?BER)), - - ?line testSetPrim:compile(Config,?PER,[]), - ?line testSetPrim_cases(?PER), - - ?line ?per_bit_opt(testSetPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetPrim_cases(?PER)), - - ?line ?uper_bin(testSetPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetPrim_cases(uper_bin)), - - ?line testSetPrim:compile(Config,?PER,[optimize]), - ?line testSetPrim_cases(?PER). - -testSetPrim_cases(Rules) -> - ?line testSetPrim:main(Rules). - - - -testSetTag(suite) -> []; -testSetTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetTag:compile(Config,?BER,[]), - ?line testSetTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetTag:compile(Config,?PER,[]), - ?line testSetTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetTag:compile(Config,?PER,[optimize]), - ?line testSetTag_cases(?PER). - -testSetTag_cases(Rules) -> - ?line testSetTag:main(Rules). - - - -testSetTypeRefCho(suite) -> []; -testSetTypeRefCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefCho:compile(Config,?BER,[]), - ?line testSetTypeRefCho_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefCho_cases(?BER)), - - ?line testSetTypeRefCho:compile(Config,?PER,[]), - ?line testSetTypeRefCho_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefCho_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefCho_cases(uper_bin)), - - ?line testSetTypeRefCho:compile(Config,?PER,[optimize]), - ?line testSetTypeRefCho_cases(?PER). - -testSetTypeRefCho_cases(Rules) -> - ?line testSetTypeRefCho:main(Rules). - - - -testSetTypeRefPrim(suite) -> []; -testSetTypeRefPrim(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefPrim:compile(Config,?BER,[]), - ?line testSetTypeRefPrim_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefPrim:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefPrim_cases(?BER)), - - ?line testSetTypeRefPrim:compile(Config,?PER,[]), - ?line testSetTypeRefPrim_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefPrim:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefPrim_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefPrim:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefPrim_cases(uper_bin)), - - ?line testSetTypeRefPrim:compile(Config,?PER,[optimize]), - ?line testSetTypeRefPrim_cases(?PER). - -testSetTypeRefPrim_cases(Rules) -> - ?line testSetTypeRefPrim:main(Rules). - - - -testSetTypeRefSeq(suite) -> []; -testSetTypeRefSeq(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefSeq:compile(Config,?BER,[]), - ?line testSetTypeRefSeq_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefSeq:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefSeq_cases(?BER)), - - ?line testSetTypeRefSeq:compile(Config,?PER,[]), - ?line testSetTypeRefSeq_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefSeq:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefSeq_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefSeq:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefSeq_cases(uper_bin)), - - ?line testSetTypeRefSeq:compile(Config,?PER,[optimize]), - ?line testSetTypeRefSeq_cases(?PER). - -testSetTypeRefSeq_cases(Rules) -> - ?line testSetTypeRefSeq:main(Rules). - - - -testSetTypeRefSet(suite) -> []; -testSetTypeRefSet(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetTypeRefSet:compile(Config,?BER,[]), - ?line testSetTypeRefSet_cases(?BER), - - ?line ?ber_driver(?BER,testSetTypeRefSet:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetTypeRefSet_cases(?BER)), - - ?line testSetTypeRefSet:compile(Config,?PER,[]), - ?line testSetTypeRefSet_cases(?PER), - - ?line ?per_bit_opt(testSetTypeRefSet:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetTypeRefSet_cases(?PER)), - - ?line ?uper_bin(testSetTypeRefSet:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetTypeRefSet_cases(uper_bin)), - - ?line testSetTypeRefSet:compile(Config,?PER,[optimize]), - ?line testSetTypeRefSet_cases(?PER). - -testSetTypeRefSet_cases(Rules) -> - ?line testSetTypeRefSet:main(Rules). - - - -testSetOf(suite) -> []; -testSetOf(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOf:compile(Config,?BER,[]), - ?line testSetOf_cases(?BER), - - ?line ?ber_driver(?BER,testSetOf:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOf_cases(?BER)), - - ?line testSetOf:compile(Config,?PER,[]), - ?line testSetOf_cases(?PER), - - ?line ?per_bit_opt(testSetOf:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOf_cases(?PER)), - - ?line ?uper_bin(testSetOf:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOf_cases(uper_bin)), - - ?line testSetOf:compile(Config,?PER,[optimize]), - ?line testSetOf_cases(?PER). - -testSetOf_cases(Rules) -> - ?line testSetOf:main(Rules). - - - -testSetOfCho(suite) -> []; -testSetOfCho(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetOfCho:compile(Config,?BER,[]), - ?line testSetOfCho_cases(?BER), - - ?line ?ber_driver(?BER,testSetOfCho:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfCho_cases(?BER)), - - ?line testSetOfCho:compile(Config,?PER,[]), - ?line testSetOfCho_cases(?PER), - - ?line ?per_bit_opt(testSetOfCho:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfCho_cases(?PER)), - - ?line ?uper_bin(testSetOfCho:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfCho_cases(uper_bin)), - - ?line testSetOfCho:compile(Config,?PER,[optimize]), - ?line testSetOfCho_cases(?PER). - -testSetOfCho_cases(Rules) -> - ?line testSetOfCho:main(Rules). - - -testSetOfExternal(suite) -> []; -testSetOfExternal(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetOfExternal:compile(Config,?BER,[]), - ?line testSetOfExternal_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfExternal_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetOfExternal:compile(Config,?PER,[]), - ?line testSetOfExternal_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfExternal_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfExternal_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetOfExternal:compile(Config,?PER,[optimize]), - ?line testSetOfExternal_cases(?PER). - -testSetOfExternal_cases(Rules) -> - ?line testSetOfExternal:main(Rules). - - - - -testSetOfTag(suite) -> []; -testSetOfTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testExternal:compile(Config,?BER,[]), - ?line testSetOfTag:compile(Config,?BER,[]), - ?line testSetOfTag_cases(?BER), - - ?line ?ber_driver(?BER,testExternal:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetOfTag_cases(?BER)), - - ?line testExternal:compile(Config,?PER,[]), - ?line testSetOfTag:compile(Config,?PER,[]), - ?line testSetOfTag_cases(?PER), - - ?line ?per_bit_opt(testExternal:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testSetOfTag_cases(?PER)), - - ?line ?uper_bin(testExternal:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testSetOfTag_cases(uper_bin)), - - ?line testExternal:compile(Config,?PER,[optimize]), - ?line testSetOfTag:compile(Config,?PER,[optimize]), - ?line testSetOfTag_cases(?PER). - -testSetOfTag_cases(Rules) -> - ?line testSetOfTag:main(Rules). - - -c_syntax(suite) -> []; -c_syntax(Config) -> - ?line DataDir% ?line testExternal:compile(Config,?PER), -% ?line testPrimExternal:compile(Config,?PER), -% ?line testPrimExternal_cases(?PER). - = ?config(data_dir,Config), - ?line _TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line {error,_R1} = asn1ct:compile(filename:join(DataDir,"Syntax")), - ?line {error,_R2} = asn1ct:compile(filename:join(DataDir,"BadTypeEnding")), - ?line {error,_R3} = asn1ct:compile(filename:join(DataDir, - "BadValueAssignment1")), - ?line {error,_R4} = asn1ct:compile(filename:join(DataDir, - "BadValueAssignment2")), - ?line {error,_R5} = asn1ct:compile(filename:join(DataDir, - "BadValueSet")), - ?line {error,_R6} = asn1ct:compile(filename:join(DataDir, - "ChoiceBadExtension")), - ?line {error,_R7} = asn1ct:compile(filename:join(DataDir, - "EnumerationBadExtension")), - ?line {error,_R8} = asn1ct:compile(filename:join(DataDir, - "Example")), - ?line {error,_R9} = asn1ct:compile(filename:join(DataDir, - "Export1")), - ?line {error,_R10} = asn1ct:compile(filename:join(DataDir, - "MissingEnd")), - ?line {error,_R11} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComma")), - ?line {error,_R12} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComponentName")), - ?line {error,_R13} = asn1ct:compile(filename:join(DataDir, - "SequenceBadComponentType")), - ?line {error,_R14} = asn1ct:compile(filename:join(DataDir, - "SeqBadComma")). - - -c_string_per(suite) -> []; -c_string_per(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"String"),[?PER,{outdir,TempDir}]). - -c_string_ber(suite) -> []; -c_string_ber(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"String"),[?BER,{outdir,TempDir}]). - - -c_implicit_before_choice(suite) -> []; -c_implicit_before_choice(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TempDir = ?config(priv_dir,Config), - ?line {error,_R2} = asn1ct:compile(filename:join(DataDir,"CCSNARG3"),[?BER,{outdir,TempDir}]). - -parse(suite) -> []; -parse(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - M1 = test_modules(), -% M2 = parse_modules(), - ?line ok = parse1(M1,DataDir,OutDir). - -parse1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[abs,{outdir,OutDir}]), - parse1(T,DataDir,OutDir); -parse1([],_,_) -> - ok. - -per(suite) -> []; -per(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = per1(per_modules(),DataDir,OutDir), - ?line ?per_bit_opt(per1_bit_opt(per_modules(),DataDir,OutDir)), - ?line ok = per1_opt(per_modules(),DataDir,OutDir). - - -per1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1(T,DataDir,OutDir); -per1([],_,_) -> - ok. - -per1_bit_opt([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,optimize,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1_bit_opt(T,DataDir,OutDir); -per1_bit_opt([],_,_) -> - ok. - -per1_opt([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?PER,optimized,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - per1_opt(T,DataDir,OutDir); -per1_opt([],_,_) -> - ok. - - -ber_choiceinseq(suite) ->[]; -ber_choiceinseq(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"ChoiceInSeq"),[?BER,{outdir,OutDir}]). - -ber_optional(suite) ->[]; -ber_optional(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"SOpttest"),[?BER,{outdir,OutDir}]), - ?line V = {'S',{'A',10,asn1_NOVALUE,asn1_NOVALUE}, - {'B',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}, - {'C',asn1_NOVALUE,111,asn1_NOVALUE}}, - ?line {ok,B} = asn1_wrapper:encode('SOpttest','S',V), - ?line Bytes = lists:flatten(B), - ?line V2 = asn1_wrapper:decode('SOpttest','S',Bytes), - ?line ok = eq(V,element(2,V2)). - -ber_optional_keyed_list(suite) ->[]; -ber_optional_keyed_list(Config) -> - case ?BER of - ber_bin_v2 -> ok; - _ -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(filename:join(DataDir,"SOpttest"), - [?BER,keyed_list,{outdir,OutDir}]), - ?line Vrecord = {'S',{'A',10,asn1_NOVALUE,asn1_NOVALUE}, - {'B',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}, - {'C',asn1_NOVALUE,111,asn1_NOVALUE}}, - ?line V = [ {a,[{scriptKey,10}]}, - {b,[]}, - {c,[{callingPartysCategory,111}]} ], - ?line {ok,B} = asn1_wrapper:encode('SOpttest','S',V), - ?line Bytes = lists:flatten(B), - ?line V2 = asn1_wrapper:decode('SOpttest','S',Bytes), - ?line ok = eq(Vrecord,element(2,V2)) - end. - - -eq(V,V) -> - ok. - - -ber_other(suite) ->[]; -ber_other(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = ber1(ber_modules(),DataDir,OutDir). - - -ber1([M|T],DataDir,OutDir) -> - ?line ok = asn1ct:compile(DataDir ++ M,[?BER,{outdir,OutDir}]), - ?line ok = asn1ct:test(list_to_atom(M)), - ber1(T,DataDir,OutDir); -ber1([],_,_) -> - ok. - -default_per(suite) ->[]; -default_per(Config) -> - default1(?PER,Config,[]). - -default_per_opt(suite) -> []; -default_per_opt(Config) -> - ?per_bit_opt(default1(?PER,Config,[optimize])), - default1(?PER,Config,[optimize]). - -default_ber(suite) ->[]; -default_ber(Config) -> - default1(?BER,Config,[]). - -default1(Rule,Config,Options) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "Def",[Rule,{outdir,OutDir}]++Options), - ?line {ok,Bytes1} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true, - bool1 = true, - bool2 = true, - bool3 = true}), - ?line {ok,{'Def1',true,true,true,true}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes1)), - - ?line {ok,Bytes2} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true}), - ?line {ok,{'Def1',true,false,false,false}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes2)), - - ?line {ok,Bytes3} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true,bool2=false}), - ?line {ok,{'Def1',true,false,false,false}} = asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes3)). - - -value_test(suite) ->[]; -value_test(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "ObjIdValues",[?BER,{outdir,OutDir}]), - ?line {ok,_} = asn1_wrapper:encode('ObjIdValues','ObjIdType','ObjIdValues':'mobileDomainId'()), - ?line ok = asn1ct:compile(DataDir ++ "ObjIdValues",[?PER,{outdir,OutDir}]), - ?line {ok,_} = asn1_wrapper:encode('ObjIdValues','ObjIdType','ObjIdValues':'mobileDomainId'()), - ?line ok = test_bad_values:tests(Config), - ok. - - -constructed(suite) -> - []; -constructed(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - ?line ok = asn1ct:compile(DataDir ++ "Constructed",[?BER,{outdir,OutDir}]), - ?line {ok,B} = asn1_wrapper:encode('Constructed','S',{'S',false}), - ?line [40,3,1,1,0] = lists:flatten(B), - ?line {ok,B1} = asn1_wrapper:encode('Constructed','S2',{'S2',false}), - ?line [40,5,48,3,1,1,0] = lists:flatten(B1), - ?line {ok,B2} = asn1_wrapper:encode('Constructed','I',10), - ?line [136,1,10] = lists:flatten(B2), - ok. - -ber_decode_error(suite) -> []; -ber_decode_error(Config) -> - ?line ok = ber_decode_error:compile(Config,?BER,[]), - ?line ok = ber_decode_error:run([]), - - ?line ok = ?ber_driver(?BER,ber_decode_error:compile(Config,?BER,[driver])), - ?line ok = ?ber_driver(?BER,ber_decode_error:run([driver])), - ok. - -h323test(suite) -> - []; -h323test(Config) -> - ?line ok = h323test:compile(Config,?PER,[]), - ?line ok = h323test:run(?PER), - ?line ?per_bit_opt(h323test:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(h323test:run(?PER)), - ?line ?uper_bin(h323test:compile(Config,uper_bin,[])), - ?line ?uper_bin(h323test:run(uper_bin)), - ?line ok = h323test:compile(Config,?PER,[optimize]), - ?line ok = h323test:run(?PER), - ok. - -per_GeneralString(suite) -> - []; -per_GeneralString(Config) -> - case erlang:module_loaded('MULTIMEDIA-SYSTEM-CONTROL') of - true -> - ok; - false -> - h323test:compile(Config,?PER,[]) - end, - UI = [109,64,1,57], - ?line {ok,_V} = asn1_wrapper:decode('MULTIMEDIA-SYSTEM-CONTROL', - 'MultimediaSystemControlMessage',UI). - -per_open_type(suite) -> - []; -per_open_type(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line ok = asn1ct:compile(DataDir ++ "OpenType",[?PER,{outdir,OutDir}]), - Stype = {'Stype',10,true}, - ?line {ok,Bytes} = asn1_wrapper:encode('OpenType','Ot',Stype), - ?line {ok,Stype} = asn1_wrapper:decode('OpenType','Ot',Bytes), - - ?line ?per_bit_opt(ok = asn1ct:compile(DataDir ++ "OpenType", - [?PER,optimize,{outdir,OutDir}])), - ?line ?per_bit_opt({ok,Bytes}=asn1_wrapper:encode('OpenType','Ot',Stype)), - ?line ?per_bit_opt({ok,Stype}=asn1_wrapper:decode('OpenType','Ot',Bytes)), - - ?line ?uper_bin(ok = asn1ct:compile(DataDir ++ "OpenType", - [uper_bin,{outdir,OutDir}])), - ?line ?uper_bin({ok,Bytes}=asn1_wrapper:encode('OpenType','Ot',Stype)), - ?line ?uper_bin({ok,Stype}=asn1_wrapper:decode('OpenType','Ot',Bytes)), - - ?line ok = asn1ct:compile(DataDir ++ "OpenType", - [?PER,optimize,{outdir,OutDir}]), - ?line {ok,Bytes} = asn1_wrapper:encode('OpenType','Ot',Stype), - ?line {ok,Stype} = asn1_wrapper:decode('OpenType','Ot',Bytes). - -testConstraints(suite) -> - []; -testConstraints(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testConstraints:compile(Config,?BER,[]), - ?line testConstraints:int_constraints(?BER), - - ?line ?ber_driver(?BER,testConstraints:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testConstraints:int_constraints(?BER)), - - ?line testConstraints:compile(Config,?PER,[]), - ?line testConstraints:int_constraints(?PER), - ?line testConstraints:refed_NNL_name(?PER), - - ?line ?per_bit_opt(testConstraints:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testConstraints:int_constraints(?PER)), - ?line ?per_bit_opt(testConstraints:refed_NNL_name(?PER)), - - ?line ?uper_bin(testConstraints:compile(Config,uper_bin,[])), - ?line ?uper_bin(testConstraints:int_constraints(uper_bin)), - ?line ?uper_bin(testConstraints:refed_NNL_name(uper_bin)), - - ?line testConstraints:compile(Config,?PER,[optimize]), - ?line testConstraints:int_constraints(?PER), - ?line testConstraints:refed_NNL_name(?PER). - -testSeqIndefinite(suite) -> []; -testSeqIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSeqIndefinite:compile(Config,?BER,[]), - ?line testSeqIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testSeqIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSeqIndefinite:main(?BER)). - -testSetIndefinite(suite) -> []; -testSetIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testSetIndefinite:compile(Config,?BER,[]), - ?line testSetIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testSetIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testSetIndefinite:main(?BER)). - -testChoiceIndefinite(suite) -> []; -testChoiceIndefinite(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testChoiceIndefinite:compile(Config,?BER,[]), - ?line testChoiceIndefinite:main(?BER), - - ?line ?ber_driver(?BER,testChoiceIndefinite:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testChoiceIndefinite:main(?BER)). - -testInfObjectClass(suite) -> - []; -testInfObjectClass(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testInfObjectClass:compile(Config,?PER,[]), - ?line testInfObjectClass:main(?PER), - ?line testInfObj:compile(Config,?PER,[]), - ?line testInfObj:main(?PER), - - ?line ?per_bit_opt(testInfObjectClass:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testInfObjectClass:main(?PER)), - ?line ?per_bit_opt(testInfObj:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testInfObj:main(?PER)), - - ?line ?uper_bin(testInfObjectClass:compile(Config,uper_bin,[])), - ?line ?uper_bin(testInfObjectClass:main(uper_bin)), - ?line ?uper_bin(testInfObj:compile(Config,uper_bin,[])), - ?line ?uper_bin(testInfObj:main(uper_bin)), - - ?line testInfObjectClass:compile(Config,?PER,[optimize]), - ?line testInfObjectClass:main(?PER), - ?line testInfObj:compile(Config,?PER,[optimize]), - ?line testInfObj:main(?PER), - - ?line testInfObjectClass:compile(Config,?BER,[]), - ?line testInfObjectClass:main(?BER), - ?line testInfObj:compile(Config,?BER,[]), - ?line testInfObj:main(?BER), - - ?line ?ber_driver(?BER,testInfObjectClass:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testInfObjectClass:main(?BER)), - ?line ?ber_driver(?BER,testInfObj:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testInfObj:main(?BER)), - - ?line testInfObj:compile_RANAPfiles(Config,?PER,[]), - - ?line ?per_bit_opt(testInfObj:compile_RANAPfiles(Config,?PER,[optimize])), - - ?line ?uper_bin(testInfObj:compile_RANAPfiles(Config,uper_bin,[])), - - ?line testInfObj:compile_RANAPfiles(Config,?PER,[optimize]), - - ?line testInfObj:compile_RANAPfiles(Config,?BER,[]). - -testParameterizedInfObj(suite) -> - []; -testParameterizedInfObj(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testParameterizedInfObj:compile(Config,?PER,[]), - ?line testParameterizedInfObj:main(?PER), - - ?line ?per_bit_opt(testParameterizedInfObj:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testParameterizedInfObj:main(?PER)), - - ?line ?uper_bin(testParameterizedInfObj:compile(Config,uper_bin,[])), - ?line ?uper_bin(testParameterizedInfObj:main(uper_bin)), - - ?line testParameterizedInfObj:compile(Config,?PER,[optimize]), - ?line testParameterizedInfObj:main(?PER), - - ?line testParameterizedInfObj:compile(Config,?BER,[]), - ?line testParameterizedInfObj:main(?BER), - - ?line ?ber_driver(?BER,testParameterizedInfObj:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testParameterizedInfObj:main(?BER)). - -testMergeCompile(suite) -> - []; -testMergeCompile(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testMergeCompile:compile(Config,?PER,[]), - ?line testMergeCompile:main(?PER), - ?line testMergeCompile:mvrasn(?PER), - - ?line ?per_bit_opt(testMergeCompile:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testMergeCompile:main(?PER)), - ?line ?per_bit_opt(testMergeCompile:mvrasn(?PER)), - - ?line ?uper_bin(testMergeCompile:compile(Config,uper_bin,[])), - ?line ?uper_bin(testMergeCompile:main(uper_bin)), - ?line ?uper_bin(testMergeCompile:mvrasn(uper_bin)), - - ?line testMergeCompile:compile(Config,?BER,[]), - ?line testMergeCompile:main(?BER), - ?line testMergeCompile:mvrasn(?BER), - - ?line ?ber_driver(?BER,testMergeCompile:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testMergeCompile:main(?BER)), - ?line ?ber_driver(?BER,testMergeCompile:mvrasn(?BER)). - -testobj(suite) -> - []; -testobj(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line ok = testRANAP:compile(Config,?PER,[]), - ?line ok = testRANAP:testobj(?PER), - ?line ok = testParameterizedInfObj:ranap(?PER), - - ?line ?per_bit_opt(ok = testRANAP:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(ok = testRANAP:testobj(?PER)), - ?line ?per_bit_opt(ok = testParameterizedInfObj:ranap(?PER)), - - ?line ?uper_bin(ok = testRANAP:compile(Config,uper_bin,[])), - ?line ?uper_bin(ok = testRANAP:testobj(uper_bin)), - ?line ?uper_bin(ok = testParameterizedInfObj:ranap(uper_bin)), - - ?line ok = testRANAP:compile(Config,?PER,[optimize]), - ?line ok = testRANAP:testobj(?PER), - ?line ok = testParameterizedInfObj:ranap(?PER), - - ?line ok = testRANAP:compile(Config,?BER,[]), - ?line ok = testRANAP:testobj(?BER), - ?line ok = testParameterizedInfObj:ranap(?BER), - - ?line ?ber_driver(?BER,testRANAP:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testRANAP:testobj(?BER)), - ?line ?ber_driver(?BER,testParameterizedInfObj:ranap(?BER)). - - -testDeepTConstr(suite) -> - []; -testDeepTConstr(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testDeepTConstr:compile(Config,?PER,[]), - ?line testDeepTConstr:main(?PER), - - ?line ?per_bit_opt(testDeepTConstr:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDeepTConstr:main(?PER)), - - ?line ?uper_bin(testDeepTConstr:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDeepTConstr:main(uper_bin)), - - ?line testDeepTConstr:compile(Config,?PER,[optimize]), - ?line testDeepTConstr:main(?PER), - - ?line testDeepTConstr:compile(Config,?BER,[]), - ?line testDeepTConstr:main(?BER), - - ?line ?ber_driver(?BER,testDeepTConstr:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDeepTConstr:main(?BER)). - -testInvokeMod(suite) -> - []; -testInvokeMod(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line ok = asn1ct:compile(filename:join(DataDir,"PrimStrings"),[{outdir,OutDir}]), - ?line {ok,_Result1} = 'PrimStrings':encode('Bs1',[1,0,1,0]), - ?line ok = asn1ct:compile(filename:join(DataDir,"PrimStrings"),[?PER,{outdir,OutDir}]), - ?line {ok,_Result2} = 'PrimStrings':encode('Bs1',[1,0,1,0]). - -testExport(suite) -> - []; -testExport(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line {error,{asn1,_Reason}} = asn1ct:compile(filename:join(DataDir,"IllegalExport"),[{outdir,OutDir}]). - -testImport(suite) -> - []; -testImport(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line _OutDir = ?config(priv_dir,Config), - ?line {error,_} = asn1ct:compile(filename:join(DataDir,"ImportsFrom"),[?BER]), - ok. - -testMegaco(suite) -> - []; -testMegaco(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - io:format("Config: ~p~n",[Config]), - ?line {ok,ModuleName1,ModuleName2} = testMegaco:compile(Config,?BER,[]), - ?line ok = testMegaco:main(ModuleName1,Config), - ?line ok = testMegaco:main(ModuleName2,Config), - - case ?BER of - ber_bin_v2 -> - ?line {ok,ModuleName3,ModuleName4} = testMegaco:compile(Config,?BER,[driver]), - ?line ok = testMegaco:main(ModuleName3,Config), - ?line ok = testMegaco:main(ModuleName4,Config); - _-> ok - end, - - ?line {ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,?PER,[]), - ?line ok = testMegaco:main(ModuleName5,Config), - ?line ok = testMegaco:main(ModuleName6,Config), - - ?line ?per_bit_opt({ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(ok = testMegaco:main(ModuleName5,Config)), - ?line ?per_bit_opt(ok = testMegaco:main(ModuleName6,Config)), - - ?line ?uper_bin({ok,ModuleName5,ModuleName6} = testMegaco:compile(Config,uper_bin,[])), - ?line ?uper_bin(ok = testMegaco:main(ModuleName5,Config)), - ?line ?uper_bin(ok = testMegaco:main(ModuleName6,Config)), - - ?line {ok,ModuleName7,ModuleName8} = testMegaco:compile(Config,?PER,[optimize]), - ?line ok = testMegaco:main(ModuleName7,Config), - ?line ok = testMegaco:main(ModuleName8,Config). - - -testMvrasn6(suite) -> []; -testMvrasn6(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testMvrasn6:compile(Config,?BER), - ?line testMvrasn6:main(). - -testContextSwitchingTypes(suite) -> []; -testContextSwitchingTypes(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testContextSwitchingTypes:compile(Config,?BER,[]), - ?line testContextSwitchingTypes:test(), - - ?line ?ber_driver(?BER,testContextSwitchingTypes:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testContextSwitchingTypes:test()), - - ?line testContextSwitchingTypes:compile(Config,?PER,[]), - ?line testContextSwitchingTypes:test(), - - ?line ?per_bit_opt(testContextSwitchingTypes:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testContextSwitchingTypes:test()), - - ?line ?uper_bin(testContextSwitchingTypes:compile(Config,uper_bin,[])), - ?line ?uper_bin(testContextSwitchingTypes:test()), - - ?line testContextSwitchingTypes:compile(Config,?PER,[optimize]), - ?line testContextSwitchingTypes:test(). - -testTypeValueNotation(suite) -> []; -testTypeValueNotation(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - case ?BER of - Ber when Ber == ber; Ber == ber_bin -> - ?line testTypeValueNotation:compile(Config,?BER,[]), - ?line testTypeValueNotation:main(?BER,dummy); - _ -> - ok - end, - - ?line ?ber_driver(?BER,testTypeValueNotation:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testTypeValueNotation:main(?BER,optimize)), - - case ?BER of - Ber2 when Ber2 == ber; Ber2 == ber_bin -> - ?line testTypeValueNotation:compile(Config,?PER,[]), - ?line testTypeValueNotation:main(?PER,dummy); - _ -> - ok - end, - - ?line ?per_bit_opt(testTypeValueNotation:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testTypeValueNotation:main(?PER,optimize)), - - ?line ?uper_bin(testTypeValueNotation:compile(Config,uper_bin,[])), - ?line ?uper_bin(testTypeValueNotation:main(uper_bin,optimize)), - case ?BER of - Ber3 when Ber3 == ber; Ber3 == ber_bin -> - ?line testTypeValueNotation:compile(Config,?PER,[optimize]), - ?line testTypeValueNotation:main(?PER,optimize); - _ -> - ok - end. - -testOpenTypeImplicitTag(suite) -> []; -testOpenTypeImplicitTag(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testOpenTypeImplicitTag:compile(Config,?BER,[]), - ?line testOpenTypeImplicitTag:main(?BER), - - ?line ?ber_driver(?BER,testOpenTypeImplicitTag:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testOpenTypeImplicitTag:main(?BER)), - - ?line testOpenTypeImplicitTag:compile(Config,?PER,[]), - ?line testOpenTypeImplicitTag:main(?PER), - - ?line ?per_bit_opt(testOpenTypeImplicitTag:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testOpenTypeImplicitTag:main(?PER)), - - ?line ?uper_bin(testOpenTypeImplicitTag:compile(Config,uper_bin,[])), - ?line ?uper_bin(testOpenTypeImplicitTag:main(uper_bin)), - - ?line testOpenTypeImplicitTag:compile(Config,?PER,[optimize]), - ?line testOpenTypeImplicitTag:main(?PER). - -duplicate_tags(suite) -> []; -duplicate_tags(Config) -> - ?line DataDir = ?config(data_dir,Config), - {error,{asn1,[{error,{type,_,_,'SeqOpt1Imp',{asn1,{duplicates_of_the_tags,_}}}}]}} = - asn1ct:compile(filename:join(DataDir,"SeqOptional2"),[abs]), - ok. - -rtUI(suite) -> []; -rtUI(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"Prim"),[?BER]), - ?line {ok,_} = asn1rt:info('Prim'), - - ?line ok = asn1ct:compile(filename:join(DataDir,"Prim"),[?PER]), - ?line {ok,_} = asn1rt:info('Prim'), - - ?line ok = asn1rt:load_driver(), - ?line ok = asn1rt:load_driver(), - ?line ok = asn1rt:unload_driver(). - -testROSE(suite) -> []; -testROSE(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testROSE:compile(Config,?BER,[]), - - ?line testROSE:compile(Config,?PER,[]), - ?line ?per_bit_opt(testROSE:compile(Config,?PER,[optimize])), - ?line ?uper_bin(testROSE:compile(Config,uper_bin,[])), - ?line testROSE:compile(Config,?PER,[optimize]). - -testINSTANCE_OF(suite) -> []; -testINSTANCE_OF(Config) -> - ?line testINSTANCE_OF:compile(Config,?BER,[]), - ?line testINSTANCE_OF:main(?BER), - - ?line ?ber_driver(?BER,testINSTANCE_OF:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testINSTANCE_OF:main(?BER)), - - ?line testINSTANCE_OF:compile(Config,?PER,[]), - ?line testINSTANCE_OF:main(?PER), - - ?line ?per_bit_opt(testINSTANCE_OF:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testINSTANCE_OF:main(?PER)), - - ?line ?uper_bin(testINSTANCE_OF:compile(Config,uper_bin,[])), - ?line ?uper_bin(testINSTANCE_OF:main(uper_bin)), - - ?line testINSTANCE_OF:compile(Config,?PER,[optimize]), - ?line testINSTANCE_OF:main(?PER). - -testTCAP(suite) -> []; -testTCAP(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testTCAP:compile(Config,?BER,[]), - ?line testTCAP:test(?BER,Config), - - ?line ?ber_driver(?BER,testTCAP:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testTCAP:test(?BER,Config)), - - ?line ?ber_driver(?BER,testTCAP:compile_asn1config(Config,?BER,[asn1config])), - ?line ?ber_driver(?BER,testTCAP:test_asn1config()). - -testDER(suite) ->[]; -testDER(Config) -> - ?line true = code:add_patha(?config(priv_dir,Config)), - - ?line testDER:compile(Config,?BER,[]), - ?line testDER:test(), - - ?line ?ber_driver(?BER,testDER:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDER:test()), - - ?line testParamBasic:compile_der(Config,?BER), - ?line testParamBasic_cases(der), - - - ?line testSeqSetDefaultVal:compile(Config,?BER), - ?line testSeqSetDefaultVal_cases(?BER). - -testSeqSetDefaultVal_cases(?BER) -> - ?line testSeqSetDefaultVal:main(?BER). - - -specialized_decodes(suite) -> []; -specialized_decodes(Config) -> - ?line test_partial_incomplete_decode:compile(Config,?BER,[optimize]), - ?line test_partial_incomplete_decode:test(?BER,Config), - ?line test_selective_decode:test(?BER,Config). - -special_decode_performance(suite) ->[]; -special_decode_performance(Config) -> - ?line ?ber_driver(?BER,test_special_decode_performance:compile(Config,?BER)), - ?line ?ber_driver(?BER,test_special_decode_performance:go(all)). - - -test_driver_load(suite) -> []; -test_driver_load(Config) -> - ?line test_driver_load:compile(Config,?PER), - ?line test_driver_load:test(?PER,5). - -test_ParamTypeInfObj(suite) -> []; -test_ParamTypeInfObj(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"IN-CS-1-Datatypes"),[ber_bin]). - -test_WS_ParamClass(suite) -> []; -test_WS_ParamClass(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"InformationFramework"), - [ber_bin]). - -test_Defed_ObjectIdentifier(suite) -> []; -test_Defed_ObjectIdentifier(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line ok = asn1ct:compile(filename:join(DataDir,"UsefulDefinitions"), - [ber_bin]). - -testSelectionType(suite) -> []; -testSelectionType(Config) -> - - ?line ok = testSelectionTypes:compile(Config,?BER,[]), - ?line {ok,_} = testSelectionTypes:test(), - - ?line ok = testSelectionTypes:compile(Config,?PER,[]), - ?line {ok,_} = testSelectionTypes:test(). - -testSSLspecs(suite) -> []; -testSSLspecs(Config) -> - - ?line ok = testSSLspecs:compile(Config,?BER, - [optimize,compact_bit_string,der]), - ?line testSSLspecs:run(?BER), - - case code:which(asn1ct) of - cover_compiled -> - ok; - _ -> - ?line ok = testSSLspecs:compile_inline(Config,?BER), - ?line ok = testSSLspecs:run_inline(?BER) - end. - -testNortel(suite) -> []; -testNortel(Config) -> - ?line DataDir = ?config(data_dir,Config), - - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[?BER]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?BER,optimize]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?BER,optimize,driver]), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[?PER]), - ?line ?per_bit_opt(ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?PER,optimize])), - ?line ?uper_bin(ok = asn1ct:compile(filename:join(DataDir,"Nortel"),[uper_bin])), - ?line ok = asn1ct:compile(filename:join(DataDir,"Nortel"), - [?PER,optimize]). -test_undecoded_rest(suite) -> []; -test_undecoded_rest(Config) -> - - ?line ok = test_undecoded_rest:compile(Config,?BER,[]), - ?line ok = test_undecoded_rest:test([]), - - ?line ok = test_undecoded_rest:compile(Config,?BER,[undec_rest]), - ?line ok = test_undecoded_rest:test(undec_rest), - - ?line ok = test_undecoded_rest:compile(Config,?PER,[]), - ?line ok = test_undecoded_rest:test([]), - - ?line ?per_bit_opt(ok = test_undecoded_rest:compile(Config,?PER,[optimize,undec_rest])), - ?line ?per_bit_opt(ok = test_undecoded_rest:test(undec_rest)), - - ?line ?uper_bin(ok = test_undecoded_rest:compile(Config,uper_bin,[undec_rest])), - ?line ?uper_bin(ok = test_undecoded_rest:test(undec_rest)), - - ?line ok = test_undecoded_rest:compile(Config,?PER,[undec_rest]), - ?line ok = test_undecoded_rest:test(undec_rest). - -test_inline(suite) -> []; -test_inline(Config) -> - case code:which(asn1ct) of - cover_compiled -> - {skip,"Not runnable when cover compiled"}; - _ -> - ?line ok=test_inline:compile(Config,?BER,[]), - ?line test_inline:main(?BER), - ?line test_inline:inline1(Config,?BER,[]), - ?line test_inline:performance2() - end. - -%test_inline_prf(suite) -> []; -%test_inline_prf(Config) -> -% ?line test_inline:performance(Config). - -testTcapsystem(suite) -> []; -testTcapsystem(Config) -> - ?line ok=testTcapsystem:compile(Config,?BER,[]). - -testNBAPsystem(suite) -> []; -testNBAPsystem(Config) -> - ?line ok=testNBAPsystem:compile(Config,?PER,?per_optimize(?BER)), - ?line ok=testNBAPsystem:test(?PER,Config). - -test_compile_options(suite) -> []; -test_compile_options(Config) -> - case code:which(asn1ct) of - cover_compiled -> - {skip,"Not runnable when cover compiled"}; - _ -> - ?line ok = test_compile_options:wrong_path(Config), - ?line ok = test_compile_options:path(Config), - ?line ok = test_compile_options:noobj(Config), - ?line ok = test_compile_options:record_name_prefix(Config), - ?line ok = test_compile_options:verbose(Config) - end. -testDoubleEllipses(suite) -> []; -testDoubleEllipses(Config) -> - ?line testDoubleEllipses:compile(Config,?BER,[]), - ?line testDoubleEllipses:main(?BER), - ?line ?ber_driver(?BER,testDoubleEllipses:compile(Config,?BER,[driver])), - ?line ?ber_driver(?BER,testDoubleEllipses:main(?BER)), - ?line ?per_bit_opt(testDoubleEllipses:compile(Config,?PER,[optimize])), - ?line ?per_bit_opt(testDoubleEllipses:main(?PER)), - ?line ?uper_bin(testDoubleEllipses:compile(Config,uper_bin,[])), - ?line ?uper_bin(testDoubleEllipses:main(uper_bin)), - ?line testDoubleEllipses:compile(Config,?PER,?per_optimize(?BER)), - ?line testDoubleEllipses:main(?PER). - -test_modified_x420(suite) -> []; -test_modified_x420(Config) -> - ?line test_modified_x420:compile(Config), - ?line test_modified_x420:test_io(Config). - -testX420(suite) -> []; -testX420(Config) -> - ?line testX420:compile(?BER,[der],Config), - ?line ok = testX420:ticket7759(?BER,Config), - ?line testX420:compile(?PER,[],Config). - -test_x691(suite) -> []; -test_x691(Config) -> - case ?PER of - per -> - ?line ok = test_x691:compile(Config,uper_bin,[]), - ?line true = test_x691:cases(uper_bin,unaligned), - ?line ok = test_x691:compile(Config,?PER,[]), - ?line true = test_x691:cases(?PER,aligned), -%% ?line ok = asn1_test_lib:ticket_7678(Config,[]), - ?line ok = asn1_test_lib:ticket_7708(Config,[]), - ?line ok = asn1_test_lib:ticket_7763(Config); - _ -> - ?line ok = test_x691:compile(Config,?PER,?per_optimize(?BER)), - ?line true = test_x691:cases(?PER,aligned) - end. -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[compact_bit_string]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[optimize]), -%% ?line ok = asn1_test_lib:ticket_7876(Config,?PER,[optimize,compact_bit_string]). - - -ticket_6143(suite) -> []; -ticket_6143(Config) -> - ?line ok = test_compile_options:ticket_6143(Config). - -testExtensionAdditionGroup(suite) -> []; -testExtensionAdditionGroup(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line PrivDir = ?config(priv_dir,Config), - ?line Path = code:get_path(), - ?line code:add_patha(PrivDir), - DoIt = fun(Erule) -> - ?line ok = asn1ct:compile(filename:join(DataDir,"Extension-Addition-Group"),[Erule,{outdir,PrivDir}]), - ?line {ok,_M} = compile:file(filename:join(DataDir,"extensionAdditionGroup"),[{i,PrivDir},{outdir,PrivDir},debug_info]), - ?line ok = extensionAdditionGroup:run(Erule) - end, - ?line [DoIt(Rule)|| Rule <- [per_bin,uper_bin,ber_bin]], - ?line code:set_path(Path). - - - -% parse_modules() -> -% ["ImportsFrom"]. - -per_modules() -> - [X || X <- test_modules()]. -ber_modules() -> - [X || X <- test_modules(), - X =/= "CommonDataTypes", - X =/= "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath", - X =/= "H323-MESSAGES", - X =/= "H235-SECURITY-MESSAGES", - X =/= "MULTIMEDIA-SYSTEM-CONTROL"]. -test_modules() -> - _Modules = [ - "BitStr", - "CommonDataTypes", - "Constraints", - "ContextSwitchingTypes", - "DS-EquipmentUser-CommonFunctionOrig-TransmissionPath", - "Enum", - "From", - "H235-SECURITY-MESSAGES", - "H323-MESSAGES", - %%"MULTIMEDIA-SYSTEM-CONTROL", recursive type , problem for asn1ct:value - "Import", - "Int", - "MAP-commonDataTypes", -% ambigous tags "MAP-insertSubscriberData-def", - "Null", - "Octetstr", - "One", - "P-Record", - "P", -% "PDUs", - "Person", - "PrimStrings", - "Real", - "XSeq", - "XSeqOf", - "XSet", - "XSetOf", - "String", - "SwCDR", -% "Syntax", - "Time" -% ANY "Tst", -% "Two", -% errors that should be detected "UndefType" -] ++ - [ - "SeqSetLib", % must be compiled before Seq and Set - "Seq", - "Set", - "SetOf", - "SeqOf", - "Prim", - "Cho", - "Def", - "Opt", - "ELDAPv3", - "LDAP" - ]. - - -common() -> -[]. - -particular() -> -[smp, ticket7904]. - - -smp(suite) -> []; -smp(Config) -> - case erlang:system_info(smp_support) of - true -> - NumOfProcs = erlang:system_info(schedulers), - io:format("smp starting ~p workers\n",[NumOfProcs]), - - ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()}, - ?line ok = testNBAPsystem:compile(Config,per_bin,[optimize]), - - Parent = self(), - - ?line ok = asn1rt:load_driver(), - - smp2(Parent,NumOfProcs,Msg,2), - - N = 10000, - - ?line {Time1,ok} = timer:tc(?MODULE,smp2,[Parent,NumOfProcs,Msg, N]), - ?line {Time1S,ok} = timer:tc(?MODULE,sequential,[NumOfProcs * N,Msg]), - - ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,driver]), - ?line {Time2,ok} = timer:tc(?MODULE,smp2,[Parent,NumOfProcs,Msg, N]), - - ?line {Time2S,ok} = timer:tc(?MODULE,sequential,[NumOfProcs * N,Msg]), - - {comment,lists:flatten(io_lib:format("Encode/decode time parallell with ~p cores: ~p [microsecs]~nEncode/decode time sequential: ~p [microsecs]",[NumOfProcs,Time1+Time2,Time1S+Time2S]))}; - false -> - {skipped,"No smp support"} - end. - -smp2(Parent,NumOfProcs,Msg, N) -> - Pids = [spawn_link(fun() -> worker(Msg,Parent, N) end) - || _ <- lists:seq(1,NumOfProcs)], - ?line ok = wait_pids(Pids). - -worker(Msg, Parent, N) -> - %% io:format("smp worker ~p with ~p worker loops.~n",[self(), N]), - worker_loop(N, Msg), - Parent ! self(). - -worker_loop(0, _Msg) -> - ok; -worker_loop(N, Msg) -> - ?line {ok,B}=asn1_wrapper:encode('NBAP-PDU-Discriptions', - 'NBAP-PDU', - Msg), - ?line {ok,_Msg}=asn1_wrapper:decode('NBAP-PDU-Discriptions', - 'NBAP-PDU', - B), - worker_loop(N - 1, Msg). - - -wait_pids([]) -> - ok; -wait_pids(Pids) -> - receive - Pid when is_pid(Pid) -> - ?line true = lists:member(Pid,Pids), - Others = lists:delete(Pid,Pids), - io:format("wait_pid got ~p, still waiting for ~p\n",[Pid,Others]), - wait_pids(Others); - Err -> - io:format("Err: ~p~n",[Err]), - ?line exit(Err) - end. - -sequential(N,Msg) -> - %%io:format("sequential encode/decode with N = ~p~n",[N]), - worker_loop(N,Msg). - --record('InitiatingMessage',{procedureCode,criticality,value}). --record('Iu-ReleaseCommand',{first,second}). - -ticket7904(suite) -> []; -ticket7904(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line OutDir = ?config(priv_dir,Config), - - ?line ok = asn1ct:compile(DataDir ++ - "RANAPextract1",[per_bin,optimize,{outdir,OutDir}]), - - Val1 = #'InitiatingMessage'{procedureCode=1, - criticality=ignore, - value=#'Iu-ReleaseCommand'{ - first=13, - second=true}}, - - ?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1), - asn1rt:unload_driver(), - ?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1). diff --git a/lib/asn1/test/asn1_common_SUITE.erl.src b/lib/asn1/test/asn1_common_SUITE.erl.src index 2fa2a09f1f..12512606d8 100644 --- a/lib/asn1/test/asn1_common_SUITE.erl.src +++ b/lib/asn1/test/asn1_common_SUITE.erl.src @@ -18,15 +18,12 @@ %% %% -common() -> [app_test, appup_test,testTimer_ber,testTimer_ber_bin, +common() -> [{group,app_test}, {group,appup_test},testTimer_ber,testTimer_ber_bin, testTimer_ber_bin_opt, testTimer_ber_bin_opt_driver, testTimer_per, testTimer_per_bin, testTimer_per_bin_opt, testTimer_uper_bin, testComment,testName2Number]. -app_test(suite) -> [{asn1_app_test,all}]. -appup_test(suite) -> [{asn1_appup_test,all}]. - testTimer_ber(suite) -> []; testTimer_ber(Config) -> ?line testTimer:compile(Config,ber,[]), diff --git a/lib/asn1/test/testContextSwitchingTypes.erl b/lib/asn1/test/testContextSwitchingTypes.erl index 260a016c6c..7d05e5c352 100644 --- a/lib/asn1/test/testContextSwitchingTypes.erl +++ b/lib/asn1/test/testContextSwitchingTypes.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -77,7 +77,7 @@ check_EXTERNAL_DVD(asn1_NOVALUE) -> ok; check_EXTERNAL_DVD(DVD) -> {error,"failed on data-value-descriptor alternative",DVD}. -check_EXTERNAL_DV(DV) when is_list(DV) -> +check_EXTERNAL_DV(DV) when is_list(DV);is_binary(DV) -> ok; check_EXTERNAL_DV(DV) -> {error,"failed on data-value alternative",DV}. diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl index ba4adb8683..b839521e24 100644 --- a/lib/common_test/src/ct_logs.erl +++ b/lib/common_test/src/ct_logs.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/common_test/src/vts.erl b/lib/common_test/src/vts.erl index 081f98e889..f0bf090804 100644 --- a/lib/common_test/src/vts.erl +++ b/lib/common_test/src/vts.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl index 40b7d2da47..c4e0d72948 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/cfg_error_9_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl index 7fcb631d06..a77d06815e 100644 --- a/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl +++ b/lib/common_test/test/ct_error_SUITE_data/error/test/timetrap_2_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl b/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl index 14eb8769ad..154c676d7e 100644 --- a/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl +++ b/lib/common_test/test/ct_groups_test_2_SUITE_data/groups_2/groups_22_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/common_test/test/ct_test_support.erl b/lib/common_test/test/ct_test_support.erl index 601d5315ce..31381abc40 100644 --- a/lib/common_test/test/ct_test_support.erl +++ b/lib/common_test/test/ct_test_support.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl index 5cc8252b99..415864b8e9 100644 --- a/lib/compiler/src/beam_bsm.erl +++ b/lib/compiler/src/beam_bsm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl index 8e96569414..1365f3d20a 100644 --- a/lib/compiler/src/beam_dead.erl +++ b/lib/compiler/src/beam_dead.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl index 9360556e00..6ea67741fa 100644 --- a/lib/compiler/src/sys_core_fold.erl +++ b/lib/compiler/src/sys_core_fold.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl index e1a593fffa..87bb5bec25 100644 --- a/lib/compiler/src/v3_core.erl +++ b/lib/compiler/src/v3_core.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml index 95941fefdd..2318ccb6d2 100644 --- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ConsumerAdmin.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosEventChannelAdmin_­ConsumerAdmin</title> - <shorttitle>..._ConsumerAdmin</shorttitle> + <title>CosEventChannelAdmin_ConsumerAdmin</title> <prepared></prepared> <responsible></responsible> <docno></docno> diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml index 51f9f11613..4495fd4450 100644 --- a/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_EventChannel.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosEventChannelAdmin_­EventChannel</title> - <shorttitle>..._EventChannel</shorttitle> + <title>CosEventChannelAdmin_EventChannel</title> <prepared></prepared> <responsible></responsible> <docno></docno> diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml index 9690c9406d..4cd20ad185 100644 --- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullConsumer.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosEventChannelAdmin_­ProxyPullConsumer</title> - <shorttitle>..._ProxyPullConsumer</shorttitle> + <title>CosEventChannelAdmin_ProxyPullConsumer</title> <prepared></prepared> <responsible></responsible> <docno></docno> diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml index fb17c450f4..830c06a87c 100644 --- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPullSupplier.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosEventChannelAdmin_­ProxyPullSupplier</title> - <shorttitle>..._ProxyPullSupplier</shorttitle> + <title>CosEventChannelAdmin_ProxyPullSupplier</title> <prepared></prepared> <responsible></responsible> <docno></docno> diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml index 21e6cfce6f..2c451acd9c 100644 --- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushConsumer.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosEventChannelAdmin_­ProxyPushConsumer</title> - <shorttitle>..._ProxyPushConsumer</shorttitle> + <title>CosEventChannelAdmin_ProxyPushConsumer</title> <prepared></prepared> <responsible></responsible> <docno></docno> diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml index be2dfcafbe..9030c0e735 100644 --- a/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_ProxyPushSupplier.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosEventChannelAdmin_­ProxyPushSupplier</title> - <shorttitle>..._ProxyPushSupplier</shorttitle> + <title>CosEventChannelAdmin_ProxyPushSupplier</title> <prepared></prepared> <responsible></responsible> <docno></docno> diff --git a/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml b/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml index ca301bb860..e68b0854d8 100644 --- a/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml +++ b/lib/cosEvent/doc/src/CosEventChannelAdmin_SupplierAdmin.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosEventChannelAdmin_­SupplierAdmin</title> - <shorttitle>..._SupplierAdmin</shorttitle> + <title>CosEventChannelAdmin_SupplierAdmin</title> <prepared></prepared> <responsible></responsible> <docno></docno> diff --git a/lib/cosEvent/doc/src/notes.xml b/lib/cosEvent/doc/src/notes.xml index 1a5c8afa17..1da5399755 100644 --- a/lib/cosEvent/doc/src/notes.xml +++ b/lib/cosEvent/doc/src/notes.xml @@ -22,8 +22,8 @@ </legalnotice> <title>cosEvent Release Notes</title> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <prepared></prepared> + <responsible></responsible> <docno></docno> <approved></approved> <checked></checked> @@ -33,6 +33,23 @@ </header> <section> + <title>cosEvent 2.1.11</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Removed superfluous usage of shy in the documentation since it can cause problem if + a buggy tool is used.</p> + <p> + Own Id: OTP-9319 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>cosEvent 2.1.10</title> <section> diff --git a/lib/cosEvent/vsn.mk b/lib/cosEvent/vsn.mk index 38999db5fa..85d3cf552b 100644 --- a/lib/cosEvent/vsn.mk +++ b/lib/cosEvent/vsn.mk @@ -1,3 +1,3 @@ -COSEVENT_VSN = 2.1.10 +COSEVENT_VSN = 2.1.11 diff --git a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml index cf1cdab966..4941f8652c 100644 --- a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml +++ b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomain.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2001</year><year>2009</year> + <year>2001</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,8 +21,7 @@ </legalnotice> - <title>CosEventDomainAdmin_­EventDomain</title> - <shorttitle>..._EventDomain</shorttitle> + <title>CosEventDomainAdmin_EventDomain</title> <prepared></prepared> <docno></docno> <approved>Niclas Eklund</approved> diff --git a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml index ea605f23a0..5eff7038d9 100644 --- a/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml +++ b/lib/cosEventDomain/doc/src/CosEventDomainAdmin_EventDomainFactory.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosEventDomainAdmin_­EventDomainFactory</title> - <shorttitle>..._EventChannel</shorttitle> + <title>CosEventDomainAdmin_EventDomainFactory</title> <prepared>Niclas Eklund</prepared> <responsible>Niclas Eklund</responsible> <docno></docno> diff --git a/lib/cosEventDomain/doc/src/notes.xml b/lib/cosEventDomain/doc/src/notes.xml index 522dcea829..585761ce65 100644 --- a/lib/cosEventDomain/doc/src/notes.xml +++ b/lib/cosEventDomain/doc/src/notes.xml @@ -32,6 +32,23 @@ </header> <section> + <title>cosEventDomain 1.1.11</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Removed superfluous usage of shy in the documentation since it can cause problem if + a buggy tool is used.</p> + <p> + Own Id: OTP-9319 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>cosEventDomain 1.1.10</title> <section> diff --git a/lib/cosEventDomain/vsn.mk b/lib/cosEventDomain/vsn.mk index f4a77ab7a8..7df47cef2e 100644 --- a/lib/cosEventDomain/vsn.mk +++ b/lib/cosEventDomain/vsn.mk @@ -1,3 +1,3 @@ -COSEVENTDOMAIN_VSN = 1.1.10 +COSEVENTDOMAIN_VSN = 1.1.11 diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml index af9141b205..7c68768aa9 100644 --- a/lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_Directory.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosFileTransfer_­Directory</title> - <shorttitle>..._Directory</shorttitle> + <title>CosFileTransfer_Directory</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml index bef7cb882f..8b317049e2 100644 --- a/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_File.xml @@ -23,11 +23,10 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosFileTransfer_­File</title> - <shorttitle>..._File</shorttitle> + <title>CosFileTransfer_File</title> <prepared></prepared> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-11-09</date> <rev>PA1</rev> diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml index c848a9830d..80cbd1f448 100644 --- a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileIterator.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,8 +21,7 @@ </legalnotice> - <title>CosFileTransfer_­FileIterator</title> - <shorttitle>..._FileIterator</shorttitle> + <title>CosFileTransfer_FileIterator</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml index 5f4542058b..5ac2c61c92 100644 --- a/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_FileTransferSession.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,8 +21,7 @@ </legalnotice> - <title>CosFileTransfer_­FileTransferSession</title> - <shorttitle>..._FileTransferSession</shorttitle> + <title>CosFileTransfer_FileTransferSession</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml b/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml index 8aa02b2153..7bb6e8d356 100644 --- a/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml +++ b/lib/cosFileTransfer/doc/src/CosFileTransfer_VirtualFileSystem.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosFileTransfer_­VirtualFileSystem</title> - <shorttitle>..._VirtualFileSystem</shorttitle> + <title>CosFileTransfer_VirtualFileSystem</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosFileTransfer/doc/src/notes.xml b/lib/cosFileTransfer/doc/src/notes.xml index 48d0c04236..53c207db2f 100644 --- a/lib/cosFileTransfer/doc/src/notes.xml +++ b/lib/cosFileTransfer/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2010</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -31,6 +31,23 @@ </header> <section> + <title>cosFileTransfer 1.1.11</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Removed superfluous usage of shy in the documentation since it can cause problem if + a buggy tool is used.</p> + <p> + Own Id: OTP-9319 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>cosFileTransfer 1.1.10</title> <section> diff --git a/lib/cosFileTransfer/vsn.mk b/lib/cosFileTransfer/vsn.mk index ef8ee53c5e..9d68ab2720 100644 --- a/lib/cosFileTransfer/vsn.mk +++ b/lib/cosFileTransfer/vsn.mk @@ -1 +1 @@ -COSFILETRANSFER_VSN = 1.1.10 +COSFILETRANSFER_VSN = 1.1.11 diff --git a/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml b/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml index 57015b3621..46c3921b66 100644 --- a/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml +++ b/lib/cosNotification/doc/src/CosNotification_AdminPropertiesAdmin.xml @@ -23,10 +23,9 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotification_­AdminPropertiesAdmin</title> - <shorttitle>..._AdminPropertiesAdmin</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotification_AdminPropertiesAdmin</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> <approved>Niclas Eklund</approved> <checked></checked> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml index 671f68d482..96ccdf1d29 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ConsumerAdmin.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­ConsumerAdmin</title> - <shorttitle>..._ConsumerAdmin</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_ConsumerAdmin</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml index b6af2e2ca3..1682cf9968 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannel.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,8 +21,7 @@ </legalnotice> - <title>CosNotifyChannelAdmin_­EventChannel</title> - <shorttitle>..._EventChannel</shorttitle> + <title>CosNotifyChannelAdmin_EventChannel</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml index 01976954e7..64e0e4dad8 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_EventChannelFactory.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,8 +21,7 @@ </legalnotice> - <title>CosNotifyChannelAdmin_­EventChannelFactory</title> - <shorttitle>..._EventChannelFactory</shorttitle> + <title>CosNotifyChannelAdmin_EventChannelFactory</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml index 8bc182a50c..7ba74547bb 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyConsumer.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­ProxyConsumer</title> - <shorttitle>..._ProxyConsumer</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_ProxyConsumer</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml index 43818e5238..d8344e004a 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullConsumer.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­ProxyPullConsumer</title> - <shorttitle>..._ProxyPullConsumer</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_ProxyPullConsumer</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml index 4c0aac7ae6..cc2c17a3ca 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPullSupplier.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­ProxyPullSupplier</title> - <shorttitle>..._ProxyPullSupplier</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_ProxyPullSupplier</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml index 697d00ea51..30ba264f74 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushConsumer.xml @@ -23,10 +23,9 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­ProxyPushConsumer</title> - <shorttitle>..._ProxyPushConsumer</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_ProxyPushConsumer</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> <approved>Niclas Eklund</approved> <checked></checked> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml index f6fc3a0f7b..d5079a5ae7 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxyPushSupplier.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­ProxyPushSupplier</title> - <shorttitle>..._ProxyPushSupplier</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_ProxyPushSupplier</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml index 81d4de929a..bdd9213a8b 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_ProxySupplier.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­ProxySupplier</title> - <shorttitle>..._ProxySupplier</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_ProxySupplier</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml index 4084fd443b..86796a2643 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullConsumer.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­SequenceProxyPullConsumer</title> - <shorttitle>..._SequenceProxyPullConsumer</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_SequenceProxyPullConsumer</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml index 16b093b9aa..c30217362a 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPullSupplier.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­SequenceProxyPullSupplier</title> - <shorttitle>..._SequenceProxyPullSupplier</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_SequenceProxyPullSupplier</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml index 964d212715..3f3e187486 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushConsumer.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,15 +21,14 @@ </legalnotice> - <title>CosNotifyChannelAdmin_­SequenceProxyPushConsumer</title> - <shorttitle>..._SequenceProxyPushConsumer</shorttitle> + <title>CosNotifyChannelAdmin_SequenceProxyPushConsumer</title> <prepared></prepared> <docno></docno> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> </header> - <module>CosNotifyChannelAdmin_­SequenceProxyPushConsumer</module> + <module>CosNotifyChannelAdmin_SequenceProxyPushConsumer</module> <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPushConsumer interface.</modulesummary> <description> <p>To get access to the record definitions for the structures use: <br></br> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml index f8ce2072e1..f85f33de01 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SequenceProxyPushSupplier.xml @@ -23,17 +23,16 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­SequenceProxyPushSupplier</title> - <shorttitle>..._SequenceProxyPushSupplier</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_SequenceProxyPushSupplier</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> </header> - <module>CosNotifyChannelAdmin_­SequenceProxyPushSupplier</module> + <module>CosNotifyChannelAdmin_SequenceProxyPushSupplier</module> <modulesummary>This module implements the OMG CosNotifyChannelAdmin::SequenceProxyPushSupplier interface.</modulesummary> <description> <p>To get access to the record definitions for the structures use: <br></br> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml index 0623d2891b..09546d9584 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullConsumer.xml @@ -23,17 +23,16 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­StructuredProxyPullConsumer</title> - <shorttitle>..._StructuredProxyPullConsumer</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_StructuredProxyPullConsumer</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> </header> - <module>CosNotifyChannelAdmin_­StructuredProxyPullConsumer</module> + <module>CosNotifyChannelAdmin_StructuredProxyPullConsumer</module> <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPullConsumer interface.</modulesummary> <description> <p>To get access to the record definitions for the structures use: <br></br> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml index 0f0bb5d985..d171851014 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPullSupplier.xml @@ -23,17 +23,16 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­StructuredProxyPullSupplier</title> - <shorttitle>..._StructuredProxyPullSupplier</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_StructuredProxyPullSupplier</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> </header> - <module>CosNotifyChannelAdmin_­StructuredProxyPullSupplier</module> + <module>CosNotifyChannelAdmin_StructuredProxyPullSupplier</module> <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPullSupplier interface.</modulesummary> <description> <p>To get access to the record definitions for the structures use: <br></br> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml index 7b7a60723e..a055a0ab36 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushConsumer.xml @@ -23,17 +23,16 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­StructuredProxyPushConsumer</title> - <shorttitle>..._StructuredProxyPushConsumer</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_StructuredProxyPushConsumer</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> </header> - <module>CosNotifyChannelAdmin_­StructuredProxyPushConsumer</module> + <module>CosNotifyChannelAdmin_StructuredProxyPushConsumer</module> <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPushConsumer interface.</modulesummary> <description> <p>To get access to the record definitions for the structures use: <br></br> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml index ab0a260a4b..f03322b819 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_StructuredProxyPushSupplier.xml @@ -23,17 +23,16 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­StructuredProxyPushSupplier</title> - <shorttitle>..._StructuredProxyPushSupplier</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_StructuredProxyPushSupplier</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> </header> - <module>CosNotifyChannelAdmin_­StructuredProxyPushSupplier</module> + <module>CosNotifyChannelAdmin_StructuredProxyPushSupplier</module> <modulesummary>This module implements the OMG CosNotifyChannelAdmin::StructuredProxyPushSupplier interface.</modulesummary> <description> <p>To get access to the record definitions for the structures use: <br></br> diff --git a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml index a567463f7d..5c7408040d 100644 --- a/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml +++ b/lib/cosNotification/doc/src/CosNotifyChannelAdmin_SupplierAdmin.xml @@ -23,10 +23,9 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyChannelAdmin_­SupplierAdmin</title> - <shorttitle>..._SupplierAdmin</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyChannelAdmin_SupplierAdmin</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> <approved>Niclas Eklund</approved> <checked></checked> diff --git a/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml b/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml index dd8ef713e8..97b15d958a 100644 --- a/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml +++ b/lib/cosNotification/doc/src/CosNotifyComm_NotifySubscribe.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosNotifyComm_­NotifySubscribe</title> - <shorttitle>..._NotifySubscribe</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosNotifyComm_NotifySubscribe</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-02-01</date> <rev>1.0</rev> diff --git a/lib/cosNotification/doc/src/ch_BNF.xml b/lib/cosNotification/doc/src/ch_BNF.xml index 73e91e3cac..f658f606d3 100644 --- a/lib/cosNotification/doc/src/ch_BNF.xml +++ b/lib/cosNotification/doc/src/ch_BNF.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -294,7 +294,7 @@ FilterID = 'CosNotifyChannelAdmin_ConsumerAdmin': </row> <row> <cell align="left" valign="middle"><c>in</c></cell> - <cell align="left" valign="middle"><c>"'Erlang' in $.FunctionalLanguages­StringSeq"</c></cell> + <cell align="left" valign="middle"><c>"'Erlang' in $.FunctionalLanguagesStringSeq"</c></cell> <cell align="left" valign="middle">Returns <c>TRUE</c>if a given element is found in the given sequence. The element must be of a simple type and the same as the sequence is defined to contain.</cell> </row> <row> @@ -394,17 +394,17 @@ Figure 1: The structure of a structured event.</icaption> </row> <row> <cell align="left" valign="middle">type_name</cell> - <cell align="left" valign="middle">"$.header.fixed_header.event_­type.type_name == 'Type'"</cell> + <cell align="left" valign="middle">"$.header.fixed_header.event_type.type_name == 'Type'"</cell> <cell align="left" valign="middle">"$type_name == 'Type'"</cell> </row> <row> <cell align="left" valign="middle">domain_name</cell> - <cell align="left" valign="middle">"$.header.fixed_header.event_­type.domain_name == 'Domain'"</cell> + <cell align="left" valign="middle">"$.header.fixed_header.event_type.domain_name == 'Domain'"</cell> <cell align="left" valign="middle">"$domain_name == 'Domain'"</cell> </row> <row> <cell align="left" valign="middle">event_name</cell> - <cell align="left" valign="middle">"$.header.fixed_header.event_­name == 'Event'"</cell> + <cell align="left" valign="middle">"$.header.fixed_header.event_name == 'Event'"</cell> <cell align="left" valign="middle">"$event_name == 'Event'"</cell> </row> <tcaption>Table 2: Fixed Header Constraint Examples</tcaption> diff --git a/lib/cosNotification/doc/src/notes.xml b/lib/cosNotification/doc/src/notes.xml index 125e25e67e..a54230c9f7 100644 --- a/lib/cosNotification/doc/src/notes.xml +++ b/lib/cosNotification/doc/src/notes.xml @@ -31,6 +31,21 @@ <file>notes.xml</file> </header> + <section><title>cosNotification 1.1.17</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p> + Removed superfluous usage of shy in the documentation since it can cause problem if + a buggy tool is used.</p> + <p> + Own Id: OTP-9319 Aux Id:</p> + </item> + </list> + </section> + </section> + <section><title>cosNotification 1.1.16</title> <section><title>Improvements and New Features</title> diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk index 6613385579..b32919a2ef 100644 --- a/lib/cosNotification/vsn.mk +++ b/lib/cosNotification/vsn.mk @@ -1,2 +1,2 @@ -COSNOTIFICATION_VSN = 1.1.16 +COSNOTIFICATION_VSN = 1.1.17 diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml index 75c7cb38cb..623e121715 100644 --- a/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertiesIterator.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,8 +21,7 @@ </legalnotice> - <title>CosPropertyService_­PropertiesIterator</title> - <shorttitle>..._PropertiesIterator</shorttitle> + <title>CosPropertyService_PropertiesIterator</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml index 1710769661..9cb5e8f489 100644 --- a/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertyNamesIterator.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosPropertyService_­PropertyNamesIterator</title> - <shorttitle>..._PropertyNamesIterator</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosPropertyService_PropertyNamesIterator</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-07-25</date> <rev>1.0</rev> diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml index 2c1671bf77..f9a7c9ca97 100644 --- a/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertySet.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosPropertyService_­PropertySet</title> - <shorttitle>..._PropertySet</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosPropertyService_PropertySet</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-07-25</date> <rev>1.0</rev> diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml index 7684998428..2dbfd05ba8 100644 --- a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDef.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2000</year><year>2009</year> + <year>2000</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,8 +21,7 @@ </legalnotice> - <title>CosPropertyService_­PropertySetDef</title> - <shorttitle>..._PropertySetDef</shorttitle> + <title>CosPropertyService_PropertySetDef</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml index 67aa579e6a..a009e70f68 100644 --- a/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertySetDefFactory.xml @@ -23,10 +23,9 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosPropertyService_­PropertySetDefFactory</title> - <shorttitle>..._PropertySetDefFactory</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosPropertyService_PropertySetDefFactory</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> <approved>Niclas Eklund</approved> <checked></checked> diff --git a/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml b/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml index 3fb4822948..62ee2bda4f 100644 --- a/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml +++ b/lib/cosProperty/doc/src/CosPropertyService_PropertySetFactory.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosPropertyService_­PropertySetFactory</title> - <shorttitle>..._PropertySetFactory</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosPropertyService_PropertySetFactory</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>2000-07-25</date> <rev>1.0</rev> diff --git a/lib/cosProperty/doc/src/notes.xml b/lib/cosProperty/doc/src/notes.xml index 540fdce762..85b2119e9d 100644 --- a/lib/cosProperty/doc/src/notes.xml +++ b/lib/cosProperty/doc/src/notes.xml @@ -22,7 +22,7 @@ </legalnotice> <title>cosProperty Release Notes</title> - <prepared>Niclas Eklund</prepared> + <prepared></prepared> <docno></docno> <approved></approved> <checked></checked> @@ -32,6 +32,23 @@ </header> <section> + <title>cosProperty 1.1.14</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Removed superfluous usage of shy in the documentation since it can cause problem if + a buggy tool is used.</p> + <p> + Own Id: OTP-9319 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>cosProperty 1.1.13</title> <section> diff --git a/lib/cosProperty/vsn.mk b/lib/cosProperty/vsn.mk index deb1eb0450..ecc4a2746c 100644 --- a/lib/cosProperty/vsn.mk +++ b/lib/cosProperty/vsn.mk @@ -1,2 +1,2 @@ -COSPROPERTY_VSN = 1.1.13 +COSPROPERTY_VSN = 1.1.14 diff --git a/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml b/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml index 4b2e57642a..2adf318674 100644 --- a/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml +++ b/lib/cosTime/doc/src/CosTimerEvent_TimerEventHandler.xml @@ -23,10 +23,9 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosTimerEvent_­TimerEventHandler</title> - <shorttitle>..._TimerEventHandler</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosTimerEvent_TimerEventHandler</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> <approved>Niclas Eklund</approved> <checked></checked> diff --git a/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml b/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml index fb3fe747e5..80f5fd1466 100644 --- a/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml +++ b/lib/cosTime/doc/src/CosTimerEvent_TimerEventService.xml @@ -23,8 +23,7 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosTimerEvent_­TimerEventService</title> - <shorttitle>..._TimerEventService</shorttitle> + <title>CosTimerEvent_TimerEventService</title> <prepared>Niclas Eklund</prepared> <responsible>Niclas Eklund</responsible> <docno></docno> diff --git a/lib/cosTime/doc/src/notes.xml b/lib/cosTime/doc/src/notes.xml index 718ca23bc5..3698e4813e 100644 --- a/lib/cosTime/doc/src/notes.xml +++ b/lib/cosTime/doc/src/notes.xml @@ -33,6 +33,23 @@ </header> <section> + <title>cosTime 1.1.11</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Removed superfluous usage of shy in the documentation since it can cause problem if + a buggy tool is used.</p> + <p> + Own Id: OTP-9319 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>cosTime 1.1.10</title> <section> diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk index ebc5aff1cc..4d982f3013 100644 --- a/lib/cosTime/vsn.mk +++ b/lib/cosTime/vsn.mk @@ -1,2 +1,2 @@ -COSTIME_VSN = 1.1.10 +COSTIME_VSN = 1.1.11 diff --git a/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml b/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml index 4b870f4b90..0222f3be86 100644 --- a/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml +++ b/lib/cosTransactions/doc/src/CosTransactions_RecoveryCoordinator.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1999</year><year>2009</year> + <year>1999</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,12 +21,11 @@ </legalnotice> - <title>CosTransactions_­RecoveryCoordinator</title> - <shorttitle>..._RecoveryCoordinator</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosTransactions_RecoveryCoordinator</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>1999-04-12</date> <rev>PA1</rev> diff --git a/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml b/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml index 2c7b6b5215..5878b41360 100644 --- a/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml +++ b/lib/cosTransactions/doc/src/CosTransactions_SubtransactionAwareResource.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1999</year><year>2009</year> + <year>1999</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -21,8 +21,7 @@ </legalnotice> - <title>CosTransactions_­SubtransactionAwareResource</title> - <shorttitle>..._SubtransactionAwareResource</shorttitle> + <title>CosTransactions_SubtransactionAwareResource</title> <prepared></prepared> <docno></docno> <checked></checked> diff --git a/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml b/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml index 162e6e8cd1..7e93aa2964 100644 --- a/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml +++ b/lib/cosTransactions/doc/src/CosTransactions_TransactionFactory.xml @@ -23,12 +23,11 @@ The Initial Developer of the Original Code is Ericsson AB. </legalnotice> - <title>CosTransactions_­TransactionFactory</title> - <shorttitle>..._TransactionFactory</shorttitle> - <prepared>Niclas Eklund</prepared> - <responsible>Niclas Eklund</responsible> + <title>CosTransactions_TransactionFactory</title> + <prepared></prepared> + <responsible></responsible> <docno></docno> - <approved>Niclas Eklund</approved> + <approved></approved> <checked></checked> <date>1999-04-12</date> <rev>PA1</rev> diff --git a/lib/cosTransactions/doc/src/notes.xml b/lib/cosTransactions/doc/src/notes.xml index 7586e3c13f..29addf424d 100644 --- a/lib/cosTransactions/doc/src/notes.xml +++ b/lib/cosTransactions/doc/src/notes.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1999</year><year>2010</year> + <year>1999</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -33,6 +33,22 @@ </header> <section> + <title>cosTransactions 1.2.11</title> + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Removed superfluous usage of shy in the documentation since it can cause problem if + a buggy tool is used.</p> + <p> + Own Id: OTP-9319 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>cosTransactions 1.2.10</title> <section> <title>Improvements and New Features</title> diff --git a/lib/cosTransactions/vsn.mk b/lib/cosTransactions/vsn.mk index 82e46f51dd..3960c58c5b 100644 --- a/lib/cosTransactions/vsn.mk +++ b/lib/cosTransactions/vsn.mk @@ -1 +1 @@ -COSTRANSACTIONS_VSN = 1.2.10 +COSTRANSACTIONS_VSN = 1.2.11 diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index 040adcfd09..276c84d601 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2010. All Rights Reserved. +# Copyright Ericsson AB 1999-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -40,7 +40,7 @@ CFLAGS = $(DED_CFLAGS) # From erts/configure SSL_LIBDIR = @SSL_LIBDIR@ SSL_INCLUDE = @SSL_INCLUDE@ - +SSL_CRYPTO_LIBNAME = @SSL_CRYPTO_LIBNAME@ INCLUDES = $(SSL_INCLUDE) $(DED_INCLUDES) @@ -84,10 +84,10 @@ DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@ ifeq ($(DYNAMIC_CRYPTO_LIB),yes) SSL_DED_LD_RUNTIME_LIBRARY_PATH = @SSL_DED_LD_RUNTIME_LIBRARY_PATH@ -CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -lcrypto +CRYPTO_LINK_LIB=$(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -l$(SSL_CRYPTO_LIBNAME) else SSL_DED_LD_RUNTIME_LIBRARY_PATH= -CRYPTO_LINK_LIB=$(SSL_LIBDIR)/libcrypto.a +CRYPTO_LINK_LIB=$(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a endif # ---------------------------------------------------- @@ -112,7 +112,7 @@ $(LIBDIR)/crypto$(TYPEMARKER).so: $(OBJS) $(LIBDIR)/crypto$(TYPEMARKER).dll: $(OBJS) $(INSTALL_DIR) $(LIBDIR) - $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -llibeay32 + $(LD) $(LDFLAGS) -o $@ $(SSL_DED_LD_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) $(OBJS) -l$(SSL_CRYPTO_LIBNAME) clean: ifeq ($(findstring win32,$(TARGET)), win32) diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c index 3ebf62d87c..c781ccb302 100644 --- a/lib/crypto/c_src/crypto.c +++ b/lib/crypto/c_src/crypto.c @@ -50,6 +50,8 @@ #include <openssl/rc2.h> #include <openssl/blowfish.h> #include <openssl/rand.h> +#include <openssl/evp.h> +#include <openssl/hmac.h> #ifdef VALGRIND # include <valgrind/memcheck.h> @@ -128,11 +130,15 @@ static ERL_NIF_TERM md4_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv static ERL_NIF_TERM md4_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM md5_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM strong_rand_bytes_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); static ERL_NIF_TERM rand_bytes_3(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); @@ -199,12 +205,18 @@ static ErlNifFunc nif_funcs[] = { {"md4_final", 1, md4_final}, {"md5_mac_n", 3, md5_mac_n}, {"sha_mac_n", 3, sha_mac_n}, + {"hmac_init", 2, hmac_init}, + {"hmac_update", 2, hmac_update}, + {"hmac_final", 1, hmac_final}, + {"hmac_final_n", 2, hmac_final}, {"des_cbc_crypt", 4, des_cbc_crypt}, {"des_ecb_crypt", 3, des_ecb_crypt}, {"des_ede3_cbc_crypt", 6, des_ede3_cbc_crypt}, {"aes_cfb_128_crypt", 4, aes_cfb_128_crypt}, {"aes_ctr_encrypt", 3, aes_ctr_encrypt}, {"aes_ctr_decrypt", 3, aes_ctr_encrypt}, + {"aes_ctr_stream_encrypt", 2, aes_ctr_stream_encrypt}, + {"aes_ctr_stream_decrypt", 2, aes_ctr_stream_encrypt}, {"rand_bytes", 1, rand_bytes_1}, {"strong_rand_bytes_nif", 1, strong_rand_bytes_nif}, {"rand_bytes", 3, rand_bytes_3}, @@ -255,6 +267,7 @@ static ERL_NIF_TERM atom_true; static ERL_NIF_TERM atom_false; static ERL_NIF_TERM atom_sha; static ERL_NIF_TERM atom_md5; +static ERL_NIF_TERM atom_ripemd160; static ERL_NIF_TERM atom_error; static ERL_NIF_TERM atom_rsa_pkcs1_padding; static ERL_NIF_TERM atom_rsa_pkcs1_oaep_padding; @@ -324,6 +337,7 @@ static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_false = enif_make_atom(env,"false"); atom_sha = enif_make_atom(env,"sha"); atom_md5 = enif_make_atom(env,"md5"); + atom_ripemd160 = enif_make_atom(env,"ripemd160"); atom_error = enif_make_atom(env,"error"); atom_rsa_pkcs1_padding = enif_make_atom(env,"rsa_pkcs1_padding"); atom_rsa_pkcs1_oaep_padding = enif_make_atom(env,"rsa_pkcs1_oaep_padding"); @@ -581,6 +595,84 @@ static ERL_NIF_TERM sha_mac_n(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[ return ret; } +static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Type, Key) */ + ErlNifBinary key; + ERL_NIF_TERM ret; + unsigned char * ctx_buf; + const EVP_MD *md; + + if (argv[0] == atom_sha) md = EVP_sha1(); + else if (argv[0] == atom_md5) md = EVP_md5(); + else if (argv[0] == atom_ripemd160) md = EVP_ripemd160(); + else goto badarg; + + if (!enif_inspect_iolist_as_binary(env, argv[1], &key)) { + badarg: + return enif_make_badarg(env); + } + + ctx_buf = enif_make_new_binary(env, sizeof(HMAC_CTX), &ret); + HMAC_CTX_init((HMAC_CTX *) ctx_buf); + HMAC_Init((HMAC_CTX *) ctx_buf, key.data, key.size, md); + + return ret; +} + +static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context, Data) */ + ErlNifBinary context, data; + ERL_NIF_TERM ret; + unsigned char * ctx_buf; + + if (!enif_inspect_binary(env, argv[0], &context) + || !enif_inspect_iolist_as_binary(env, argv[1], &data) + || context.size != sizeof(HMAC_CTX)) { + return enif_make_badarg(env); + } + + ctx_buf = enif_make_new_binary(env, sizeof(HMAC_CTX), &ret); + memcpy(ctx_buf, context.data, context.size); + HMAC_Update((HMAC_CTX *)ctx_buf, data.data, data.size); + + return ret; +} + +static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* (Context) or (Context, HashLen) */ + ErlNifBinary context; + ERL_NIF_TERM ret; + HMAC_CTX ctx; + unsigned char mac_buf[EVP_MAX_MD_SIZE]; + unsigned char * mac_bin; + unsigned int req_len = 0; + unsigned int mac_len; + + if (!enif_inspect_binary(env, argv[0], &context)) { + return enif_make_badarg(env); + } + if (argc == 2 && !enif_get_uint(env, argv[1], &req_len)) { + return enif_make_badarg(env); + } + + if (context.size != sizeof(ctx)) { + return enif_make_badarg(env); + } + memcpy(&ctx, context.data, context.size); + + HMAC_Final(&ctx, mac_buf, &mac_len); + HMAC_CTX_cleanup(&ctx); + + if (argc == 2 && req_len < mac_len) { + // Only truncate to req_len bytes if asked. + mac_len = req_len; + } + mac_bin = enif_make_new_binary(env, mac_len, &ret); + memcpy(mac_bin, mac_buf, mac_len); + + return ret; +} + static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Key, Ivec, Text, IsEncrypt) */ ErlNifBinary key, ivec, text; @@ -695,6 +787,46 @@ static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM return ret; } +/* Initializes state for ctr streaming (de)encryption +*/ +static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{/* ({Key, IVec, ECount, Num}, Data) */ + ErlNifBinary key_bin, ivec_bin, text_bin, ecount_bin; + AES_KEY aes_key; + unsigned int num; + ERL_NIF_TERM ret, num2_term, cipher_term, ivec2_term, ecount2_term, new_state_term; + int state_arity; + const ERL_NIF_TERM *state_term; + unsigned char * ivec2_buf; + unsigned char * ecount2_buf; + + if (!enif_get_tuple(env, argv[0], &state_arity, &state_term) + || state_arity != 4 + || !enif_inspect_iolist_as_binary(env, state_term[0], &key_bin) + || AES_set_encrypt_key(key_bin.data, key_bin.size*8, &aes_key) != 0 + || !enif_inspect_binary(env, state_term[1], &ivec_bin) || ivec_bin.size != 16 + || !enif_inspect_binary(env, state_term[2], &ecount_bin) || ecount_bin.size != AES_BLOCK_SIZE + || !enif_get_uint(env, state_term[3], &num) + || !enif_inspect_iolist_as_binary(env, argv[1], &text_bin)) { + return enif_make_badarg(env); + } + + ivec2_buf = enif_make_new_binary(env, ivec_bin.size, &ivec2_term); + ecount2_buf = enif_make_new_binary(env, ecount_bin.size, &ecount2_term); + + memcpy(ivec2_buf, ivec_bin.data, 16); + memcpy(ecount2_buf, ecount_bin.data, ecount_bin.size); + + AES_ctr128_encrypt((unsigned char *) text_bin.data, + enif_make_new_binary(env, text_bin.size, &cipher_term), + text_bin.size, &aes_key, ivec2_buf, ecount2_buf, &num); + + num2_term = enif_make_uint(env, num); + new_state_term = enif_make_tuple4(env, state_term[0], ivec2_term, ecount2_term, num2_term); + ret = enif_make_tuple2(env, new_state_term, cipher_term); + return ret; +} + static ERL_NIF_TERM rand_bytes_1(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Bytes) */ unsigned bytes; diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml index 1ccea6df79..179ba4498c 100644 --- a/lib/crypto/doc/src/crypto.xml +++ b/lib/crypto/doc/src/crypto.xml @@ -282,6 +282,57 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </desc> </func> <func> + <name>hmac_init(Type, Key) -> Context</name> + <fsummary></fsummary> + <type> + <v>Type = sha | md5 | ripemd160</v> + <v>Key = iolist() | binary()</v> + <v>Context = binary()</v> + </type> + <desc> + <p>Initializes the context for streaming HMAC operations. <c>Type</c> determines + which hash function to use in the HMAC operation. <c>Key</c> is the authentication + key. The key can be any length.</p> + </desc> + </func> + <func> + <name>hmac_update(Context, Data) -> NewContext</name> + <fsummary></fsummary> + <type> + <v>Context = NewContext = binary()</v> + <v>Data = iolist() | binary()</v> + </type> + <desc> + <p>Updates the HMAC represented by <c>Context</c> using the given <c>Data</c>. <c>Context</c> + must have been generated using an HMAC init function (such as + <seealso marker="#hmac_init/2">hmac_init</seealso>). <c>Data</c> can be any length. <c>NewContext</c> + must be passed into the next call to <c>hmac_update</c>.</p> + </desc> + </func> + <func> + <name>hmac_final(Context) -> Mac</name> + <fsummary></fsummary> + <type> + <v>Context = Mac = binary()</v> + </type> + <desc> + <p>Finalizes the HMAC operation referenced by <c>Context</c>. The size of the resultant MAC is + determined by the type of hash function used to generate it.</p> + </desc> + </func> + <func> + <name>hmac_final_n(Context, HashLen) -> Mac</name> + <fsummary></fsummary> + <type> + <v>Context = Mac = binary()</v> + <v>HashLen = non_neg_integer()</v> + </type> + <desc> + <p>Finalizes the HMAC operation referenced by <c>Context</c>. <c>HashLen</c> must be greater than + zero. <c>Mac</c> will be a binary with at most <c>HashLen</c> bytes. Note that if HashLen is greater than the actual number of bytes returned from the underlying hash, the returned hash will have fewer than <c>HashLen</c> bytes.</p> + </desc> + </func> + <func> <name>sha_mac(Key, Data) -> Mac</name> <fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary> <type> @@ -589,6 +640,55 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]> </desc> </func> <func> + <name>aes_ctr_stream_init(Key, IVec) -> State</name> + <fsummary></fsummary> + <type> + <v>State = { K, I, E, C }</v> + <v>Key = K = iolist()</v> + <v>IVec = I = E = binary()</v> + <v>C = integer()</v> + </type> + <desc> + <p>Initializes the state for use in streaming AES encryption using Counter mode (CTR). + <c>Key</c> is the AES key and must be either 128, 192, or 256 bts long. <c>IVec</c> is + an arbitrary initializing vector of 128 bits (16 bytes). This state is for use with + <seealso marker="#aes_ctr_stream_encrypt/2">aes_ctr_stream_encrypt</seealso> and + <seealso marker="#aes_ctr_stream_decrypt/2">aes_ctr_stream_decrypt</seealso>.</p> + </desc> + </func> + <func> + <name>aes_ctr_stream_encrypt(State, Text) -> { NewState, Cipher}</name> + <fsummary></fsummary> + <type> + <v>Text = iolist() | binary()</v> + <v>Cipher = binary()</v> + </type> + <desc> + <p>Encrypts <c>Text</c> according to AES in Counter mode (CTR). This function can be + used to encrypt a stream of text using a series of calls instead of requiring all + text to be in memory. <c>Text</c> can be any number of bytes. State is initialized using + <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming + encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>. + <c>Cipher</c> is the encrypted cipher text.</p> + </desc> + </func> + <func> + <name>aes_ctr_stream_decrypt(State, Cipher) -> { NewState, Text }</name> + <fsummary></fsummary> + <type> + <v>Cipher = iolist() | binary()</v> + <v>Text = binary()</v> + </type> + <desc> + <p>Decrypts <c>Cipher</c> according to AES in Counter mode (CTR). This function can be + used to decrypt a stream of ciphertext using a series of calls instead of requiring all + ciphertext to be in memory. <c>Cipher</c> can be any number of bytes. State is initialized using + <seealso marker="#aes_ctr_stream_init/2">aes_ctr_stream_init</seealso>. <c>NewState</c> is the new streaming + encryption state that must be passed to the next call to <c>aes_ctr_stream_encrypt</c>. + <c>Text</c> is the decrypted data.</p> + </desc> + </func> + <func> <name>erlint(Mpint) -> N</name> <name>mpint(N) -> Mpint</name> <fsummary>Convert between binary multi-precision integer and erlang big integer</fsummary> diff --git a/lib/crypto/doc/src/licenses.xml b/lib/crypto/doc/src/licenses.xml index bae87a373e..0b791acfa2 100644 --- a/lib/crypto/doc/src/licenses.xml +++ b/lib/crypto/doc/src/licenses.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2003</year><year>2009</year> + <year>2003</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -37,7 +37,7 @@ This chapter contains in extenso versions <title>OpenSSL License</title> <code type="none"> /* ==================================================================== - * Copyright (c) 1998-2002 The OpenSSL Project. All rights reserved. + * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl index cc7b3acc9c..c35dfcebab 100644 --- a/lib/crypto/src/crypto.erl +++ b/lib/crypto/src/crypto.erl @@ -28,6 +28,7 @@ %-export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]). %-export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]). -export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac_96/2]). +-export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]). -export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]). -export([des_ecb_encrypt/2, des_ecb_decrypt/2]). -export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]). @@ -53,6 +54,7 @@ -export([aes_cbc_256_encrypt/3, aes_cbc_256_decrypt/3]). -export([aes_cbc_ivec/1]). -export([aes_ctr_encrypt/3, aes_ctr_decrypt/3]). +-export([aes_ctr_stream_init/2, aes_ctr_stream_encrypt/2, aes_ctr_stream_decrypt/2]). -export([dh_generate_parameters/2, dh_check/1]). %% Testing see below @@ -64,6 +66,7 @@ %% sha512, sha512_init, sha512_update, sha512_final, md5_mac, md5_mac_96, sha_mac, sha_mac_96, + sha_mac_init, sha_mac_update, sha_mac_final, des_cbc_encrypt, des_cbc_decrypt, des_ecb_encrypt, des_ecb_decrypt, des_ede3_cbc_encrypt, des_ede3_cbc_decrypt, @@ -85,6 +88,7 @@ %% idea_cbc_encrypt, idea_cbc_decrypt, aes_cbc_256_encrypt, aes_cbc_256_decrypt, aes_ctr_encrypt, aes_ctr_decrypt, + aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt, info_lib]). -type rsa_digest_type() :: 'md5' | 'sha'. @@ -217,6 +221,19 @@ sha_final(_Context) -> ?nif_stub. %% %% +%% HMAC (multiple hash options) +%% +-spec hmac_init(atom(), iodata()) -> binary(). +-spec hmac_update(binary(), iodata()) -> binary(). +-spec hmac_final(binary()) -> binary(). +-spec hmac_final_n(binary(), integer()) -> binary(). + +hmac_init(_Type, _Key) -> ?nif_stub. +hmac_update(_Context, _Data) -> ? nif_stub. +hmac_final(_Context) -> ? nif_stub. +hmac_final_n(_Context, _HashLen) -> ? nif_stub. + +%% %% MD5_MAC %% -spec md5_mac(iodata(), iodata()) -> binary(). @@ -243,7 +260,7 @@ sha_mac_96(Key, Data) -> sha_mac_n(Key,Data,12). sha_mac_n(_Key,_Data,_MacSz) -> ?nif_stub. - + %% %% CRYPTO FUNCTIONS %% @@ -579,6 +596,22 @@ aes_ctr_encrypt(_Key, _IVec, _Data) -> ?nif_stub. aes_ctr_decrypt(_Key, _IVec, _Cipher) -> ?nif_stub. %% +%% AES - in counter mode (CTR) with state maintained for multi-call streaming +%% +-type ctr_state() :: { iodata(), binary(), binary(), integer() }. + +-spec aes_ctr_stream_init(iodata(), binary()) -> ctr_state(). +-spec aes_ctr_stream_encrypt(ctr_state(), binary()) -> + { ctr_state(), binary() }. +-spec aes_ctr_stream_decrypt(ctr_state(), binary()) -> + { ctr_state(), binary() }. + +aes_ctr_stream_init(Key, IVec) -> + {Key, IVec, << 0:128 >>, 0}. +aes_ctr_stream_encrypt({_Key, _IVec, _ECount, _Num}=_State, _Data) -> ?nif_stub. +aes_ctr_stream_decrypt({_Key, _IVec, _ECount, _Num}=_State, _Cipher) -> ?nif_stub. + +%% %% XOR - xor to iolists and return a binary %% NB doesn't check that they are the same size, just concatenates %% them and sends them to the driver diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl index 854a8b4485..283aadb6ea 100644 --- a/lib/crypto/test/crypto_SUITE.erl +++ b/lib/crypto/test/crypto_SUITE.erl @@ -31,6 +31,11 @@ md4_update/1, sha/1, sha_update/1, + hmac_update_sha/1, + hmac_update_sha_n/1, + hmac_update_md5/1, + hmac_update_md5_io/1, + hmac_update_md5_n/1, sha256/1, sha256_update/1, sha512/1, @@ -44,6 +49,7 @@ aes_cbc/1, aes_cbc_iter/1, aes_ctr/1, + aes_ctr_stream/1, mod_exp_test/1, rand_uniform_test/1, strong_rand_test/1, @@ -67,9 +73,10 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [link_test, md5, md5_update, md4, md4_update, md5_mac, md5_mac_io, sha, sha_update, + hmac_update_sha, hmac_update_sha_n, hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5, %% sha256, sha256_update, sha512,sha512_update, des_cbc, aes_cfb, aes_cbc, - aes_cbc_iter, aes_ctr, des_cbc_iter, des_ecb, + aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb, rand_uniform_test, strong_rand_test, rsa_verify_test, dsa_verify_test, rsa_sign_test, dsa_sign_test, rsa_encrypt_decrypt, dh, exor_test, @@ -284,6 +291,101 @@ sha(Config) when is_list(Config) -> hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")). +%% +hmac_update_sha_n(doc) -> + ["Request a larger-than-allowed SHA1 HMAC using hmac_init, hmac_update, and hmac_final_n. " + "Expected values for examples are generated using crypto:sha_mac." ]; +hmac_update_sha_n(suite) -> + []; +hmac_update_sha_n(Config) when is_list(Config) -> + ?line Key = hexstr2bin("00010203101112132021222330313233" + "04050607141516172425262734353637" + "08090a0b18191a1b28292a2b38393a3b" + "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"), + ?line Data = "Sampl", + ?line Data2 = "e #1", + ?line Ctx = crypto:hmac_init(sha, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), + ?line Mac = crypto:hmac_final_n(Ctx3, 1024), + ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])), + ?line m(Exp, Mac), + ?line m(size(Exp), size(Mac)). + + +hmac_update_sha(doc) -> + ["Generate an SHA1 HMAC using hmac_init, hmac_update, and hmac_final. " + "Expected values for examples are generated using crypto:sha_mac." ]; +hmac_update_sha(suite) -> + []; +hmac_update_sha(Config) when is_list(Config) -> + ?line Key = hexstr2bin("00010203101112132021222330313233" + "04050607141516172425262734353637" + "08090a0b18191a1b28292a2b38393a3b" + "0c0d0e0f1c1d1e1f2c2d2e2f3c3d3e3f"), + ?line Data = "Sampl", + ?line Data2 = "e #1", + ?line Ctx = crypto:hmac_init(sha, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), + ?line Mac = crypto:hmac_final(Ctx3), + ?line Exp = crypto:sha_mac(Key, lists:flatten([Data, Data2])), + ?line m(Exp, Mac). + +hmac_update_md5(doc) -> + ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " + "Expected values for examples are generated using crypto:md5_mac." ]; +hmac_update_md5(suite) -> + []; +hmac_update_md5(Config) when is_list(Config) -> + % ?line Key2 = ["A fine speach", "by a fine man!"], + Key2 = "A fine speach by a fine man!", + ?line Long1 = "Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.", + ?line Long2 = "Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.", + ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.", + ?line CtxA = crypto:hmac_init(md5, Key2), + ?line CtxB = crypto:hmac_update(CtxA, Long1), + ?line CtxC = crypto:hmac_update(CtxB, Long2), + ?line CtxD = crypto:hmac_update(CtxC, Long3), + ?line Mac2 = crypto:hmac_final(CtxD), + ?line Exp2 = crypto:md5_mac(Key2, lists:flatten([Long1, Long2, Long3])), + ?line m(Exp2, Mac2). + + +hmac_update_md5_io(doc) -> + ["Generate an MD5 HMAC using hmac_init, hmac_update, and hmac_final. " + "Expected values for examples are generated using crypto:md5_mac." ]; +hmac_update_md5_io(suite) -> + []; +hmac_update_md5_io(Config) when is_list(Config) -> + ?line Key = ["A fine speach", "by a fine man!"], + ?line Data = "Sampl", + ?line Data2 = "e #1", + ?line Ctx = crypto:hmac_init(md5, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), + ?line Mac = crypto:hmac_final(Ctx3), + ?line Exp = crypto:md5_mac(Key, lists:flatten([Data, Data2])), + ?line m(Exp, Mac). + + +hmac_update_md5_n(doc) -> + ["Generate a shortened MD5 HMAC using hmac_init, hmac_update, and hmac_final. " + "Expected values for examples are generated using crypto:md5_mac." ]; +hmac_update_md5_n(suite) -> + []; +hmac_update_md5_n(Config) when is_list(Config) -> + ?line Key = ["A fine speach", "by a fine man!"], + ?line Data = "Sampl", + ?line Data2 = "e #1", + ?line Ctx = crypto:hmac_init(md5, Key), + ?line Ctx2 = crypto:hmac_update(Ctx, Data), + ?line Ctx3 = crypto:hmac_update(Ctx2, Data2), + ?line Mac = crypto:hmac_final_n(Ctx3, 12), + ?line Exp = crypto:md5_mac_96(Key, lists:flatten([Data, Data2])), + ?line m(Exp, Mac). + + %% %% sha_update(doc) -> @@ -673,6 +775,77 @@ aes_ctr_do(Key,{IVec, Plain, Cipher}) -> ?line m(C, hexstr2bin(Cipher)), ?line m(P, crypto:aes_ctr_decrypt(Key, I, C)). +aes_ctr_stream(doc) -> "CTR Streaming"; +aes_ctr_stream(Config) when is_list(Config) -> + %% Sample data from NIST Spec.Publ. 800-38A + %% F.5.1 CTR-AES128.Encrypt + Key128 = hexstr2bin("2b7e151628aed2a6abf7158809cf4f3c"), + Samples128 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block + ["6bc1bee22e409f", "96e93d7e117393172a"], % Plaintext + ["874d6191b620e3261bef6864990db6ce"]}, % Ciphertext + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00", + ["ae2d8a57", "1e03ac9c", "9eb76fac", "45af8e51"], + ["9806f66b7970fdff","8617187bb9fffdff"]}, + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01", + ["30c81c46a35c", "e411e5fbc119", "1a0a52ef"], + ["5ae4df3e","dbd5d3","5e5b4f0902","0db03eab"]}, + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02", + ["f69f2445df4f9b17ad2b417be66c3710"], + ["1e031dda2fbe","03d1792170a0","f3009cee"]}], + lists:foreach(fun(S) -> aes_ctr_stream_do(Key128,S) end, Samples128), + + %% F.5.3 CTR-AES192.Encrypt + Key192 = hexstr2bin("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), + Samples192 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block + ["6bc1bee22e409f96e93d7e117393172a"], % Plaintext + ["1abc9324","17521c","a24f2b04","59fe7e6e0b"]}, % Ciphertext + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00", + ["ae2d8a57", "1e03ac9c9eb76fac", "45af8e51"], + ["090339ec0aa6faefd5ccc2c6f4ce8e94"]}, + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01", + ["30c81c46a35ce411", "e5fbc1191a0a52ef"], + ["1e36b26bd1","ebc670d1bd1d","665620abf7"]}, + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02", + ["f69f2445", "df4f9b17ad", "2b417be6", "6c3710"], + ["4f78a7f6d2980958","5a97daec58c6b050"]}], + lists:foreach(fun(S) -> aes_ctr_stream_do(Key192,S) end, Samples192), + + %% F.5.5 CTR-AES256.Encrypt + Key256 = hexstr2bin("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"), + Samples256 = [{"f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", % Input Block + ["6bc1bee22e409f96", "e93d7e117393172a"], % Plaintext + ["601ec313775789", "a5b7a7f504bbf3d228"]}, % Ciphertext + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff00", + ["ae2d8a571e03ac9c9eb76fac45af8e51"], + ["f443e3ca","4d62b59aca84","e990cacaf5c5"]}, + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff01", + ["30c81c46","a35ce411","e5fbc119","1a0a52ef"], + ["2b0930daa23de94ce87017ba2d84988d"]}, + {"f0f1f2f3f4f5f6f7f8f9fafbfcfdff02", + ["f69f2445df4f","9b17ad2b41","7be66c3710"], + ["dfc9c5","8db67aada6","13c2dd08","457941a6"]}], + lists:foreach(fun(S) -> aes_ctr_stream_do(Key256,S) end, Samples256). + + +aes_ctr_stream_do(Key,{IVec, PlainList, CipherList}) -> + ?line I = hexstr2bin(IVec), + ?line S = crypto:aes_ctr_stream_init(Key, I), + ?line C = aes_ctr_stream_do_iter( + S, PlainList, [], + fun(S2,P) -> crypto:aes_ctr_stream_encrypt(S2, P) end), + ?line m(C, hexstr2bin(lists:flatten(CipherList))), + ?line P = aes_ctr_stream_do_iter( + S, CipherList, [], + fun(S2,C2) -> crypto:aes_ctr_stream_decrypt(S2, C2) end), + ?line m(P, hexstr2bin(lists:flatten(PlainList))). + +aes_ctr_stream_do_iter(_State, [], Acc, _CipherFun) -> + iolist_to_binary(lists:reverse(Acc)); +aes_ctr_stream_do_iter(State, [Plain|Rest], Acc, CipherFun) -> + ?line P = hexstr2bin(Plain), + ?line {S2, C} = CipherFun(State, P), + aes_ctr_stream_do_iter(S2, Rest, [C | Acc], CipherFun). + %% %% mod_exp_test(doc) -> @@ -1127,7 +1300,8 @@ worker_loop(0, _) -> worker_loop(N, Config) -> Funcs = { md5, md5_update, md5_mac, md5_mac_io, sha, sha_update, des_cbc, aes_cfb, aes_cbc, des_cbc_iter, rand_uniform_test, strong_rand_test, - rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test }, + rsa_verify_test, exor_test, rc4_test, rc4_stream_test, mod_exp_test, + hmac_update_md5, hmac_update_sha, aes_ctr_stream }, F = element(random:uniform(size(Funcs)),Funcs), %%io:format("worker ~p calling ~p\n",[self(),F]), diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk index 740c68d8fa..e754aabc44 100644 --- a/lib/crypto/vsn.mk +++ b/lib/crypto/vsn.mk @@ -1 +1 @@ -CRYPTO_VSN = 2.0.2.2 +CRYPTO_VSN = 2.0.3 diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl index b8da57d3f9..dc5a3fed37 100644 --- a/lib/dialyzer/src/dialyzer_succ_typings.erl +++ b/lib/dialyzer/src/dialyzer_succ_typings.erl @@ -158,20 +158,27 @@ postprocess_dataflow_warns([], _State, WAcc, Acc) -> postprocess_dataflow_warns([{?WARN_CONTRACT_RANGE, {CallF, CallL}, Msg}|Rest], #st{codeserver = Codeserver} = State, WAcc, Acc) -> {contract_range, [Contract, M, F, A, ArgStrings, CRet]} = Msg, - {ok, {{ContrF, _ContrL} = FileLine, _C}} = - dialyzer_codeserver:lookup_mfa_contract({M,F,A}, Codeserver), - case CallF =:= ContrF of - true -> + case dialyzer_codeserver:lookup_mfa_contract({M,F,A}, Codeserver) of + {ok, {{ContrF, _ContrL} = FileLine, _C}} -> + case CallF =:= ContrF of + true -> + NewMsg = {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]}, + W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg}, + Filter = + fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false; + (_) -> true + end, + FilterWAcc = lists:filter(Filter, WAcc), + postprocess_dataflow_warns(Rest, State, FilterWAcc, [W|Acc]); + false -> + postprocess_dataflow_warns(Rest, State, WAcc, Acc) + end; + error -> + %% The contract is not in a module that is currently under analysis. + %% We display the warning in the file/line of the call. NewMsg = {contract_range, [Contract, M, F, ArgStrings, CallL, CRet]}, - W = {?WARN_CONTRACT_RANGE, FileLine, NewMsg}, - Filter = - fun({?WARN_CONTRACT_TYPES, FL, _}) when FL =:= FileLine -> false; - (_) -> true - end, - FilterWAcc = lists:filter(Filter, WAcc), - postprocess_dataflow_warns(Rest, State, FilterWAcc, [W|Acc]); - false -> - postprocess_dataflow_warns(Rest, State, WAcc, Acc) + W = {?WARN_CONTRACT_RANGE, {CallF, CallL}, NewMsg}, + postprocess_dataflow_warns(Rest, State, WAcc, [W|Acc]) end; postprocess_dataflow_warns([W|Rest], State, Wacc, Acc) -> postprocess_dataflow_warns(Rest, State, Wacc, [W|Acc]). diff --git a/lib/diameter/.gitignore b/lib/diameter/.gitignore new file mode 100644 index 0000000000..5afcbedc23 --- /dev/null +++ b/lib/diameter/.gitignore @@ -0,0 +1,58 @@ + +# Match at any level. +*~ +autom4te.cache + +# Compiler derivatives +# +# Do not use too creative wildcards. +# Those might ignore files that should not be ignored. + +i686-pc-linux-gnu +x86_64-unknown-linux-gnu +i386-apple-darwin[0-9]*.[0-9]*.[0-9]* +sparc-sun-solaris[0-9]*.[0-9]* +i386-pc-solaris[0-9]*.[0-9]* +i386-unknown-freebsd[0-9]*.[0-9]* +tile-tilera-linux-gnu +powerpc-unknown-linux-gnu + +# Mac OS X +a.out.dSYM/ + +# Anchored from $DIAMETER_TOP +/config.log +/config.status + +/Makefile +/configure + + +# General patterns for applications in lib. +# +# Assume that all test/Emakefiles are generated. +# +# Any application with a checked-in test/Emakefile should +# use a negative pattern in its own .gitignore. + +# +# Files generated by configure. +# + +/configure +/config.log +/config.status + + +# +# Generated documentation. (ie. not doc/src) +# + +/doc/[^s]* + + +# +# Files generated when building/running tests +# + +/test/*.log diff --git a/lib/diameter/AUTHORS b/lib/diameter/AUTHORS new file mode 100644 index 0000000000..40bd970276 --- /dev/null +++ b/lib/diameter/AUTHORS @@ -0,0 +1,10 @@ +Original Authors: + + Anders Svensson + Ulf Wiger + +Contributors: + + + + diff --git a/lib/diameter/Makefile.in b/lib/diameter/Makefile.in new file mode 100644 index 0000000000..cf38c26045 --- /dev/null +++ b/lib/diameter/Makefile.in @@ -0,0 +1,88 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk +else +include $(DIAMETER_TOP)/make/target.mk +include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk +endif + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include vsn.mk +VSN=$(DIAMETER_VSN) + +DIAMETER_TOP = @DIAMETER_TOP@ + + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +include subdirs.mk + +SUB_DIRECTORIES = $(SUB_DIRS) doc/src + +SPECIAL_TARGETS = + +ifneq ($(ERL_TOP),) +ifneq ($(PREFIX),) +CONFIGURE_OPTS += --prefix=$(PREFIX) +endif +endif + + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/otp_subdir.mk +else +include $(DIAMETER_TOP)/make/subdir.mk +endif + +.PHONY: reconf conf info version dialyzer + +reconf: + autoconf + +conf: do_configure + +do_configure: configure + ./configure $(CONFIGURE_OPTS) + +configure: configure.in + autoconf + +info: + @echo "APP_VSN: $(APP_VSN)" + @echo "DIAMETER_VSN: $(DIAMETER_VSN)" + +version: + @echo "$(VSN)" + + +dialyzer: + (cd ./ebin; \ + dialyzer --build_plt \ + --output_plt ../priv/diameter.plt \ + -r ../../diameter/ebin \ + --verbose) diff --git a/lib/diameter/TAR.exclude b/lib/diameter/TAR.exclude new file mode 100644 index 0000000000..4a2b3192c5 --- /dev/null +++ b/lib/diameter/TAR.exclude @@ -0,0 +1,2 @@ +diameter/doc/standard + diff --git a/lib/diameter/aclocal.m4 b/lib/diameter/aclocal.m4 new file mode 100644 index 0000000000..2abb47dba2 --- /dev/null +++ b/lib/diameter/aclocal.m4 @@ -0,0 +1,65 @@ +dnl +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 1998-2011. All Rights Reserved. +dnl +dnl The contents of this file are subject to the Erlang Public License, +dnl Version 1.1, (the "License"); you may not use this file except in +dnl compliance with the License. You should have received a copy of the +dnl Erlang Public License along with this software. If not, it can be +dnl retrieved online at http://www.erlang.org/. +dnl +dnl Software distributed under the License is distributed on an "AS IS" +dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +dnl the License for the specific language governing rights and limitations +dnl under the License. +dnl +dnl %CopyrightEnd% +dnl + +dnl +dnl aclocal.m4 +dnl +dnl Local macros used in configure.in. The Local Macros which +dnl could/should be part of autoconf are prefixed LM_, macros specific +dnl to the Erlang system are prefixed ERL_. +dnl + +dnl ---------------------------------------------------------------------- +dnl +dnl LM_PROG_INSTALL_DIR +dnl +dnl Figure out how to create directories with parents. +dnl (In my opinion INSTALL_DIR is a bad name, MKSUBDIRS or something is better) +dnl +dnl We prefer 'install -d', but use 'mkdir -p' if it exists. +dnl If none of these methods works, we give up. +dnl + + +AC_DEFUN(LM_PROG_INSTALL_DIR, +[AC_CACHE_CHECK(how to create a directory including parents, +ac_cv_prog_mkdir_p, +[ +temp_name_base=config.$$ +temp_name=$temp_name_base/x/y/z +$INSTALL -d $temp_name >/dev/null 2>&1 +ac_cv_prog_mkdir_p=none +if test -d $temp_name; then + ac_cv_prog_mkdir_p="$INSTALL -d" +else + mkdir -p $temp_name >/dev/null 2>&1 + if test -d $temp_name; then + ac_cv_prog_mkdir_p="mkdir -p" + fi +fi +rm -fr $temp_name_base +]) + +case "${ac_cv_prog_mkdir_p}" in + none) AC_MSG_ERROR(don't know how create directories with parents) ;; + *) INSTALL_DIR="$ac_cv_prog_mkdir_p" AC_SUBST(INSTALL_DIR) ;; +esac +]) + + diff --git a/lib/diameter/autoconf/config.guess b/lib/diameter/autoconf/config.guess new file mode 100755 index 0000000000..38a833903b --- /dev/null +++ b/lib/diameter/autoconf/config.guess @@ -0,0 +1,1519 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2007-05-17' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner <[email protected]>. +# Please send patches to <[email protected]>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <[email protected]>." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# ([email protected] 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep __ELF__ >/dev/null + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # [email protected] (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | ix86xen:SunOS:5.*:*) + echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include <stdio.h> /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <sys/systemcfg.h> + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[45]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include <stdlib.h> + #include <unistd.h> + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep __LP64__ >/dev/null + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <unistd.h> + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips + #undef mipsel + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mipsel + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef mips64 + #undef mips64el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=mips64el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=mips64 + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + tile:Linux:*:*) + echo tile-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa:Linux:*:*) + echo xtensa-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + a.out-i386-linux) + echo "${UNAME_MACHINE}-pc-linux-gnuaout" + exit ;; + coff-i386) + echo "${UNAME_MACHINE}-pc-linux-gnucoff" + exit ;; + "") + # Either a pre-BFD a.out linker (linux-gnuoldld) or + # one that does not give us useful --help. + echo "${UNAME_MACHINE}-pc-linux-gnuoldld" + exit ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include <features.h> + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` + echo ${UNAME_MACHINE}-pc-isc$UNAME_REL + elif /bin/uname -X 2>/dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i386. + echo i386-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says <[email protected]> + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes <[email protected]>. + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From [email protected]. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From [email protected]. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From [email protected]. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c <<EOF +#ifdef _SEQUENT_ +# include <sys/types.h> +# include <sys/utsname.h> +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include <sys/param.h> + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include <sys/param.h> +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 <<EOF +$0: unable to guess system type + +This script, last modified $timestamp, has failed to recognize +the operating system you are using. It is advised that you +download the most up to date version of the config scripts from + + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess +and + http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub + +If the version you run ($0) is already up to date, please +send the following data and any information you think might be +pertinent to <[email protected]> in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/lib/diameter/autoconf/config.sub b/lib/diameter/autoconf/config.sub new file mode 100755 index 0000000000..f43233b104 --- /dev/null +++ b/lib/diameter/autoconf/config.sub @@ -0,0 +1,1630 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +# Inc. + +timestamp='2007-04-29' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to <[email protected]>. Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to <[email protected]>." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64vr | mips64vrel \ + | mips64orion | mips64orionel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa-* \ + | ymp-* \ + | z8k-*) + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16c) + basic_machine=cr16c-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + tile*) + basic_machine=tile-tilera + os=-linux-gnu + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/lib/diameter/autoconf/configure.vxworks b/lib/diameter/autoconf/configure.vxworks new file mode 100755 index 0000000000..33aa497680 --- /dev/null +++ b/lib/diameter/autoconf/configure.vxworks @@ -0,0 +1,147 @@ +#!/bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: +# Patrik Winroth +# + + +# vxworks_ppc860 vxworks_ppc603 vxworks_ppc603_longcall vxworks_cpu32 vxworks_sparc +# vxworks_ppc750 vxworks_simso + +case $# in +1) host=$1 ;; +*) echo "usage: configure.vxworks host-configuration"; exit 1 ;; +esac + +case $1 in +vxworks_cpu32) ;; +vxworks_ppc750) ;; +vxworks_ppc860) ;; +vxworks_ppc603) ;; +vxworks_ppc603_nolongcall) ;; +vxworks_sparc) ;; +vxworks_simso) ;; +vxworks_simlinux) ;; +vxworks_ppc32) ;; +*) echo "usage: configure.vxworks TARGET"; + echo "where TARGET is one of vxworks_cpu32, vxworks_ppc750, vxworks_ppc860, vxworks_ppc603, vxworks_ppc603_nolongcall, vxworks_sparc, vxworks_simso, vxworks_simlinux, vxworks_ppc32"; exit 1;; +esac + +if [ "x$ERL_TOP" = x ]; then + echo "You need to set ERL_TOP!" + exit 1 +fi + + +target=$host + +# Find out the HOST and WIND_BASE environment +HOST_TYPE=${HOST_TYPE:=sun4-solaris2} +case $1 in +vxworks_ppc750) VXTOP=Tornado2.2 ;; +vxworks_simso) VXTOP=WindRiver ;; +vxworks_simlinux) VXTOP=WindRiver ;; +vxworks_ppc32) VXTOP=WindRiver ;; +*) VXTOP=wind ;; +esac + +WIND_BASE=${WIND_BASE:=`ypmatch tornado passwd | awk -F: '{print $6}'`/$VXTOP} + +# These are created by autoconf. +MKDIRS="${ERL_TOP}/lib/os_mon/priv/bin/$target + ${ERL_TOP}/lib/os_mon/priv/obj/$target + ${ERL_TOP}/lib/orber/priv/obj/$target + ${ERL_TOP}/lib/orber/priv/bin/$target + ${ERL_TOP}/lib/ic/priv/lib/$target + ${ERL_TOP}/lib/ic/priv/obj/$target + ${ERL_TOP}/lib/asn1/priv/lib/$target + ${ERL_TOP}/lib/asn1/priv/obj/$target + ${ERL_TOP}/lib/erl_interface/obj/$target + ${ERL_TOP}/lib/erl_interface/obj.debug/$target + ${ERL_TOP}/lib/erl_interface/bin/$target + ${ERL_TOP}/lib/runtime_tools/priv/lib/$target + ${ERL_TOP}/lib/runtime_tools/priv/obj/$target + ${ERL_TOP}/erts/obj/$target + ${ERL_TOP}/erts/obj.debug/$target + ${ERL_TOP}/bin/$target" + +for dir in $MKDIRS; do + test ! -d "$dir" && mkdir -p "$dir" +done + +# +# Create Makefiles for vxWorks. +# +my_root=${ERL_TOP}/erts/emulator +emu_test=$my_root/test +beam=$my_root/beam +erts_lib_src=${ERL_TOP}/erts/lib_src +erts_incl=${ERL_TOP}/erts/include +erts_incl_intrnl=${ERL_TOP}/erts/include/internal +etcdir=${ERL_TOP}/erts/etc/common +erlint_dir=${ERL_TOP}/lib/erl_interface/src +epmd_dir=${ERL_TOP}/erts/epmd/src +os_mon_dir=${ERL_TOP}/lib/os_mon/c_src +orber_dir=${ERL_TOP}/lib/orber/c_src +ic_dir=${ERL_TOP}/lib/ic/c_src +asn1_dir=${ERL_TOP}/lib/asn1/c_src +internal_tools_dir=${ERL_TOP} +libdir=${ERL_TOP}/lib +tsdir=$libdir/test_server/src +zlibdir=${ERL_TOP}/erts/emulator/zlib +runtime_tools_dir=${ERL_TOP}/lib/runtime_tools/c_src +tools_dir=${ERL_TOP}/lib/tools/c_src + +CONFIG_FILES="${ERL_TOP}/erts/emulator/$host/Makefile + $erts_lib_src/$host/Makefile + $erts_incl/$host/erl_int_sizes_config.h + $erts_incl_intrnl/$host/ethread.mk + $erts_incl_intrnl/$host/ethread_header_config.h + $etcdir/$host/Makefile + $erlint_dir/$host/Makefile + $erlint_dir/$host/eidefs.mk + $epmd_dir/$host/Makefile + $internal_tools_dir/make/$host/otp.mk + $os_mon_dir/$host/Makefile + $zlibdir/$host/Makefile + $ic_dir/$host/Makefile + $asn1_dir/$host/Makefile + $runtime_tools_dir/$host/Makefile + $tools_dir/$host/Makefile + $orber_dir/$host/Makefile" + +for file in $CONFIG_FILES; do + new_name=`echo $file|sed "s%/$host/%/$target/%"` + dir=`echo $new_name|sed 's%/[^/][^/]*$%%'` + if test "$dir" != "$new_name" && test "$dir" != .; then + test ! -d "$dir" && mkdir "$dir" + fi + + sole_name=`echo $file|sed "s%.*$target/%%"` + in_file=`echo $dir|sed "s%/[^/][^/]*$%/$sole_name.in%"` + echo "creating $new_name" + sed -f vxworks/sed.$target -f vxworks/sed.general \ + -e "s,@HOST_TYPE@,$HOST_TYPE,g" \ + -e "s,@WIND_BASE@,$WIND_BASE,g" \ + -e "s,@TARGET@,$target,g" \ + $in_file > $new_name +done + + diff --git a/lib/diameter/autoconf/install-sh b/lib/diameter/autoconf/install-sh new file mode 100755 index 0000000000..a5897de6ea --- /dev/null +++ b/lib/diameter/autoconf/install-sh @@ -0,0 +1,519 @@ +#!/bin/sh +# install - install a program, script, or datafile + +scriptversion=2006-12-25.00 + +# This originates from X11R5 (mit/util/scripts/install.sh), which was +# later released in X11R6 (xc/config/util/install.sh) with the +# following copyright and license. +# +# Copyright (C) 1994 X Consortium +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- +# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Except as contained in this notice, the name of the X Consortium shall not +# be used in advertising or otherwise to promote the sale, use or other deal- +# ings in this Software without prior written authorization from the X Consor- +# tium. +# +# +# FSF changes to this file are in the public domain. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. + +nl=' +' +IFS=" "" $nl" + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit=${DOITPROG-} +if test -z "$doit"; then + doit_exec=exec +else + doit_exec=$doit +fi + +# Put in absolute file names if you don't have them in your path; +# or use environment vars. + +chgrpprog=${CHGRPPROG-chgrp} +chmodprog=${CHMODPROG-chmod} +chownprog=${CHOWNPROG-chown} +cmpprog=${CMPPROG-cmp} +cpprog=${CPPROG-cp} +mkdirprog=${MKDIRPROG-mkdir} +mvprog=${MVPROG-mv} +rmprog=${RMPROG-rm} +stripprog=${STRIPPROG-strip} + +posix_glob='?' +initialize_posix_glob=' + test "$posix_glob" != "?" || { + if (set -f) 2>/dev/null; then + posix_glob= + else + posix_glob=: + fi + } +' + +posix_mkdir= + +# Desired mode of installed file. +mode=0755 + +chgrpcmd= +chmodcmd=$chmodprog +chowncmd= +mvcmd=$mvprog +rmcmd="$rmprog -f" +stripcmd= + +src= +dst= +dir_arg= +dst_arg= + +copy_on_change=false +no_target_directory= + +usage="\ +Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE + or: $0 [OPTION]... SRCFILES... DIRECTORY + or: $0 [OPTION]... -t DIRECTORY SRCFILES... + or: $0 [OPTION]... -d DIRECTORIES... + +In the 1st form, copy SRCFILE to DSTFILE. +In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. +In the 4th, create DIRECTORIES. + +Options: + --help display this help and exit. + --version display version info and exit. + + -c (ignored) + -C install only if different (preserve the last data modification time) + -d create directories instead of installing files. + -g GROUP $chgrpprog installed files to GROUP. + -m MODE $chmodprog installed files to MODE. + -o USER $chownprog installed files to USER. + -s $stripprog installed files. + -t DIRECTORY install into DIRECTORY. + -T report an error if DSTFILE is a directory. + +Environment variables override the default commands: + CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG + RMPROG STRIPPROG +" + +while test $# -ne 0; do + case $1 in + -c) ;; + + -C) copy_on_change=true;; + + -d) dir_arg=true;; + + -g) chgrpcmd="$chgrpprog $2" + shift;; + + --help) echo "$usage"; exit $?;; + + -m) mode=$2 + case $mode in + *' '* | *' '* | *' +'* | *'*'* | *'?'* | *'['*) + echo "$0: invalid mode: $mode" >&2 + exit 1;; + esac + shift;; + + -o) chowncmd="$chownprog $2" + shift;; + + -s) stripcmd=$stripprog;; + + -t) dst_arg=$2 + shift;; + + -T) no_target_directory=true;; + + --version) echo "$0 $scriptversion"; exit $?;; + + --) shift + break;; + + -*) echo "$0: invalid option: $1" >&2 + exit 1;; + + *) break;; + esac + shift +done + +if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then + # When -d is used, all remaining arguments are directories to create. + # When -t is used, the destination is already specified. + # Otherwise, the last argument is the destination. Remove it from $@. + for arg + do + if test -n "$dst_arg"; then + # $@ is not empty: it contains at least $arg. + set fnord "$@" "$dst_arg" + shift # fnord + fi + shift # arg + dst_arg=$arg + done +fi + +if test $# -eq 0; then + if test -z "$dir_arg"; then + echo "$0: no input file specified." >&2 + exit 1 + fi + # It's OK to call `install-sh -d' without argument. + # This can happen when creating conditional directories. + exit 0 +fi + +if test -z "$dir_arg"; then + trap '(exit $?); exit' 1 2 13 15 + + # Set umask so as not to create temps with too-generous modes. + # However, 'strip' requires both read and write access to temps. + case $mode in + # Optimize common cases. + *644) cp_umask=133;; + *755) cp_umask=22;; + + *[0-7]) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw='% 200' + fi + cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; + *) + if test -z "$stripcmd"; then + u_plus_rw= + else + u_plus_rw=,u+rw + fi + cp_umask=$mode$u_plus_rw;; + esac +fi + +for src +do + # Protect names starting with `-'. + case $src in + -*) src=./$src;; + esac + + if test -n "$dir_arg"; then + dst=$src + dstdir=$dst + test -d "$dstdir" + dstdir_status=$? + else + + # Waiting for this to be detected by the "$cpprog $src $dsttmp" command + # might cause directories to be created, which would be especially bad + # if $src (and thus $dsttmp) contains '*'. + if test ! -f "$src" && test ! -d "$src"; then + echo "$0: $src does not exist." >&2 + exit 1 + fi + + if test -z "$dst_arg"; then + echo "$0: no destination specified." >&2 + exit 1 + fi + + dst=$dst_arg + # Protect names starting with `-'. + case $dst in + -*) dst=./$dst;; + esac + + # If destination is a directory, append the input filename; won't work + # if double slashes aren't ignored. + if test -d "$dst"; then + if test -n "$no_target_directory"; then + echo "$0: $dst_arg: Is a directory" >&2 + exit 1 + fi + dstdir=$dst + dst=$dstdir/`basename "$src"` + dstdir_status=0 + else + # Prefer dirname, but fall back on a substitute if dirname fails. + dstdir=` + (dirname "$dst") 2>/dev/null || + expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$dst" : 'X\(//\)[^/]' \| \ + X"$dst" : 'X\(//\)$' \| \ + X"$dst" : 'X\(/\)' \| . 2>/dev/null || + echo X"$dst" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q' + ` + + test -d "$dstdir" + dstdir_status=$? + fi + fi + + obsolete_mkdir_used=false + + if test $dstdir_status != 0; then + case $posix_mkdir in + '') + # Create intermediate dirs using mode 755 as modified by the umask. + # This is like FreeBSD 'install' as of 1997-10-28. + umask=`umask` + case $stripcmd.$umask in + # Optimize common cases. + *[2367][2367]) mkdir_umask=$umask;; + .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; + + *[0-7]) + mkdir_umask=`expr $umask + 22 \ + - $umask % 100 % 40 + $umask % 20 \ + - $umask % 10 % 4 + $umask % 2 + `;; + *) mkdir_umask=$umask,go-w;; + esac + + # With -d, create the new directory with the user-specified mode. + # Otherwise, rely on $mkdir_umask. + if test -n "$dir_arg"; then + mkdir_mode=-m$mode + else + mkdir_mode= + fi + + posix_mkdir=false + case $umask in + *[123567][0-7][0-7]) + # POSIX mkdir -p sets u+wx bits regardless of umask, which + # is incompatible with FreeBSD 'install' when (umask & 300) != 0. + ;; + *) + tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ + trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 + + if (umask $mkdir_umask && + exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 + then + if test -z "$dir_arg" || { + # Check for POSIX incompatibilities with -m. + # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or + # other-writeable bit of parent directory when it shouldn't. + # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. + ls_ld_tmpdir=`ls -ld "$tmpdir"` + case $ls_ld_tmpdir in + d????-?r-*) different_mode=700;; + d????-?--*) different_mode=755;; + *) false;; + esac && + $mkdirprog -m$different_mode -p -- "$tmpdir" && { + ls_ld_tmpdir_1=`ls -ld "$tmpdir"` + test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" + } + } + then posix_mkdir=: + fi + rmdir "$tmpdir/d" "$tmpdir" + else + # Remove any dirs left behind by ancient mkdir implementations. + rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null + fi + trap '' 0;; + esac;; + esac + + if + $posix_mkdir && ( + umask $mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" + ) + then : + else + + # The umask is ridiculous, or mkdir does not conform to POSIX, + # or it failed possibly due to a race condition. Create the + # directory the slow way, step by step, checking for races as we go. + + case $dstdir in + /*) prefix='/';; + -*) prefix='./';; + *) prefix='';; + esac + + eval "$initialize_posix_glob" + + oIFS=$IFS + IFS=/ + $posix_glob set -f + set fnord $dstdir + shift + $posix_glob set +f + IFS=$oIFS + + prefixes= + + for d + do + test -z "$d" && continue + + prefix=$prefix$d + if test -d "$prefix"; then + prefixes= + else + if $posix_mkdir; then + (umask=$mkdir_umask && + $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break + # Don't fail if two instances are running concurrently. + test -d "$prefix" || exit 1 + else + case $prefix in + *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; + *) qprefix=$prefix;; + esac + prefixes="$prefixes '$qprefix'" + fi + fi + prefix=$prefix/ + done + + if test -n "$prefixes"; then + # Don't fail if two instances are running concurrently. + (umask $mkdir_umask && + eval "\$doit_exec \$mkdirprog $prefixes") || + test -d "$dstdir" || exit 1 + obsolete_mkdir_used=true + fi + fi + fi + + if test -n "$dir_arg"; then + { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && + { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || + test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 + else + + # Make a couple of temp file names in the proper directory. + dsttmp=$dstdir/_inst.$$_ + rmtmp=$dstdir/_rm.$$_ + + # Trap to clean up those temp files at exit. + trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 + + # Copy the file name to the temp name. + (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && + + # and set any options; do chmod last to preserve setuid bits. + # + # If any of these fail, we abort the whole thing. If we want to + # ignore errors from any of these, just make sure not to ignore + # errors from the above "$doit $cpprog $src $dsttmp" command. + # + { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && + { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && + { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && + { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && + + # If -C, don't bother to copy if it wouldn't change the file. + if $copy_on_change && + old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && + new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && + + eval "$initialize_posix_glob" && + $posix_glob set -f && + set X $old && old=:$2:$4:$5:$6 && + set X $new && new=:$2:$4:$5:$6 && + $posix_glob set +f && + + test "$old" = "$new" && + $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 + then + rm -f "$dsttmp" + else + # Rename the file to the real destination. + $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || + + # The rename failed, perhaps because mv can't rename something else + # to itself, or perhaps because mv is so ancient that it does not + # support -f. + { + # Now remove or move aside any old file at destination location. + # We try this two ways since rm can't unlink itself on some + # systems and the destination file might be busy for other + # reasons. In this case, the final cleanup might fail but the new + # file should still install successfully. + { + test ! -f "$dst" || + $doit $rmcmd -f "$dst" 2>/dev/null || + { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && + { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } + } || + { echo "$0: cannot unlink or rename $dst" >&2 + (exit 1); exit 1 + } + } && + + # Now rename the file to the real destination. + $doit $mvcmd "$dsttmp" "$dst" + } + fi || exit 1 + + trap '' 0 + fi +done + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "scriptversion=" +# time-stamp-format: "%:y-%02m-%02d.%02H" +# time-stamp-end: "$" +# End: diff --git a/lib/diameter/autoconf/vxworks/sed.general b/lib/diameter/autoconf/vxworks/sed.general new file mode 100644 index 0000000000..77b306aa0a --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.general @@ -0,0 +1,125 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Patrik Winroth +# +# This sed program file is intended to be used when creating Makefiles +# for vxworks from the generic Makefile.in that is found in a number +# of directories (see configure.vxworks). +# +# This is the general part that is common for all architectures. +# + +# Size of data types. +s|^#undef SIZEOF_CHAR|#define SIZEOF_CHAR 1| +s|^#undef SIZEOF_SHORT|#define SIZEOF_SHORT 2| +s|^#undef SIZEOF_INT|#define SIZEOF_INT 4| +s|^#undef SIZEOF_LONG_LONG|#define SIZEOF_LONG_LONG 8| +s|^#undef SIZEOF_LONG$|#define SIZEOF_LONG 4| + +# General stuff. +s|@erts_rootdir@|/clearcase/otp/erts| + +s|@LIBOBJS@|$(OBJDIR)/elib_malloc.o| +s|@DLOAD_LIB@|| +s|@LDFLAGS@|| +# FIXME: A bit strange to clear out remaining DED_* +s|@DED_LDFLAGS@|| +s|@DED_CFLAGS@|| +s|@STATIC_CFLAGS@|| +s|@GCCLIB@|libgcc.a| +s|@DEFS@|| +s|@DEXPORT@|| +s|@DCFLAGS@|| +s|@THR_DEFS@|| +s|@THR_LIBS@|| +s|@THR_LIB_NAME@|| +s|@THR_X_LIBS@|| +s|@ETHR_X_LIBS@|| +s|@ETHR_LIBS@|| +s|@ETHR_LIB_NAME@|| +s|@ETHR_DEFS@|| +s|@ETHR_THR_LIB_BASE@|| +s|@EMU_THR_DEFS@|| +s|@EMU_THR_LIBS@|| +s|@EMU_THR_LIB_NAME@|ethread| +s|@ERTS_ENABLE_KERNEL_POLL@|no| +s|@cc_root@|/clearcase/otp/| +# Define VxWorks even though cross-compiling. +s|@HCFLAGS@|-DVXWORKS| +s|@HCLIBS@|| +s|@ENABLE_ALLOC_TYPE_VARS@|| +s|@TERMCAP_LIB@|| +s|@ERTS_BUILD_SMP_EMU@|no| +s|@ERTS_BUILD_HYBRID_EMU@|no| +s|@HAVE_VALGRIND@|no| +s|@EXEEXT@|| +s|@WITH_SCTP@|| + +# HiPE +s|@HIPE_ENABLED@|| +s|@PERFCTR_PATH@|| +s|@USE_PERFCTR@|| + +# m4 +s|@OPSYS@|noopsys| + +# Conditional inclusion of applications +s|@HIPE_APP@|| +s|@SSL_APP@|ssl| +s|@CRYPTO_APP@|crypto| +s|@SSH_APP@|ssh| + +# The target tools prefix, prepended to all cc,ld,as etc commands +s|@TTPREFIX@|GCC_EXEC_PREFIX=@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/host/@HOST_TYPE@/bin/| + +# Install programs etc +s|@PERL@|perl| +s|@INSTALL@|/usr/ucb/install -c| +s|@INSTALL_PROGRAM@|${INSTALL}| +s|@INSTALL_SCRIPT@|${INSTALL}| +s|@INSTALL_DATA@|${INSTALL} -m 644| +s|@INSTALL_DIR@|$(INSTALL) -d| +s|@RM@|/bin/rm| +s|@MKDIR@|/bin/mkdir| +s|@ERLANG_OSTYPE@|vxworks| +s|@vxworks_reclaim@|reclaim.h| +s|@os_mon_programs@|| +s|@erlexec@|erl.exec| +s|@EMU_LIBOBJS@|| + +# General CFLAGS +s|@GENERAL_CFLAGS@|-DHAVE_LOCALTIME_R -DHAVE_GMTIME_R -DENABLE_ELIB_MALLOC -DELIB_HEAP_USER -DELIB_SORTED_BLOCKS -DWORDS_BIGENDIAN -DELIB_DONT_INITIALIZE -DSIZEOF_CHAR=1 -DSIZEOF_SHORT=2 -DSIZEOF_INT=4 -DSIZEOF_LONG=4 -DSIZEOF_LONG_LONG=8 -DSIZEOF_VOID_P=4 -DERTS_USE_PORT_TASKS=1|g +s|@WFLAGS@|| + +# Thread flags for eidefs.mk (erl_interface) +s|@EI_THREADS@|false| + +# Make java code compile although we don't test it on VxWorks (no license) +s|@JAVAC@|javac| + +# What is this anyway? +# Disable it and see what breaks. +#s|@ded_soname@|| + +# Only variable substituted directly +s|$(LDFLAGS)|-r -d| +s|@LIBRT@|| +# XXX What is EFFLAGS? Not used in the emulator Makefile.in anyway. +s|$(EFLAGS)|-DENABLE_ELIB_MALLOC -DELIB_HEAP_USER -DELIB_SORTED_BLOCKS| + diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 b/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 new file mode 100644 index 0000000000..5a1590e786 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 @@ -0,0 +1,45 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Patrik Winroth +# +# This sed program file is intended to be used when creating Makefiles for vxworks +# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) +# +# +# +s|@host@|vxworks_cpu32| +s|@system_type@|vxworks_cpu32| +s|@CC@|@TTPREFIX@cc68k| +s|@HCC@|gcc| +s|@LD@|@TTPREFIX@ld68k| +s|@LIBS@|| +s|@DED_LD@|@TTPREFIX@ld68k| +s|@DED_CFLAGS@|@CFLAGS@| +s|@DEBUG_FLAGS@|-g| +s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/m68k-wrs-vxworks/cygnus-2.7.2-960126/m68000/msoft-float/libgcc.a| +s|@RANLIB@|@TTPREFIX@ranlib68k| +s|@AR@|@TTPREFIX@ar68k| +s|@STRIP@|@TTPREFIX@strip68k| +s|@SYMPREFIX@|_| +s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/m68k-wrs-vxworks/cygnus-2.7.2-960126/m68000/msoft-float -lgcc| + +s|@LIB_CFLAGS@|@CFLAGS@| + +s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=CPU32 -mnobitfield -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -fno-builtin -nostdinc -fvolatile -msoft-float| +#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=CPU32 -mnobitfield -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -fno-builtin -nostdinc -fvolatile -msoft-float| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 new file mode 100644 index 0000000000..9104b24ed3 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 @@ -0,0 +1,52 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2006-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Peter Andersson +# +# This sed program file is intended to be used when creating Makefiles for vxworks +# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) +# +# +# +s|@host@|vxworks_ppc32| +s|@system_type@|vxworks_ppc32| +s|@ARCH@|ppc32| +s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccppc -mlongcall| +s|@HCC@|gcc| +s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldppc| +s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/workbench-2.3/@HOST_TYPE@/bin/stripppc| +s|@SYMPREFIX@|| +s|@LIBS@|| +s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/ppc/PPC32/common -lgcc| +s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldppc| +s|@DED_CFLAGS@|@CFLAGS@| +s|@DEBUG_CFLAGS@|@CFLAGS@| +# generate dwarf debug code on PPC .. +s|@DEBUG_FLAGS@|-gdwarf| +# remove -g option +s|TYPE_FLAGS = -g |TYPE_FLAGS = | +s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/ppc/PPC32/common/libgcc.a| +s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibppc| +s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arppc| +# -Dasm(X)= is for beam + +s|@LIB_CFLAGS@|@CFLAGS@| + +s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC32 -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/powerpc-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | + +#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC32 -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -I@WIND_BASE@/vxworks-6.3/target/h -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 new file mode 100644 index 0000000000..e1dd7c5afd --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 @@ -0,0 +1,51 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Patrik Winroth +# +# This sed program file is intended to be used when creating Makefiles for vxworks +# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) +# +# +# +s|@host@|vxworks_ppc603| +s|@system_type@|vxworks_ppc603| +s|@ARCH@|ppc603| +s|@CC@|@TTPREFIX@ccppc -mlongcall| +s|@HCC@|gcc| +s|@LD@|@TTPREFIX@ldppc| +s|@STRIP@|@TTPREFIX@stripppc| +s|@SYMPREFIX@|| +s|@LIBS@|| +s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126 -lgcc| +s|@DED_LD@|@TTPREFIX@ldppc| +s|@DED_CFLAGS@|@CFLAGS@| +s|@DEBUG_CFLAGS@|@CFLAGS@| +# generate dwarf debug code on PPC .. +s|@DEBUG_FLAGS@|-gdwarf| +# remove -g option +s|TYPE_FLAGS = -g |TYPE_FLAGS = | +s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/libgcc.a| +s|@RANLIB@|@TTPREFIX@ranlibppc| +s|@AR@|@TTPREFIX@arppc| +# -Dasm(X)= is for beam + +s|@LIB_CFLAGS@|@CFLAGS@| + +s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| +#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall new file mode 100644 index 0000000000..5d7673d323 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall @@ -0,0 +1,51 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Patrik Winroth +# +# This sed program file is intended to be used when creating Makefiles for vxworks +# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) +# +# +# +s|@host@|vxworks_ppc603| +s|@system_type@|vxworks_ppc603| +s|@ARCH@|ppc603| +s|@CC@|@TTPREFIX@ccppc| +s|@HCC@|gcc| +s|@LD@|@TTPREFIX@ldppc| +s|@STRIP@|@TTPREFIX@stripppc| +s|@SYMPREFIX@|| +s|@LIBS@|| +s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126 -lgcc| +s|@DED_LD@|@TTPREFIX@ldppc| +s|@DED_CFLAGS@|@CFLAGS@| +# generate dwarf debug code on PPC .. +s|@DEBUG_FLAGS@|-gdwarf| +# remove -g option +s|TYPE_FLAGS = -g |TYPE_FLAGS = | +s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/libgcc.a| +s|@RANLIB@|@TTPREFIX@ranlibppc| +s|@AR@|@TTPREFIX@arppc| +# -Dasm(X)= is for beam + +s|@LIB_CFLAGS@|@CFLAGS@| + +s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| +#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| + diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 new file mode 100644 index 0000000000..7a3c32df5b --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 @@ -0,0 +1,50 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Patrik Winroth +# +# This sed program file is intended to be used when creating Makefiles for vxworks +# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) +# +# +# +s|@host@|vxworks_ppc860| +s|@system_type@|vxworks_ppc860| +s|@ARCH@|ppc860| +s|@CC@|@TTPREFIX@ccppc -mlongcall| +s|@HCC@|gcc| +s|@LD@|@TTPREFIX@ldppc| +s|@STRIP@|@TTPREFIX@stripppc| +s|@SYMPREFIX@|| +s|@LIBS@|| +s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/soft-float -lgcc| +s|@DED_LD@|@TTPREFIX@ldppc| +s|@DED_CFLAGS@|@CFLAGS@| +s|@DEBUG_CFLAGS@|@CFLAGS@| +# generate dwarf debug code on PPC .. +s|@DEBUG_FLAGS@|-gdwarf| +# remove -g option (go for dwarf) +s|TYPE_FLAGS = -g |TYPE_FLAGS = | +s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/soft-float/libgcc.a| +s|@RANLIB@|@TTPREFIX@ranlibppc| +s|@AR@|@TTPREFIX@arppc| + +s|@LIB_CFLAGS@|@CFLAGS@| + +s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC860 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mcpu=860 -fvolatile -fno-builtin -fno-for-scope -msoft-float -D_GNU_TOOL -nostdinc| +#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC860 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mcpu=powerpc -fvolatile -fno-builtin -fno-for-scope -msoft-float -D_GNU_TOOL -nostdinc| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux b/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux new file mode 100644 index 0000000000..56eae6507c --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux @@ -0,0 +1,59 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2008-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Peter Andersson +# +# This sed program file is intended to be used when creating Makefiles for vxworks +# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) +# +# +# +s|@host@|vxworks_simlinux| +s|@system_type@|vxworks_simlinux| +s|@ARCH@|simlinux| + +s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccpentium| + +s|@HCC@|gcc| + +s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldpentium| + +#s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/strip| +s|@STRIP@|| + +s|@SYMPREFIX@|| +s|@LIBS@|| +s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/simlinux/SIMLINUX/common -lgcc| + +s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldpentium| + +s|@DED_CFLAGS@|@CFLAGS@| +s|@DEBUG_CFLAGS@|@CFLAGS@| +# remove -g option +s|TYPE_FLAGS = -g |TYPE_FLAGS = | +s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/simlinux/SIMLINUX/common/libgcc.a| + +s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibpentium| + +s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arpentium| + +# -Dasm(X)= is for beam +s|@LIB_CFLAGS@|@CFLAGS@| + +s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMLINUX -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/i586-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -fvolatile -fno-builtin | +#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMLINUX -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_simso b/lib/diameter/autoconf/vxworks/sed.vxworks_simso new file mode 100644 index 0000000000..6b845d31de --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_simso @@ -0,0 +1,64 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2005-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Peter Andersson +# +# This sed program file is intended to be used when creating Makefiles for vxworks +# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) +# +# +# +s|@host@|vxworks_simso| +s|@system_type@|vxworks_simso| +s|@ARCH@|simso| + +# Tornado2.2: s|@CC@|@TTPREFIX@ccsimso| +s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccsparc| + +s|@HCC@|gcc| + +# Tornado2.2: s|@LD@|@TTPREFIX@ldsimso| +s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldsparc| + +# Tornado2.2: s|@STRIP@|@TTPREFIX@stripsimso| +s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/stripsparc| + +s|@SYMPREFIX@|| +s|@LIBS@|| +s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/simso/SIMSPARCSOLARIS/common -lgcc| + +# Tornado2.2: s|@DED_LD@|@TTPREFIX@ldsimso| +s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldsparc| + +s|@DED_CFLAGS@|@CFLAGS@| +s|@DEBUG_CFLAGS@|@CFLAGS@| +# remove -g option +s|TYPE_FLAGS = -g |TYPE_FLAGS = | +s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/simso/SIMSPARCSOLARIS/common/libgcc.a| + +# Tornado2.2: s|@RANLIB@|@TTPREFIX@ranlibsimso| +s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibsparc| + +# Tornado2.2: s|@AR@|arsimso| +s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arsparc| + +# -Dasm(X)= is for beam +s|@LIB_CFLAGS@|@CFLAGS@| + +s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMSPARCSOLARIS -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/sparc-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -fvolatile -fno-builtin | +#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMSPARCSOLARIS -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_sparc b/lib/diameter/autoconf/vxworks/sed.vxworks_sparc new file mode 100644 index 0000000000..6f637d8746 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_sparc @@ -0,0 +1,38 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Author: Patrik Winroth +# +# This sed program file is intended to be used when creating Makefiles for vxworks +# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) +# + +# ccsparc -O2 doesn't work when compiling "rundir"/gc.c - signal 11 is generated when trying +# therefore it is compiled with -O1 instead, which works - get a new ccsparc ! +s/\$(COMPILE\.emu) -o \$@ -c gc\.c/$(CC) @CFLAGS@ @DEFS@ -O1 $(BEAM_MODE) -I$(SYSDIR) -I$(EMUDIR) -I. $(CPPFLAGS) -c -o $@ -c gc.c/ +s/@host@/vxworks_sparc/ +s/@system_type@/vxworks_sparc/ +s/@CC@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/bin\/ccsparc/ +s/@HCC@/gcc/ +s/@LD@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/bin\/ldsparc/ +s/@DEBUG_FLAGS@/-g/ +s/@GCCLIB_PATH@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/lib\/gcc-lib\/sparc-wrs-vxworks\/cygnus-2.2.3.1\/libgcc.a/ +s/@RANLIB@/ranlibsparc/ +s/@AR@/arsparc/ +s/@CFLAGS@/-I\/home\/gandalf\/bsproj\/BS.2\/UOS\/vw\/5.2\/h -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DCPU=SPARC -DVXWORKS -fno-builtin -nostdinc/ + diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc new file mode 100755 index 0000000000..f5cf3ebc10 --- /dev/null +++ b/lib/diameter/bin/diameterc @@ -0,0 +1,155 @@ +#!/usr/bin/env escript +%% Use -*- erlang -*- mode in Erlang + +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameterc). + +-mode(compile). + +-include_lib("kernel/include/file.hrl"). + +%% The parsed command line. +-record(argv, {file, + options = [{outdir, "."}], + output = [erl, hrl]}). + +usage() -> + io:format( + "~w [options] file~n" + "~n" + " Compile a diameter dictionary file (.dia) to Erlang source (.erl)~n" + " and/or header (.hrl) files.~n" + "~n" + " options:~n" + " -h = print this message~n" + " -v = verbose output~n" + " -o dir = set the output directory (default .)~n" + " -i dir = set an include directory for inherited beams~n" + " -E = no .erl output~n" + " -H = no .hrl output~n" + " -d = write intermediate files (.spec and .forms)~n", + [?MODULE]). + +main(Args) -> + %% Add the ebin directory relative to the script path. + BinDir = filename:dirname(escript:script_name()), + code:add_path(filename:join([BinDir, "..", "ebin"])), + halt(gen(Args)). + +gen(Args) -> + try parse_args(Args) of + #argv{} = A -> + compile(A) + catch + throw: usage -> + usage(), + 0; + throw: Reason -> + error_msg(norm(Reason)), + 1 + end. + +compile(#argv{file = File, options = Opts} = A) -> + try + Spec = diameter_spec_util:parse(File, Opts), + maybe_output(A, Spec, Opts, spec), %% the spec file + maybe_output(A, Spec, Opts, erl), %% the erl file + maybe_output(A, Spec, Opts, hrl), %% The hrl file + 0 + catch + error: Reason -> + error_msg({"ERROR: ~p~n ~p", [Reason, erlang:get_stacktrace()]}), + 2 + end. + +maybe_output(#argv{file = File, output = Output}, Spec, Opts, Mode) -> + lists:member(Mode, Output) + andalso diameter_codegen:from_spec(File, Spec, Opts, Mode). + +error_msg({Fmt, Args}) -> + io:format(standard_error, Fmt ++ "~n", Args). + +norm({_,_} = T) -> + T; +norm(Str) -> + {Str, []}. + +%% parse_args/1 + +parse_args(Args) + when is_list(Args) -> + arg(Args, #argv{}). + +arg(["-h" | _], _) -> + throw(usage); + +arg(["-v" | Args], #argv{options = Opts} = A) -> + arg(Args, A#argv{options = [verbose | Opts]}); + +arg(["-o", Dir | Args], #argv{options = Opts} = A) -> + true = dir_exists(Dir), + arg(Args, A#argv{options = [{outdir, Dir} | Opts]}); + +arg(["-i", Dir | Args], #argv{options = Opts} = A) -> + true = dir_exists(Dir), + arg(Args, A#argv{options = Opts ++ [{include, Dir}]}); + +arg(["-E" | Args], #argv{output = Output} = A) -> + arg(Args, A#argv{output = lists:delete(erl, Output)}); + +arg(["-H" | Args], #argv{output = Output} = A) -> + arg(Args, A#argv{output = lists:delete(hrl, Output)}); + +arg(["-d" | Args], #argv{options = Opts, output = Output} = A) -> + arg(Args, A#argv{options = [debug | Opts], + output = [spec | Output]}); + +arg([[$- = M, C, H | T] | Args], A) %% clustered options + when C /= $i, C /= $o -> + arg([[M,C], [M,H|T] | Args], A); + +arg([File], A) -> + true = file_exists(File), + A#argv{file = File}; + +arg([], _) -> + throw("No input file"); + +arg([Bad | _], _) -> + throw({"Unknown option: ~p", [Bad]}). + +%% path_exists/2 + +path_exists(File, Type) -> + case file:read_file_info(File) of + {ok, #file_info{type = Type}} -> + true; + {ok, #file_info{type = WrongType}} -> + throw({"Invalid type for file: ~p, ~p", [WrongType, File]}); + _ -> + throw({"No such file: ~p", [File]}) + end. + +file_exists(File) -> + path_exists(File, regular). + +dir_exists(File) -> + path_exists(File, directory). diff --git a/lib/diameter/configure.in b/lib/diameter/configure.in new file mode 100644 index 0000000000..9aca3859c5 --- /dev/null +++ b/lib/diameter/configure.in @@ -0,0 +1,138 @@ +dnl Process this file with autoconf to produce a configure script. + +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 1998-2011. All Rights Reserved. +dnl +dnl The contents of this file are subject to the Erlang Public License, +dnl Version 1.1, (the "License"); you may not use this file except in +dnl compliance with the License. You should have received a copy of the +dnl Erlang Public License along with this software. If not, it can be +dnl retrieved online at http://www.erlang.org/. +dnl +dnl Software distributed under the License is distributed on an "AS IS" +dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +dnl the License for the specific language governing rights and limitations +dnl under the License. +dnl +dnl %CopyrightEnd% + +if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then + # We do not want to use a common cache! + cache_file=/dev/null +fi + +AC_INIT(vsn.mk) + +dnl <STANDALONE DIAMETER> +dnl This is needed for diameters own environment to rock, +dnl but since we are now integrated into OTP, we skip it. +dnl In order to build stand-alone we need atleast 2.63... +dnl AC_PREREQ(2.63) +dnl </STANDALONE DIAMETER> + +dnl LM_PRECIOUS_VARS + + +dnl The OTP source tree is the default "top", +dnl but we can also define our own top: DIAMETER_TOP + +if test -n "$ERL_TOP" || test -d $ERL_TOP ; then + erl_top=${ERL_TOP} + AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf) + DIAMETER_TOP=${ERL_TOP}/lib/diameter +else + AC_ARG_VAR(DIAMETER_TOP, [Diameter top source directory]) + if test -n "$DIAMETER_TOP" || test -d $DIAMETER_TOP ; then + AC_CONFIG_AUX_DIRS(autoconf) + fi + + dnl <STANDALONE DIAMETER> + dnl AC_ERLANG_SUBST_ROOT_DIR + dnl AC_ERLANG_SUBST_LIB_DIR + dnl AC_ERLANG_CHECK_LIB([erl_docgen], + dnl [echo "erl_docgen version \"$ERLANG_LIB_VER_erl_docgen\"" + dnl echo "is installed in \"$ERLANG_LIB_DIR_erl_docgen\""], + dnl [AC_MSG_ERROR([erl_docgen was not found!])]) + dnl AC_ERLANG_CHECK_LIB([test_server], + dnl [echo "test_server version \"$ERLANG_LIB_VER_test_server\"" + dnl echo "is installed in \"$ERLANG_LIB_DIR_test_server\""], + dnl [AC_MSG_ERROR([test_server was not found!])]) + dnl </STANDALONE DIAMETER> + +fi + +AC_SUBST(DIAMETER_TOP) +export DIAMETER_TOP + +if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then + AC_CANONICAL_HOST +fi + +TARGET=$host +AC_SUBST(TARGET) + +if test "x$erl_top" = "x"; then + dnl STANDALONE DIAMETER + AC_CHECK_PROGS(XSLTPROC, xsltproc) + if test -z "$XSLTPROC"; then + echo "xsltproc" >> doc/CONF_INFO + AC_MSG_WARN([No 'xsltproc' command found: the documentation can not be built]) + fi + + AC_CHECK_PROGS(FOP, fop) + if test -z "$FOP"; then + AC_MSG_ERROR([No 'fop' command found: the documentation can not be built]) + fi +fi + +dnl +dnl We can live with Solaris /usr/ucb/install +dnl +case $host in + *-*-solaris*|free_source) + if test -x /usr/ucb/install; then + INSTALL="/usr/ucb/install -c" + fi + ;; + *) + ;; +esac +AC_PROG_INSTALL +LM_PROG_INSTALL_DIR + +case $host_os in + darwin*) + dnl Need to preserve modification time on archives; + dnl otherwise, ranlib has to be run on archives + dnl again after installation. + INSTALL_DATA="$INSTALL_DATA -p";; + *) + ;; +esac + +dnl +dnl Fix for Tilera install permissions +dnl + +case $build in + *tile*) + INSTALL_PROGRAM="$INSTALL_PROGRAM -m755" + INSTALL_SCRIPT="$INSTALL_SCRIPT -m755" + ;; + *) + ;; +esac + + +dnl <STANDALONE DIAMETER> +dnl AC_ERLANG_NEED_ERL([$PATH]) +dnl AC_ERLANG_NEED_ERLC([$PATH]) +dnl </STANDALONE DIAMETER> + +AC_OUTPUT( + Makefile:Makefile.in + src/app/diameter.mk:src/app/diameter.mk.in + make/$host/rules.mk:make/rules.mk.in + ) + diff --git a/lib/diameter/doc/html/.gitignore b/lib/diameter/doc/html/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/diameter/doc/html/.gitignore diff --git a/lib/diameter/doc/man1/.gitignore b/lib/diameter/doc/man1/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/diameter/doc/man1/.gitignore diff --git a/lib/diameter/doc/man3/.gitignore b/lib/diameter/doc/man3/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/diameter/doc/man3/.gitignore diff --git a/lib/diameter/doc/man4/.gitignore b/lib/diameter/doc/man4/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/diameter/doc/man4/.gitignore diff --git a/lib/diameter/doc/pdf/.gitignore b/lib/diameter/doc/pdf/.gitignore new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/lib/diameter/doc/pdf/.gitignore diff --git a/lib/diameter/doc/src/.gitignore b/lib/diameter/doc/src/.gitignore new file mode 100644 index 0000000000..feeb378fd8 --- /dev/null +++ b/lib/diameter/doc/src/.gitignore @@ -0,0 +1,2 @@ + +/depend.mk diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile new file mode 100644 index 0000000000..1453138cb6 --- /dev/null +++ b/lib/diameter/doc/src/Makefile @@ -0,0 +1,198 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk +else +include $(DIAMETER_TOP)/make/target.mk +include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk +endif + +include ../../vsn.mk + +VSN = $(DIAMETER_VSN) + +RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +include files.mk + +XML_REF_FILES = $(XML_REF1_FILES) $(XML_REF3_FILES) $(XML_REF4_FILES) + +XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) \ + $(XML_REF_FILES) \ + $(XML_PART_FILES) $(XML_CHAPTER_FILES) + +INTERNAL_HTML_FILES = $(TECHNICAL_DESCR_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_APP_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) +HTML_EXTRA_FILES = $(XML_EXTRA_FILES:%.xml=$(HTMLDIR)/%.html) +HTML_PART_FILES = $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_FILES = $(HTML_APP_FILES) $(HTML_EXTRA_FILES) $(HTML_PART_FILES) + +INFO_FILE = ../../info + +HTML_REF_FILES = $(XML_REF_FILES:%.xml=$(HTMLDIR)/%.html) + +HTML_CHAPTER_FILES = $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) + +EXTRA_FILES = \ + $(DEFAULT_GIF_FILES) \ + $(DEFAULT_HTML_FILES) \ + $(HTML_REF_FILES) \ + $(HTML_CHAPTER_FILES) + +MAN1_FILES = $(XML_REF1_FILES:%.xml=$(MAN1DIR)/%.1) +MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3) +MAN4_FILES = $(XML_REF4_FILES:%.xml=$(MAN4DIR)/%.4) + +HTML_REF_MAN_FILE = $(HTMLDIR)/index.html + +TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf + +STANDARD_DIR = ../standard +STANDARDS = + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +XML_FLAGS += +DVIPS_FLAGS += + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +$(HTMLDIR)/%.gif: %.gif + $(INSTALL_DATA) $< $@ + +docs: pdf html man + +ldocs: local_docs $(INDEX_TARGET) + +$(TOP_PDF_FILE): $(XML_FILES) + +pdf: $(TOP_PDF_FILE) + +html: gifs $(HTML_REF_MAN_FILE) + +clean clean_docs: clean_pdf clean_html clean_man + rm -f errs core *~ + rm -f depend.mk + +clean_pdf: + rm -f $(PDFDIR)/* + +clean_man: + rm -f $(MAN1DIR)/* $(MAN3DIR)/* $(MAN4DIR)/* + +clean_html: + rm -rf $(HTMLDIR)/* + +gifs: $(GIF_FILES:%=$(HTMLDIR)/%) + +man: $(MAN1_FILES) $(MAN3_FILES) $(MAN4_FILES) + +$(INDEX_TARGET): $(INDEX_SRC) $(APP_FILE) + sed -e 's/%VSN%/$(VSN)/; \ + s/%ERLANG_SITE%/www\.erlang\.se\//; \ + s/%UP_ONE_LEVEL%/..\/..\/..\/doc\/index.html/; \ + s/%OFF_PRINT%/pdf\/diameter-$(VSN).pdf/' $< > $@ + +depend: depend.mk + +debug opt: + +info: + @echo "->Makefile<-" + @echo "" + @echo "DOCSUPPORT = $(DOCSUPPORT)" + @echo "" + @echo "INDEX_FILE = $(INDEX_FILE)" + @echo "INDEX_SRC = $(INDEX_SRC)" + @echo "INDEX_TARGET = $(INDEX_TARGET)" + @echo "" + @echo "XML_APPLICATION_FILES = $(XML_APPLICATION_FILES)" + @echo "XML_PART_FILES = $(XML_PART_FILES)" + @echo "XML_REF1_FILES = $(XML_REF1_FILES)" + @echo "XML_REF3_FILES = $(XML_REF3_FILES)" + @echo "XML_REF4_FILES = $(XML_REF4_FILES)" + @echo "XML_CHAPTER_FILES = $(XML_CHAPTER_FILES)" + @echo "" + @echo "GIF_FILES = $(GIF_FILES)" + @echo "" + @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)" + @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)" + @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)" + @echo "" + @echo "MAN1_FILES = $(MAN1_FILES)" + @echo "MAN3_FILES = $(MAN3_FILES)" + @echo "MAN4_FILES = $(MAN4_FILES)" + @echo "" + @echo "HTML_FILES = $(HTML_FILES)" + @echo "TOP_HTML_FILES = $(TOP_HTML_FILES)" + @echo "" + @echo "DEFAULT_HTML_FILES = $(DEFAULT_HTML_FILES)" + @echo "DEFAULT_GIF_FILES = $(DEFAULT_GIF_FILES)" + @echo "" + @echo "" + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/otp_release_targets.mk +else +include $(DIAMETER_TOP)/make/release_targets.mk +endif + +release_docs_spec: $(LOCAL)docs + $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf + $(INSTALL_DIR) $(RELSYSDIR)/doc/html + $(INSTALL_DIR) $(RELEASE_PATH)/man/man1 + $(INSTALL_DIR) $(RELEASE_PATH)/man/man3 + $(INSTALL_DIR) $(RELEASE_PATH)/man/man4 + $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf + $(INSTALL_DATA) $(HTMLDIR)/*.* $(RELSYSDIR)/doc/html + $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR) + $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1 + $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3 + $(INSTALL_DATA) $(MAN4_FILES) $(RELEASE_PATH)/man/man4 + [ -z "$(LOCAL)" ] || cp -r $(HTMLDIR)/js $(RELSYSDIR)/doc/html + echo $(LOCAL) + +release_spec: + +depend.mk: depend.sed $(XML_REF_FILES) $(XML_CHAPTER_FILES) Makefile + (for f in $(XML_REF_FILES) $(XML_CHAPTER_FILES); do \ + sed -f $< $$f | sed "s@%FILE%@`basename $$f .xml`@g"; \ + done) \ + > $@ + +-include depend.mk + +.PHONY: clean clean_html clean_man clean_pdf \ + depend debug opt info \ + docs gifs html ldocs man pdf \ + release_docs_spec release_spec diff --git a/lib/diameter/doc/src/book.xml b/lib/diameter/doc/src/book.xml new file mode 100644 index 0000000000..960296528b --- /dev/null +++ b/lib/diameter/doc/src/book.xml @@ -0,0 +1,56 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE book SYSTEM "book.dtd"> + +<book xmlns:xi="http://www.w3.org/2001/XInclude"> + +<header titlestyle="normal"> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>Diameter</title> +<prepared></prepared> +<docno></docno> +<date></date> +<rev></rev> +<file>book.xml</file> +</header> + +<insidecover> +</insidecover> + +<pagetext>Diameter</pagetext> + +<preamble> +<contents level="2"></contents> +</preamble> + +<parts lift="no"> +<xi:include href="user_man.xml"/> +</parts> + +<applications> +<xi:include href="ref_man.xml"/> +</applications> + +<releasenotes> +<xi:include href="notes.xml"/> +</releasenotes> + +<index></index> + +</book> diff --git a/lib/diameter/doc/src/depend.sed b/lib/diameter/doc/src/depend.sed new file mode 100644 index 0000000000..5973c4586e --- /dev/null +++ b/lib/diameter/doc/src/depend.sed @@ -0,0 +1,34 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +# +# Generate dependencies for html output. The output is further +# massaged in Makefile. +# + +/^<com>\([^<]*\)<\/com>/b rf +/^<module>\([^<]*\)<\/module>/b rf + +/^<chapter>/!d + +s@@$(HTMLDIR)/%FILE%.html: %FILE%.xml@ +q + +:rf +s@@$(HTMLDIR)/\1.html: %FILE%.xml@ +q diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml new file mode 100644 index 0000000000..36b6cbf0cf --- /dev/null +++ b/lib/diameter/doc/src/diameter.xml @@ -0,0 +1,1154 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> +<header> + +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>diameter(3)</title> + +<prepared>Anders Svensson</prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev>%VSN%</rev> +<file>diameter.xml</file> + +</header> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<module>diameter</module> +<modulesummary>Main API of the diameter application.</modulesummary> + +<description> +<p> +This module provides the interface with which a user +creates a service that sends and receives messages using the +Diameter protocol as defined in RFC 3588.</p> + +<p> +Basic usage consists of creating a representation of a +locally implemented Diameter peer and its capabilities with <seealso +marker="#start_service">start_service/2</seealso>, adding transport +capability using <seealso +marker="#add_transport">add_transport/2</seealso> and sending Diameter +requests and receiving Diameter answers with <seealso +marker="#call">call/4</seealso>. +Incoming Diameter requests are communicated as callbacks to a +<seealso +marker="diameter_app">diameter_app(3)</seealso> callback modules as +specified in the service configuration.</p> + +<p> +Beware the difference between <em>diameter application</em> and +<em>Diameter application</em>. +The former refers to the Erlang application named diameter whose main +api is defined here, the latter to an application of the Diameter +protocol in the sense of RFC 3588. +More generally, capitalized Diameter refers to the RFC +and diameter to this implementation.</p> + +<p> +The diameter application must be started before calling functions in +this module.</p> + +</description> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> +<section> +<title>DATA TYPES</title> + +<taglist> + +<tag><c>Address()</c></tag> +<tag><c>DiameterIdentity()</c></tag> +<tag><c>Time()</c></tag> +<tag><c>Unsigned32()</c></tag> +<tag><c>UTF8String()</c></tag> +<item> +<p> +Types corresponding to RFC 3588 AVP Data Formats. +Defined in <seealso marker="diameter_dict">diameter_dict(4)</seealso>.</p> + +<marker id="application_alias"/> +</item> + +<tag><c>application_alias() = term()</c></tag> +<item> +<p> +A name identifying a Diameter application in +service configuration passed to <seealso +marker="#start_service">start_service/2</seealso> and passed to +<seealso marker="#call">call/4</seealso> when sending requests +belonging to the application.</p> + +<marker id="application_module"/> +</item> + +<tag><c>application_module() = Mod | [Mod | ExtraArgs]</c></tag> +<item> +<code> +Mod = atom() +ExtraArgs = list() +</code> + +<p> +A module implementing the callback interface defined in <seealso +marker="diameter_app">diameter_app(3)</seealso>, along with any +extra arguments to be appended to those documented for the interface. +Any extra arguments are appended to the documented list of arguments for +each function. +Note that additional arguments specific to an outgoing request be +specified to <seealso marker="#call">call/4</seealso>, in which case +the call-specific arguments are appended to any specified with the +callback module.</p> + +<marker id="application_opt"/> +</item> + +<tag><c>application_opt()</c></tag> +<item> + +<p> +Options defining a Diameter application as configured in an +<c>application</c> option passed to +<seealso marker="#start_service">start_service/2</seealso>.</p> + +<taglist> + +<tag><c>{alias, application_alias()}</c></tag> +<item> +<p> +An unique identifier for the application in the scope of the +service. +Optional, defaults to the value of the <c>dictionary</c> option.</p> +</item> + +<tag><c>{dictionary, atom()}</c></tag> +<item> +<p> +The name of an encode/decode module for the Diameter +messages defined by the application. +These modules are generated from a specification file whose format is +documented in <seealso +marker="diameter_dict">diameter_dict(4)</seealso>.</p> +</item> + +<tag><c>{module, application_module()}</c></tag> +<item> +<p> +A callback module with which messages of the Diameter application are +handled. +See <seealso marker="diameter_app">diameter_app(3)</seealso> for +information on the required interface and semantics.</p> +</item> + +<tag><c>{state, term()}</c></tag> +<item> +<p> +The initial callback state. +Defaults to the value of the <c>alias</c> option if unspecified. +The prevailing state is passed to certain +<seealso marker="diameter_app">diameter_app(3)</seealso> +callbacks, which can then return a new state.</p> +</item> + +<tag><c>{call_mutates_state, true|false}</c></tag> +<item> +<p> +Specifies whether or not the <seealso +marker="diameter_app#pick_peer">pick_peer/4</seealso> +application callback (following from a call to +<seealso marker="#call">call/4</seealso>) +can modifiy state, +Defaults to <c>false</c> if unspecified.</p> + +<p> +Note that <seealso +marker="diameter_app#pick_peer">pick_peer</seealso> callbacks are +serialized when these are allowed to modify state, which is a +potential performance bottleneck. +A simple Diameter client may suffer no ill effects from using mutable +state but a server or agent that responds to incoming request but +sending its own requests should probably avoid it.</p> +</item> + +<tag><c>{answer_errors, callback|report|discard}</c></tag> +<item> +<p> +Determines the manner in which incoming answer messages containing +decode errors are handled. +If <c>callback</c> then errors result in a <seealso +marker="diameter_app#handle_answer">handle_answer/4</seealso> +callback in the same fashion as for <seealso +marker="diameter_app#handle_request">handle_request/3</seealso>, in the +<c>errors</c> field of the <c>diameter_packet</c> record passed into +the callback. +If <c>report</c> then an answer containing errors is discarded +without a callback and a warning report is written to the log. +If <c>discard</c> then an answer containing errors is silently +discarded without a callback. +In both the <c>report</c> and <c>discard</c> cases the return value +for the <seealso marker="#call">call/4</seealso> invocation in +question is as if a callback had taken place and returned +<c>{error, failure}</c>.</p> + +<p> +Defaults to <c>report</c> if unspecified.</p> +</item> + +</taglist> + +<marker id="call_opt"/> +</item> + +<tag><c>call_opt()</c></tag> +<item> + +<p> +Options available to <seealso marker="#call">call/4</seealso> when +sending an outgoing Diameter request.</p> + +<taglist> + +<tag><c>{extra, list()}</c></tag> +<item> +<p> +Extra arguments to append to callbacks to the callback +module in question. +These are appended to any extra arguments configured with the callback +itself. +Multiple options append to the argument list.</p> +</item> + +<tag><c>{filter, peer_filter()}</c></tag> +<item> +<p> +A filter to apply to the list of available peers before passing them to +the <seealso marker="diameter_app#pick_peer">pick_peer/4</seealso> +callback for the application in question. +Multiple options are equivalent a single <c>all</c> filter on the +corresponding list of filters. +Defaults to <c>none</c>.</p> +</item> + +<tag><c>{timeout, Unsigned32()}</c></tag> +<item> +<p> +The number of milliseconds after which the request should +timeout. +Defaults to 5000.</p> +</item> + +<tag><c>detach</c></tag> +<item> +<p> +Causes <seealso marker="#call">call/4</seealso> to return <c>ok</c> as +soon as the request in +question has been encoded instead of waiting for and returning +the result from a subsequent +<seealso marker="diameter_app#handle_answer">handle_answer/4</seealso> +or <seealso +marker="diameter_app#handle_error">handle_error/4</seealso> +callback.</p> +</item> + +</taglist> + +<marker id="capability"/> +</item> + +<tag><c>capability()</c></tag> +<item> + +<p> +AVP values used in outgoing CER/CEA messages during capabilities exchange. +Can be configured both on a service and a transport, the latter taking +precedence over the former.</p> + +<taglist> + +<tag><c>{'Origin-Host', DiameterIdentity()}</c></tag> +<item> +<p> +Value of the Origin-Host AVP in outgoing messages.</p> +</item> + +<tag><c>{'Origin-Realm', DiameterIdentity()}</c></tag> +<item> +<p> +Value of the Origin-Realm AVP in outgoing messages.</p> +</item> + +<tag><c>{'Host-IP-Address', [Address()]}</c></tag> +<item> +<p> +Values of Host-IP-Address AVPs. +Optional.</p> + +<p> +The list of addresses is available to the start function of a +transport module, which either uses them as is or returns a new list +(typically as configured as <c>transport_config()</c> on the +transport module in question) in order for the correct list of +addresses to be sent in capabilities exchange messages.</p> +</item> + +<tag><c>{'Vendor-Id', Unsigned32()}</c></tag> +<item> +<p> +Value of the Vendor-Id AVP sent in an outgoing capabilities +exchange message.</p> +</item> + +<tag><c>{'Product-Name', UTF8String()}</c></tag> +<item> +<p> +Value of the Product-Name AVP sent in an outgoing capabilities +exchange message.</p> +</item> + +<tag><c>{'Origin-State-Id', Unsigned32()}</c></tag> +<item> +<p> +Value of Origin-State-Id to be included in outgoing messages sent by +diameter itself. +In particular, the AVP will be included in CER/CEA and DWR/DWA messages. +Optional.</p> + +<p> +Setting a value of <c>0</c> (zero) is equivalent to not setting a +value as documented in RFC 3588. +The function <seealso +marker="#origin_state_id">origin_state_id/0</seealso> +can be used as to retrieve a value that is set when the diameter +application is started.</p> +</item> + +<tag><c>{'Supported-Vendor-Id', [Unsigned32()]}</c></tag> +<item> +<p> +Values of Supported-Vendor-Id AVPs sent in an outgoing +capabilities exchange message. +Optional, defaults to the empty list.</p> +</item> + +<tag><c>{'Auth-Application-Id', [Unsigned32()]}</c></tag> +<item> +<p> +Values of Auth-Application-Id AVPs sent in an outgoing +capabilities exchange message. +Optional, defaults to the empty list.</p> +</item> + +<tag><c>{'Acct-Application-Id', [Unsigned32()]}</c></tag> +<item> +<p> +Values of Acct-Application-Id AVPs sent in an outgoing +capabilities exchange message. +Optional, defaults to the empty list.</p> +</item> + +<tag><c>{'Vendor-Specific-Application-Id', [Grouped()]}</c></tag> +<item> +<p> +Values of Vendor-Specific-Application-Id AVPs sent in +an outgoing capabilities exchange message. +Optional, defaults to the empty list.</p> +</item> + +<tag><c>{'Firmware-Revision', Unsigned32()}</c></tag> +<item> +<p> +Value of the Firmware-Revision AVP sent in an outgoing capabilities +exchange message. +Optional.</p> +</item> + +</taglist> + +<p> +Note that each tuple communicates one or more AVP values. +It is an error to specify duplicate tuples.</p> + +<marker id="evaluable"/> +</item> + +<tag><c>evaluable() = {M,F,A} | fun() | [evaluable() | A]</c></tag> +<item> +<p> +An expression that can be evaluated as a function in the following +sense.</p> + +<code> +eval([{M,F,A} | T]) -> + apply(M, F, T ++ A); +eval([F|A]) -> + apply(F, A); +eval(F) -> + eval([F]). +</code> + +<p> +Evaluating an evaluable() <c>E</c> on an argument list <c>A</c> +is meant in the sense of <c>eval([E|A])</c>.</p> + +<p> +Beware of using local funs (that is, fun expressions not of the +form <c>fun Module:Name/Arity</c>) in situations in which the fun is +not short-lived and code is to be upgraded at runtime since any +processes retaining such a fun will have a reference to old code.</p> + +<marker id="peer_filter"/> +</item> + +<tag><c>peer_filter() = term()</c></tag> +<item> +<p> +A filter passed to <seealso marker="#call">call/4</seealso> +in order to select candidate peers for a +<seealso marker="diameter_app#pick_peer">pick_peer/4</seealso> +callback. +Has one of the following types.</p> + +<taglist> + +<tag><c>none</c></tag> +<item> +<p> +Matches any peer. +This is a convenience that provides a filter equivalent to no +filter at all.</p> +</item> + +<tag><c>host</c></tag> +<item> +<p> +Matches only those peers whose <c>Origin-Host</c> has the same value +as <c>Destination-Host</c> in the outgoing request in question, +or any peer if the request does not contain +a <c>Destination-Host</c> AVP.</p> +</item> + +<tag><c>realm</c></tag> +<item> +<p> +Matches only those peers whose <c>Origin-Realm</c> has the same value +as <c>Destination-Realm</c> in the outgoing request in question, +or any peer if the request does not contain +a <c>Destination-Realm</c> AVP.</p> +</item> + +<tag><c>{host, any|UTF8String()}</c></tag> +<item> +<p> +Matches only those peers whose <c>Origin-Host</c> has the +specified value, or all peers if the atom <c>any</c>.</p> +</item> + +<tag><c>{realm, any|UTF8String()</c></tag> +<item> +<p> +Matches only those peers whose <c>Origin-Realm</c> has the +value, or all peers if the atom <c>any</c>.</p> +</item> + +<tag><c>{eval, evaluable()}</c></tag> +<item> +<p> +Matches only those peers for which the specified evaluable() evaluates +to true on the peer's <c>diameter_caps</c> record.</p> +</item> + +<tag><c>{neg, peer_filter()}</c></tag> +<item> +<p> +Matches only those peers not matched by the specified filter.</p> +</item> + +<tag><c>{all, [peer_filter()]}</c></tag> +<item> +<p> +Matches only those peers matched by each filter of the specified list.</p> +</item> + +<tag><c>{any, [peer_filter()]}</c></tag> +<item> +<p> +Matches only those peers matched by at least one filter of the +specified list.</p> +</item> + +</taglist> + +<marker id="service_event"/> +</item> + +<tag><c>service_event() = #diameter_event{}</c></tag> +<item> +<p> +Event message sent to processes that have subscribed using <seealso +marker="#subscribe">subscribe/1</seealso>.</p> + +<p> +The <c>info</c> field of the event record can be one of the +following.</p> + +<taglist> + +<tag><c>{up, Ref, Peer, Config, Pkt}</c></tag> +<tag><c>{up, Ref, Peer, Config}</c></tag> +<tag><c>{down, Ref, Peer, Config}</c></tag> +<item> +<code> +Ref = transport_ref() +Peer = diameter_app:peer() +Config = {connect|listen, [transport_opt()]} +Pkt = #diameter_packet{} +</code> + +<p> +Reports that the RFC 3539 watchdog state machine has +transitioned into (<c>up</c>) or out of (<c>down</c>) the open +state. +If a <c>diameter_packet</c> record is present in an <c>up</c> tuple +then there has been an exchange of capabilities exchange messages and +the record contains the received CER or CEA, otherwise the +connection has reestablished without the loss or transport +connectivity.</p> + +<p> +Note that a single up/down event for a given peer corresponds to +as many peer_up/down callbacks as there are Diameter +applications shared by the peer, as determined during capablilities +exchange. +That is, the event communicates connectivity with the +peer as a whole while the callbacks communicate connectivity with +respect to individual Diameter applications.</p> +</item> + +<tag><c>{reconnect, Ref, Opts}</c></tag> +<item> +<code> +Ref = transport_ref() +Opts = [transport_opt()] +</code> + +<p> +A connecting transport is attempting to establish/reestablish a +transport connection with a peer following <c>reconnect_timer</c> or +<c>watchdog_timer</c> expiry.</p> +</item> + +</taglist> + +<p> +For forward compatibility, a subscriber should be prepared to receive +<c>diameter_event.info</c> of forms other than those documented +above.</p> + +<marker id="service_name"/> +</item> + +<tag><c>service_name() = term()</c></tag> +<item> +<p> +The name of a service as passed to <seealso +marker="#start_service">start_service/2</seealso> and with which the +service is identified. +There can be at most one service with a given name on a given node. +Note that <c>erlang:make_ref/0</c> can be used to generate a service name +that is somewhat unique.</p> + +<marker id="service_opt"/> +</item> + +<tag><c>service_opt()</c></tag> +<item> +<p> +Options accepted by <seealso +marker="#start_service">start_service/2</seealso>. +Can be any <c>capability()</c> tuple as +well as the following.</p> + +<taglist> + +<tag><c>{application, [application_opt()]}</c></tag> +<item> +<p> +Defines a Diameter application supported by the service.</p> + +<p> +A service must define one application for each Diameter application it +intends to support. +For an outgoing Diameter request, the application is specified by +passing the desired application's <c>application_alias()</c> to +<seealso marker="#call">call/4</seealso>, while for an +incoming request the application identifier in the message +header determines the application (and callback module), the +application identifier being specified in the <seealso +marker="diameter_dict">dictionary</seealso> file defining the +application.</p> +</item> + +</taglist> + +<marker id="transport_opt"/> +</item> + +<tag><c>transport_opt()</c></tag> +<item> +<p> +Options accepted by <seealso +marker="#add_transport">add_transport/2</seealso>.</p> + +<taglist> +<tag><c>{transport_module, atom()}</c></tag> +<item> +<p> +A module implementing a transport process as defined in <seealso +marker="diameter_transport">diameter_transport(3)</seealso>. +Defaults to <c>diameter_tcp</c> if unspecified.</p> + +<p> +The interface required of a transport module is documented in <seealso +marker="diameter_transport">diameter_transport(3)</seealso>.</p> +</item> + +<tag><c>{transport_config, term()}</c></tag> +<item> +<p> +A term passed as the third argument to the <seealso +marker="diameter_transport#start">start/3</seealso> function of +the relevant <c>transport_module</c> in order to start a transport process. +Defaults to the empty list if unspecified.</p> +</item> + +<tag><c>{applications, [application_alias()]}</c></tag> +<item> +<p> +The list of Diameter applications to which usage of the transport +should be restricted. +Defaults to all applications configured on the service +in question.</p> +</item> + +<tag><c>{capabilities, [capability()]}</c></tag> +<item> +<p> +AVP's used to construct outgoing CER/CEA messages. +Any AVP specified takes precedence over a corresponding value specified +for the service in question.</p> +</item> + +<tag><c>{watchdog_timer, TwInit}</c></tag> +<item> +<code> +TwInit = Unsigned32() + | {M,F,A} +</code> + +<p> +The RFC 3539 watchdog timer. +An integer value is interpreted as the RFC's TwInit in milliseconds, +a jitter of ± 2 seconds being added at each rearming of the +timer to compute the RFC's Tw. +An MFA is expected to return the RFC's Tw directly, with jitter +applied, allowing the jitter calculation to be performed by +the callback.</p> + +<p> +An integer value must be at least 6000 as required by RFC 3539. +Defaults to 30000 if unspecified.</p> +</item> + +<tag><c>{reconnect_timer, Tc}</c></tag> +<item> +<code> +Tc = Unsigned32() +</code> + +<p> +For a connecting transport, the RFC 3588 Tc timer, in milliseconds. +Note that this timer determines the frequency with which the transport +will attempt to establish a connection with its peer only <em>before</em> +an initial connection is established: once there is an initial +connection it's watchdog_timer that determines the frequency of +reconnection attempts, as required by RFC 3539.</p> + +<p> +For a listening transport, the timer specifies the time after which a +previously connected peer will be forgotten: a connection after this time is +regarded as an initial connection rather than a reestablishment, +causing the RFC 3539 state machine to pass to state OPEN rather than +REOPEN. +Note that these semantics are not goverened by the RFC and +that a listening transport's reconnect_timer should be greater than its +peers's Tc plus jitter.</p> + +<p> +Defaults to 30000 for a connecting transport and 60000 for a listening +transport.</p> +</item> + +</taglist> + +<p> +Unrecognized options are silently ignored but are returned unmodified +by <seealso +marker="#service_info">service_info/2</seealso> and can be referred to +in predicate functions passed to <seealso +marker="#remove_transport">remove_transport/2</seealso>.</p> + +</item> + +</taglist> + +</section> + +<marker id="add_transport"/> +<funcs> + +<!-- ===================================================================== --> + +<func> +<name>add_transport(SvcName, {connect|listen, Options}) + -> {ok, Ref} | {error, Reason}</name> +<fsummary>Add transport capability to a service.</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>Options = [transport_opt()]</v> +<v>Ref = ref()</v> +<v>Reason = term()</v> +</type> +<desc> +<p> +Add transport capability to a service.</p> + +<p> +The service will start a transport process(es) in order to establish a +connection with the peer, either by connecting to the peer +(<c>connect</c>) or by accepting incoming connection requests +(<c>listen</c>). +A connecting transport establishes transport connections with at most +one peer, an listening transport potentially with many.</p> + +<p> +The diameter application takes responsibility for exchanging +CER/CEA with the peer. +Upon successful completion of capabilities exchange the service +calls each relevant application module's <seealso +marker="diameter_app#peer_up">peer_up/3</seealso> callback +after which the caller can exchange Diameter messages with the peer over +the transport. +In addition to CER/CEA, the service takes responsibility for the +handling of DWR/DWA and required by RFC 3539 as well as for DPR/DPA.</p> + +<p> +The returned reference uniquely identifies the transport within the +scope of the service. +Note that the function returns before a transport connection has been +established. +It is not an error to add a transport to a service that has not yet +been configured: a service can be started after configuring +transports.</p> + +<marker id="call"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>call(SvcName, App, Request, Options) -> ok | Answer | {error, Reason}</name> +<fsummary>Send a Diameter request message.</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>App = application_alias()</v> +<v>Request = diameter_app:message()</v> +<v>Answer = term()</v> +<v>Options = [call_opt()]</v> +</type> +<desc> +<p> +Send a Diameter request message and possibly return the answer or error.</p> + +<p> +<c>App</c> identifies the Diameter application in which the request is +defined and callbacks to the corresponding callback module +will follow as described below and in <seealso +marker="diameter_app">diameter_app(3)</seealso>. +Unless the <c>detach</c> option has been specified to cause an earlier +return, the call returns either when an answer message is received +from the peer or an error occurs. +In the case of an answer, the return value is as returned by a +<seealso +marker="diameter_app#handle_answer">handle_answer/4</seealso> +callback. +In the case of an error, whether or not the error is returned directly +by diameter or from a <seealso +marker="diameter_app#handle_error">handle_error/4</seealso> +callback depends on whether or not the outgoing request is +successfully encoded for transmission from the peer, the cases being +documented below.</p> + +<p> +If there are no suitable peers, or if +<seealso marker="diameter_app#pick_peer">pick_peer/4</seealso> +rejects them by returning 'false', then <c>{error, no_connection}</c> +is returned. +If <seealso marker="diameter_app#pick_peer">pick_peer/4</seealso> +selects a candidate peer then a request process is spawned for the +outgoing request, in which there is a +<seealso +marker="diameter_app#prepare_request">prepare_request/3</seealso> +callback, the message is encoded and sent.</p> + +<p> +There are several error cases which may prevent an +answer from being received and passed to a +<seealso marker="diameter_app#handle_answer">handle_answer/4</seealso> +callback:</p> + +<list> + +<item> +<p> +If the initial encode of the outgoing request +fails, then the request process fails and <c>{error, encode}</c> +is returned.</p> +</item> + +<item> +<p> +If the request is successfully encoded and sent but +the answer times out then a +<seealso marker="diameter_app#handle_error">handle_error/4</seealso> +callback takes place with <c>Reason = timeout</c>.</p> +</item> + +<item> +<p> +If the request is successfully encoded and sent but the service in +question is stopped before an answer is received then a +<seealso marker="diameter_app#handle_error">handle_error/4</seealso> +callback takes place <c>Reason = cancel</c>.</p> +</item> + +<item> +<p> +If the transport connection with the peer goes down after the request +has been sent but before an answer has been received then an attempt +is made to resend the request to an alternate peer. +If no such peer is available, or if the subsequent +<seealso marker="diameter_app#pick_peer">pick_peer/4</seealso> +callback rejects the candidates, then a +<seealso marker="diameter_app#handle_error">handle_error/4</seealso> +callback takes place with <c>Reason = failover</c>. +If a peer is selected then a +<seealso +marker="diameter_app#prepare_retransmit">prepare_retransmit/3</seealso> +callback takes place, after which the semantics are the same as +following an initial +<seealso marker="diameter_app#prepare_request"> +prepare_request/3</seealso> +callback.</p> +</item> + +<item> +<p> +If an encode error takes place during +retransmission then the request process fails and +<c>{error, failure}</c> is returned.</p> +</item> + +<item> +<p> +If an application callback made in processing the request fails +(pick_peer, prepare_request, prepare_retransmit, +handle_answer or handle_error) then either +<c>{error, encode}</c> or <c>{error, failure}</c> +is returned depending on whether or not there has been an +attempt to send the request over the transport.</p> +</item> + +</list> + +<p> +Note that <c>{error, encode}</c> is the only return value which +guarantees that the request has <em>not</em> been sent over the +transport.</p> + +<marker id="origin_state_id"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>origin_state_id() -> Unsigned32()</name> +<fsummary>Returns a reasonable Origin-State-Id.</fsummary> +<desc> +<p> +Return a reasonable value for use as Origin-State-Id in +outgoing messages.</p> + +<p> +The value returned is the number of seconds since 19680120T031408Z, +the first value that can be encoded as a Diameter Time(), +at the time the diameter application was started.</p> + +<marker id="remove_transport"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>remove_transport(SvcName, Pred) -> ok</name> +<fsummary>Remove previously added transports.</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>Pred = Fun | MFA | ref() | list() | true | false</v> +<v></v> +<v>Fun = fun((reference(), connect|listen, list()) -> boolean())</v> +<v> | fun((reference(), list()) -> boolean())</v> +<v> | fun((list()) -> boolean())</v> +<v>MFA = {atom(), atom(), list()}</v> +</type> +<desc> +<p> +Remove previously added transports.</p> + +<p> +<c>Pred</c> determines which transports to remove. +An arity-3-valued <c>Pred</c> removes all transports for which +<c>Pred(Ref, Type, Opts)</c> returns <c>true</c>, where <c>Type</c> and +<c>Opts</c> are as passed to <seealso +marker="#add_transport">add_transport/2</seealso> and <c>Ref</c> is +as returned by the corresponding call. +The remaining forms are equivalent to an arity-3 fun as follows.</p> + +<code> +Pred = fun(reference(), list()): fun(Ref, _, Opts) -> Pred(Ref, Opts) end +Pred = fun(list()): fun(_, _, Opts) -> Pred(Opts) end +Pred = reference(): fun(Ref, _, _) -> Pred == Ref end +Pred = list(): fun(_, _, Opts) -> [] == Pred -- Opts end +Pred = true: fun(_, _, _) -> true end +Pred = false: fun(_, _, _) -> false end +Pred = {M,F,A}: fun(Ref, Type, Opts) -> apply(M, F, [Ref, Type, Opts | A]) end +</code> + +<p> +Removing a transport causes all associated transport connections to +be broken. +A base application DPR message with +Disconnect-Cause <c>DO_NOT_WANT_TO_TALK_TO_YOU</c> will be sent +to each connected peer before disassociating the transport configuration +from the service and terminating the transport upon reception of +DPA or timeout.</p> + +<!-- TODO: document the timeout value, possibly make configurable. --> + +<marker id="service_info"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>service_info(SvcName, Item) -> Value</name> +<fsummary>Return specific information about a started service.</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>Value = term()</v> +</type> +<desc> +<p> +Return information about a started service.</p> + +<marker id="services"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>services() -> [SvcName]</name> +<fsummary>Return the list of started services.</fsummary> +<type> +<v>SvcName = service_name()</v> +</type> +<desc> +<p> +Return the list of started services.</p> + +<marker id="session_id"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>session_id(Ident) -> OctetString()</name> +<fsummary>Return a value for a Session-Id AVP.</fsummary> +<type> +<v>Ident = DiameterIdentity()</v> +</type> +<desc> +<p> +Return a value for a Session-Id AVP.</p> + +<p> +The value has the form required by section 8.8 of RFC 3588. +Ident should be the Origin-Host of the peer from which +the message containing the returned value will be sent.</p> + +<marker id="start"/> +</desc> +</func> + +<!-- ===================================================================== --> +<func> +<name>start() -> ok | {error, Reason}</name> +<fsummary>Start the diameter application.</fsummary> +<desc> +<p> +Start the diameter application.</p> + +<p> +The diameter application must be started before starting a service. +In a production system this will typically be accomplished by a boot +file, not by calling <c>start/0</c> explicitly.</p> + +<marker id="start_service"/> +</desc> +</func> + +<!-- ===================================================================== --> +<func> +<name>start_service(SvcName, Options) -> ok | {error, Reason}</name> +<fsummary>Start a Diameter service.</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>Options = [service_opt()]</v> +<v>Reason = term()</v> +</type> +<desc> +<p> +Start a diameter service.</p> + +<p> +A service defines a locally-implemented Diameter peer, specifying the +capabilities of the peer to be used during capabilities exchange and +the Diameter applications that it supports. +Transports are added to a service using <seealso +marker="#add_transport">add_transport/2</seealso>.</p> + +<marker id="stop_service"/> +</desc> +</func> + +<!-- ===================================================================== --> +<func> +<name>stop() -> ok | {error, Reason}</name> +<fsummary>Stop the diameter application.</fsummary> +<desc> +<p> +Stop the diameter application.</p> + +<p> +</p> + +<marker id="stop_service"/> +</desc> +</func> + +<!-- ===================================================================== --> +<func> +<name>stop_service(SvcName) -> ok | {error, Reason}</name> +<fsummary>Stop a Diameter service.</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>Reason = term()</v> +</type> +<desc> +<p> +Stop a diameter service.</p> + +<marker id="subscribe"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>subscribe(SvcName) -> true</name> +<fsummary>Subscribe to event messages.</fsummary> +<type> +<v>SvcName = service_name()</v> +</type> +<desc> +<p> +Subscribe to <c>service_event()</c> messages from a service.</p> + +<p> +It is not an error to subscribe to events from a service +that does not yet exist.</p> + +<marker id="unsubscribe"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>unsubscribe(SvcName) -> true</name> +<fsummary>Unsubscribe to event messages.</fsummary> +<type> +<v>SvcName = service_name()</v> +</type> +<desc> +<p> +Unsubscribe to event messages from a service.</p> + +</desc> +</func> + +</funcs> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> +<section> +<title>SEE ALSO</title> + +<p> +<seealso marker="diameter_app">diameter_app(3)</seealso>, +<seealso marker="diameter_transport">diameter_transport(3)</seealso>, +<seealso marker="diameter_dict">diameter_dict(4)</seealso></p> + +</section> + +</erlref> diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml new file mode 100644 index 0000000000..fc359b9d1d --- /dev/null +++ b/lib/diameter/doc/src/diameter_app.xml @@ -0,0 +1,608 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> +<header> + +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>diameter_app(3)</title> +<prepared>Anders Svensson</prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev>%REV%</rev> +<file>diameter_app.xml</file> + +</header> + +<module>diameter_app</module> +<modulesummary> +Callback module of a Diameter application.</modulesummary> + +<description> + +<p> +A diameter service as started by <seealso +marker="diameter#start_service">diameter:start_service/2</seealso> +configures one of more Diameter applications, each of whose +configuration specifies a callback that handles messages specific to +its application. +The messages and AVPs of the Diameter application are defined in a +dictionary file whose format is documented in +<seealso marker="diameter_dict">diameter_dict(4)</seealso> +while the callback module is documented here. +The callback module implements the Diameter application-specific +functionality of a service.</p> + +<p> +A callback module must export all of the functions documented below. +The functions themselves are of three distinct flavours:</p> + +<list> +<item> +<p> +<seealso marker="#peer_up">peer_up/3</seealso> and +<seealso marker="#peer_down">peer_down/3</seealso> signal the +attainment or loss of connectivity with a Diameter peer.</p> +</item> + +<item> +<p> +<seealso marker="#pick_peer">pick_peer/4</seealso>, +<seealso marker="#prepare_request">prepare_request/3</seealso>, +<seealso marker="#prepare_retransmit">prepare_retransmit/3</seealso>, +<seealso marker="#handle_answer">handle_answer/4</seealso> +and <seealso marker="#handle_error">handle_error/4</seealso> are (or may +be) called as a consequence of a call to <seealso +marker="diameter#call">diameter:call/4</seealso> to send an outgoing +Diameter request message.</p> +</item> + +<item> +<p> +<seealso marker="#handle_request">handle_request/3</seealso> +is called in response to an incoming Diameter request message.</p> +</item> + +</list> + +</description> + +<note> +<p> +The arities given for the the callback functions here assume no extra +arguments. +All functions will also be passed any extra arguments configured with +the callback module itself when calling <seealso +marker="diameter#start_service">diameter:start_service/2</seealso> +and, for the call-specific callbacks, any extra arguments passed to +<seealso marker="diameter#call">diameter:call/4</seealso>.</p> +</note> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<section> +<title>DATA TYPES</title> + +<taglist> + +<tag><c>capabilities() = #diameter_caps{}</c></tag> +<item> +<p> +A record containing the identities of +the local and remote Diameter peers having an established transport +connection, as well as the capabilities as +determined by capabilities exchange. +Each field of the record is a 2-tuple consisting of +values for the (local) host and (remote) peer. +Optional or possibly multiple values are encoded as lists of values, +mandatory values as the bare value.</p> +</item> + +<tag><c>message() = record() | list()</c></tag> +<item> +<p> +The representation of a Diameter message as passed to +<seealso marker="diameter#call">diameter:call/4</seealso>. +The record representation is as outlined in +<seealso +marker="diameter_dict#MESSAGE_RECORDS">diameter_dict(4)</seealso>: +a message as defined in a dictionary file is encoded as a record with +one field for each component AVP. +Equivalently, a message can also be encoded as a list whose head is +the atom-valued message name (the record name minus any +prefix specified in the relevant dictionary file) and whose tail is a +list of <c>{FieldName, FieldValue}</c> pairs.</p> + +<p> +A third representation allows a message to be specified as a list +whose head is a <c>diameter_header</c> record and whose tail is a list +of <c>diameter_avp</c> records. +This representation is used by diameter itself when relaying requests +as directed by the return value of a +<seealso marker="#handle_request">handle_request/3</seealso> +callback. +It differs from the other other two in that it bypasses the checks for +messages that do not agree with their definitions in the dictionary in +question (since relays agents must handle arbitrary request): messages +are sent exactly as specified.</p> + +</item> + +<tag><c>packet() = #diameter_packet{}</c></tag> +<item> +<p> +A container for incoming and outgoing Diameters message that's passed +through encode/decode and transport. +Fields of a packet() record should not be set in return values except +as documented.</p> +</item> + +<tag><c>peer_ref() = term()</c></tag> +<item> +<p> +A term identifying a transport connection with a Diameter peer. +Should be treated opaquely.</p> +</item> + +<tag><c>peer() = {peer_ref(), capabilities()}</c></tag> +<item> +<p> +A tuple representing a Diameter peer connection.</p> +</item> + +<tag><c>service_name() = term()</c></tag> +<item> +<p> +The service supporting the Diameter application. +Specified to <seealso +marker="diameter#start_service">diameter:start_service/2</seealso> +when starting the service.</p> +</item> + +<tag><c>state() = term()</c></tag> +<item> +<p> +The state maintained by the application callback functions +<seealso marker="#peer_up">peer_up/3</seealso>, +<seealso marker="#peer_down">peer_down/3</seealso> and (optionally) +<seealso marker="#pick_peer">pick_peer/4</seealso>. +The initial state is configured in the call to +<seealso +marker="diameter#start_service">diameter:start_service/2</seealso> +that configures the application on a service. +Callback functions returning a state are evaluated in a common +service-specific process while +those not returning state are evaluated in a request-specific +process.</p> +</item> + +</taglist> + +<marker id="peer_up"/> +</section> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<funcs> + +<func> +<name>Mod:peer_up(SvcName, Peer, State) -> NewState</name> +<fsummary>Invoked when a transport connection has been established</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>Peer = peer()</v> +<v>State = NewState = state()</v> +</type> +<desc> +<p> +Invoked when a transport connection has been established +and a successful capabilities exchange has indicated that the peer +supports the Diameter application of the application on which +the callback module in question has been configured.</p> + +<marker id="peer_down"/> +</desc> +</func> + +<func> +<name>Mod:peer_down(SvcName, Peer, State) -> NewState</name> +<fsummary>Invoked when a transport connection has been lost.</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>Peer = peer()</v> +<v>State = NewState = state()</v> +</type> +<desc> +<p> +Invoked when a transport connection has been lost following a previous +call to <seealso marker="#peer_up">peer_up/3</seealso>.</p> + +<marker id="pick_peer"/> +</desc> +</func> + +<func> +<name>Mod:pick_peer(Candidates, Reserved, SvcName, State) + -> {ok, Peer} | {Peer, NewState} | false</name> +<fsummary>Select a target peer for an outgoing request.</fsummary> +<type> +<v>Candidates = [peer()]</v> +<v>Peer = peer() | false</v> +<v>SvcName = service_name()</v> +<v>State = NewState = state()</v> +</type> +<desc> +<p> +Invoked as a consequence of a call to <seealso +marker="diameter#call">diameter:call/4</seealso> to select a destination +peer for an outgoing request, the return value indicating the selected peer. +A new application state can also be returned but only if the Diameter +application in question was +configured with the option <c>call_mutates_state</c> set to +<c>true</c>, as documented for <seealso +marker="diameter#start_service">diameter:start_service/2</seealso>.</p> + +<p> +The candidate peers list will only include those +which are selected by any <c>filter</c> option specified in the call to +<seealso marker="diameter#call">diameter:call/4</seealso>, and only +those which have indicated support for the Diameter application in +question.</p> + +<p> +The return values <c>false</c> and <c>{false, State}</c> are +equivalent when callback state is mutable, as are +<c>{ok, Peer}</c> and <c>{Peer, State}</c>. +Returning a peer as <c>false</c> causes <c>{error, no_connection}</c> +to be returned from <seealso marker="diameter#call">diameter:call/4</seealso>. +Returning a peer() from an initial pick_peer/4 callback will result in a +<seealso marker="#prepare_request">prepare_request/3</seealso> callback +followed by either <seealso +marker="#handle_answer">handle_answer/4</seealso> +or <seealso marker="#handle_error">handle_error/4</seealso> depending +on whether or not an answer message is received from the peer. +If transport with the peer is lost before this then a new <seealso +marker="#pick_peer">pick_peer/4</seealso> callback takes place to +select an alternate peer.</p> + +<p> +Note that there is no guarantee that a <seealso +marker="#pick_peer">pick_peer/4</seealso> callback to select +an alternate peer will be followed by any additional callbacks, only +that the initial <seealso +marker="#pick_peer">pick_peer/4</seealso> will be, since a +retransmission to an alternate peer is abandoned if an answer is +received from a previously selected peer.</p> + +<marker id="prepare_request"/> +</desc> + +</func> + +<func> +<name>Mod:prepare_request(Packet, SvcName, Peer) -> Action</name> +<fsummary>Return a request for encoding and transport.</fsummary> +<type> +<v>Packet = packet()</v> +<v>SvcName = service_name()</v> +<v>Peer = peer()</v> +<v>Action = {send, packet() | message()} | {discard, Reason} | discard</v> +</type> +<desc> +<p> +Invoked to return a request for encoding and transport. +Allows the sender to access the selected peer's capabilities +in order to set (for example) <c>Destination-Host</c> and/or +<c>Destination-Realm</c> in the outgoing request, although the +callback need not be limited to this usage. +Many implementations may simply want to return <c>{send, Packet}</c></p> + +<p> +A returned packet() should set the request to be encoded in its +<c>msg</c> field and can set the <c>transport_data</c> field in order +to pass information to the transport module. +Extra arguments passed to <seealso +marker="diameter#call">diameter:call/4</seealso> can be used to +communicate transport data to the callback. +A returned packet() can also set the <c>header</c> field to a +<c>diameter_header</c> record in order to specify values that should +be preserved in the outgoing request, although this should typically +not be necessary and allows the callback to set header values +inappropriately. +A returned <c>length</c>, <c>cmd_code</c> or <c>application_id</c> is +ignored.</p> + +<p> +Returning <c>{discard, Reason}</c> causes the request to be aborted +and the <seealso +marker="diameter#call">diameter:call/4</seealso> for which the +callback has taken place to return <c>{error, Reason}</c>. +Returning <c>discard</c> is equivalent to returning <c>{discard, +discarded}</c>.</p> + +<marker id="prepare_retransmit"/> +</desc> +</func> + +<func> +<name>Mod:prepare_retransmit(Packet, SvcName, Peer) -> Result</name> +<fsummary>Return a request for encoding and retransmission.</fsummary> +<type> +<v>Packet = packet()</v> +<v>SvcName = service_name()</v> +<v>Peer = peer()</v> +<v>Result = {send, packet() | message()} | {discard, Reason} | discard</v> +</type> +<desc> +<p> +Invoked to return a request for encoding and retransmission. +Has the same role as <seealso +marker="#prepare_request">prepare_request/3</seealso> in the case that +a peer connection is lost an an alternate peer selected but the +argument packet() is as returned by the initial +<c>prepare_request/3</c>.</p> + +<p> +Returning <c>{discard, Reason}</c> causes the request to be aborted +and a <seealso +marker="#handle_error">handle_error/4</seealso> callback to +take place with <c>Reason</c> as initial argument. +Returning <c>discard</c> is equivalent to returning <c>{discard, +discarded}</c>.</p> + +<marker id="handle_answer"/> +</desc> +</func> + +<func> +<name>Mod:handle_answer(Packet, Request, SvcName, Peer) -> Result</name> +<fsummary>Receive an answer message from a peer.</fsummary> +<type> +<v>Packet = packet()</v> +<v>Request = message()</v> +<v>SvcName = service_name()</v> +<v>Peer = peer()</v> +<v>Result = term()</v> +</type> +<desc> +<p> +Invoked when an answer message is received from a peer. +The return value is returned from the call to <seealso +marker="diameter#call">diameter:call/4</seealso> for which the +callback takes place unless the <c>detach</c> option was +specified.</p> + +<p> +The decoded answer record is in the <c>msg</c> field of the argument +packet(), +the undecoded binary in the <c>packet</c> field. +<c>Request</c> is the outgoing request message as was returned from +<seealso marker="#prepare_request">prepare_request/3</seealso> or +<seealso marker="#prepare_retransmit">prepare_retransmit/3</seealso> +before the request was passed to the transport.</p> + +<p> +For any given call to <seealso +marker="diameter#call">diameter:call/4</seealso> there is at most one +call to the handle_answer callback of the application in question: any +duplicate answer (due to retransmission or otherwise) is discarded. +Similarly, only one of <c>handle_answer/4</c> or <c>handle_error/4</c> is +called for any given request.</p> + +<p> +By default, an incoming answer message that cannot be successfully +decoded causes the request process in question to fail, causing the +relevant call to <seealso +marker="diameter#call">diameter:call/4</seealso> +to return <c>{error, failure} (unless the <c>detach</c> option was +specified)</c>. +In particular, there is no <c>handle_error/4</c> callback in this +case. +Application configuration may change this behaviour as described for +<seealso +marker="diameter#start_service">diameter:start_service/2</seealso>.</p> + +<marker id="handle_error"/> +</desc> +</func> + +<func> +<name>Mod:handle_error(Reason, Request, SvcName, Peer) -> Result</name> +<fsummary>Return an error from a outgoing request.</fsummary> +<type> +<v>Reason = timeout | failover | term()</v> +<v>Request = message()</v> +<v>SvcName = service_name()</v> +<v>Peer = peer()</v> +<v>Result = term()</v> +</type> +<desc> +<p> +Invoked when an error occurs before an answer message is received from +a peer in response to an outgoing request. +The return value is returned from the call to <seealso +marker="diameter#call">diameter:call/4</seealso> for which the +callback takes place (unless the <c>detach</c> option was +specified).</p> + +<p> +Reason <c>timeout</c> indicates that an answer message has not been +received within the required time. +Reason <c>failover</c> indicates +that the transport connection to the peer to which the request has +been sent has been lost but that not alternate node was available, +possibly because a <seealso marker="#pick_peer">pick_peer/4</seealso> +callback returned false.</p> + +<marker id="handle_request"/> +</desc> +</func> + +<func> +<name>Mod:handle_request(Packet, SvcName, Peer) -> Action</name> +<fsummary>Receive an incoming request.</fsummary> +<type> +<v>Packet = packet()</v> +<v>SvcName = term()</v> +<v>Peer = peer()</v> +<v>Action = Reply | {relay, Opts} | discard | {eval, Action, ContF}</v> +<v>Reply = {reply, message()} + | {protocol_error, 3000..3999}</v> +<v>Opts = diameter:call_opts()</v> +<v>ContF = diameter:evaluable()</v> +</type> +<desc> +<p> +Invoked when a request message is received from a peer. +The application in which the callback takes place (that is, the +callback module as configured with <seealso +marker="diameter#start_service">diameter:start_service/2</seealso>) +is determined by the Application Identifier in the header of the +incoming request message, the selected module being the one +whose corresponding <seealso +marker="diameter_dict#MESSAGE_RECORDS">dictionary</seealso> declares +itself as defining either the application in question or the Relay +application.</p> + +<p> +The argument packet() has the following signature.</p> + +<code> +#diameter_packet{header = #diameter_header{}, + avps = [#diameter_avp{}], + msg = record() | undefined, + errors = ['Unsigned32'() | {'Unsigned32'(), #diameter_avp{}}], + bin = binary(), + transport_data = term()} +</code> + +<p> +The <c>msg</c> field will be <c>undefined</c> only in case the request has +been received in the relay application. +Otherwise it contains the record representing the request as outlined +in <seealso +marker="diameter_dict#MESSAGE_RECORDS">diameter_dict(4)</seealso>.</p> + +<p> +The <c>errors</c> field specifies any Result-Code's identifying errors +that were encountered in decoding the request. +In this case diameter will set both Result-Code and +Failed-AVP AVP's in a returned +answer message() before sending it to the peer: +the returned message() need only set any other required AVP's. +Note that the errors detected by diameter are all of the 5xxx series +(Permanent Failures). +The <c>errors</c> list is empty if the request has been received in +the relay application.</p> + +<p> +The <c>transport_data</c> field contains an arbitrary term passed into +diameter from the transport module in question, or the atom +<c>undefined</c> if the transport specified no data. +The term is preserved in the packet() containing any answer message +sent back to the transport process unless another value is explicitly +specified.</p> + +<p> +The semantics of each of the possible return values are as follows.</p> + +<taglist> + +<tag><c>{reply, message()}</c></tag> +<item> +<p> +Send the specified answer message to the peer.</p> +</item> + +<tag><c>{protocol_error, 3000..3999}</c></tag> +<item> +<p> +Send an answer message to the peer containing the specified +protocol error. +Equivalent to</p> +<code> +{reply, ['answer-message' | Avps] +</code> +<p> +where <c>Avps</c> sets the Origin-Host, Origin-Realm, the specified +Result-Code and (if the request sent one) Session-Id AVP's.</p> + +<p> +Note that RFC 3588 mandates that only answers with a 3xxx series +Result-Code (protocol errors) may set the E bit. +Returning a non-3xxx value in a <c>protocol_error</c> tuple +will cause the request process in question to fail.</p> +</item> + +<tag><c>{relay, Opts}</c></tag> +<item> +<p> +Relay a request to another peer. +The appropriate Route-Record AVP will be added to the relayed request +by diameter and <seealso marker="#pick_peer">pick_peer/4</seealso> +and <seealso marker="#prepare_request">prepare_request/3</seealso> +callback will take place just as if <seealso +marker="diameter#call">diameter:call/4</seealso> had been called +explicitly. +However, returning a <c>relay</c> tuple also causes the End-to-End +Identifier to be preserved in the header of the relayed request as +required by RFC 3588.</p> + +<p> +The returned <c>Opts</c> should not specify <c>detach</c> and +the <seealso marker="#handle_answer">handle_answer/4</seealso> +callback following from a relayed request must return its first +argument, the <c>diameter_packet</c> record containing the answer +message. +Note that the <c>extra</c> option can be specified to supply arguments +that can distinguish the relay case from others if so desired, +although the form of the request message may be sufficient.</p> +</item> + +<tag><c>discard</c></tag> +<item> +<p> +Discard the request.</p> +</item> + +<tag><c>{eval, Action, ContF}</c></tag> +<item> +<p> +Handle the request as if <c>Action</c> has been returned and then +evaluate <c>ContF</c> in the request process.</p> +</item> + +</taglist> + +<p> +Note that diameter will respond to protocol errors in an incoming +request without invoking <c>handle_request/3</c>.</p> + +</desc> +</func> + +</funcs> + +</erlref> diff --git a/lib/diameter/doc/src/diameter_compile.xml b/lib/diameter/doc/src/diameter_compile.xml new file mode 100644 index 0000000000..72bac30709 --- /dev/null +++ b/lib/diameter/doc/src/diameter_compile.xml @@ -0,0 +1,124 @@ +<?xml version="1.0" encoding="iso-8859-1" ?> +<!DOCTYPE comref SYSTEM "comref.dtd"> + +<comref> +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> + +The program may be used and/or copied only with the written permission +from Ericsson AB, or in accordance with the terms and conditions +stipulated in the agreement/contract under which the program has been +supplied. + +</legalnotice> + +<title>diameterc(1)</title> + +<prepared></prepared> +<docno></docno> +<date></date> +<rev></rev> +<file>diameter_compile.xml</file> +</header> + +<com>diameterc</com> +<comsummary><![CDATA[diameterc [<options>] <file>]]></comsummary> + +<description> + +<p> +The diameterc utility is used to transform diameter +<seealso marker="diameter_dict">dictionary files</seealso> +into Erlang source. +The resulting source implements the interface diameter requires +to encode and decode the dictionary's messages and AVP's.</p> + +</description> + +<section> +<title>USAGE</title> + +<taglist> + +<tag><![CDATA[diameterc [<options>] <file>]]></tag> +<item> +<p> +Transforms a single dictionary file. Valid options are as follows.</p> + +<!-- Leave -h/d/v undocumented, except for the usage message from the + utility itself. --> + +<taglist> +<tag><![CDATA[-o <dir>]]></tag> +<item> +<p> +Specifies the directory into which the generated source should be written. +Defaults to the current working directory.</p> +</item> + +<tag><![CDATA[-i <dir>]]></tag> +<item> +<p> +Specifies a directory to add to the code path. +Typically used to point at beam files corresponding to dictionaries +included by the one being compiled (using the <c>@includes</c> directive): +inclusion is a beam dependency, not an erl/hrl dependency.</p> + +<p> +Multiple <c>-i</c> options can be specified.</p> +</item> + +<tag><![CDATA[-E]]></tag> +<item> +<p> +Supresses erl generation.</p> +</item> + +<tag><![CDATA[-H]]></tag> +<item> +<p> +Supresses hrl generation.</p> +</item> + +</taglist> + +</item> +</taglist> + +</section> + +<!-- ===================================================================== --> + +<section> +<title>EXIT STATUS</title> + +<p> +Returns 0 on success, non-zero on failure.</p> + +</section> + +<!-- ===================================================================== --> + +<section> +<title>BUGS</title> + +<p> +The identification of errors in the source file is poor.</p> + +</section> + +<!-- ===================================================================== --> + +<section> +<title>SEE ALSO</title> + +<p> +<seealso marker="diameter_dict">diameter_dict(4)</seealso></p> + +</section> + +</comref> diff --git a/lib/diameter/doc/src/diameter_dict.xml b/lib/diameter/doc/src/diameter_dict.xml new file mode 100644 index 0000000000..a87f59bad5 --- /dev/null +++ b/lib/diameter/doc/src/diameter_dict.xml @@ -0,0 +1,608 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "fileref.dtd"> + +<fileref> +<header> + +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>diameter_dict(4)</title> +<prepared>Anders Svensson</prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev>%VSN%</rev> +<file>diameter_dict.xml</file> +</header> + +<!-- ===================================================================== --> + +<file>diameter_dict</file> +<filesummary>Dictionary inteface of the diameter application.</filesummary> + +<description> +<p> +A diameter service as configured with <seealso +marker="diameter#start_service">diameter:start_service/2</seealso> +specifies one or more supported Diameter applications. +Each Diameter application specifies a dictionary module that knows how +to encode and decode its messages and AVP's. +The dictionary module is in turn generated from a file that defines +these messages and AVP's. +The format of such a file is defined in +<seealso marker="#FILE_FORMAT">FILE FORMAT</seealso> below. +Users add support for their specific applications by creating +dictionary files, compiling them to Erlang modules using +<seealso marker="diameterc">diameterc</seealso> and configuring the +resulting dictionaries modules on a service.</p> + +<p> +The codec generation also results in a hrl file that defines records +for the messages and grouped AVP's defined for the application, these +records being what a user of the diameter application sends and receives. +(Modulo other available formats as discussed in <seealso +marker="diameter_app">diameter_app(3)</seealso>.) +These records and the underlying Erlang data types corresponding to +Diameter data formats are discussed in <seealso +marker="#MESSAGE_RECORDS">MESSAGE RECORDS</seealso> and <seealso +marker="#DATA_TYPES">DATA TYPES</seealso> respectively. +The generated hrl also contains defines for the possible values of +AVPs of type Enumerated.</p> + +<p> +The diameter application includes three dictionary modules +corresponding to applications defined in section 2.4 of RFC 3588: +<c>diameter_gen_base_rfc3588</c> for the Diameter Common Messages +application with application identifier 0, +<c>diameter_gen_accounting</c> for the Diameter Base Accounting +application with application identifier 3 and +<c>diameter_gen_relay</c>the Relay application with application +identifier 0xFFFFFFFF. +The Common Message and Relay applications are the only applications +that diameter itself has any specific knowledge of. +The Common Message application is used for messages that diameter +itself handles: CER/CEA, DWR/DWA and DPR/DPA. +The Relay application is given special treatment with regard to +encode/decode since the messages and AVP's it handles are not specifically +defined.</p> + +<marker id="FILE_FORMAT"/> +</description> + +<!-- ===================================================================== --> + +<section> +<title>FILE FORMAT</title> + +<p> +A dictionary file consists of distinct sections. +Each section starts with a line consisting of a tag +followed by zero or more arguments. +Each section ends at the the start of the next section or end of file. +Tags consist of an ampersand character followed by a keyword and are +separated from their arguments by whitespace. +Whitespace within a section separates individual tokens but its +quantity is insignificant.</p> + +<p> +The tags, their arguments and the contents of each corresponding +section are as follows. +Each section can occur only once unless otherwise specified. +The order in which sections are specified is unimportant.</p> + +<taglist> + +<tag><c>@id Number</c></tag> +<item> +<p> +Defines the integer Number as the Diameter Application Id of the +application in question. +The section has empty content.</p> + +<p> +The Application Id is set in the Diameter Header of outgoing messages +of the application, and the value in the header of an incoming message +is used to identify the relevant dictionary module.</p> + +<p> +Example:</p> + +<code> +@id 16777231 +</code> + +</item> + +<tag><c>@name Mod</c></tag> +<item> +<p> +Defines the name of the generated dictionary module. +The section has empty content. +Mod must match the regular expression '^[a-zA-Z0-9][-_a-zA-Z0-9]*$'; +that is, contains only alphanumerics, hyphens and underscores begin with an +alphanumeric.</p> + +<p> +A name is optional and defaults to the name of the dictionary file +minus any extension. +Note that a generated module must have a unique name an not colide +with another module in the system.</p> + +<p> +Example:</p> + +<code> +@name etsi_e2 +</code> + +</item> + +<tag><c>@prefix Name</c></tag> +<item> +<p> +Defines Name as the prefix to be added to record and constant names in +the generated dictionary module and hrl. +The section has empty content. +Name must be of the same form as a @name.</p> + +<p> +A prefix is optional but can +be used to disambiguate record and constant names +resulting from similarly named messages and AVP's in different +Diameter applications.</p> + +<p> +Example:</p> + +<code> +@prefix etsi_e2_ +</code> + +</item> + +<tag><c>@vendor Number Name</c></tag> +<item> +<p> +Defines the integer Number as the the default Vendor-ID of AVP's for +which the V flag is set. +Name documents the owner of the application +but is otherwise unused. +The section has empty content.</p> + +<p> +Example:</p> + +<code> +@vendor 13019 ETSI +</code> + +</item> + +<tag><c>@avp_vendor_id Number</c></tag> +<item> +<p> +Defines the integer Number as the Vendor-ID of the AVP's listed in the +section content, overriding the <c>@vendor</c> default. +The section content consists of AVP names. +Can occur zero or more times (with different values of Number).</p> + +<p> +Example:</p> + +<code> +@avp_vendor_id 2937 + +WWW-Auth +Domain-Index +Region-Set +</code> + +</item> + +<tag><c>@inherits Mod</c></tag> +<item> +<p> +Defines the name of a generated dictionary module containing AVP +definitions referenced by the dictionary but not defined by it. +The section content is empty.</p> + +<p> +Can occur 0 or more times (with different values of Mod) but all +dictionaries should typically inherit RFC3588 AVPs from +<c>diameter_gen_base_rfc3588</c>.</p> + +<p> +Example:</p> + +<code> +@inherits diameter_gen_base_rfc3588 +</code> + +</item> + +<tag><c>@avp_types</c></tag> +<item> +<p> +Defines the name, code, type and flags of individual AVPs. +The section consists of definitions of the form</p> + +<p><c>Name Code Type Flags</c></p> + +<p> +where Code is the integer AVP code, Flags is a string of V, +M and P characters indicating the flags to be +set on an outgoing AVP or a single - (minus) character if none are to +be set. +Type identifies either an AVP Data Format as defined in <seealso +marker="#DATA_TYPES">DATA TYPES</seealso> below or a +type as defined by a <c>@custom_types</c> tag.</p> + +<p> +Example:</p> + +<code> +@avp_types + +Location-Information 350 Grouped VM +Requested-Information 353 Enumerated V +</code> + +<p> +Note that the P flag has been deprecated by the Diameter Maintenance +and Extensions Working Group of the IETF: diameter will set the P flag +to 0 as mandated by the current draft standard.</p> + +</item> + +<tag><c>@custom_types Mod</c></tag> +<item> +<p> +Defines AVPs for which module Mod provides encode/decode. +The section contents consists of type names. +For each AVP Name defined with custom type Type, Mod should export the +function Name/3 with arguments encode|decode, Type and Data, +the latter being the term to be encoded/decoded. +The function returns the encoded/decoded value.</p> + +<p> +Can occur 0 or more times (with different values of Mod).</p> + +<p> +Example:</p> + +<code> +@custom_types rfc4005_types + +Framed-IP-Address +</code> +</item> + +<tag><c>@messages</c></tag> +<item> +<p> +Defines the messages of the application. +The section content consists of definitions of the form specified in +section 3.2 of RFC 3588, "Command Code ABNF specification".</p> + +<!-- RFC 4740 RTR/RTA --> +<code> +@messages + +RTR ::= < Diameter Header: 287, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Host } + { SIP-Deregistration-Reason } + [ Destination-Realm ] + [ User-Name ] + * [ SIP-AOR ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +RTA ::= < Diameter Header: 287, PXY > + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] +</code> + +</item> + +<tag><c>@grouped</c></tag> +<item> +<p> +Defines the contents of the AVPs of the application having type +Grouped. +The section content consists of definitions of the form specified in +section 4.4 of RFC 3588, "Grouped AVP Values".</p> + +<p> +Example:</p> + +<code> +@grouped + +SIP-Deregistration-Reason ::= < AVP Header: 383 > + { SIP-Reason-Code } + [ SIP-Reason-Info ] + * [ AVP ] +</code> +</item> + +<tag><c>@enum Name</c></tag> +<item> +<p> +Defines values of AVP Name having type Enumerated. +Section content consists of names and corresponding integer values. +Integer values can be prefixed with 0x to be interpreted as +hexidecimal.</p> + +<p> +Can occur 0 or more times (with different values of Name).</p> + +<p> +Example:</p> + +<code> +@enum SIP-Reason-Code + +PERMANENT_TERMINATION 0 +NEW_SIP_SERVER_ASSIGNED 1 +SIP_SERVER_CHANGE 2 +REMOVE_SIP_SERVER 3 +</code> +</item> + +</taglist> + +<p> +Comments can be included in a dictionary file using semicolon: +text from a semicolon to end of line is ignored.</p> + +<marker id="MESSAGE_RECORDS"/> +</section> + +<!-- ===================================================================== --> + +<section> +<title>MESSAGE RECORDS</title> + +<p> +The hrl generated from a dictionary specification defines records for the +messages and grouped AVPs defined in <c>@messages</c> and +<c>@grouped</c> sections. +For each message or grouped AVP definition, a record is defined whose +name is the message or AVP name prefixed with any dictionary prefix +defined with <c>@prefix</c> and whose fields are the names of the AVPs +contained in the message or grouped AVP in the order specified in the +definition in question. +For example, the grouped AVP</p> + +<code> +SIP-Deregistration-Reason ::= < AVP Header: 383 > + { SIP-Reason-Code } + [ SIP-Reason-Info ] + * [ AVP ] +</code> + +<p> +will result in the following record definition given an empty +prefix.</p> + +<code> +-record('SIP-Deregistration-Reason' {'SIP-Reason-Code', + 'SIP-Reason-Info', + 'AVP'}). +</code> + +<p> +The values encoded in the fields of generated records depends on the +type and number of times the AVP can occur. +In particular, an AVP which is specified as occurring exactly once is +encoded as a value of the AVP's type while an AVP with any other +specification is encoded as a list of values of the AVP's type. +The AVP's type is as specified in the AVP definition, the RFC 3588 +types being described below.</p> + +<marker id="DATA_TYPES"/> +</section> + +<!-- ===================================================================== --> + +<section> +<title>DATA TYPES</title> + +<p> +The data formats defined in sections 4.2 ("Basic AVP Data +Formats") and 4.3 ("Derived AVP Data Formats") of RFC 3588 are encoded +as values of the types defined here. +Values are passed to <seealso +marker="diameter#call">diameter:call/4</seealso> +in a request record when sending a request, returned in a resulting +answer record and passed to a <seealso +marker="diameter_app#handle_request">handle_request</seealso> +callback upon reception of an incoming request.</p> + +<p> +<em>Basic AVP Data Formats</em></p> + +<marker id="OctetString"/> +<marker id="Integer32"/> +<marker id="Integer64"/> +<marker id="Unsigned32"/> +<marker id="Unsigned64"/> +<marker id="Float32"/> +<marker id="Float64"/> +<marker id="Grouped"/> + +<code> +OctetString() = [0..255] +Integer32() = -2147483647..2147483647 +Integer64() = -9223372036854775807..9223372036854775807 +Unsigned32() = 0..4294967295 +Unsigned64() = 0..18446744073709551615 +Float32() = '-infinity' | float() | infinity +Float64() = '-infinity' | float() | infinity +Grouped() = record() +</code> + +<p> +On encode, an OctetString() can be specified as an iolist(), +excessively large floats (in absolute value) are equivalent to +<c>infinity</c> or <c>'-infinity'</c> and excessively large integers +result in encode failure. +The records for grouped AVPs are as discussed in the previous +section.</p> + +<p> +<em>Derived AVP Data Formats</em></p> + +<marker id="Address"/> +<code> +Address() = OctetString() + | tuple() +</code> + +<p> +On encode, an OctetString() IPv4 address is parsed in the usual +x.x.x.x format while an IPv6 address is parsed in any of the formats +specified by section 2.2 of RFC 2373, "Text Representation of +Addresses". +An IPv4 tuple() has length 4 and contains values of type 0..255. +An IPv6 tuple() has length 8 and contains values of type 0..65535. +The tuple representation is used on decode.</p> + +<marker id="Time"/> +<code> +Time() = {date(), time()} + +where + + date() = {Year, Month, Day} + time() = {Hour, Minute, Second} + + Year = integer() + Month = 1..12 + Day = 1..31 + Hour = 0..23 + Minute = 0..59 + Second = 0..59 +</code> + +<p> +Additionally, values that can be encoded are +limited by way of their encoding as four octets as required by RFC +3588 with the required extension from RFC 2030. +In particular, only values between <c>{{1968,1,20},{3,14,8}}</c> +and <c>{{2104,2,26},{9,42,23}}</c> (both inclusive) can be encoded.</p> + +<marker id="UTF8String"/> +<code> +UTF8String() = [integer()] +</code> + +<p> +List elements are the UTF-8 encodings of the individual characters +in the string. +Invalid codepoints will result in encode/decode failure.</p> + +<marker id="DiameterIdentity"/> +<code> +DiameterIdentity() = OctetString() +</code> + +<p> +A value must have length at least 1.</p> + +<marker id="DiameterURI"/> +<code> +DiameterURI() = OctetString() + | #diameter_URI{type = Type, + fqdn = FQDN, + port = Port, + transport = Transport, + protocol = Protocol} + +where + + Type = aaa | aaas + FQDN = OctetString() + Port = integer() + Transport = sctp | tcp + Protocol = diameter | radius | 'tacacs+' +</code> + +<p> +On encode, fields port, transport and protocol default to 3868, sctp +and diameter respectively. +The grammar of an OctetString-valued DiameterURI() is as specified in +section 4.3 of RFC 3588. +The record representation is used on decode.</p> + +<marker id="Enumerated"/> +<code> +Enumerated() = Integer32() +</code> + +<p> +On encode, values can be specified using the macros defined in a +dictionary's hrl file.</p> + +<marker id="IPFilterRule"/> +<marker id="QoSFilterRule"/> +<code> +IPFilterRule() = OctetString() +QoSFilterRule() = OctetString() +</code> + +<p> +Values of these types are not currently parsed by diameter.</p> + +</section> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<section> +<title>SEE ALSO</title> + +<p> +<seealso marker="diameterc">diameterc(1)</seealso>, +<seealso marker="diameter">diameter(3)</seealso>, +<seealso marker="diameter_app">diameter_app(3)</seealso></p> + +</section> + +</fileref> diff --git a/lib/diameter/doc/src/diameter_examples.xml b/lib/diameter/doc/src/diameter_examples.xml new file mode 100644 index 0000000000..966d1f1eee --- /dev/null +++ b/lib/diameter/doc/src/diameter_examples.xml @@ -0,0 +1,45 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> +<header> + +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> + +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>Examples</title> +<prepared></prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev></rev> +<file>diameter_examples.xml</file> +</header> + +<!-- ===================================================================== --> + +<p> +To be written. +Example code can be found in the diameter application's +<c>examples</c> subdirectory.</p> + +</chapter> + diff --git a/lib/diameter/doc/src/diameter_intro.xml b/lib/diameter/doc/src/diameter_intro.xml new file mode 100644 index 0000000000..ef08002a8b --- /dev/null +++ b/lib/diameter/doc/src/diameter_intro.xml @@ -0,0 +1,95 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> + +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>Introduction</title> +<prepared></prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev></rev> +<file>diameter_intro.xml</file> +</header> + +<p> +The diameter application is an implementation of the Diameter protocol +as defined by RFC 3588. +It supports arbitrary Diameter applications by way of a +<em>dictionary</em> interface that allows messages and AVP's to be +defined and input into diameter as configuration. +It has support for all roles defined in the RFC: client, server and +agent. +This chapter provides a short overview of the application.</p> + +<p> +A Diameter peer is implemented by configuring a <em>service</em> and +one or more <em>transports</em> using the interface module +<seealso marker="diameter">diameter</seealso>. +The service configuration defines the Diameter applications to be +supported by the peer and, typically, the capabilities that it should +send to remote peers at capabilities exchange upon the establishment +of transport connections. +A transport is configured on a service and provides protocol-specific +send/receive functionality by way of a transport interface defined by +diameter and implemented by a transport module. +The diameter application provides two transport modules: <seealso +marker="diameter_tcp">diameter_tcp</seealso> and <seealso +marker="diameter_sctp">diameter_sctp</seealso> for transport over TCP +(using <c>gen_tcp</c>) and SCTP (using <c>gen_sctp</c>) respectively. +Other transports can be provided by any module that implements +diameter's <seealso marker="diameter_transport">transport +interface</seealso>.</p> + +<p> +While a service typically implements a single Diameter peer (as +identified by an Origin-Host AVP), transports can themselves be +associated with capabilities AVP's so that a single service be used to +implement more than one Diameter peer.</p> + +<p> +Each Diameter application defined on a service is configured with a +callback module that implements the <seealso +marker="diameter_app">application interface</seealso> through which +diameter communicates the connectivity of remote peers, requests peer +selection for outgoing requests, and communicates the reception of +incoming Diameter request and answer messages. +An application using diameter implements these application callback +modules to provide the functionality of the Diameter peer(s) it +implements.</p> + +<p> +Each Diameter application is also configured with one or more +dictionary modules +that provide encode/decode functionality for outgoing/incoming +Diameter messages. +A module is generated from a <seealso +marker="diameter_dict">specification file</seealso> using the <seealso +marker="diameterc">diameterc</seealso> utility. +Dictionaries for the RFC 3588 Diameter Common Messages, Base +Accounting and Relay applications are provided by the diameter +application.</p> + +</chapter> + diff --git a/lib/diameter/doc/src/diameter_sctp.xml b/lib/diameter/doc/src/diameter_sctp.xml new file mode 100644 index 0000000000..d0377f4b38 --- /dev/null +++ b/lib/diameter/doc/src/diameter_sctp.xml @@ -0,0 +1,133 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>diameter_sctp(3)</title> +<prepared>Anders Svensson</prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev></rev> +<file>diameter_sctp.xml</file> +</header> + +<module>diameter_sctp</module> +<modulesummary>Diameter transport over SCTP.</modulesummary> + +<description> + +<p> +This module implements diameter transport over SCTP using gen_sctp. +It can be specified as the value of a transport_module option to +<seealso +marker="diameter#add_transport">diameter:add_transport/2</seealso> +and implements the behaviour documented in +<seealso marker="diameter_transport">diameter_transport(3)</seealso>.</p> + +<marker id="start"/> +</description> + +<!-- ===================================================================== --> + +<funcs> + +<func> +<name>start({Type, Ref}, Svc, [Opt]) + -> {ok, Pid, [LAddr]} | {error, Reason}</name> +<fsummary>Start a transport process.</fsummary> +<type> +<v>Type = connect | accept</v> +<v>Ref = reference()</v> +<v>Svc = #diameter_service{}</v> +<v>Opt = {raddr, ip_address()} | {rport, integer()} | term()</v> +<v>Pid = pid()</v> +<v>LAddr = ip_address()</v> +<v>Reason = term()</v> +</type> +<desc> + +<p> +The start function required by <seealso +marker="diameter_transport#start">diameter_transport(3)</seealso>.</p> + +<p> +The only diameter_sctp-specific argument is the options list. +Options <c>raddr</c> and <c>rport</c> specify the remote address +and port for a connector and not valid for a listener. +The former is required while latter defaults to 3868 if unspecified. +More than one <c>raddr</c> option can be specified, in which case the +connector in question attempts each in sequence until an association +is established. +Remaining options are any accepted by gen_sctp:open/1, with the exception +of options <c>mode</c>, <c>binary</c>, <c>list</c>, <c>active</c> +and <c>sctp_events</c>. +Note that options <c>ip</c> and <c>port</c> specify the local address +and port respectively.</p> + +<p> +Multiple <c>ip</c> options can be specified for a multihomed peer. +If none are specified then the values of Host-IP-Address +on the service are used. (In particular, one of these must be specified.) +Option <c>port</c> defaults to 3868 for a listener and 0 for a connector.</p> + +<p> +diameter_sctp uses the <c>transport_data</c> field of +the <c>diameter_packet</c> record to communicate the stream on which an +inbound message has been received, or on which an outbound message +should be sent: the value will be of the form <c>{stream, Id}</c> +on an inbound message passed to a <seealso +marker="diameter_app#handle_request">handle_request</seealso> or <seealso +marker="diameter_app#handle_answer">handle_answer</seealso> callback. +For an outbound message, either <c>undefined</c> (explicitly of +by specifying the outbound message as a <c>binary()</c>) or a tuple +should be set in the return value of <seealso +marker="diameter_app#handle_request">handle_request</seealso> +(typically by retaining the value passed into this function) +or <seealso +marker="diameter_app#prepare_request">prepare_request</seealso>. +The value <c>undefined</c> uses a "next outbound stream" id and then +increments this modulo the total number outbound streams. That +is, successive values of <c>undefined</c> cycle through all outbound +streams.</p> + +<!-- TODO: Some way of getting at the number of available outbound --> +<!-- streams. --> + +</desc> +</func> + +</funcs> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<section> +<title>SEE ALSO</title> + +<p> +<seealso marker="diameter_transport">diameter_transport(3)</seealso></p> + +</section> + +</erlref> diff --git a/lib/diameter/doc/src/diameter_soc.xml b/lib/diameter/doc/src/diameter_soc.xml new file mode 100644 index 0000000000..4f8581a904 --- /dev/null +++ b/lib/diameter/doc/src/diameter_soc.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> + +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>Standards Compliance</title> +<prepared></prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev></rev> +<file>diameter_soc.xml</file> + +</header> + +<p> +Known points of questionable or non-compliance.</p> + +<!-- ===================================================================== --> + +<section> +<title>RFC 3588</title> + +<list> + +<item> +<p> +The End-to-End Security framework (section 2.9) isn't implemented +since it is largely unspecified. +The document that was to describe it +(reference [AAACMS]) was abandoned in an uncompleted state several +years ago and the current draft RFC deprecates the framework, +including the P Flag in the AVP header.</p> +</item> + +<item> +<p> +There is no TLS support. +It's unclear (aka uninvestigated) how TLS would impact +diameter but IPsec can be used without it needing to know.</p> +</item> + +<item> +<p> +There is no explicit support for peer discovery (section 5.2). +It can possibly be implemented on top of diameter as is but this is +probably something that diameter should do. +The current draft deprecates portions of the original RFC's mechanisms +however.</p> +</item> + +<item> +<p> +The peer state machine's election process (section 5.6.4) isn't +implemented as specified since it assumes knowledge of a +peer's Origin-Host before sending it a CER. (The identity becoming known +upon reception of CEA.) +The possibility of configuring +the peer's Origin-Host could be added, along with handling of the case +that it sends something else, but for many applications this will +just be unnecessary configuration of a value that it has no control over.</p> +</item> +<!-- Transport protocol plus address/port, which we do know when + sending and receiving CER, is enough to definitely identify + the peer. However, there's nothing stopping a peer from using + different identities on different transport protocols, even + if it's maybe a bit far-fetched. --> + +</list> + +</section> + +<!-- ===================================================================== --> + +<section> +<title>RFC 3539</title> + +<p> +RFC 3539 is more difficult to comply to since it discusses +problems as much as it requires functionality but all the MUST's are +covered, the watchdog state machine being the primary one. +Of the optional functionality, load balancing is left to the +diameter user (since it's the one deciding who to send to) and +there is no Congestion Manager.</p> + +</section> + +</chapter> diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml new file mode 100644 index 0000000000..5d6e07b1b8 --- /dev/null +++ b/lib/diameter/doc/src/diameter_tcp.xml @@ -0,0 +1,110 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>diameter_tcp(3)</title> +<prepared>Anders Svensson</prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev></rev> +<file>diameter_tcp.xml</file> +</header> + +<module>diameter_tcp</module> +<modulesummary>Diameter transport over TCP.</modulesummary> + +<description> + +<p> +This module implements diameter transport over TCP using gen_tcp. +It can be specified as the value of a transport_module option to +<seealso +marker="diameter#add_transport">diameter:add_transport/2</seealso> +and implements the behaviour documented in +<seealso marker="diameter_transport">diameter_transport(3)</seealso>.</p> + +<marker id="start"/> +</description> + +<!-- ===================================================================== --> + +<funcs> + +<func> +<name>start({Type, Ref}, Svc, [Opt]) + -> {ok, Pid, [LAddr]} | {error, Reason}</name> +<fsummary>Start a transport process.</fsummary> +<type> +<v>Type = connect | accept</v> +<v>Ref = reference()</v> +<v>Svc = #diameter_service{}</v> +<v>Opt = {raddr, ip_address()} | {rport, integer()} | term()</v> +<v>Pid = pid()</v> +<v>LAddr = ip_address()</v> +<v>Reason = term()</v> +</type> +<desc> + +<p> +The start function required by <seealso +marker="diameter_transport#start">diameter_transport(3)</seealso>.</p> + +<p> +The only diameter_tcp-specific argument is the options list. +Options <c>raddr</c> and <c>rport</c> specify the remote address +and port for a connector and not valid for a listener. +Remaining options are any accepted by gen_tcp:connect/3 for +a connector, or gen_tcp:listen/2 for a listener, with the exception +of <c>binary</c>, <c>packet</c> and <c>active</c>. +Also, option <c>port</c> can be specified for a listener to specify the +local listening port, the default being the standardized 3868 if +unspecified. +Note that option <c>ip</c> specifies the local address.</p> + +<p> +If the service specifies more than one Host-IP-Address and +option <c>ip</c> is unspecified then then the +first of the service's addresses is used as the local address.</p> + +<p> +The returned local address list has length one.</p> + +</desc> +</func> + +</funcs> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<section> +<title>SEE ALSO</title> + +<p> +<seealso marker="diameter_transport">diameter_transport(3)</seealso></p> + +</section> + +</erlref> diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml new file mode 100644 index 0000000000..37cc871e75 --- /dev/null +++ b/lib/diameter/doc/src/diameter_transport.xml @@ -0,0 +1,203 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE erlref SYSTEM "erlref.dtd"> + +<erlref> +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>diameter_transport(3)</title> +<prepared>Anders Svensson</prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev></rev> +<file>diameter_transport.xml</file> +</header> + +<module>diameter_transport</module> +<modulesummary>Diameter transport interface.</modulesummary> + +<description> + +<p> +A module specified as a <c>transport_module</c> to <seealso +marker="diameter#add_transport">diameter:add_transport/2</seealso> +must implement the interface documented here. +The interface consists of a function with which +diameter starts a transport process and a message interface with which +the transport process communicates with the process that starts it (aka its +parent).</p> + +<marker id="start"/> +</description> + +<!-- ===================================================================== --> + +<funcs> + +<func> +<name>Mod:start({Type, Ref}, Svc, Opts) + -> {ok, Pid} | {ok, Pid, LAddrs} | {error, Reason}</name> +<fsummary>Start a transport process.</fsummary> +<type> +<v>Type = connect | accept</v> +<v>Ref = reference()</v> +<v>Svc = #diameter_service{}</v> +<v>Opts = term()</v> +<v>Pid = pid()</v> +<v>LAddrs = [ip_address()]</v> +<v>Reason = term()</v> +</type> +<desc> +<p> +Start a transport process. +Called by diameter as a consequence of a call to <seealso +marker="diameter#add_transport">diameter:add_transport/2</seealso> in +order to establish or accept a transport connection respectively. +A transport process maintains a connection with a single remote peer.</p> + +<p> +The first argument indicates whether the transport process in question +is being started for a connecting (<c>connect</c>) or listening +(<c>accept</c>) transport. +In the latter case, transport processes are started as required to +accept connections from multiple peers. +Ref is in each case the same value that was returned from the +call to <seealso +marker="diameter#add_transport">diameter:add_transport/2</seealso> +that has lead to starting of a transport process.</p> + +<p> +A transport process must implement the message interface documented below. +It should retain the pid of its parent, monitor the parent and terminate if +it dies. +It should not link to the parent. +It should exit if its transport connection with its peer is lost.</p> + +<p> +Transport processes for a given service are started sequentially.</p> + +<p> +The start function should use the 'Host-IP-Address' list on the service, +namely <c>Svc#diameter_service.host_ip_address</c>, and/or +<c>Opts</c> to select an appropriate list of local IP addresses, +and should return this list if different from the service addresses. +The returned list is used to populate 'Host-IP-Address' AVPs in outgoing +capabilities exchange messages, the service addresses being used +otherwise.</p> + +<marker id="MESSAGES"/> +</desc> +</func> + +</funcs> + +<!-- ===================================================================== --> + +<section> +<title>MESSAGES</title> + +<p> +All messages sent over the transport interface are of the +form <c>{diameter, term()}</c>.</p> + +<p> +A transport process can expect the following messages from +diameter.</p> + +<taglist> + +<tag><c>{diameter, {send, Packet}}</c></tag> +<item> +<p> +An outbound Diameter message. +Packet can be either <c>binary()</c> (the message to be sent) +or a <c>#diameter_packet{}</c> whose <c>transport_data</c> field +containes a value other than undefined.</p> +</item> + +<tag><c>{diameter, {close, Pid}}</c></tag> +<item> +<p> +A request to close the transport connection. +The transport process should terminate after closing the +connection. +Pid is the pid() of the parent process.</p> +</item> + +</taglist> + +<p> +A transport process should send the following messages +to its parent.</p> + +<taglist> + +<tag><c>{diameter, {self(), connected}}</c></tag> +<item> +<p> +Inform the parent that the transport process with Type = accept has +established a connection with the peer. +Not sent if the transport process has Type = connect.</p> +</item> + +<tag><c>{diameter, {self(), connected, Remote}}</c></tag> +<item> +<p> +Inform the parent that the transport process with Type = connect +has established a connection with a peer. +Not sent if the transport process has Type = accept. +Remote is an arbitrary term that uniquely identifies the remote +endpoint to which the transport has connected.</p> +</item> + +<tag><c>{diameter, {recv, Packet}}</c></tag> +<item> +<p> +An inbound Diameter message. +Packet can be either <c>binary()</c> (the message to be sent) +or <c>#diameter_packet{}</c> +whose <c>packet</c> field contains a <c>binary()</c>. +Any value (other than undefined) set in +the <c>transport_data</c> field will be passed back with a +corresponding answer message in the case that the inbound message is a +request unless the sender sets another value. +How the <c>transport_data</c> is used/interpreted is up to the +transport module.</p> +</item> + +</taglist> + +</section> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<section> +<title>SEE ALSO</title> + +<p> +<seealso marker="diameter_tcp">diameter_tcp(3)</seealso>, +<seealso marker="diameter_sctp">diameter_sctp(3)</seealso></p> + +</section> + +</erlref> diff --git a/lib/diameter/doc/src/diameter_using.xml b/lib/diameter/doc/src/diameter_using.xml new file mode 100644 index 0000000000..809b76bdf3 --- /dev/null +++ b/lib/diameter/doc/src/diameter_using.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> + +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>Using the stack</title> +<prepared></prepared> +<responsible></responsible> +<docno></docno> +<approved></approved> +<checked></checked> +<date></date> +<rev></rev> +<file>diameter_using.xml</file> + +</header> + +<p> +To be written.</p> + +<!-- ===================================================================== --> + +</chapter> diff --git a/lib/diameter/doc/src/files.mk b/lib/diameter/doc/src/files.mk new file mode 100644 index 0000000000..79d53abceb --- /dev/null +++ b/lib/diameter/doc/src/files.mk @@ -0,0 +1,52 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +XML_APPLICATION_FILES = \ + ref_man.xml + +XML_REF1_FILES = \ + diameter_compile.xml + +XML_REF3_FILES = \ + diameter.xml \ + diameter_app.xml \ + diameter_transport.xml \ + diameter_tcp.xml \ + diameter_sctp.xml + +XML_REF4_FILES = \ + diameter_dict.xml + +XML_PART_FILES = \ + user_man.xml + +XML_EXTRA_FILES = + +XML_CHAPTER_FILES = \ + diameter_intro.xml \ + diameter_using.xml \ + diameter_examples.xml \ + diameter_soc.xml \ + notes.xml + +BOOK_FILES = \ + book.xml + +GIF_FILES = \ + notes.gif diff --git a/lib/diameter/doc/src/notes.gif b/lib/diameter/doc/src/notes.gif Binary files differnew file mode 100644 index 0000000000..e000cca26a --- /dev/null +++ b/lib/diameter/doc/src/notes.gif diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml new file mode 100644 index 0000000000..eafddd7d1e --- /dev/null +++ b/lib/diameter/doc/src/notes.xml @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE chapter SYSTEM "chapter.dtd"> + +<chapter> + +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>Release Notes</title> +<prepared></prepared> +<docno></docno> +<date></date> +<rev></rev> +<file>notes.xml</file> +</header> + +<p> +Releases are listed in reverse chronological order, most recent +first.</p> + +<!-- ===================================================================== --> + +<section> +<title>diameter 0.9</title> + +<p> +Initial release of the diameter application.</p> + +<p> +Known issues or limitations:</p> + +<list> + +<item> +<p> +Some agent-related functionality is not entirely complete. +In particular, support for proxy agents, that advertise specific +Diameter applications but otherwise relay messages in much the same +way as relay agents (for which a <seealso +marker="diameter_app#handle_request">handle_request/3</seealso> +callback can return a <c>relay</c> tuple), will be completed in an +upcoming release. +There may also be more explicit support for redirect agents, although +redirect behaviour can be implemented with the current +functionality.</p> + +</item> + +<item> +<p> +There is some asymmetry in the treatment of messages sent as +<c>diameter_header/avp</c> records and those sent in the "normal" +fashion, and not all of this is documented. +This is related to the previous point since this form of sending a +message was introduced specifically to handle relay agent behaviour +using the same callback interface as for client/server behaviour.</p> +</item> + +<item> +<p> +The User's Guide is currently quite thin. +The introductory chapter followed by the examples (in the application +<c>examples</c> subdirectory) may be sufficient +for those having some familiarity with the Diameter protocol but the +intention is to provide more introductory text. +The reference documentation is quite complete, although some points +could likely be expanded upon.</p> +</item> + +<item> +<p> +The function <seealso +marker="diameter#service_info">diameter:service_info/2</seealso> +can be used to retrieve information about a started service +(statistics, information about connected peers, etc) but +this is not yet documented and both the input and output may change +in the next release.</p> +</item> + + +</list> + +<p> +See <seealso marker="diameter_soc">Standards Compliance</seealso> for +standards-related issues.</p> +</section> + +</chapter> diff --git a/lib/diameter/doc/src/ref_man.xml b/lib/diameter/doc/src/ref_man.xml new file mode 100644 index 0000000000..137ce79094 --- /dev/null +++ b/lib/diameter/doc/src/ref_man.xml @@ -0,0 +1,48 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE application SYSTEM "application.dtd"> + +<application xmlns:xi="http://www.w3.org/2001/XInclude"> + +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>Diameter Reference Manual</title> +<prepared></prepared> +<docno></docno> +<date></date> +<rev></rev> +<file>ref_man.xml</file> +</header> + +<description> +<p> +The Diameter application is a framework for building +applications on top of the Diameter protocol. </p> + +</description> + +<xi:include href="diameter.xml"/> +<xi:include href="diameter_compile.xml"/> +<xi:include href="diameter_app.xml"/> +<xi:include href="diameter_dict.xml"/> +<xi:include href="diameter_transport.xml"/> +<xi:include href="diameter_tcp.xml"/> +<xi:include href="diameter_sctp.xml"/> + +</application> diff --git a/lib/diameter/doc/src/user_man.xml b/lib/diameter/doc/src/user_man.xml new file mode 100644 index 0000000000..a6416c7e23 --- /dev/null +++ b/lib/diameter/doc/src/user_man.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="latin1" ?> +<!DOCTYPE part SYSTEM "part.dtd"> + +<part xmlns:xi="http://www.w3.org/2001/XInclude"> + +<header> +<copyright> +<year>2011</year> +<holder>Ericsson AB. All Rights Reserved.</holder> +</copyright> +<legalnotice> +The contents of this file are subject to the Erlang Public License, +Version 1.1, (the "License"); you may not use this file except in +compliance with the License. You should have received a copy of the +Erlang Public License along with this software. If not, it can be +retrieved online at http://www.erlang.org/. + +Software distributed under the License is distributed on an "AS IS" +basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +the License for the specific language governing rights and limitations +under the License. + +</legalnotice> + +<title>Diameter Users Guide</title> +<prepared></prepared> +<docno></docno> +<date></date> +<rev></rev> +<file>user_man.xml</file> +</header> +<description> + +<p> +The diameter application is a framework for building +applications on top of the Diameter protocol. </p> +</description> + +<xi:include href="diameter_intro.xml"/> +<xi:include href="diameter_using.xml"/> +<xi:include href="diameter_examples.xml"/> +<xi:include href="diameter_soc.xml"/> + +</part> diff --git a/lib/diameter/doc/standard/draft-ietf-dime-capablities-update-07.txt b/lib/diameter/doc/standard/draft-ietf-dime-capablities-update-07.txt new file mode 100644 index 0000000000..bb7ec2d08c --- /dev/null +++ b/lib/diameter/doc/standard/draft-ietf-dime-capablities-update-07.txt @@ -0,0 +1,392 @@ +
+
+
+Network Working Group K. Jiao
+Internet-Draft Huawei
+Intended status: Standards Track G. Zorn
+Expires: April 27, 2011 Network Zen
+ October 24, 2010
+
+
+ The Diameter Capabilities Update Application
+ draft-ietf-dime-capablities-update-07
+
+Abstract
+
+ This document defines a new Diameter application and associated
+ command codes. The Capabilities Update application is intended to
+ allow the dynamic update of certain Diameter peer capabilities while
+ the peer-to-peer connection is in the open state.
+
+Status of this Memo
+
+ This Internet-Draft is submitted in full conformance with the
+ provisions of BCP 78 and BCP 79.
+
+ Internet-Drafts are working documents of the Internet Engineering
+ Task Force (IETF). Note that other groups may also distribute
+ working documents as Internet-Drafts. The list of current Internet-
+ Drafts is at http://datatracker.ietf.org/drafts/current/.
+
+ Internet-Drafts are draft documents valid for a maximum of six months
+ and may be updated, replaced, or obsoleted by other documents at any
+ time. It is inappropriate to use Internet-Drafts as reference
+ material or to cite them other than as "work in progress."
+
+ This Internet-Draft will expire on April 27, 2011.
+
+Copyright Notice
+
+ Copyright (c) 2010 IETF Trust and the persons identified as the
+ document authors. All rights reserved.
+
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document. Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document. Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+
+
+
+Jiao & Zorn Expires April 27, 2011 [Page 1]
+
+Internet-Draft Diameter Capabilities Update October 2010
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3
+ 2. Specification of Requirements . . . . . . . . . . . . . . . . . 3
+ 3. Diameter Protocol Considerations . . . . . . . . . . . . . . . 3
+ 4. Capabilities Update . . . . . . . . . . . . . . . . . . . . . . 3
+ 4.1. Command-Code Values . . . . . . . . . . . . . . . . . . . . 4
+ 4.1.1. Capabilities-Update-Request . . . . . . . . . . . . . . 5
+ 4.1.2. Capabilities-Update-Answer . . . . . . . . . . . . . . 5
+ 5. Security Considerations . . . . . . . . . . . . . . . . . . . . 6
+ 6. IANA Considerations . . . . . . . . . . . . . . . . . . . . . . 6
+ 6.1. Application Identifier . . . . . . . . . . . . . . . . . . 6
+ 6.2. Command Codes . . . . . . . . . . . . . . . . . . . . . . . 6
+ 7. Contributors . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 8. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 6
+ 9. References . . . . . . . . . . . . . . . . . . . . . . . . . . 6
+ 9.1. Normative References . . . . . . . . . . . . . . . . . . . 6
+ 9.2. Informative References . . . . . . . . . . . . . . . . . . 7
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 7
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Jiao & Zorn Expires April 27, 2011 [Page 2]
+
+Internet-Draft Diameter Capabilities Update October 2010
+
+
+1. Introduction
+
+ Capabilities exchange is an important component of the Diameter Base
+ Protocol [I-D.ietf-dime-rfc3588bis], allowing peers to exchange
+ identities and Diameter capabilities (protocol version number,
+ supported Diameter applications, security mechanisms, etc.). As
+ defined in RFC 3588, however, the capabilities exchange process takes
+ place only once, at the inception of a transport connection between a
+ given pair of peers. Therefore, if a peer's capabilities change (due
+ to software update, for example), the existing connection(s) must be
+ torn down (along with all of the associated user sessions) and
+ restarted before the modified capabilities can be advertised.
+
+ This document defines a new Diameter application intended to allow
+ the dynamic update of a subset of Diameter peer capabilities over an
+ existing connection. Because the Capabilities Update application
+ specified herein operates over an existing transport connection,
+ modification of certain capabilities is prohibited. Specifically,
+ modifying the security mechanism in use is not allowed; if the
+ security method used between a pair of peers is changed the affected
+ connection MUST be restarted.
+
+
+2. Specification of Requirements
+
+ The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT",
+ "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this
+ document are to be interpreted as described in RFC 2119 [RFC2119].
+
+
+3. Diameter Protocol Considerations
+
+ This section details the relationship of the Diameter Capabilities
+ Update application to the Diameter Base Protocol.
+
+ This document specifies Diameter Application-ID <TBD1>. Diameter
+ nodes conforming to this specification MUST advertise support by
+ including the value <TBD1> in the Auth-Application-Id of the
+ Capabilities-Exchange-Request (CER) and Capabilities-Exchange-Answer
+ (CEA) commands [I-D.ietf-dime-rfc3588bis].
+
+
+4. Capabilities Update
+
+ When the capabilities of a Diameter node conforming to this
+ specification change, it MUST notify all of the nodes with which it
+ has an open transport connection and which have also advertised
+ support for the Capabilities Update application using the
+
+
+
+Jiao & Zorn Expires April 27, 2011 [Page 3]
+
+Internet-Draft Diameter Capabilities Update October 2010
+
+
+ Capabilities-Update-Request (CUR) message (Section 4.1.1). This
+ message allows the update of a peer's capabilities (supported
+ Diameter applications, etc.).
+
+ A Diameter node only issues a given command to those peers that have
+ advertised support for the Diameter application that defines the
+ command; a Diameter node must cache the supported applications in
+ order to ensure that unrecognized commands and/or Attribute-Value
+ Pairs (AVPs) are not unnecessarily sent to a peer.
+
+ The receiver of the CUR MUST determine common applications by
+ computing the intersection of its own set of supported Application Id
+ against all of the application identifier AVPs (Auth-Application-Id,
+ Acct-Application-Id and Vendor-Specific- Application-Id) present in
+ the CUR. The value of the Vendor-Id AVP in the Vendor-Specific-
+ Application-Id MUST NOT be used during computation.
+
+ If the receiver of a CUR does not have any applications in common
+ with the sender then it MUST return a Capabilities-Update-Answer
+ (CUA) (Section 4.1.2) with the Result-Code AVP set to
+ DIAMETER_NO_COMMON_APPLICATION [I-D.ietf-dime-rfc3588bis], and SHOULD
+ disconnect the transport layer connection; however, if active
+ sessions are using the connection, peers MAY delay disconnection
+ until the sessions can be redirected or gracefully terminated. Note
+ that receiving a CUA from a peer advertising itself as a Relay (see
+ [I-D.ietf-dime-rfc3588bis], Section 2.4) MUST be interpreted as
+ having common applications with the peer.
+
+ As for CER/CEA messages, the CUR and CUA messages MUST NOT be
+ proxied, redirected or relayed.
+
+ Even though the CUR/CUA messages cannot be proxied, it is still
+ possible for an upstream agent to receive a message for which there
+ are no peers available to handle the application that corresponds to
+ the Command-Code. This could happen if, for example, the peers are
+ too busy or down. In such instances, the 'E' bit MUST be set in the
+ answer message with the Result-Code AVP set to
+ DIAMETER_UNABLE_TO_DELIVER to inform the downstream peer to take
+ action (e.g., re-routing requests to an alternate peer).
+
+4.1. Command-Code Values
+
+ This section defines Command-Code [I-D.ietf-dime-rfc3588bis] values
+ that MUST be supported by all Diameter implementations conforming to
+ this specification. The following Command Codes are defined (using
+ modified ABNF [I-D.ietf-dime-rfc3588bis]) in this document:
+ Capabilities-Update-Request (CUR, Section 4.1.1) and Capabilities-
+ Update-Answer (CUA, Section 4.1.2).
+
+
+
+Jiao & Zorn Expires April 27, 2011 [Page 4]
+
+Internet-Draft Diameter Capabilities Update October 2010
+
+
+4.1.1. Capabilities-Update-Request
+
+ The Capabilities-Update-Request (CUR), indicated by the Command-Code
+ set to <CUCC> and the Command Flags' 'R' bit set, is sent to update
+ local capabilities. Upon detection of a transport failure, this
+ message MUST NOT be sent to an alternate peer.
+
+ When Diameter is run over the Stream Control Transmission Protocol
+ [RFC4960], which allows connections to span multiple interfaces and
+ multiple IP addresses, the Capabilities-Update-Request message MUST
+ contain one Host-IP-Address AVP for each potential IP address that
+ may be locally used when transmitting Diameter messages.
+
+ Message Format
+
+ <CUR> ::= < Diameter Header: <CUCC>, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+ 1* { Host-IP-Address }
+ { Vendor-Id }
+ { Product-Name }
+ [ Origin-State-Id ]
+ * [ Supported-Vendor-Id ]
+ * [ Auth-Application-Id ]
+ * [ Acct-Application-Id ]
+ * [ Vendor-Specific-Application-Id ]
+ [ Firmware-Revision ]
+ * [ AVP ]
+
+4.1.2. Capabilities-Update-Answer
+
+ The Capabilities-Update-Answer, indicated by the Command-Code set to
+ <CUCC> and the Command Flags' 'R' bit cleared, is sent in response to
+ a CUR message.
+
+ Message Format
+
+ <CUA> ::= < Diameter Header: <CUCC> >
+ { Origin-Host }
+ { Origin-Realm }
+ { Result-Code }
+ [ Error-Message ]
+ * [ AVP ]
+
+
+
+
+
+
+
+
+Jiao & Zorn Expires April 27, 2011 [Page 5]
+
+Internet-Draft Diameter Capabilities Update October 2010
+
+
+5. Security Considerations
+
+ The security considerations applicable to the Diameter Base Protocol
+ [I-D.ietf-dime-rfc3588bis] are also applicable to this document.
+
+
+6. IANA Considerations
+
+ This section explains the criteria to be used by the IANA for
+ assignment of numbers within namespaces used within this document.
+
+6.1. Application Identifier
+
+ This specification assigns the value <TBD1> from the Application
+ Identifiers namespace [I-D.ietf-dime-rfc3588bis]. See Section 3 for
+ the assignment of the namespace in this specification.
+
+6.2. Command Codes
+
+ This specification assigns the value <CUCC> from the Command Codes
+ namespace [I-D.ietf-dime-rfc3588bis]. See Section 4.1 for the
+ assignment of the namespace in this specification.
+
+
+7. Contributors
+
+ This document is based upon work done by Tina Tsou.
+
+
+8. Acknowledgements
+
+ Thanks to Sebastien Decugis, Niklas Neumann, Subash Comerica, Lionel
+ Morand, Dan Romascanu, Dan Harkins and Ravi for helpful review and
+ discussion.
+
+
+9. References
+
+9.1. Normative References
+
+ [I-D.ietf-dime-rfc3588bis]
+ Fajardo, V., Arkko, J., Loughney, J., and G. Zorn,
+ "Diameter Base Protocol", draft-ietf-dime-rfc3588bis-25
+ (work in progress), September 2010.
+
+ [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate
+ Requirement Levels", BCP 14, RFC 2119, March 1997.
+
+
+
+
+Jiao & Zorn Expires April 27, 2011 [Page 6]
+
+Internet-Draft Diameter Capabilities Update October 2010
+
+
+9.2. Informative References
+
+ [RFC4960] Stewart, R., "Stream Control Transmission Protocol",
+ RFC 4960, September 2007.
+
+
+Authors' Addresses
+
+ Jiao Kang
+ Huawei Technologies
+ Section B1, Huawei Industrial Base
+ Bantian, Longgang District
+ Shenzhen 518129
+ P.R. China
+
+ Phone: +86 755 2878-6690
+ Email: [email protected]
+
+
+ Glen Zorn
+ Network Zen
+ 227/358 Thanon Sanphawut
+ Bang Na, Bangkok 10260
+ Thailand
+
+ Phone: +66 (0) 87-040-4617
+ Email: [email protected]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Jiao & Zorn Expires April 27, 2011 [Page 7]
+
diff --git a/lib/diameter/doc/standard/draft-ietf-dime-rfc3588bis-26.txt b/lib/diameter/doc/standard/draft-ietf-dime-rfc3588bis-26.txt new file mode 100644 index 0000000000..87b9562f93 --- /dev/null +++ b/lib/diameter/doc/standard/draft-ietf-dime-rfc3588bis-26.txt @@ -0,0 +1,8681 @@ + + + +DIME V. Fajardo, Ed. +Internet-Draft Telcordia Technologies +Obsoletes: 3588 (if approved) J. Arkko +Intended status: Standards Track Ericsson Research +Expires: July 24, 2011 J. Loughney + Nokia Research Center + G. Zorn + Network Zen + January 20, 2011 + + + Diameter Base Protocol + draft-ietf-dime-rfc3588bis-26.txt + +Abstract + + The Diameter base protocol is intended to provide an Authentication, + Authorization and Accounting (AAA) framework for applications such as + network access or IP mobility in both local and roaming situations. + This document specifies the message format, transport, error + reporting, accounting and security services used by all Diameter + applications. The Diameter base protocol as defined in this document + must be supported by all Diameter implementations. + +Status of this Memo + + This Internet-Draft is submitted in full conformance with the + provisions of BCP 78 and BCP 79. + + Internet-Drafts are working documents of the Internet Engineering + Task Force (IETF). Note that other groups may also distribute + working documents as Internet-Drafts. The list of current Internet- + Drafts is at http://datatracker.ietf.org/drafts/current/. + + Internet-Drafts are draft documents valid for a maximum of six months + and may be updated, replaced, or obsoleted by other documents at any + time. It is inappropriate to use Internet-Drafts as reference + material or to cite them other than as "work in progress." + + This Internet-Draft will expire on July 24, 2011. + +Copyright Notice + + Copyright (c) 2011 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents + + + +Fajardo, et al. Expires July 24, 2011 [Page 1] + +Internet-Draft Diameter Base Protocol January 2011 + + + (http://trustee.ietf.org/license-info) in effect on the date of + publication of this document. Please review these documents + carefully, as they describe your rights and restrictions with respect + to this document. Code Components extracted from this document must + include Simplified BSD License text as described in Section 4.e of + the Trust Legal Provisions and are provided without warranty as + described in the Simplified BSD License. + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . 6 + 1.1. Diameter Protocol . . . . . . . . . . . . . . . . . . . . 8 + 1.1.1. Description of the Document Set . . . . . . . . . . . 9 + 1.1.2. Conventions Used in This Document . . . . . . . . . . 10 + 1.1.3. Changes from RFC3588 . . . . . . . . . . . . . . . . 10 + 1.2. Terminology . . . . . . . . . . . . . . . . . . . . . . . 12 + 1.3. Approach to Extensibility . . . . . . . . . . . . . . . . 17 + 1.3.1. Defining New AVP Values . . . . . . . . . . . . . . . 18 + 1.3.2. Creating New AVPs . . . . . . . . . . . . . . . . . . 18 + 1.3.3. Creating New Commands . . . . . . . . . . . . . . . . 18 + 1.3.4. Creating New Diameter Applications . . . . . . . . . 19 + 2. Protocol Overview . . . . . . . . . . . . . . . . . . . . . . 21 + 2.1. Transport . . . . . . . . . . . . . . . . . . . . . . . . 22 + 2.1.1. SCTP Guidelines . . . . . . . . . . . . . . . . . . . 23 + 2.2. Securing Diameter Messages . . . . . . . . . . . . . . . 24 + 2.3. Diameter Application Compliance . . . . . . . . . . . . . 24 + 2.4. Application Identifiers . . . . . . . . . . . . . . . . . 24 + 2.5. Connections vs. Sessions . . . . . . . . . . . . . . . . 25 + 2.6. Peer Table . . . . . . . . . . . . . . . . . . . . . . . 26 + 2.7. Routing Table . . . . . . . . . . . . . . . . . . . . . . 27 + 2.8. Role of Diameter Agents . . . . . . . . . . . . . . . . . 28 + 2.8.1. Relay Agents . . . . . . . . . . . . . . . . . . . . 29 + 2.8.2. Proxy Agents . . . . . . . . . . . . . . . . . . . . 30 + 2.8.3. Redirect Agents . . . . . . . . . . . . . . . . . . . 31 + 2.8.4. Translation Agents . . . . . . . . . . . . . . . . . 32 + 2.9. Diameter Path Authorization . . . . . . . . . . . . . . . 33 + 3. Diameter Header . . . . . . . . . . . . . . . . . . . . . . . 35 + 3.1. Command Codes . . . . . . . . . . . . . . . . . . . . . . 38 + 3.2. Command Code ABNF specification . . . . . . . . . . . . . 38 + 3.3. Diameter Command Naming Conventions . . . . . . . . . . . 41 + 4. Diameter AVPs . . . . . . . . . . . . . . . . . . . . . . . . 42 + 4.1. AVP Header . . . . . . . . . . . . . . . . . . . . . . . 42 + 4.1.1. Optional Header Elements . . . . . . . . . . . . . . 43 + 4.2. Basic AVP Data Formats . . . . . . . . . . . . . . . . . 44 + 4.3. Derived AVP Data Formats . . . . . . . . . . . . . . . . 45 + 4.3.1. Common Derived AVPs . . . . . . . . . . . . . . . . . 45 + 4.4. Grouped AVP Values . . . . . . . . . . . . . . . . . . . 52 + + + +Fajardo, et al. Expires July 24, 2011 [Page 2] + +Internet-Draft Diameter Base Protocol January 2011 + + + 4.4.1. Example AVP with a Grouped Data type . . . . . . . . 53 + 4.5. Diameter Base Protocol AVPs . . . . . . . . . . . . . . . 56 + 5. Diameter Peers . . . . . . . . . . . . . . . . . . . . . . . 59 + 5.1. Peer Connections . . . . . . . . . . . . . . . . . . . . 59 + 5.2. Diameter Peer Discovery . . . . . . . . . . . . . . . . . 60 + 5.3. Capabilities Exchange . . . . . . . . . . . . . . . . . . 61 + 5.3.1. Capabilities-Exchange-Request . . . . . . . . . . . . 63 + 5.3.2. Capabilities-Exchange-Answer . . . . . . . . . . . . 63 + 5.3.3. Vendor-Id AVP . . . . . . . . . . . . . . . . . . . . 64 + 5.3.4. Firmware-Revision AVP . . . . . . . . . . . . . . . . 64 + 5.3.5. Host-IP-Address AVP . . . . . . . . . . . . . . . . . 64 + 5.3.6. Supported-Vendor-Id AVP . . . . . . . . . . . . . . . 65 + 5.3.7. Product-Name AVP . . . . . . . . . . . . . . . . . . 65 + 5.4. Disconnecting Peer connections . . . . . . . . . . . . . 65 + 5.4.1. Disconnect-Peer-Request . . . . . . . . . . . . . . . 66 + 5.4.2. Disconnect-Peer-Answer . . . . . . . . . . . . . . . 66 + 5.4.3. Disconnect-Cause AVP . . . . . . . . . . . . . . . . 66 + 5.5. Transport Failure Detection . . . . . . . . . . . . . . . 67 + 5.5.1. Device-Watchdog-Request . . . . . . . . . . . . . . . 67 + 5.5.2. Device-Watchdog-Answer . . . . . . . . . . . . . . . 67 + 5.5.3. Transport Failure Algorithm . . . . . . . . . . . . . 68 + 5.5.4. Failover and Failback Procedures . . . . . . . . . . 68 + 5.6. Peer State Machine . . . . . . . . . . . . . . . . . . . 69 + 5.6.1. Incoming connections . . . . . . . . . . . . . . . . 71 + 5.6.2. Events . . . . . . . . . . . . . . . . . . . . . . . 72 + 5.6.3. Actions . . . . . . . . . . . . . . . . . . . . . . . 73 + 5.6.4. The Election Process . . . . . . . . . . . . . . . . 75 + 6. Diameter message processing . . . . . . . . . . . . . . . . . 76 + 6.1. Diameter Request Routing Overview . . . . . . . . . . . . 76 + 6.1.1. Originating a Request . . . . . . . . . . . . . . . . 77 + 6.1.2. Sending a Request . . . . . . . . . . . . . . . . . . 77 + 6.1.3. Receiving Requests . . . . . . . . . . . . . . . . . 78 + 6.1.4. Processing Local Requests . . . . . . . . . . . . . . 78 + 6.1.5. Request Forwarding . . . . . . . . . . . . . . . . . 78 + 6.1.6. Request Routing . . . . . . . . . . . . . . . . . . . 78 + 6.1.7. Predictive Loop Avoidance . . . . . . . . . . . . . . 79 + 6.1.8. Redirecting Requests . . . . . . . . . . . . . . . . 79 + 6.1.9. Relaying and Proxying Requests . . . . . . . . . . . 80 + 6.2. Diameter Answer Processing . . . . . . . . . . . . . . . 82 + 6.2.1. Processing received Answers . . . . . . . . . . . . . 82 + 6.2.2. Relaying and Proxying Answers . . . . . . . . . . . . 82 + 6.3. Origin-Host AVP . . . . . . . . . . . . . . . . . . . . . 83 + 6.4. Origin-Realm AVP . . . . . . . . . . . . . . . . . . . . 83 + 6.5. Destination-Host AVP . . . . . . . . . . . . . . . . . . 83 + 6.6. Destination-Realm AVP . . . . . . . . . . . . . . . . . . 84 + 6.7. Routing AVPs . . . . . . . . . . . . . . . . . . . . . . 84 + 6.7.1. Route-Record AVP . . . . . . . . . . . . . . . . . . 84 + 6.7.2. Proxy-Info AVP . . . . . . . . . . . . . . . . . . . 84 + + + +Fajardo, et al. Expires July 24, 2011 [Page 3] + +Internet-Draft Diameter Base Protocol January 2011 + + + 6.7.3. Proxy-Host AVP . . . . . . . . . . . . . . . . . . . 85 + 6.7.4. Proxy-State AVP . . . . . . . . . . . . . . . . . . . 85 + 6.8. Auth-Application-Id AVP . . . . . . . . . . . . . . . . . 85 + 6.9. Acct-Application-Id AVP . . . . . . . . . . . . . . . . . 85 + 6.10. Inband-Security-Id AVP . . . . . . . . . . . . . . . . . 85 + 6.11. Vendor-Specific-Application-Id AVP . . . . . . . . . . . 86 + 6.12. Redirect-Host AVP . . . . . . . . . . . . . . . . . . . . 87 + 6.13. Redirect-Host-Usage AVP . . . . . . . . . . . . . . . . . 87 + 6.14. Redirect-Max-Cache-Time AVP . . . . . . . . . . . . . . . 88 + 7. Error Handling . . . . . . . . . . . . . . . . . . . . . . . 90 + 7.1. Result-Code AVP . . . . . . . . . . . . . . . . . . . . . 92 + 7.1.1. Informational . . . . . . . . . . . . . . . . . . . . 92 + 7.1.2. Success . . . . . . . . . . . . . . . . . . . . . . . 93 + 7.1.3. Protocol Errors . . . . . . . . . . . . . . . . . . . 93 + 7.1.4. Transient Failures . . . . . . . . . . . . . . . . . 94 + 7.1.5. Permanent Failures . . . . . . . . . . . . . . . . . 95 + 7.2. Error Bit . . . . . . . . . . . . . . . . . . . . . . . . 98 + 7.3. Error-Message AVP . . . . . . . . . . . . . . . . . . . . 99 + 7.4. Error-Reporting-Host AVP . . . . . . . . . . . . . . . . 99 + 7.5. Failed-AVP AVP . . . . . . . . . . . . . . . . . . . . . 99 + 7.6. Experimental-Result AVP . . . . . . . . . . . . . . . . . 100 + 7.7. Experimental-Result-Code AVP . . . . . . . . . . . . . . 100 + 8. Diameter User Sessions . . . . . . . . . . . . . . . . . . . 101 + 8.1. Authorization Session State Machine . . . . . . . . . . . 102 + 8.2. Accounting Session State Machine . . . . . . . . . . . . 107 + 8.3. Server-Initiated Re-Auth . . . . . . . . . . . . . . . . 112 + 8.3.1. Re-Auth-Request . . . . . . . . . . . . . . . . . . . 112 + 8.3.2. Re-Auth-Answer . . . . . . . . . . . . . . . . . . . 113 + 8.4. Session Termination . . . . . . . . . . . . . . . . . . . 114 + 8.4.1. Session-Termination-Request . . . . . . . . . . . . . 115 + 8.4.2. Session-Termination-Answer . . . . . . . . . . . . . 115 + 8.5. Aborting a Session . . . . . . . . . . . . . . . . . . . 116 + 8.5.1. Abort-Session-Request . . . . . . . . . . . . . . . . 116 + 8.5.2. Abort-Session-Answer . . . . . . . . . . . . . . . . 117 + 8.6. Inferring Session Termination from Origin-State-Id . . . 118 + 8.7. Auth-Request-Type AVP . . . . . . . . . . . . . . . . . . 118 + 8.8. Session-Id AVP . . . . . . . . . . . . . . . . . . . . . 119 + 8.9. Authorization-Lifetime AVP . . . . . . . . . . . . . . . 120 + 8.10. Auth-Grace-Period AVP . . . . . . . . . . . . . . . . . . 121 + 8.11. Auth-Session-State AVP . . . . . . . . . . . . . . . . . 121 + 8.12. Re-Auth-Request-Type AVP . . . . . . . . . . . . . . . . 121 + 8.13. Session-Timeout AVP . . . . . . . . . . . . . . . . . . . 122 + 8.14. User-Name AVP . . . . . . . . . . . . . . . . . . . . . . 122 + 8.15. Termination-Cause AVP . . . . . . . . . . . . . . . . . . 122 + 8.16. Origin-State-Id AVP . . . . . . . . . . . . . . . . . . . 124 + 8.17. Session-Binding AVP . . . . . . . . . . . . . . . . . . . 124 + 8.18. Session-Server-Failover AVP . . . . . . . . . . . . . . . 125 + 8.19. Multi-Round-Time-Out AVP . . . . . . . . . . . . . . . . 126 + + + +Fajardo, et al. Expires July 24, 2011 [Page 4] + +Internet-Draft Diameter Base Protocol January 2011 + + + 8.20. Class AVP . . . . . . . . . . . . . . . . . . . . . . . . 126 + 8.21. Event-Timestamp AVP . . . . . . . . . . . . . . . . . . . 126 + 9. Accounting . . . . . . . . . . . . . . . . . . . . . . . . . 127 + 9.1. Server Directed Model . . . . . . . . . . . . . . . . . . 127 + 9.2. Protocol Messages . . . . . . . . . . . . . . . . . . . . 128 + 9.3. Accounting Application Extension and Requirements . . . . 128 + 9.4. Fault Resilience . . . . . . . . . . . . . . . . . . . . 129 + 9.5. Accounting Records . . . . . . . . . . . . . . . . . . . 129 + 9.6. Correlation of Accounting Records . . . . . . . . . . . . 130 + 9.7. Accounting Command-Codes . . . . . . . . . . . . . . . . 131 + 9.7.1. Accounting-Request . . . . . . . . . . . . . . . . . 131 + 9.7.2. Accounting-Answer . . . . . . . . . . . . . . . . . . 132 + 9.8. Accounting AVPs . . . . . . . . . . . . . . . . . . . . . 133 + 9.8.1. Accounting-Record-Type AVP . . . . . . . . . . . . . 133 + 9.8.2. Acct-Interim-Interval AVP . . . . . . . . . . . . . . 134 + 9.8.3. Accounting-Record-Number AVP . . . . . . . . . . . . 135 + 9.8.4. Acct-Session-Id AVP . . . . . . . . . . . . . . . . . 135 + 9.8.5. Acct-Multi-Session-Id AVP . . . . . . . . . . . . . . 135 + 9.8.6. Accounting-Sub-Session-Id AVP . . . . . . . . . . . . 135 + 9.8.7. Accounting-Realtime-Required AVP . . . . . . . . . . 136 + 10. AVP Occurrence Table . . . . . . . . . . . . . . . . . . . . 137 + 10.1. Base Protocol Command AVP Table . . . . . . . . . . . . . 137 + 10.2. Accounting AVP Table . . . . . . . . . . . . . . . . . . 138 + 11. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 140 + 11.1. Changes to AVP Header Allocation . . . . . . . . . . . . 140 + 11.2. Diameter Header . . . . . . . . . . . . . . . . . . . . . 140 + 11.3. AVP Values . . . . . . . . . . . . . . . . . . . . . . . 140 + 11.3.1. Experimental-Result-Code AVP . . . . . . . . . . . . 140 + 11.4. Diameter TCP, SCTP, TLS/TCP and DTLS/SCTP Port Numbers . 141 + 11.5. S-NAPTR Parameters . . . . . . . . . . . . . . . . . . . 141 + 12. Diameter protocol related configurable parameters . . . . . . 142 + 13. Security Considerations . . . . . . . . . . . . . . . . . . . 143 + 13.1. TLS/TCP and DTLS/SCTP Usage . . . . . . . . . . . . . . . 143 + 13.2. Peer-to-Peer Considerations . . . . . . . . . . . . . . . 144 + 14. References . . . . . . . . . . . . . . . . . . . . . . . . . 145 + 14.1. Normative References . . . . . . . . . . . . . . . . . . 145 + 14.2. Informational References . . . . . . . . . . . . . . . . 147 + Appendix A. Acknowledgements . . . . . . . . . . . . . . . . . . 149 + A.1. RFC3588bis . . . . . . . . . . . . . . . . . . . . . . . 149 + A.2. RFC3588 . . . . . . . . . . . . . . . . . . . . . . . . . 150 + Appendix B. S-NAPTR Example . . . . . . . . . . . . . . . . . . 151 + Appendix C. Duplicate Detection . . . . . . . . . . . . . . . . 152 + Appendix D. Internationalized Domain Names . . . . . . . . . . . 154 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . 155 + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 5] + +Internet-Draft Diameter Base Protocol January 2011 + + +1. Introduction + + Authentication, Authorization and Accounting (AAA) protocols such as + TACACS [RFC1492] and RADIUS [RFC2865] were initially deployed to + provide dial-up PPP [RFC1661] and terminal server access. Over time, + AAA support was needed on many new access technologies, the scale and + complexity of AAA networks grew, and AAA was also used on new + applications (such as voice over IP). This lead to new demands on + AAA protocols. + + Network access requirements for AAA protocols are summarized in + [RFC2989]. These include: + + + Failover + + [RFC2865] does not define failover mechanisms, and as a result, + failover behavior differs between implementations. In order to + provide well-defined failover behavior, Diameter supports + application-layer acknowledgements, and defines failover + algorithms and the associated state machine. This is described in + Section 5.5 and [RFC3539]. + + Transmission-level security + + [RFC2865] defines an application-layer authentication and + integrity scheme that is required only for use with Response + packets. While [RFC2869] defines an additional authentication and + integrity mechanism, use is only required during Extensible + Authentication Protocol (EAP) sessions. While attribute-hiding is + supported, [RFC2865] does not provide support for per-packet + confidentiality. In accounting, [RFC2866] assumes that replay + protection is provided by the backend billing server, rather than + within the protocol itself. + + While [RFC3162] defines the use of IPsec with RADIUS, support for + IPsec is not required. In order to provide universal support for + transmission-level security, and enable both intra- and inter- + domain AAA deployments, Diameter provides support for TLS/TCP and + DTLS/SCTP. Security is discussed in Section 13. + + + Reliable transport + + + RADIUS runs over UDP, and does not define retransmission behavior; + as a result, reliability varies between implementations. As + described in [RFC2975], this is a major issue in accounting, where + + + +Fajardo, et al. Expires July 24, 2011 [Page 6] + +Internet-Draft Diameter Base Protocol January 2011 + + + packet loss may translate directly into revenue loss. In order to + provide well defined transport behavior, Diameter runs over + reliable transport mechanisms (TCP, SCTP) as defined in [RFC3539]. + + + Agent support + + [RFC2865] does not provide for explicit support for agents, + including Proxies, Redirects and Relays. Since the expected + behavior is not defined, it varies between implementations. + Diameter defines agent behavior explicitly; this is described in + Section 2.8. + + + Server-initiated messages + + While RADIUS server-initiated messages are defined in [RFC5176], + support is optional. This makes it difficult to implement + features such as unsolicited disconnect or re-authentication/ + re-authorization on demand across a heterogeneous deployment. To + tackle this issue, support for server-initiated messages is + mandatory in Diameter. + + + Transition support + + While Diameter does not share a common protocol data unit (PDU) + with RADIUS, considerable effort has been expended in enabling + backward compatibility with RADIUS, so that the two protocols may + be deployed in the same network. Initially, it is expected that + Diameter will be deployed within new network devices, as well as + within gateways enabling communication between legacy RADIUS + devices and Diameter agents. This capability enables Diameter + support to be added to legacy networks, by addition of a gateway + or server speaking both RADIUS and Diameter. + + In addition to addressing the above requirements, Diameter also + provides support for the following: + + + Capability negotiation + + RADIUS does not support error messages, capability negotiation, or + a mandatory/non-mandatory flag for attributes. Since RADIUS + clients and servers are not aware of each other's capabilities, + they may not be able to successfully negotiate a mutually + acceptable service, or in some cases, even be aware of what + service has been implemented. Diameter includes support for error + + + +Fajardo, et al. Expires July 24, 2011 [Page 7] + +Internet-Draft Diameter Base Protocol January 2011 + + + handling (Section 7), capability negotiation (Section 5.3), and + mandatory/non-mandatory Attribute-Value Pairs (AVPs) (Section + 4.1). + + + Peer discovery and configuration + + RADIUS implementations typically require that the name or address + of servers or clients be manually configured, along with the + corresponding shared secrets. This results in a large + administrative burden, and creates the temptation to reuse the + RADIUS shared secret, which can result in major security + vulnerabilities if the Request Authenticator is not globally and + temporally unique as required in [RFC2865]. Through DNS, Diameter + enables dynamic discovery of peers (see Section 5.2). Derivation + of dynamic session keys is enabled via transmission-level + security. + + + Over time, the capabilities of Network Access Server (NAS) devices + have increased substantially. As a result, while Diameter is a + considerably more sophisticated protocol than RADIUS, it remains + feasible to implement it within embedded devices. + +1.1. Diameter Protocol + + The Diameter base protocol provides the following facilities: + + o Ability to exchange messages and deliver AVPs + + o Capabilities negotiation + + o Error notification + + o Extensibility, through addition of new applications, commands and + AVPs (required in [RFC2989]). + + o Basic services necessary for applications, such as handling of + user sessions or accounting + + All data delivered by the protocol is in the form of AVPs. Some of + these AVP values are used by the Diameter protocol itself, while + others deliver data associated with particular applications that + employ Diameter. AVPs may be arbitrarily added to Diameter messages, + the only restriction being that the Augmented Backus-Naur Form (ABNF, + [RFC5234]) Command Code syntax specification (Section 3.2) is + satisfied. AVPs are used by the base Diameter protocol to support + the following required features: + + + +Fajardo, et al. Expires July 24, 2011 [Page 8] + +Internet-Draft Diameter Base Protocol January 2011 + + + o Transporting of user authentication information, for the purposes + of enabling the Diameter server to authenticate the user. + + o Transporting of service-specific authorization information, + between client and servers, allowing the peers to decide whether a + user's access request should be granted. + + o Exchanging resource usage information, which may be used for + accounting purposes, capacity planning, etc. + + o Routing, relaying, proxying and redirecting of Diameter messages + through a server hierarchy. + + The Diameter base protocol satisfies the minimum requirements for an + AAA protocol, as specified by [RFC2989]. The base protocol may be + used by itself for accounting purposes only, or it may be used with a + Diameter application, such as Mobile IPv4 [RFC4004], or network + access [RFC4005]. It is also possible for the base protocol to be + extended for use in new applications, via the addition of new + commands or AVPs. The initial focus of Diameter was network access + and accounting applications. A truly generic AAA protocol used by + many applications might provide functionality not provided by + Diameter. Therefore, it is imperative that the designers of new + applications understand their requirements before using Diameter. + See Section 2.4 for more information on Diameter applications. + + Any node can initiate a request. In that sense, Diameter is a peer- + to-peer protocol. In this document, a Diameter Client is a device at + the edge of the network that performs access control, such as a + Network Access Server (NAS) or a Foreign Agent (FA). A Diameter + client generates Diameter messages to request authentication, + authorization, and accounting services for the user. A Diameter + agent is a node that does not provide local user authentication or + authorization services; agents include proxies, redirects and relay + agents. A Diameter server performs authentication and/or + authorization of the user. A Diameter node may act as an agent for + certain requests while acting as a server for others. + + The Diameter protocol also supports server-initiated messages, such + as a request to abort service to a particular user. + +1.1.1. Description of the Document Set + + The Diameter specification consists of an updated version of the base + protocol specification (this document) and the Transport Profile + [RFC3539]. This document obsoletes RFC 3588. A summary of the base + protocol updates included in this document can be found in + Section 1.1.3. + + + +Fajardo, et al. Expires July 24, 2011 [Page 9] + +Internet-Draft Diameter Base Protocol January 2011 + + + This document defines the base protocol specification for AAA, which + includes support for accounting. There are also a myriad of + applications documents describing applications that use this base + specification for Authentication, Authorization and Accounting. + These application documents specify how to use the Diameter protocol + within the context of their application. + + The Transport Profile document [RFC3539] discusses transport layer + issues that arise with AAA protocols and recommendations on how to + overcome these issues. This document also defines the Diameter + failover algorithm and state machine. + + Clarifications on the Routing of Diameter Request based on Username + and the Realm [RFC5729] defines specific behavior on how to route + request based on the content of the User-Name AVP (Attribute Value + Pair). + +1.1.2. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + +1.1.3. Changes from RFC3588 + + This document obsoletes RFC 3588 but is fully backward compatible + with that document. The changes introduced in this document focus on + fixing issues that have surfaced during implementation of [RFC3588]. + An overview of some the major changes are given below. + + o Deprecated the use of Inband-Security AVP for negotiating + transport layer security. It has been generally considered that + bootstrapping of TLS via Inband-Security AVP creates certain + security risk because it does not completely protect the + information carried in the CER (Capabilities Exchange Request)/CEA + (Capabilities Exchange Answer). This version of Diameter adopted + a common approach of defining a well-known secured port that peers + should use when communicating via TLS/TCP and DTLS/SCTP. This new + approach augments the existing Inband-Security negotiation but + does not completely replace it. The old method is kept for + backwards compatibility reasons. + + o Deprecated the exchange of CER/CEA messages in the open state. + This feature was implied in the peer state machine table of + [RFC3588] but it was not clearly defined anywhere else in that + document. As work on this document progressed, it became clear + that the multiplicity of meaning and use of Application Id AVPs in + the CER/CEA messages (and the messages themselves) is seen as an + + + +Fajardo, et al. Expires July 24, 2011 [Page 10] + +Internet-Draft Diameter Base Protocol January 2011 + + + abuse of the Diameter extensibility rules and thus required + simplification. It is assumed that the capabilities exchange in + the open state will be re-introduced in a separate specification + which clearly defines new commands for this feature. + + o Simplified Security Requirements. The use of a secured transport + for exchanging Diameter messages remains mandatory. However, TLS/ + TCP and DTLS/SCTP has become the primary method of securing + Diameter and IPsec is a secondary alternative. See Section 13 for + details. The support for the End-to-End security framework + (E2ESequence AVP and 'P'-bit in the AVP header) has also been + deprecated. + + o Diameter Extensibility Changes. This includes fixes to the + Diameter extensibility description (Section 1.3 and others) to + better aid Diameter application designers; in addition, the new + specification relaxes the policy with respect to the allocation of + command codes for vendor-specific uses. + + o Application Id Usage. Clarify the proper use of Application Id + information which can be found in multiple places within a + Diameter message. This includes correlating Application Ids found + in the message headers and AVPs. These changes also clearly + specify the proper Application Id value to use for specific base + protocol messages (ASR/ASA, STR/STA) as well as clarifying the + content and use of Vendor-Specific-Application-Id. + + o Routing Fixes. This document more clearly specifies what + information (AVPs and Application Id) can be used for making + general routing decisions. A rule for the prioritization of + redirect routing criteria when multiple route entries are found + via redirects has also been added (See Section 6.13 for details). + + o Simplification of Diameter Peer Discovery. The Diameter discovery + process now supports only widely used discovery schemes; the rest + have been deprecated (see Section 5.2 for details). + + There are many other many miscellaneous fixes that have been + introduced in this document that may not be considered significant + but they are important nonetheless. Examples are removal of obsolete + types, fixes to command ABNFs, fixes to the state machine, + clarification of the election process, message validation, fixes to + Failed-AVP and Result-Code AVP values, etc. A comprehensive list of + changes is not shown here for practical reasons. + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 11] + +Internet-Draft Diameter Base Protocol January 2011 + + +1.2. Terminology + + AAA + + Authentication, Authorization and Accounting. + + + ABNF + + Augmented Backus-Naur Form [RFC5234]. A metalanguage with its own + formal syntax and rules. It is based on the Backus-Naur Form and + is used to define message exchanges in a bi-directional + communications protocol. + + + Accounting + + The act of collecting information on resource usage for the + purpose of capacity planning, auditing, billing or cost + allocation. + + + Accounting Record + + An accounting record represents a summary of the resource + consumption of a user over the entire session. Accounting servers + creating the accounting record may do so by processing interim + accounting events or accounting events from several devices + serving the same user. + + + Authentication + + The act of verifying the identity of an entity (subject). + + + Authorization + + The act of determining whether a requesting entity (subject) will + be allowed access to a resource (object). + + + AVP + + The Diameter protocol consists of a header followed by one or more + Attribute-Value-Pairs (AVPs). An AVP includes a header and is + used to encapsulate protocol-specific data (e.g., routing + information) as well as authentication, authorization or + + + +Fajardo, et al. Expires July 24, 2011 [Page 12] + +Internet-Draft Diameter Base Protocol January 2011 + + + accounting information. + + + Diameter Agent + + A Diameter Agent is a Diameter Node that provides either relay, + proxy, redirect or translation services. + + + Diameter Client + + A Diameter Client is a Diameter Node that supports Diameter client + applications as well as the base protocol. Diameter Clients are + often implemented in devices situated at the edge of a network and + provide access control services for that network. Typical + examples of Diameter Clients include the Network Access Server + (NAS) and the Mobile IP Foreign Agent (FA). + + + Diameter Node + + A Diameter Node is a host process that implements the Diameter + protocol, and acts either as a Client, Agent or Server. + + + Diameter Peer + + If a Diameter Node shares a direct transport connection with + another Diameter Node, it is a Diameter Peer to that Diameter + Node. + + + Diameter Server + + A Diameter Server is a Diameter Node that handles authentication, + authorization and accounting requests for a particular realm. By + its very nature, a Diameter Server must support Diameter server + applications in addition to the base protocol. + + + Downstream + + Downstream is used to identify the direction of a particular + Diameter message from the Home Server towards the Diameter Client. + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 13] + +Internet-Draft Diameter Base Protocol January 2011 + + + Home Realm + + A Home Realm is the administrative domain with which the user + maintains an account relationship. + + + Home Server + + A Diameter Server which serves the Home Realm. + + + Interim accounting + + An interim accounting message provides a snapshot of usage during + a user's session. It is typically implemented in order to provide + for partial accounting of a user's session in the case a device + reboot or other network problem prevents the delivery of a session + summary message or session record. + + + Local Realm + + A local realm is the administrative domain providing services to a + user. An administrative domain may act as a local realm for + certain users, while being a home realm for others. + + + Multi-session + + A multi-session represents a logical linking of several sessions. + Multi-sessions are tracked by using the Acct-Multi-Session-Id. An + example of a multi-session would be a Multi-link PPP bundle. Each + leg of the bundle would be a session while the entire bundle would + be a multi-session. + + + Network Access Identifier + + The Network Access Identifier, or NAI [RFC4282], is used in the + Diameter protocol to extract a user's identity and realm. The + identity is used to identify the user during authentication and/or + authorization, while the realm is used for message routing + purposes. + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 14] + +Internet-Draft Diameter Base Protocol January 2011 + + + Proxy Agent or Proxy + + In addition to forwarding requests and responses, proxies make + policy decisions relating to resource usage and provisioning. + This is typically accomplished by tracking the state of NAS + devices. While proxies typically do not respond to client + Requests prior to receiving a Response from the server, they may + originate Reject messages in cases where policies are violated. + As a result, proxies need to understand the semantics of the + messages passing through them, and may not support all Diameter + applications. + + + Realm + + The string in the NAI that immediately follows the '@' character. + NAI realm names are required to be unique, and are piggybacked on + the administration of the DNS namespace. Diameter makes use of + the realm, also loosely referred to as domain, to determine + whether messages can be satisfied locally, or whether they must be + routed or redirected. In RADIUS, realm names are not necessarily + piggybacked on the DNS namespace but may be independent of it. + + + Real-time Accounting + + Real-time accounting involves the processing of information on + resource usage within a defined time window. Time constraints are + typically imposed in order to limit financial risk. The Diameter + Credit Control Application [RFC4006] is an example of an + application that defines real-time accounting functionality. + + + Relay Agent or Relay + + Relays forward requests and responses based on routing-related + AVPs and routing table entries. Since relays do not make policy + decisions, they do not examine or alter non-routing AVPs. As a + result, relays never originate messages, do not need to understand + the semantics of messages or non-routing AVPs, and are capable of + handling any Diameter application or message type. Since relays + make decisions based on information in routing AVPs and realm + forwarding tables they do not keep state on NAS resource usage or + sessions in progress. + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 15] + +Internet-Draft Diameter Base Protocol January 2011 + + + Redirect Agent + + Rather than forwarding requests and responses between clients and + servers, redirect agents refer clients to servers and allow them + to communicate directly. Since redirect agents do not sit in the + forwarding path, they do not alter any AVPs transiting between + client and server. Redirect agents do not originate messages and + are capable of handling any message type, although they may be + configured only to redirect messages of certain types, while + acting as relay or proxy agents for other types. As with proxy + agents, redirect agents do not keep state with respect to sessions + or NAS resources. + + + Session + + A session is a related progression of events devoted to a + particular activity. Diameter application documents provide + guidelines as to when a session begins and ends. All Diameter + packets with the same Session-Id are considered to be part of the + same session. + + + Stateful Agent + + A stateful agent is one that maintains session state information, + by keeping track of all authorized active sessions. Each + authorized session is bound to a particular service, and its state + is considered active either until it is notified otherwise, or by + expiration. + + + Sub-session + + A sub-session represents a distinct service (e.g., QoS or data + characteristics) provided to a given session. These services may + happen concurrently (e.g., simultaneous voice and data transfer + during the same session) or serially. These changes in sessions + are tracked with the Accounting-Sub-Session-Id. + + + Transaction state + + The Diameter protocol requires that agents maintain transaction + state, which is used for failover purposes. Transaction state + implies that upon forwarding a request, the Hop-by-Hop identifier + is saved; the field is replaced with a locally unique identifier, + which is restored to its original value when the corresponding + + + +Fajardo, et al. Expires July 24, 2011 [Page 16] + +Internet-Draft Diameter Base Protocol January 2011 + + + answer is received. The request's state is released upon receipt + of the answer. A stateless agent is one that only maintains + transaction state. + + + Translation Agent + + A translation agent is a stateful Diameter node that performs + protocol translation between Diameter and another AAA protocol, + such as RADIUS. + + + Transport Connection + + A transport connection is a TCP or SCTP connection existing + directly between two Diameter peers, otherwise known as a Peer-to- + Peer Connection. + + + Upstream + + Upstream is used to identify the direction of a particular + Diameter message from the Diameter Client towards the Home Server. + + + User + + The entity or device requesting or using some resource, in support + of which a Diameter client has generated a request. + + +1.3. Approach to Extensibility + + The Diameter protocol is designed to be extensible, using several + mechanisms, including: + + o Defining new AVP values + + o Creating new AVPs + + o Creating new commands + + o Creating new applications + + From the point of view of extensibility Diameter authentication, + authorization and accounting applications are treated in the same + way. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 17] + +Internet-Draft Diameter Base Protocol January 2011 + + + Note: Protocol designers should try to re-use existing functionality, + namely AVP values, AVPs, commands, and Diameter applications. Reuse + simplifies standardization and implementation. To avoid potential + interoperability issues it is important to ensure that the semantics + of the re-used features are well understood. Given that Diameter can + also carry RADIUS attributes as Diameter AVPs, such re-use + considerations apply also to existing RADIUS attributes that may be + useful in a Diameter application. + +1.3.1. Defining New AVP Values + + In order to allocate a new AVP value for AVPs defined in the Diameter + Base protocol, the IETF needs to approve a new RFC that describes the + AVP value. IANA considerations for these AVP values are discussed in + Section 11.4. + + The allocation of AVP values for other AVPs is guided by the IANA + considerations of the document that defines those AVPs. Typically, + allocation of new values for an AVP defined in an IETF RFC should + require IETF Review [RFC5226], whereas values for vendor-specific + AVPs can be allocated by the vendor. + +1.3.2. Creating New AVPs + + A new AVP being defined MUST use one of the data types listed in + Section 4.2 or Section 4.3. If an appropriate derived data type is + already defined, it SHOULD be used instead of a base data type to + encourage reusability and good design practice. + + In the event that a logical grouping of AVPs is necessary, and + multiple "groups" are possible in a given command, it is recommended + that a Grouped AVP be used (see Section 4.4). + + The creation of new AVPs can happen in various ways. The recommended + approach is to define a new general-purpose AVP in a standards track + RFC approved by the IETF. However, as described in Section 11.1.1 + there are also other mechanisms. + +1.3.3. Creating New Commands + + A new Command Code MUST be allocated when required AVPs (those + indicated as {AVP} in the ABNF definition) are added to, deleted from + or redefined in (for example, by changing a required AVP into an + optional one) an existing command. + + Furthermore, if the transport characteristics of a command are + changed (for example, with respect to the number of round trips + required) a new Command Code MUST be registered. + + + +Fajardo, et al. Expires July 24, 2011 [Page 18] + +Internet-Draft Diameter Base Protocol January 2011 + + + A change to the ABNF of a command, such as described above, MUST + result in the definition of a new Command Code. This subsequently + leads to the need to define a new Diameter Application for any + application that will use that new Command. + + The IANA considerations for commands are discussed in Section 11.2.1. + +1.3.4. Creating New Diameter Applications + + Every Diameter application specification MUST have an IANA assigned + Application Id (see Section 2.4 and Section 11.3). The managed + Application Id space is flat and there is no relationship between + different Diameter applications with respect to their Application + Ids. As such, there is no versioning support provided by these + application Ids itself; every Diameter application is a standalone + application. If the application has a relationship with other + Diameter applications, such a relationship is not known to Diameter. + + Before describing the rules for creating new Diameter applications it + is important to discuss the semantics of the AVPs occurrences as + stated in the ABNF and the M-bit flag (Section 4.1) for an AVP. + There is no relationship imposed between the two; they are set + independently. + + o The ABNF indicates what AVPs are placed into a Diameter Command by + the sender of that Command. Often, since there are multiple modes + of protocol interactions many of the AVPs are indicated as + optional. + + o The M-bit allows the sender to indicate to the receiver whether or + not understanding the semantics of an AVP and its content is + mandatory. If the M-bit is set by the sender and the receiver + does not understand the AVP or the values carried within that AVP + then a failure is generated (see Section 7). + + It is the decision of the protocol designer when to develop a new + Diameter application rather than extending Diameter in other ways. + However, a new Diameter application MUST be created when one or more + of the following criteria are met: + + + M-bit Setting + + An AVP with the M-bit in the MUST column of the AVP flag table is + added to an existing Command/Application. + + An AVP with the M-bit in the MAY column of the AVP flag table is + added to an existing Command/Application. + + + +Fajardo, et al. Expires July 24, 2011 [Page 19] + +Internet-Draft Diameter Base Protocol January 2011 + + + Note: The M-bit setting for a given AVP is relevant to an + Application and each command within that application which + includes the AVP. That is, if an AVP appears in two commands for + application Foo and the M-bit settings are different in each + command, then there should be two AVP flag tables describing when + to set the M-bit. + + Commands + + A new command is used within the existing application either + because an additional command is added, an existing command has + been modified so that a new Command Code had to be registered, or + a command has been deleted. + + If the ABNF definition of a command allows it, an implementation may + add arbitrary optional AVPs with the M-bit cleared (including vendor- + specific AVPs) to that command without needing to define a new + application. Please refer to Section 11.1.1 for details. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 20] + +Internet-Draft Diameter Base Protocol January 2011 + + +2. Protocol Overview + + The base Diameter protocol concerns itself with establishing + connections to peers, capabilities negotiation, how messages are sent + and routed through peers, and how the connections are eventually torn + down. The base protocol also defines certain rules that apply to all + message exchanges between Diameter nodes. + + Communication between Diameter peers begins with one peer sending a + message to another Diameter peer. The set of AVPs included in the + message is determined by a particular Diameter application. One AVP + that is included to reference a user's session is the Session-Id. + + The initial request for authentication and/or authorization of a user + would include the Session-Id AVP. The Session-Id is then used in all + subsequent messages to identify the user's session (see Section 8 for + more information). The communicating party may accept the request, + or reject it by returning an answer message with the Result-Code AVP + set to indicate an error occurred. The specific behavior of the + Diameter server or client receiving a request depends on the Diameter + application employed. + + Session state (associated with a Session-Id) MUST be freed upon + receipt of the Session-Termination-Request, Session-Termination- + Answer, expiration of authorized service time in the Session-Timeout + AVP, and according to rules established in a particular Diameter + application. + + The base Diameter protocol may be used by itself for accounting + applications. For authentication and authorization, it is always + extended for a particular application. + + Diameter Clients MUST support the base protocol, which includes + accounting. In addition, they MUST fully support each Diameter + application that is needed to implement the client's service, e.g., + NASREQ and/or Mobile IPv4. A Diameter Client MUST be referred to as + "Diameter X Client" where X is the application which it supports, and + not a "Diameter Client". + + Diameter Servers MUST support the base protocol, which includes + accounting. In addition, they MUST fully support each Diameter + application that is needed to implement the intended service, e.g., + NASREQ and/or Mobile IPv4. A Diameter Server MUST be referred to as + "Diameter X Server" where X is the application which it supports, and + not a "Diameter Server". + + Diameter Relays and redirect agents are transparent to the Diameter + applications but they MUST support the Diameter base protocol, which + + + +Fajardo, et al. Expires July 24, 2011 [Page 21] + +Internet-Draft Diameter Base Protocol January 2011 + + + includes accounting, and all Diameter applications. + + Diameter proxies MUST support the base protocol, which includes + accounting. In addition, they MUST fully support each Diameter + application that is needed to implement proxied services, e.g., + NASREQ and/or Mobile IPv4. A Diameter proxy MUST be referred to as + "Diameter X Proxy" where X is the application which it supports, and + not a "Diameter Proxy". + +2.1. Transport + + The Diameter Transport profile is defined in [RFC3539]. + + The base Diameter protocol is run on port 3868 for both TCP [RFC793] + and SCTP [RFC4960]. For TLS [RFC5246] and DTLS [RFC4347], a Diameter + node that initiate a connection prior to any message exchanges MUST + run on port [TBD]. It is assumed that TLS is run on top of TCP when + it is used and DTLS is run on top of SCTP when it is used. + + If the Diameter peer does not support receiving TLS/TCP and DTLS/SCTP + connections on port [TBD], i.e. the peer complies only with + [RFC3588], then the initiator MAY revert to using TCP or SCTP and on + port 3868. Note that this scheme is kept for the purpose of + backwards compatibility only and that there are inherent security + vulnerabilities when the initial CER/CEA messages are sent un- + protected (see Section 5.6). + + Diameter clients MUST support either TCP or SCTP, while agents and + servers SHOULD support both. + + A Diameter node MAY initiate connections from a source port other + than the one that it declares it accepts incoming connections on, and + MUST be prepared to receive connections on port 3868 for TCP or SCTP + and port [TBD] for TLS/TCP and DTLS/SCTP connections. A given + Diameter instance of the peer state machine MUST NOT use more than + one transport connection to communicate with a given peer, unless + multiple instances exist on the peer in which case a separate + connection per process is allowed. + + When no transport connection exists with a peer, an attempt to + connect SHOULD be periodically made. This behavior is handled via + the Tc timer (see Section 12 for details), whose recommended value is + 30 seconds. There are certain exceptions to this rule, such as when + a peer has terminated the transport connection stating that it does + not wish to communicate. + + When connecting to a peer and either zero or more transports are + specified, TLS SHOULD be tried first, followed by DTLS, then by TCP + + + +Fajardo, et al. Expires July 24, 2011 [Page 22] + +Internet-Draft Diameter Base Protocol January 2011 + + + and finally by SCTP. See Section 5.2 for more information on peer + discovery. + + Diameter implementations SHOULD be able to interpret ICMP protocol + port unreachable messages as explicit indications that the server is + not reachable, subject to security policy on trusting such messages. + Further guidance regarding the treatment of ICMP errors can be found + in [RFC5927] and [RFC5461]. Diameter implementations SHOULD also be + able to interpret a reset from the transport and timed-out connection + attempts. If Diameter receives data from the lower layer that cannot + be parsed or identified as a Diameter error made by the peer, the + stream is compromised and cannot be recovered. The transport + connection MUST be closed using a RESET call (send a TCP RST bit) or + an SCTP ABORT message (graceful closure is compromised). + +2.1.1. SCTP Guidelines + + Diameter messages SHOULD be mapped into SCTP streams in a way that + avoids head-of-the-line (HOL) blocking. Among different ways of + performing the mapping that fulfill this requirement it is + RECOMMENDED that a Diameter node sends every Diameter message + (request or response) over the stream zero with the unordered flag + set. However, Diameter nodes MAY select and implement other design + alternatives for avoiding HOL blocking such as using multiple streams + with the unordered flag cleared (as originally instructed in + RFC3588). On the receiving side, a Diameter entity MUST be ready to + receive Diameter messages over any stream and it is free to return + responses over a different stream. This way, both sides manage the + available streams in the sending direction, independently of the + streams chosen by the other side to send a particular Diameter + message. These messages can be out-of-order and belong to different + Diameter sessions. + + Out-of-order delivery has special concerns during a connection + establishment and termination. When a connection is established, the + responder side sends a CEA message and moves to R-Open state as + specified in Section 5.6. If an application message is sent shortly + after the CEA and delivered out-of-order, the initiator side, still + in Wait-I-CEA state, will discard the application message and close + the connection. In order to avoid this race condition, the receiver + side SHOULD NOT use out-of-order delivery methods until the first + message has been received from the initiator, proving that it has + moved to I-Open state. To trigger such message, the receiver side + could send a DWR immediatly after sending CEA. Upon reception of the + corresponding DWA, the receiver side should start using out-of-order + delivery methods to counter the HOL blocking. + + Another race condition may occur when DPR and DPA messages are used. + + + +Fajardo, et al. Expires July 24, 2011 [Page 23] + +Internet-Draft Diameter Base Protocol January 2011 + + + Both DPR and DPA are small in size, thus they may be delivered faster + to the peer than application messages when out-of-order delivery + mechanism is used. Therefore, it is possible that a DPR/DPA exchange + completes while application messages are still in transit, resulting + to a loss of these messages. An implementation could mitigate this + race condition, for example, using timers and wait for a short period + of time for pending application level messages to arrive before + proceeding to disconnect the transport connection. Eventually, lost + messages are handled by the retransmission mechanism described in + Section 5.5.4. + +2.2. Securing Diameter Messages + + Connections between Diameter peers SHOULD be protected by TLS/TCP and + DTLS/SCTP. All Diameter base protocol implementations MUST support + the use of TLS/TCP and DTLS/SCTP. If desired, alternative security + mechanisms that are independent of Diameter, such as IPsec [RFC4301], + can be deployed to secure connections between peers. The Diameter + protocol MUST NOT be used without any security mechanism. + +2.3. Diameter Application Compliance + + Application Ids are advertised during the capabilities exchange phase + (see Section 5.3). Advertising support of an application implies + that the sender supports the functionality specified in the + respective Diameter application specification. + + Implementations MAY add arbitrary optional AVPs with the M-bit + cleared (including vendor-specific AVPs) to a command defined in an + application, but only if the command's ABNF syntax specification + allows for it. Please refer to Section 11.1.1 for details. + +2.4. Application Identifiers + + Each Diameter application MUST have an IANA assigned Application Id + (see Section 11.3). The base protocol does not require an + Application Id since its support is mandatory. During the + capabilities exchange, Diameter nodes inform their peers of locally + supported applications. Furthermore, all Diameter messages contain + an Application Id, which is used in the message forwarding process. + + The following Application Id values are defined: + + Diameter Common Messages 0 + Diameter Base Accounting 3 + Relay 0xffffffff + + Relay and redirect agents MUST advertise the Relay Application + + + +Fajardo, et al. Expires July 24, 2011 [Page 24] + +Internet-Draft Diameter Base Protocol January 2011 + + + Identifier, while all other Diameter nodes MUST advertise locally + supported applications. The receiver of a Capabilities Exchange + message advertising Relay service MUST assume that the sender + supports all current and future applications. + + Diameter relay and proxy agents are responsible for finding an + upstream server that supports the application of a particular + message. If none can be found, an error message is returned with the + Result-Code AVP set to DIAMETER_UNABLE_TO_DELIVER. + +2.5. Connections vs. Sessions + + This section attempts to provide the reader with an understanding of + the difference between connection and session, which are terms used + extensively throughout this document. + + A connection refers to a transport level connection between two peers + that is used to send and receive Diameter messages. A session is a + logical concept at the application layer existing between the + Diameter client and the Diameter server; it is identified via the + Session-Id AVP. + + + +--------+ +-------+ +--------+ + | Client | | Relay | | Server | + +--------+ +-------+ +--------+ + <----------> <----------> + peer connection A peer connection B + + <-----------------------------> + User session x + + Figure 1: Diameter connections and sessions + + In the example provided in Figure 1, peer connection A is established + between the Client and the Relay. Peer connection B is established + between the Relay and the Server. User session X spans from the + Client via the Relay to the Server. Each "user" of a service causes + an auth request to be sent, with a unique session identifier. Once + accepted by the server, both the client and the server are aware of + the session. + + It is important to note that there is no relationship between a + connection and a session, and that Diameter messages for multiple + sessions are all multiplexed through a single connection. Also note + that Diameter messages pertaining to the session, both application + specific and those that are defined in this document such as ASR/ASA, + RAR/RAA and STR/STA MUST carry the Application Id of the application. + + + +Fajardo, et al. Expires July 24, 2011 [Page 25] + +Internet-Draft Diameter Base Protocol January 2011 + + + Diameter messages pertaining to peer connection establishment and + maintenance such as CER/CEA, DWR/DWA and DPR/DPA MUST carry an + Application Id of zero (0). + +2.6. Peer Table + + The Diameter Peer Table is used in message forwarding, and referenced + by the Routing Table. A Peer Table entry contains the following + fields: + + Host identity + + Following the conventions described for the DiameterIdentity + derived AVP data format in Section 4.3. This field contains the + contents of the Origin-Host (Section 6.3) AVP found in the CER or + CEA message. + + + StatusT + + This is the state of the peer entry, and MUST match one of the + values listed in Section 5.6. + + + Static or Dynamic + + Specifies whether a peer entry was statically configured or + dynamically discovered. + + + Expiration time + + Specifies the time at which dynamically discovered peer table + entries are to be either refreshed, or expired. + + + TLS/TCP and DTLS/SCTP Enabled + + Specifies whether TLS/TCP and DTLS/SCTP is to be used when + communicating with the peer. + + + Additional security information, when needed (e.g., keys, + certificates) + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 26] + +Internet-Draft Diameter Base Protocol January 2011 + + +2.7. Routing Table + + All Realm-Based routing lookups are performed against what is + commonly known as the Routing Table (see Section 12). A Routing + Table Entry contains the following fields: + + Realm Name + + This is the field that is MUST be used as a primary key in the + routing table lookups. Note that some implementations perform + their lookups based on longest-match-from-the-right on the realm + rather than requiring an exact match. + + + Application Identifier + + An application is identified by an Application Id. A route entry + can have a different destination based on the Application Id in + the message header. This field MUST be used as a secondary key + field in routing table lookups. + + + Local Action + + The Local Action field is used to identify how a message should be + treated. The following actions are supported: + + + 1. LOCAL - Diameter messages that can be satisfied locally, and + do not need to be routed to another Diameter entity. + + 2. RELAY - All Diameter messages that fall within this category + MUST be routed to a next hop Diameter entity that is indicated + by the identifier described below. Routing is done without + modifying any non-routing AVPs. See Section 6.1.9 for + relaying guidelines + + 3. PROXY - All Diameter messages that fall within this category + MUST be routed to a next Diameter entity that is indicated by + the identifier described below. The local server MAY apply + its local policies to the message by including new AVPs to the + message prior to routing. See Section 6.1.9 for proxying + guidelines. + + 4. REDIRECT - Diameter messages that fall within this category + MUST have the identity of the home Diameter server(s) + appended, and returned to the sender of the message. See + Section 6.1.8 for redirect guidelines. + + + +Fajardo, et al. Expires July 24, 2011 [Page 27] + +Internet-Draft Diameter Base Protocol January 2011 + + + Server Identifier + + One or more servers to which the message is to be routed. These + servers MUST also be present in the Peer table. When the Local + Action is set to RELAY or PROXY, this field contains the identity + of the server(s) the message MUST be routed to. When the Local + Action field is set to REDIRECT, this field contains the identity + of one or more servers the message MUST be redirected to. + + Static or Dynamic + + Specifies whether a route entry was statically configured or + dynamically discovered. + + Expiration time + + Specifies the time at which a dynamically discovered route table + entry expires. + + It is important to note that Diameter agents MUST support at least + one of the LOCAL, RELAY, PROXY or REDIRECT modes of operation. + Agents do not need to support all modes of operation in order to + conform with the protocol specification, but MUST follow the protocol + compliance guidelines in Section 2. Relay agents and proxies MUST + NOT reorder AVPs. + + The routing table MAY include a default entry that MUST be used for + any requests not matching any of the other entries. The routing + table MAY consist of only such an entry. + + When a request is routed, the target server MUST have advertised the + Application Id (see Section 2.4) for the given message, or have + advertised itself as a relay or proxy agent. Otherwise, an error is + returned with the Result-Code AVP set to DIAMETER_UNABLE_TO_DELIVER. + +2.8. Role of Diameter Agents + + In addition to clients and servers, the Diameter protocol introduces + relay, proxy, redirect, and translation agents, each of which is + defined in Section 1.3. These Diameter agents are useful for several + reasons: + + o They can distribute administration of systems to a configurable + grouping, including the maintenance of security associations. + + o They can be used for concentration of requests from an number of + co-located or distributed NAS equipment sets to a set of like user + groups. + + + +Fajardo, et al. Expires July 24, 2011 [Page 28] + +Internet-Draft Diameter Base Protocol January 2011 + + + o They can do value-added processing to the requests or responses. + + o They can be used for load balancing. + + o A complex network will have multiple authentication sources, they + can sort requests and forward towards the correct target. + + The Diameter protocol requires that agents maintain transaction + state, which is used for failover purposes. Transaction state + implies that upon forwarding a request, its Hop-by-Hop identifier is + saved; the field is replaced with a locally unique identifier, which + is restored to its original value when the corresponding answer is + received. The request's state is released upon receipt of the + answer. A stateless agent is one that only maintains transaction + state. + + The Proxy-Info AVP allows stateless agents to add local state to a + Diameter request, with the guarantee that the same state will be + present in the answer. However, the protocol's failover procedures + require that agents maintain a copy of pending requests. + + A stateful agent is one that maintains session state information by + keeping track of all authorized active sessions. Each authorized + session is bound to a particular service, and its state is considered + active either until the agent is notified otherwise, or the session + expires. Each authorized session has an expiration, which is + communicated by Diameter servers via the Session-Timeout AVP. + + Maintaining session state may be useful in certain applications, such + as: + + o Protocol translation (e.g., RADIUS <-> Diameter) + + o Limiting resources authorized to a particular user + + o Per user or transaction auditing + + A Diameter agent MAY act in a stateful manner for some requests and + be stateless for others. A Diameter implementation MAY act as one + type of agent for some requests, and as another type of agent for + others. + +2.8.1. Relay Agents + + Relay Agents are Diameter agents that accept requests and route + messages to other Diameter nodes based on information found in the + messages (e.g., Destination-Realm). This routing decision is + performed using a list of supported realms, and known peers. This is + + + +Fajardo, et al. Expires July 24, 2011 [Page 29] + +Internet-Draft Diameter Base Protocol January 2011 + + + known as the Routing Table, as is defined further in Section 2.7. + + Relays may, for example, be used to aggregate requests from multiple + Network Access Servers (NASes) within a common geographical area + (POP). The use of Relays is advantageous since it eliminates the + need for NASes to be configured with the necessary security + information they would otherwise require to communicate with Diameter + servers in other realms. Likewise, this reduces the configuration + load on Diameter servers that would otherwise be necessary when NASes + are added, changed or deleted. + + Relays modify Diameter messages by inserting and removing routing + information, but do not modify any other portion of a message. + Relays SHOULD NOT maintain session state but MUST maintain + transaction state. + + +------+ ---------> +------+ ---------> +------+ + | | 1. Request | | 2. Request | | + | NAS | | DRL | | HMS | + | | 4. Answer | | 3. Answer | | + +------+ <--------- +------+ <--------- +------+ + example.net example.net example.com + + Figure 2: Relaying of Diameter messages + + The example provided in Figure 2 depicts a request issued from NAS, + which is an access device, for the user [email protected]. Prior to + issuing the request, NAS performs a Diameter route lookup, using + "example.com" as the key, and determines that the message is to be + relayed to DRL, which is a Diameter Relay. DRL performs the same + route lookup as NAS, and relays the message to HMS, which is + example.com's Home Diameter Server. HMS identifies that the request + can be locally supported (via the realm), processes the + authentication and/or authorization request, and replies with an + answer, which is routed back to NAS using saved transaction state. + + Since Relays do not perform any application level processing, they + provide relaying services for all Diameter applications, and + therefore MUST advertise the Relay Application Id. + +2.8.2. Proxy Agents + + Similarly to relays, proxy agents route Diameter messages using the + Diameter Routing Table. However, they differ since they modify + messages to implement policy enforcement. This requires that proxies + maintain the state of their downstream peers (e.g., access devices) + to enforce resource usage, provide admission control, and + provisioning. + + + +Fajardo, et al. Expires July 24, 2011 [Page 30] + +Internet-Draft Diameter Base Protocol January 2011 + + + Proxies may, for example, be used in call control centers or access + ISPs that provide outsourced connections, they can monitor the number + and types of ports in use, and make allocation and admission + decisions according to their configuration. + + Since enforcing policies requires an understanding of the service + being provided, Proxies MUST only advertise the Diameter applications + they support. + +2.8.3. Redirect Agents + + Redirect agents are useful in scenarios where the Diameter routing + configuration needs to be centralized. An example is a redirect + agent that provides services to all members of a consortium, but does + not wish to be burdened with relaying all messages between realms. + This scenario is advantageous since it does not require that the + consortium provide routing updates to its members when changes are + made to a member's infrastructure. + + Since redirect agents do not relay messages, and only return an + answer with the information necessary for Diameter agents to + communicate directly, they do not modify messages. Since redirect + agents do not receive answer messages, they cannot maintain session + state. + + The example provided in Figure 3 depicts a request issued from the + access device, NAS, for the user [email protected]. The message is + forwarded by the NAS to its relay, DRL, which does not have a routing + entry in its Diameter Routing Table for example.com. DRL has a + default route configured to DRD, which is a redirect agent that + returns a redirect notification to DRL, as well as HMS' contact + information. Upon receipt of the redirect notification, DRL + establishes a transport connection with HMS, if one doesn't already + exist, and forwards the request to it. + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 31] + +Internet-Draft Diameter Base Protocol January 2011 + + + +------+ + | | + | DRD | + | | + +------+ + ^ | + 2. Request | | 3. Redirection + | | Notification + | v + +------+ ---------> +------+ ---------> +------+ + | | 1. Request | | 4. Request | | + | NAS | | DRL | | HMS | + | | 6. Answer | | 5. Answer | | + +------+ <--------- +------+ <--------- +------+ + example.net example.net example.com + + Figure 3: Redirecting a Diameter Message + + Since redirect agents do not perform any application level + processing, they provide relaying services for all Diameter + applications, and therefore MUST advertise the Relay Application + Identifier. + +2.8.4. Translation Agents + + A translation agent is a device that provides translation between two + protocols (e.g., RADIUS<->Diameter, TACACS+<->Diameter). Translation + agents are likely to be used as aggregation servers to communicate + with a Diameter infrastructure, while allowing for the embedded + systems to be migrated at a slower pace. + + Given that the Diameter protocol introduces the concept of long-lived + authorized sessions, translation agents MUST be session stateful and + MUST maintain transaction state. + + Translation of messages can only occur if the agent recognizes the + application of a particular request, and therefore translation agents + MUST only advertise their locally supported applications. + + +------+ ---------> +------+ ---------> +------+ + | | RADIUS Request | | Diameter Request | | + | NAS | | TLA | | HMS | + | | RADIUS Answer | | Diameter Answer | | + +------+ <--------- +------+ <--------- +------+ + example.net example.net example.com + + Figure 4: Translation of RADIUS to Diameter + + + + +Fajardo, et al. Expires July 24, 2011 [Page 32] + +Internet-Draft Diameter Base Protocol January 2011 + + +2.9. Diameter Path Authorization + + As noted in Section 2.2, Diameter provides transmission level + security for each connection using TLS/TCP and DTLS/SCTP. Therefore, + each connection can be authenticated, replay and integrity protected. + + In addition to authenticating each connection, each connection as + well as the entire session MUST also be authorized. Before + initiating a connection, a Diameter Peer MUST check that its peers + are authorized to act in their roles. For example, a Diameter peer + may be authentic, but that does not mean that it is authorized to act + as a Diameter Server advertising a set of Diameter applications. + + Prior to bringing up a connection, authorization checks are performed + at each connection along the path. Diameter capabilities negotiation + (CER/CEA) also MUST be carried out, in order to determine what + Diameter applications are supported by each peer. Diameter sessions + MUST be routed only through authorized nodes that have advertised + support for the Diameter application required by the session. + + As noted in Section 6.1.9, a relay or proxy agent MUST append a + Route-Record AVP to all requests forwarded. The AVP contains the + identity of the peer the request was received from. + + The home Diameter server, prior to authorizing a session, MUST check + the Route-Record AVPs to make sure that the route traversed by the + request is acceptable. For example, administrators within the home + realm may not wish to honor requests that have been routed through an + untrusted realm. By authorizing a request, the home Diameter server + is implicitly indicating its willingness to engage in the business + transaction as specified by the contractual relationship between the + server and the previous hop. A DIAMETER_AUTHORIZATION_REJECTED error + message (see Section 7.1.5) is sent if the route traversed by the + request is unacceptable. + + A home realm may also wish to check that each accounting request + message corresponds to a Diameter response authorizing the session. + Accounting requests without corresponding authorization responses + SHOULD be subjected to further scrutiny, as should accounting + requests indicating a difference between the requested and provided + service. + + Forwarding of an authorization response is considered evidence of a + willingness to take on financial risk relative to the session. A + local realm may wish to limit this exposure, for example, by + establishing credit limits for intermediate realms and refusing to + accept responses which would violate those limits. By issuing an + accounting request corresponding to the authorization response, the + + + +Fajardo, et al. Expires July 24, 2011 [Page 33] + +Internet-Draft Diameter Base Protocol January 2011 + + + local realm implicitly indicates its agreement to provide the service + indicated in the authorization response. If the service cannot be + provided by the local realm, then a DIAMETER_UNABLE_TO_COMPLY error + message MUST be sent within the accounting request; a Diameter client + receiving an authorization response for a service that it cannot + perform MUST NOT substitute an alternate service, and then send + accounting requests for the alternate service instead. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 34] + +Internet-Draft Diameter Base Protocol January 2011 + + +3. Diameter Header + + A summary of the Diameter header format is shown below. The fields + are transmitted in network byte order. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Version | Message Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | command flags | Command-Code | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Application-ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Hop-by-Hop Identifier | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | End-to-End Identifier | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AVPs ... + +-+-+-+-+-+-+-+-+-+-+-+-+- + + Version + + This Version field MUST be set to 1 to indicate Diameter Version + 1. + + Message Length + + The Message Length field is three octets and indicates the length + of the Diameter message including the header fields and the padded + AVPs. Thus the message length field is always a multiple of 4. + + Command Flags + + The Command Flags field is eight bits. The following bits are + assigned: + + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |R P E T r r r r| + +-+-+-+-+-+-+-+-+ + + R(equest) + + If set, the message is a request. If cleared, the message is + an answer. + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 35] + +Internet-Draft Diameter Base Protocol January 2011 + + + P(roxiable) + + If set, the message MAY be proxied, relayed or redirected. If + cleared, the message MUST be locally processed. + + + E(rror) + + If set, the message contains a protocol error, and the message + will not conform to the ABNF described for this command. + Messages with the 'E' bit set are commonly referred to as error + messages. This bit MUST NOT be set in request messages. See + Section 7.2. + + + T(Potentially re-transmitted message) + + This flag is set after a link failover procedure, to aid the + removal of duplicate requests. It is set when resending + requests not yet acknowledged, as an indication of a possible + duplicate due to a link failure. This bit MUST be cleared when + sending a request for the first time, otherwise the sender MUST + set this flag. Diameter agents only need to be concerned about + the number of requests they send based on a single received + request; retransmissions by other entities need not be tracked. + Diameter agents that receive a request with the T flag set, + MUST keep the T flag set in the forwarded request. This flag + MUST NOT be set if an error answer message (e.g., a protocol + error) has been received for the earlier message. It can be + set only in cases where no answer has been received from the + server for a request and the request is sent again. This flag + MUST NOT be set in answer messages. + + + r(eserved) + + These flag bits are reserved for future use, and MUST be set to + zero, and ignored by the receiver. + + Command-Code + + The Command-Code field is three octets, and is used in order to + communicate the command associated with the message. The 24-bit + address space is managed by IANA (see Section 11.2.1). + + Command-Code values 16,777,214 and 16,777,215 (hexadecimal values + FFFFFE -FFFFFF) are reserved for experimental use (See Section + 11.3). + + + +Fajardo, et al. Expires July 24, 2011 [Page 36] + +Internet-Draft Diameter Base Protocol January 2011 + + + Application-ID + + Application-ID is four octets and is used to identify to which + application the message is applicable for. The application can be + an authentication application, an accounting application or a + vendor specific application. See Section 11.3 for the possible + values that the application-id may use. + + The value of the application-id field in the header MUST be the + same as any relevant application-id AVPs contained in the message. + + Hop-by-Hop Identifier + + The Hop-by-Hop Identifier is an unsigned 32-bit integer field (in + network byte order) and aids in matching requests and replies. + The sender MUST ensure that the Hop-by-Hop identifier in a request + is unique on a given connection at any given time, and MAY attempt + to ensure that the number is unique across reboots. The sender of + an Answer message MUST ensure that the Hop-by-Hop Identifier field + contains the same value that was found in the corresponding + request. The Hop-by-Hop identifier is normally a monotonically + increasing number, whose start value was randomly generated. An + answer message that is received with an unknown Hop-by-Hop + Identifier MUST be discarded. + + + End-to-End Identifier + + The End-to-End Identifier is an unsigned 32-bit integer field (in + network byte order) and is used to detect duplicate messages. + Upon reboot implementations MAY set the high order 12 bits to + contain the low order 12 bits of current time, and the low order + 20 bits to a random value. Senders of request messages MUST + insert a unique identifier on each message. The identifier MUST + remain locally unique for a period of at least 4 minutes, even + across reboots. The originator of an Answer message MUST ensure + that the End-to-End Identifier field contains the same value that + was found in the corresponding request. The End-to-End Identifier + MUST NOT be modified by Diameter agents of any kind. The + combination of the Origin-Host (see Section 6.3) and this field is + used to detect duplicates. Duplicate requests SHOULD cause the + same answer to be transmitted (modulo the hop-by-hop Identifier + field and any routing AVPs that may be present), and MUST NOT + affect any state that was set when the original request was + processed. Duplicate answer messages that are to be locally + consumed (see Section 6.2) SHOULD be silently discarded. + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 37] + +Internet-Draft Diameter Base Protocol January 2011 + + + AVPs + + AVPs are a method of encapsulating information relevant to the + Diameter message. See Section 4 for more information on AVPs. + +3.1. Command Codes + + Each command Request/Answer pair is assigned a command code, and the + sub-type (i.e., request or answer) is identified via the 'R' bit in + the Command Flags field of the Diameter header. + + + Every Diameter message MUST contain a command code in its header's + Command-Code field, which is used to determine the action that is to + be taken for a particular message. The following Command Codes are + defined in the Diameter base protocol: + + Command-Name Abbrev. Code Reference + -------------------------------------------------------- + Abort-Session-Request ASR 274 8.5.1 + Abort-Session-Answer ASA 274 8.5.2 + Accounting-Request ACR 271 9.7.1 + Accounting-Answer ACA 271 9.7.2 + Capabilities-Exchange- CER 257 5.3.1 + Request + Capabilities-Exchange- CEA 257 5.3.2 + Answer + Device-Watchdog-Request DWR 280 5.5.1 + Device-Watchdog-Answer DWA 280 5.5.2 + Disconnect-Peer-Request DPR 282 5.4.1 + Disconnect-Peer-Answer DPA 282 5.4.2 + Re-Auth-Request RAR 258 8.3.1 + Re-Auth-Answer RAA 258 8.3.2 + Session-Termination- STR 275 8.4.1 + Request + Session-Termination- STA 275 8.4.2 + Answer + +3.2. Command Code ABNF specification + + Every Command Code defined MUST include a corresponding ABNF + specification, which is used to define the AVPs that MUST or MAY be + present when sending the message. The following format is used in + the definition: + + command-def = <command-name> "::=" diameter-message + + command-name = diameter-name + + + +Fajardo, et al. Expires July 24, 2011 [Page 38] + +Internet-Draft Diameter Base Protocol January 2011 + + + diameter-name = ALPHA *(ALPHA / DIGIT / "-") + + diameter-message = header [ *fixed] [ *required] [ *optional] + + header = "<" "Diameter Header:" command-id + [r-bit] [p-bit] [e-bit] [application-id] ">" + + application-id = 1*DIGIT + + command-id = 1*DIGIT + ; The Command Code assigned to the command + + r-bit = ", REQ" + ; If present, the 'R' bit in the Command + ; Flags is set, indicating that the message + ; is a request, as opposed to an answer. + + p-bit = ", PXY" + ; If present, the 'P' bit in the Command + ; Flags is set, indicating that the message + ; is proxiable. + + e-bit = ", ERR" + ; If present, the 'E' bit in the Command + ; Flags is set, indicating that the answer + ; message contains a Result-Code AVP in + ; the "protocol error" class. + + fixed = [qual] "<" avp-spec ">" + ; Defines the fixed position of an AVP + + required = [qual] "{" avp-spec "}" + ; The AVP MUST be present and can appear + ; anywhere in the message. + + + optional = [qual] "[" avp-name "]" + ; The avp-name in the 'optional' rule cannot + ; evaluate to any AVP Name which is included + ; in a fixed or required rule. The AVP can + ; appear anywhere in the message. + ; + ; NOTE: "[" and "]" have a slightly different + ; meaning than in ABNF (RFC 5234]). These braces + ; cannot be used to express optional fixed rules + ; (such as an optional ICV at the end). To do this, + ; the convention is '0*1fixed'. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 39] + +Internet-Draft Diameter Base Protocol January 2011 + + + qual = [min] "*" [max] + ; See ABNF conventions, RFC 5234 Section 4. + ; The absence of any qualifiers depends on + ; whether it precedes a fixed, required, or + ; optional rule. If a fixed or required rule has + ; no qualifier, then exactly one such AVP MUST + ; be present. If an optional rule has no + ; qualifier, then 0 or 1 such AVP may be + ; present. If an optional rule has a qualifier, + ; then the value of min MUST be 0 if present. + + min = 1*DIGIT + ; The minimum number of times the element may + ; be present. If absent, the default value is zero + ; for fixed and optional rules and one for required + ; rules. The value MUST be at least one for for + ; required rules. + + max = 1*DIGIT + ; The maximum number of times the element may + ; be present. If absent, the default value is + ; infinity. A value of zero implies the AVP MUST + ; NOT be present. + + avp-spec = diameter-name + ; The avp-spec has to be an AVP Name, defined + ; in the base or extended Diameter + ; specifications. + + avp-name = avp-spec / "AVP" + ; The string "AVP" stands for *any* arbitrary AVP + ; Name, not otherwise listed in that command code + ; definition. Addition this AVP is recommended for + ; all command ABNFs to allow for extensibility. + + + + The following is a definition of a fictitious command code: + + Example-Request ::= < Diameter Header: 9999999, REQ, PXY > + { User-Name } + * { Origin-Host } + * [ AVP ] + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 40] + +Internet-Draft Diameter Base Protocol January 2011 + + +3.3. Diameter Command Naming Conventions + + Diameter command names typically includes one or more English words + followed by the verb Request or Answer. Each English word is + delimited by a hyphen. A three-letter acronym for both the request + and answer is also normally provided. + + An example is a message set used to terminate a session. The command + name is Session-Terminate-Request and Session-Terminate-Answer, while + the acronyms are STR and STA, respectively. + + Both the request and the answer for a given command share the same + command code. The request is identified by the R(equest) bit in the + Diameter header set to one (1), to ask that a particular action be + performed, such as authorizing a user or terminating a session. Once + the receiver has completed the request it issues the corresponding + answer, which includes a result code that communicates one of the + following: + + o The request was successful + + o The request failed + + o An additional request has to be sent to provide information the + peer requires prior to returning a successful or failed answer. + + o The receiver could not process the request, but provides + information about a Diameter peer that is able to satisfy the + request, known as redirect. + + Additional information, encoded within AVPs, may also be included in + answer messages. + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 41] + +Internet-Draft Diameter Base Protocol January 2011 + + +4. Diameter AVPs + + Diameter AVPs carry specific authentication, accounting, + authorization and routing information as well as configuration + details for the request and reply. + + Each AVP of type OctetString MUST be padded to align on a 32-bit + boundary, while other AVP types align naturally. A number of zero- + valued bytes are added to the end of the AVP Data field till a word + boundary is reached. The length of the padding is not reflected in + the AVP Length field. + +4.1. AVP Header + + The fields in the AVP header MUST be sent in network byte order. The + format of the header is: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AVP Code | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V M P r r r r r| AVP Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Vendor-ID (opt) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data ... + +-+-+-+-+-+-+-+-+ + + AVP Code + + The AVP Code, combined with the Vendor-Id field, identifies the + attribute uniquely. AVP numbers 1 through 255 are reserved for + re-use of RADIUS attributes, without setting the Vendor-Id field. + AVP numbers 256 and above are used for Diameter, which are + allocated by IANA (see Section 11.1). + + + AVP Flags + + The AVP Flags field informs the receiver how each attribute must + be handled. The 'r' (reserved) bits are unused and SHOULD be set + to 0. Note that subsequent Diameter applications MAY define + additional bits within the AVP Header, and an unrecognized bit + SHOULD be considered an error. The 'P' bit has been reserved for + future usage of end-to-end security. At the time of writing there + are no end-to-end security mechanisms specified therefore the 'P' + bit SHOULD be set to 0. + + + +Fajardo, et al. Expires July 24, 2011 [Page 42] + +Internet-Draft Diameter Base Protocol January 2011 + + + The 'M' Bit, known as the Mandatory bit, indicates whether the + receiver of the AVP MUST parse and understand the semantic of the + AVP including its content. The receiving entity MUST return an + appropriate error message if it receives an AVP that has the M-bit + set but does not understand it. An exception applies when the AVP + is embedded within a Grouped AVP. See Section 4.4 for details. + Diameter Relay and redirect agents MUST NOT reject messages with + unrecognized AVPs. + + The 'M' bit MUST be set according to the rules defined in the + application specification which introduces or re-uses this AVP. + Within a given application, the M-bit setting for an AVP is either + defined for all command types or for each command type. + + AVPs with the 'M' bit cleared are informational only and a + receiver that receives a message with such an AVP that is not + supported, or whose value is not supported, MAY simply ignore the + AVP. + + The 'V' bit, known as the Vendor-Specific bit, indicates whether + the optional Vendor-ID field is present in the AVP header. When + set the AVP Code belongs to the specific vendor code address + space. + + AVP Length + + The AVP Length field is three octets, and indicates the number of + octets in this AVP including the AVP Code, AVP Length, AVP Flags, + Vendor-ID field (if present) and the AVP data. If a message is + received with an invalid attribute length, the message MUST be + rejected. + +4.1.1. Optional Header Elements + + The AVP Header contains one optional field. This field is only + present if the respective bit-flag is enabled. + + + Vendor-ID + + The Vendor-ID field is present if the 'V' bit is set in the AVP + Flags field. The optional four-octet Vendor-ID field contains the + IANA assigned "SMI Network Management Private Enterprise Codes" + [RFC3232] value, encoded in network byte order. Any vendor or + standardization organization that are also treated like vendors in + the IANA managed "SMI Network Management Private Enterprise Codes" + space wishing to implement a vendor-specific Diameter AVP MUST use + their own Vendor-ID along with their privately managed AVP address + + + +Fajardo, et al. Expires July 24, 2011 [Page 43] + +Internet-Draft Diameter Base Protocol January 2011 + + + space, guaranteeing that they will not collide with any other + vendor's vendor-specific AVP(s), nor with future IETF AVPs. + + A vendor ID value of zero (0) corresponds to the IETF adopted AVP + values, as managed by the IANA. Since the absence of the vendor + ID field implies that the AVP in question is not vendor specific, + implementations MUST NOT use the zero (0) vendor ID. + +4.2. Basic AVP Data Formats + + The Data field is zero or more octets and contains information + specific to the Attribute. The format and length of the Data field + is determined by the AVP Code and AVP Length fields. The format of + the Data field MUST be one of the following base data types or a data + type derived from the base data types. In the event that a new Basic + AVP Data Format is needed, a new version of this RFC MUST be created. + + + OctetString + + The data contains arbitrary data of variable length. Unless + otherwise noted, the AVP Length field MUST be set to at least 8 + (12 if the 'V' bit is enabled). AVP Values of this type that are + not a multiple of four-octets in length is followed by the + necessary padding so that the next AVP (if any) will start on a + 32-bit boundary. + + + Integer32 + + 32 bit signed value, in network byte order. The AVP Length field + MUST be set to 12 (16 if the 'V' bit is enabled). + + + Integer64 + + 64 bit signed value, in network byte order. The AVP Length field + MUST be set to 16 (20 if the 'V' bit is enabled). + + + Unsigned32 + + 32 bit unsigned value, in network byte order. The AVP Length + field MUST be set to 12 (16 if the 'V' bit is enabled). + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 44] + +Internet-Draft Diameter Base Protocol January 2011 + + + Unsigned64 + + 64 bit unsigned value, in network byte order. The AVP Length + field MUST be set to 16 (20 if the 'V' bit is enabled). + + + Float32 + + This represents floating point values of single precision as + described by [FLOATPOINT]. The 32-bit value is transmitted in + network byte order. The AVP Length field MUST be set to 12 (16 if + the 'V' bit is enabled). + + + Float64 + + This represents floating point values of double precision as + described by [FLOATPOINT]. The 64-bit value is transmitted in + network byte order. The AVP Length field MUST be set to 16 (20 if + the 'V' bit is enabled). + + + Grouped + + The Data field is specified as a sequence of AVPs. Each of these + AVPs follows - in the order in which they are specified - + including their headers and padding. The AVP Length field is set + to 8 (12 if the 'V' bit is enabled) plus the total length of all + included AVPs, including their headers and padding. Thus the AVP + length field of an AVP of type Grouped is always a multiple of 4. + + +4.3. Derived AVP Data Formats + + In addition to using the Basic AVP Data Formats, applications may + define data formats derived from the Basic AVP Data Formats. An + application that defines new Derived AVP Data Formats MUST include + them in a section entitled "Derived AVP Data Formats", using the same + format as the definitions below. Each new definition MUST be either + defined or listed with a reference to the RFC that defines the + format. + +4.3.1. Common Derived AVPs + + The following are commonly used Derived AVP Data Formats. + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 45] + +Internet-Draft Diameter Base Protocol January 2011 + + + Address + + The Address format is derived from the OctetString AVP Base + Format. It is a discriminated union, representing, for example a + 32-bit (IPv4) [RFC791] or 128-bit (IPv6) [RFC4291] address, most + significant octet first. The first two octets of the Address AVP + represents the AddressType, which contains an Address Family + defined in [IANAADFAM]. The AddressType is used to discriminate + the content and format of the remaining octets. + + + Time + + The Time format is derived from the OctetString AVP Base Format. + The string MUST contain four octets, in the same format as the + first four bytes are in the NTP timestamp format. The NTP + Timestamp format is defined in Chapter 3 of [RFC5905]. + + This represents the number of seconds since 0h on 1 January 1900 + with respect to the Coordinated Universal Time (UTC). + + On 6h 28m 16s UTC, 7 February 2036 the time value will overflow. + SNTP [RFC5905] describes a procedure to extend the time to 2104. + This procedure MUST be supported by all Diameter nodes. + + + UTF8String + + The UTF8String format is derived from the OctetString AVP Base + Format. This is a human readable string represented using the + ISO/IEC IS 10646-1 character set, encoded as an OctetString using + the UTF-8 [RFC3629] transformation format described in RFC 3629. + + Since additional code points are added by amendments to the 10646 + standard from time to time, implementations MUST be prepared to + encounter any code point from 0x00000001 to 0x7fffffff. Byte + sequences that do not correspond to the valid encoding of a code + point into UTF-8 charset or are outside this range are prohibited. + + The use of control codes SHOULD be avoided. When it is necessary + to represent a new line, the control code sequence CR LF SHOULD be + used. + + The use of leading or trailing white space SHOULD be avoided. + + For code points not directly supported by user interface hardware + or software, an alternative means of entry and display, such as + hexadecimal, MAY be provided. + + + +Fajardo, et al. Expires July 24, 2011 [Page 46] + +Internet-Draft Diameter Base Protocol January 2011 + + + For information encoded in 7-bit US-ASCII, the UTF-8 charset is + identical to the US-ASCII charset. + + UTF-8 may require multiple bytes to represent a single character / + code point; thus the length of an UTF8String in octets may be + different from the number of characters encoded. + + Note that the AVP Length field of an UTF8String is measured in + octets, not characters. + + DiameterIdentity + + The DiameterIdentity format is derived from the OctetString AVP + Base Format. + + DiameterIdentity = FQDN/Realm + + + DiameterIdentity value is used to uniquely identify either: + + * A Diameter node for purposes of duplicate connection and + routing loop detection. + + * A Realm to determine whether messages can be satisfied locally, + or whether they must be routed or redirected. + + + When a DiameterIdentity is used to identify a Diameter node the + contents of the string MUST be the FQDN of the Diameter node. If + multiple Diameter nodes run on the same host, each Diameter node + MUST be assigned a unique DiameterIdentity. If a Diameter node + can be identified by several FQDNs, a single FQDN should be picked + at startup, and used as the only DiameterIdentity for that node, + whatever the connection it is sent on. Note that in this + document, DiameterIdentity is in ASCII form in order to be + compatible with existing DNS infrastructure. See Appendix D for + interactions between the Diameter protocol and Internationalized + Domain Name (IDNs). + + + DiameterURI + + The DiameterURI MUST follow the Uniform Resource Identifiers (URI) + syntax [RFC3986] rules specified below: + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 47] + +Internet-Draft Diameter Base Protocol January 2011 + + + "aaa://" FQDN [ port ] [ transport ] [ protocol ] + + ; No transport security + + "aaas://" FQDN [ port ] [ transport ] [ protocol ] + + ; Transport security used + + FQDN = Fully Qualified Host Name + + port = ":" 1*DIGIT + + ; One of the ports used to listen for + ; incoming connections. + ; If absent, the default Diameter port + ; (3868) is assumed if no transport + ; security is used and port (TBD) when + ; transport security (TLS/TCP and DTLS/SCTP) is used. + + transport = ";transport=" transport-protocol + + ; One of the transports used to listen + ; for incoming connections. If absent, + ; the default protocol is assumed to be TCP. + ; UDP MUST NOT be used when the aaa-protocol + ; field is set to diameter. + + transport-protocol = ( "tcp" / "sctp" / "udp" ) + + protocol = ";protocol=" aaa-protocol + + ; If absent, the default AAA protocol + ; is Diameter. + + aaa-protocol = ( "diameter" / "radius" / "tacacs+" ) + + The following are examples of valid Diameter host identities: + + aaa://host.example.com;transport=tcp + aaa://host.example.com:6666;transport=tcp + aaa://host.example.com;protocol=diameter + aaa://host.example.com:6666;protocol=diameter + aaa://host.example.com:6666;transport=tcp;protocol=diameter + aaa://host.example.com:1813;transport=udp;protocol=radius + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 48] + +Internet-Draft Diameter Base Protocol January 2011 + + + Enumerated + + Enumerated is derived from the Integer32 AVP Base Format. The + definition contains a list of valid values and their + interpretation and is described in the Diameter application + introducing the AVP. + + + IPFilterRule + + The IPFilterRule format is derived from the OctetString AVP Base + Format and uses the ASCII charset. The rule syntax is a modified + subset of ipfw(8) from FreeBSD. Packets may be filtered based on + the following information that is associated with it: + + Direction (in or out) + Source and destination IP address (possibly masked) + Protocol + Source and destination port (lists or ranges) + TCP flags + IP fragment flag + IP options + ICMP types + + Rules for the appropriate direction are evaluated in order, with + the first matched rule terminating the evaluation. Each packet is + evaluated once. If no rule matches, the packet is dropped if the + last rule evaluated was a permit, and passed if the last rule was + a deny. + + IPFilterRule filters MUST follow the format: + + action dir proto from src to dst [options] + + action permit - Allow packets that match the rule. + deny - Drop packets that match the rule. + + dir "in" is from the terminal, "out" is to the + terminal. + + proto An IP protocol specified by number. The "ip" + keyword means any protocol will match. + + src and dst <address/mask> [ports] + + The <address/mask> may be specified as: + ipno An IPv4 or IPv6 number in dotted- + quad or canonical IPv6 form. Only + + + +Fajardo, et al. Expires July 24, 2011 [Page 49] + +Internet-Draft Diameter Base Protocol January 2011 + + + this exact IP number will match the + rule. + ipno/bits An IP number as above with a mask + width of the form 192.0.2.10/24. In + this case, all IP numbers from + 192.0.2.0 to 192.0.2.255 will match. + The bit width MUST be valid for the + IP version and the IP number MUST + NOT have bits set beyond the mask. + For a match to occur, the same IP + version must be present in the + packet that was used in describing + the IP address. To test for a + particular IP version, the bits part + can be set to zero. The keyword + "any" is 0.0.0.0/0 or the IPv6 + equivalent. The keyword "assigned" + is the address or set of addresses + assigned to the terminal. For IPv4, + a typical first rule is often "deny + in ip! assigned" + + The sense of the match can be inverted by + preceding an address with the not modifier (!), + causing all other addresses to be matched + instead. This does not affect the selection of + port numbers. + + With the TCP, UDP and SCTP protocols, optional + ports may be specified as: + + {port/port-port}[,ports[,...]] + + The '-' notation specifies a range of ports + (including boundaries). + + Fragmented packets that have a non-zero offset + (i.e., not the first fragment) will never match + a rule that has one or more port + specifications. See the frag option for + details on matching fragmented packets. + + options: + frag Match if the packet is a fragment and this is not + the first fragment of the datagram. frag may not + be used in conjunction with either tcpflags or + TCP/UDP port specifications. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 50] + +Internet-Draft Diameter Base Protocol January 2011 + + + ipoptions spec + Match if the IP header contains the comma + separated list of options specified in spec. The + supported IP options are: + + ssrr (strict source route), lsrr (loose source + route), rr (record packet route) and ts + (timestamp). The absence of a particular option + may be denoted with a '!'. + + tcpoptions spec + Match if the TCP header contains the comma + separated list of options specified in spec. The + supported TCP options are: + + mss (maximum segment size), window (tcp window + advertisement), sack (selective ack), ts (rfc1323 + timestamp) and cc (rfc1644 t/tcp connection + count). The absence of a particular option may + be denoted with a '!'. + + established + TCP packets only. Match packets that have the RST + or ACK bits set. + + setup TCP packets only. Match packets that have the SYN + bit set but no ACK bit. + + + tcpflags spec + TCP packets only. Match if the TCP header + contains the comma separated list of flags + specified in spec. The supported TCP flags are: + + fin, syn, rst, psh, ack and urg. The absence of a + particular flag may be denoted with a '!'. A rule + that contains a tcpflags specification can never + match a fragmented packet that has a non-zero + offset. See the frag option for details on + matching fragmented packets. + + icmptypes types + ICMP packets only. Match if the ICMP type is in + the list types. The list may be specified as any + combination of ranges or individual types + separated by commas. Both the numeric values and + the symbolic values listed below can be used. The + supported ICMP types are: + + + +Fajardo, et al. Expires July 24, 2011 [Page 51] + +Internet-Draft Diameter Base Protocol January 2011 + + + echo reply (0), destination unreachable (3), + source quench (4), redirect (5), echo request + (8), router advertisement (9), router + solicitation (10), time-to-live exceeded (11), IP + header bad (12), timestamp request (13), + timestamp reply (14), information request (15), + information reply (16), address mask request (17) + and address mask reply (18). + + There is one kind of packet that the access device MUST always + discard, that is an IP fragment with a fragment offset of one. + This is a valid packet, but it only has one use, to try to + circumvent firewalls. + + An access device that is unable to interpret or apply a deny rule + MUST terminate the session. An access device that is unable to + interpret or apply a permit rule MAY apply a more restrictive + rule. An access device MAY apply deny rules of its own before the + supplied rules, for example to protect the access device owner's + infrastructure. + + +4.4. Grouped AVP Values + + The Diameter protocol allows AVP values of type 'Grouped'. This + implies that the Data field is actually a sequence of AVPs. It is + possible to include an AVP with a Grouped type within a Grouped type, + that is, to nest them. AVPs within an AVP of type Grouped have the + same padding requirements as non-Grouped AVPs, as defined in Section + 4. + + The AVP Code numbering space of all AVPs included in a Grouped AVP is + the same as for non-grouped AVPs. Receivers of a Grouped AVP that + does not have the 'M' (mandatory) bit set and one or more of the + encapsulated AVPs within the group has the 'M' (mandatory) bit set + MAY simply be ignored if the Grouped AVP itself is unrecognized. The + rule applies even if the encapsulated AVP with its 'M' (mandatory) + bit set is further encapsulated within other sub-groups; i.e. other + Grouped AVPs embedded within the Grouped AVP. + + Every Grouped AVP defined MUST include a corresponding grammar, using + ABNF [RFC5234] (with modifications), as defined below. + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 52] + +Internet-Draft Diameter Base Protocol January 2011 + + + grouped-avp-def = <name> "::=" avp + + name-fmt = ALPHA *(ALPHA / DIGIT / "-") + + name = name-fmt + ; The name has to be the name of an AVP, + ; defined in the base or extended Diameter + ; specifications. + + avp = header [ *fixed] [ *required] [ *optional] + + header = "<" "AVP-Header:" avpcode [vendor] ">" + + avpcode = 1*DIGIT + ; The AVP Code assigned to the Grouped AVP + + vendor = 1*DIGIT + ; The Vendor-ID assigned to the Grouped AVP. + ; If absent, the default value of zero is + ; used. + +4.4.1. Example AVP with a Grouped Data type + + The Example-AVP (AVP Code 999999) is of type Grouped and is used to + clarify how Grouped AVP values work. The Grouped Data field has the + following ABNF grammar: + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 53] + +Internet-Draft Diameter Base Protocol January 2011 + + + Example-AVP ::= < AVP Header: 999999 > + { Origin-Host } + 1*{ Session-Id } + *[ AVP ] + + An Example-AVP with Grouped Data follows. + + The Origin-Host AVP is required (Section 6.3). In this case: + + Origin-Host = "example.com". + + + One or more Session-Ids must follow. Here there are two: + + Session-Id = + "grump.example.com:33041;23432;893;0AF3B81" + + Session-Id = + "grump.example.com:33054;23561;2358;0AF3B82" + + optional AVPs included are + + Recovery-Policy = <binary> + 2163bc1d0ad82371f6bc09484133c3f09ad74a0dd5346d54195a7cf0b35 + 2cabc881839a4fdcfbc1769e2677a4c1fb499284c5f70b48f58503a45c5 + c2d6943f82d5930f2b7c1da640f476f0e9c9572a50db8ea6e51e1c2c7bd + f8bb43dc995144b8dbe297ac739493946803e1cee3e15d9b765008a1b2a + cf4ac777c80041d72c01e691cf751dbf86e85f509f3988e5875dc905119 + 26841f00f0e29a6d1ddc1a842289d440268681e052b30fb638045f7779c + 1d873c784f054f688f5001559ecff64865ef975f3e60d2fd7966b8c7f92 + + Futuristic-Acct-Record = <binary> + fe19da5802acd98b07a5b86cb4d5d03f0314ab9ef1ad0b67111ff3b90a0 + 57fe29620bf3585fd2dd9fcc38ce62f6cc208c6163c008f4258d1bc88b8 + 17694a74ccad3ec69269461b14b2e7a4c111fb239e33714da207983f58c + 41d018d56fe938f3cbf089aac12a912a2f0d1923a9390e5f789cb2e5067 + d3427475e49968f841 + + The data for the optional AVPs is represented in hex since the format + of these AVPs is neither known at the time of definition of the + Example-AVP group, nor (likely) at the time when the example instance + of this AVP is interpreted - except by Diameter implementations which + support the same set of AVPs. The encoding example illustrates how + padding is used and how length fields are calculated. Also note that + AVPs may be present in the Grouped AVP value which the receiver + cannot interpret (here, the Recover-Policy and Futuristic-Acct-Record + AVPs). The length of the Example-AVP is the sum of all the length of + the member AVPs including their padding plus the Example-AVP header + + + +Fajardo, et al. Expires July 24, 2011 [Page 54] + +Internet-Draft Diameter Base Protocol January 2011 + + + size. + + + This AVP would be encoded as follows: + + 0 1 2 3 4 5 6 7 + +-------+-------+-------+-------+-------+-------+-------+-------+ + 0 | Example AVP Header (AVP Code = 999999), Length = 496 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 8 | Origin-Host AVP Header (AVP Code = 264), Length = 19 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 16 | 'e' | 'x' | 'a' | 'm' | 'p' | 'l' | 'e' | '.' | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 24 | 'c' | 'o' | 'm' |Padding| Session-Id AVP Header | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 32 | (AVP Code = 263), Length = 49 | 'g' | 'r' | 'u' | 'm' | + +-------+-------+-------+-------+-------+-------+-------+-------+ + . . . + +-------+-------+-------+-------+-------+-------+-------+-------+ + 72 | 'F' | '3' | 'B' | '8' | '1' |Padding|Padding|Padding| + +-------+-------+-------+-------+-------+-------+-------+-------+ + 80 | Session-Id AVP Header (AVP Code = 263), Length = 50 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 88 | 'g' | 'r' | 'u' | 'm' | 'p' | '.' | 'e' | 'x' | + +-------+-------+-------+-------+-------+-------+-------+-------+ + . . . + +-------+-------+-------+-------+-------+-------+-------+-------+ + 120| '5' | '8' | ';' | '0' | 'A' | 'F' | '3' | 'B' | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 128| '8' | '2' |Padding|Padding| Recovery-Policy Header (AVP | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 136| Code = 8341), Length = 223 | 0x21 | 0x63 | 0xbc | 0x1d | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 144| 0x0a | 0xd8 | 0x23 | 0x71 | 0xf6 | 0xbc | 0x09 | 0x48 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + . . . + +-------+-------+-------+-------+-------+-------+-------+-------+ + 352| 0x8c | 0x7f | 0x92 |Padding| Futuristic-Acct-Record Header | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 328|(AVP Code = 15930),Length = 137| 0xfe | 0x19 | 0xda | 0x58 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 336| 0x02 | 0xac | 0xd9 | 0x8b | 0x07 | 0xa5 | 0xb8 | 0xc6 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + . . . + +-------+-------+-------+-------+-------+-------+-------+-------+ + 488| 0xe4 | 0x99 | 0x68 | 0xf8 | 0x41 |Padding|Padding|Padding| + +-------+-------+-------+-------+-------+-------+-------+-------+ + + + + +Fajardo, et al. Expires July 24, 2011 [Page 55] + +Internet-Draft Diameter Base Protocol January 2011 + + +4.5. Diameter Base Protocol AVPs + + The following table describes the Diameter AVPs defined in the base + protocol, their AVP Code values, types, possible flag values. + + Due to space constraints, the short form DiamIdent is used to + represent DiameterIdentity. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 56] + +Internet-Draft Diameter Base Protocol January 2011 + + + +----------+ + | AVP Flag | + | rules | + |----+-----| + AVP Section | |MUST | + Attribute Name Code Defined Data Type |MUST| NOT | + -----------------------------------------|----+-----| + Acct- 85 9.8.2 Unsigned32 | M | V | + Interim-Interval | | | + Accounting- 483 9.8.7 Enumerated | M | V | + Realtime-Required | | | + Acct- 50 9.8.5 UTF8String | M | V | + Multi-Session-Id | | | + Accounting- 485 9.8.3 Unsigned32 | M | V | + Record-Number | | | + Accounting- 480 9.8.1 Enumerated | M | V | + Record-Type | | | + Accounting- 44 9.8.4 OctetString| M | V | + Session-Id | | | + Accounting- 287 9.8.6 Unsigned64 | M | V | + Sub-Session-Id | | | + Acct- 259 6.9 Unsigned32 | M | V | + Application-Id | | | + Auth- 258 6.8 Unsigned32 | M | V | + Application-Id | | | + Auth-Request- 274 8.7 Enumerated | M | V | + Type | | | + Authorization- 291 8.9 Unsigned32 | M | V | + Lifetime | | | + Auth-Grace- 276 8.10 Unsigned32 | M | V | + Period | | | + Auth-Session- 277 8.11 Enumerated | M | V | + State | | | + Re-Auth-Request- 285 8.12 Enumerated | M | V | + Type | | | + Class 25 8.20 OctetString| M | V | + Destination-Host 293 6.5 DiamIdent | M | V | + Destination- 283 6.6 DiamIdent | M | V | + Realm | | | + Disconnect-Cause 273 5.4.3 Enumerated | M | V | + Error-Message 281 7.3 UTF8String | | V,M | + Error-Reporting- 294 7.4 DiamIdent | | V,M | + Host | | | + Event-Timestamp 55 8.21 Time | M | V | + Experimental- 297 7.6 Grouped | M | V | + Result | | | + -----------------------------------------|----+-----| + + + + +Fajardo, et al. Expires July 24, 2011 [Page 57] + +Internet-Draft Diameter Base Protocol January 2011 + + + +----------+ + | AVP Flag | + | rules | + |----+-----| + AVP Section | |MUST | + Attribute Name Code Defined Data Type |MUST| NOT | + -----------------------------------------|----+-----| + Experimental- 298 7.7 Unsigned32 | M | V | + Result-Code | | | + Failed-AVP 279 7.5 Grouped | M | V | + Firmware- 267 5.3.4 Unsigned32 | | V,M | + Revision | | | + Host-IP-Address 257 5.3.5 Address | M | V | + Inband-Security | M | V | + -Id 299 6.10 Unsigned32 | | | + Multi-Round- 272 8.19 Unsigned32 | M | V | + Time-Out | | | + Origin-Host 264 6.3 DiamIdent | M | V | + Origin-Realm 296 6.4 DiamIdent | M | V | + Origin-State-Id 278 8.16 Unsigned32 | M | V | + Product-Name 269 5.3.7 UTF8String | | V,M | + Proxy-Host 280 6.7.3 DiamIdent | M | V | + Proxy-Info 284 6.7.2 Grouped | M | V | + Proxy-State 33 6.7.4 OctetString| M | V | + Redirect-Host 292 6.12 DiamURI | M | V | + Redirect-Host- 261 6.13 Enumerated | M | V | + Usage | | | + Redirect-Max- 262 6.14 Unsigned32 | M | V | + Cache-Time | | | + Result-Code 268 7.1 Unsigned32 | M | V | + Route-Record 282 6.7.1 DiamIdent | M | V | + Session-Id 263 8.8 UTF8String | M | V | + Session-Timeout 27 8.13 Unsigned32 | M | V | + Session-Binding 270 8.17 Unsigned32 | M | V | + Session-Server- 271 8.18 Enumerated | M | V | + Failover | | | + Supported- 265 5.3.6 Unsigned32 | M | V | + Vendor-Id | | | + Termination- 295 8.15 Enumerated | M | V | + Cause | | | + User-Name 1 8.14 UTF8String | M | V | + Vendor-Id 266 5.3.3 Unsigned32 | M | V | + Vendor-Specific- 260 6.11 Grouped | M | V | + Application-Id | | | + -----------------------------------------|----+-----| + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 58] + +Internet-Draft Diameter Base Protocol January 2011 + + +5. Diameter Peers + + This section describes how Diameter nodes establish connections and + communicate with peers. + +5.1. Peer Connections + + Connections between diameter peers are established using their valid + DiameterIdentity. A Diameter node initiating a connection to a peer + MUST know the peers DiameterIdentity. Methods for discovering a + Diameter peer can be found in Section 5.2. + + Although a Diameter node may have many possible peers that it is able + to communicate with, it may not be economical to have an established + connection to all of them. At a minimum, a Diameter node SHOULD have + an established connection with two peers per realm, known as the + primary and secondary peers. Of course, a node MAY have additional + connections, if it is deemed necessary. Typically, all messages for + a realm are sent to the primary peer, but in the event that failover + procedures are invoked, any pending requests are sent to the + secondary peer. However, implementations are free to load balance + requests between a set of peers. + + Note that a given peer MAY act as a primary for a given realm, while + acting as a secondary for another realm. + + When a peer is deemed suspect, which could occur for various reasons, + including not receiving a DWA within an allotted timeframe, no new + requests should be forwarded to the peer, but failover procedures are + invoked. When an active peer is moved to this mode, additional + connections SHOULD be established to ensure that the necessary number + of active connections exists. + + There are two ways that a peer is removed from the suspect peer list: + + + 1. The peer is no longer reachable, causing the transport connection + to be shutdown. The peer is moved to the closed state. + + 2. Three watchdog messages are exchanged with accepted round trip + times, and the connection to the peer is considered stabilized. + + In the event the peer being removed is either the primary or + secondary, an alternate peer SHOULD replace the deleted peer, and + assume the role of either primary or secondary. + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 59] + +Internet-Draft Diameter Base Protocol January 2011 + + +5.2. Diameter Peer Discovery + + Allowing for dynamic Diameter agent discovery will make it possible + for simpler and more robust deployment of Diameter services. In + order to promote interoperable implementations of Diameter peer + discovery, the following mechanisms are described. These are based + on existing IETF standards. The first option (manual configuration) + MUST be supported by all Diameter nodes, while the latter option + (DNS) MAY be supported. + + There are two cases where Diameter peer discovery may be performed. + The first is when a Diameter client needs to discover a first-hop + Diameter agent. The second case is when a Diameter agent needs to + discover another agent - for further handling of a Diameter + operation. In both cases, the following 'search order' is + recommended: + + + 1. The Diameter implementation consults its list of static + (manually) configured Diameter agent locations. These will be + used if they exist and respond. + + + 2. The Diameter implementation performs a NAPTR query for a server + in a particular realm. The Diameter implementation has to know + in advance which realm to look for a Diameter agent. This could + be deduced, for example, from the 'realm' in a NAI that a + Diameter implementation needed to perform a Diameter operation + on. + + The NAPTR usage in Diameter follows the S-NAPTR DDDS application + [RFC3958] in which the SERVICE field includes tags for the + desired application and supported application protocol. The + application service tag for a Diameter application is 'aaa' and + the supported application protocol tags are 'diameter.tcp', + 'diameter.sctp', 'diameter.dtls' or 'diameter.tls.tcp'. + + The client can follow the resolution process defined by the + S-NAPTR DDDS [RFC3958] application to find a matching SRV, A or + AAAA record of a suitable peer. The domain suffixes in the NAPTR + replacement field SHOULD match the domain of the original query. + An example can be found in Appendix B. + + 3. If no NAPTR records are found, the requester directly queries for + SRV records '_diameter._sctp'.realm, '_diameter._dtls'.realm, + '_diameter._tcp'.realm and '_diameter._tls'.realm depending on + the requesters network protocol capabilities. If SRV records are + found then the requester can perform address record query (A RR's + + + +Fajardo, et al. Expires July 24, 2011 [Page 60] + +Internet-Draft Diameter Base Protocol January 2011 + + + and/or AAAA RR's) for the target hostname specified in the SRV + records. If no SRV records are found, the requester gives up. + + If the server is using a site certificate, the domain name in the + NAPTR query and the domain name in the replacement field MUST both be + valid based on the site certificate handed out by the server in the + TLS/TCP and DTLS/SCTP or IKE exchange. Similarly, the domain name in + the SRV query and the domain name in the target in the SRV record + MUST both be valid based on the same site certificate. Otherwise, an + attacker could modify the DNS records to contain replacement values + in a different domain, and the client could not validate that this + was the desired behavior, or the result of an attack. + + Also, the Diameter Peer MUST check to make sure that the discovered + peers are authorized to act in its role. Authentication via IKE or + TLS/TCP and DTLS/SCTP, or validation of DNS RRs via DNSSEC is not + sufficient to conclude this. For example, a web server may have + obtained a valid TLS/TCP and DTLS/SCTP certificate, and secured RRs + may be included in the DNS, but this does not imply that it is + authorized to act as a Diameter Server. + + Authorization can be achieved for example, by configuration of a + Diameter Server CA. Alternatively this can be achieved by definition + of OIDs within TLS/TCP and DTLS/SCTP or IKE certificates so as to + signify Diameter Server authorization. + + A dynamically discovered peer causes an entry in the Peer Table (see + Section 2.6) to be created. Note that entries created via DNS MUST + expire (or be refreshed) within the DNS TTL. If a peer is discovered + outside of the local realm, a routing table entry (see Section 2.7) + for the peer's realm is created. The routing table entry's + expiration MUST match the peer's expiration value. + +5.3. Capabilities Exchange + + When two Diameter peers establish a transport connection, they MUST + exchange the Capabilities Exchange messages, as specified in the peer + state machine (see Section 5.6). This message allows the discovery + of a peer's identity and its capabilities (protocol version number, + supported Diameter applications, security mechanisms, etc.) + + The receiver only issues commands to its peers that have advertised + support for the Diameter application that defines the command. A + Diameter node MUST cache the supported applications in order to + ensure that unrecognized commands and/or AVPs are not unnecessarily + sent to a peer. + + A receiver of a Capabilities-Exchange-Req (CER) message that does not + + + +Fajardo, et al. Expires July 24, 2011 [Page 61] + +Internet-Draft Diameter Base Protocol January 2011 + + + have any applications in common with the sender MUST return a + Capabilities-Exchange-Answer (CEA) with the Result-Code AVP set to + DIAMETER_NO_COMMON_APPLICATION, and SHOULD disconnect the transport + layer connection. Note that receiving a CER or CEA from a peer + advertising itself as a Relay (see Section 2.4) MUST be interpreted + as having common applications with the peer. + + The receiver of the Capabilities-Exchange-Request (CER) MUST + determine common applications by computing the intersection of its + own set of supported Application Id against all of the application + identifier AVPs (Auth-Application-Id, Acct-Application-Id and Vendor- + Specific-Application-Id) present in the CER. The value of the + Vendor-Id AVP in the Vendor-Specific-Application-Id MUST NOT be used + during computation. The sender of the Capabilities-Exchange-Answer + (CEA) SHOULD include all of its supported applications as a hint to + the receiver regarding all of its application capabilities. + + Diameter implementations SHOULD first attempt to establish a TLS/TCP + and DTLS/SCTP connection prior to the CER/CEA exchange. This + protects the capabilities information of both peers. To support + older Diameter implementations that do not fully conform to this + document, the transport security MAY still be negotiated via Inband- + Security AVP. In this case, the receiver of a Capabilities-Exchange- + Req (CER) message that does not have any security mechanisms in + common with the sender MUST return a Capabilities-Exchange-Answer + (CEA) with the Result-Code AVP set to DIAMETER_NO_COMMON_SECURITY, + and SHOULD disconnect the transport layer connection. + + CERs received from unknown peers MAY be silently discarded, or a CEA + MAY be issued with the Result-Code AVP set to DIAMETER_UNKNOWN_PEER. + In both cases, the transport connection is closed. If the local + policy permits receiving CERs from unknown hosts, a successful CEA + MAY be returned. If a CER from an unknown peer is answered with a + successful CEA, the lifetime of the peer entry is equal to the + lifetime of the transport connection. In case of a transport + failure, all the pending transactions destined to the unknown peer + can be discarded. + + The CER and CEA messages MUST NOT be proxied, redirected or relayed. + + Since the CER/CEA messages cannot be proxied, it is still possible + that an upstream agent receives a message for which it has no + available peers to handle the application that corresponds to the + Command-Code. In such instances, the 'E' bit is set in the answer + message (see Section 7.) with the Result-Code AVP set to + DIAMETER_UNABLE_TO_DELIVER to inform the downstream to take action + (e.g., re-routing request to an alternate peer). + + + + +Fajardo, et al. Expires July 24, 2011 [Page 62] + +Internet-Draft Diameter Base Protocol January 2011 + + + With the exception of the Capabilities-Exchange-Request message, a + message of type Request that includes the Auth-Application-Id or + Acct-Application-Id AVPs, or a message with an application-specific + command code, MAY only be forwarded to a host that has explicitly + advertised support for the application (or has advertised the Relay + Application Id). + +5.3.1. Capabilities-Exchange-Request + + The Capabilities-Exchange-Request (CER), indicated by the Command- + Code set to 257 and the Command Flags' 'R' bit set, is sent to + exchange local capabilities. Upon detection of a transport failure, + this message MUST NOT be sent to an alternate peer. + + When Diameter is run over SCTP [RFC4960] or DTLS/SCTP [RFC6083], + which allow for connections to span multiple interfaces and multiple + IP addresses, the Capabilities-Exchange-Request message MUST contain + one Host-IP- Address AVP for each potential IP address that MAY be + locally used when transmitting Diameter messages. + + Message Format + + <CER> ::= < Diameter Header: 257, REQ > + { Origin-Host } + { Origin-Realm } + 1* { Host-IP-Address } + { Vendor-Id } + { Product-Name } + [ Origin-State-Id ] + * [ Supported-Vendor-Id ] + * [ Auth-Application-Id ] + * [ Inband-Security-Id ] + * [ Acct-Application-Id ] + * [ Vendor-Specific-Application-Id ] + [ Firmware-Revision ] + * [ AVP ] + +5.3.2. Capabilities-Exchange-Answer + + The Capabilities-Exchange-Answer (CEA), indicated by the Command-Code + set to 257 and the Command Flags' 'R' bit cleared, is sent in + response to a CER message. + + When Diameter is run over SCTP [RFC4960] or DTLS/SCTP [RFC6083], + which allow connections to span multiple interfaces, hence, multiple + IP addresses, the Capabilities-Exchange-Answer message MUST contain + one Host-IP-Address AVP for each potential IP address that MAY be + locally used when transmitting Diameter messages. + + + +Fajardo, et al. Expires July 24, 2011 [Page 63] + +Internet-Draft Diameter Base Protocol January 2011 + + + Message Format + + <CEA> ::= < Diameter Header: 257 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + 1* { Host-IP-Address } + { Vendor-Id } + { Product-Name } + [ Origin-State-Id ] + [ Error-Message ] + [ Failed-AVP ] + * [ Supported-Vendor-Id ] + * [ Auth-Application-Id ] + * [ Inband-Security-Id ] + * [ Acct-Application-Id ] + * [ Vendor-Specific-Application-Id ] + [ Firmware-Revision ] + * [ AVP ] + +5.3.3. Vendor-Id AVP + + The Vendor-Id AVP (AVP Code 266) is of type Unsigned32 and contains + the IANA "SMI Network Management Private Enterprise Codes" [RFC3232] + value assigned to the vendor of the Diameter device. It is + envisioned that the combination of the Vendor-Id, Product-Name + (Section 5.3.7) and the Firmware-Revision (Section 5.3.4) AVPs may + provide useful debugging information. + + A Vendor-Id value of zero in the CER or CEA messages is reserved and + indicates that this field is ignored. + +5.3.4. Firmware-Revision AVP + + The Firmware-Revision AVP (AVP Code 267) is of type Unsigned32 and is + used to inform a Diameter peer of the firmware revision of the + issuing device. + + For devices that do not have a firmware revision (general purpose + computers running Diameter software modules, for instance), the + revision of the Diameter software module may be reported instead. + +5.3.5. Host-IP-Address AVP + + The Host-IP-Address AVP (AVP Code 257) is of type Address and is used + to inform a Diameter peer of the sender's IP address. All source + addresses that a Diameter node expects to use with SCTP [RFC4960] or + DTLS/SCTP [RFC6083] MUST be advertised in the CER and CEA messages by + + + +Fajardo, et al. Expires July 24, 2011 [Page 64] + +Internet-Draft Diameter Base Protocol January 2011 + + + including a Host-IP-Address AVP for each address. + +5.3.6. Supported-Vendor-Id AVP + + The Supported-Vendor-Id AVP (AVP Code 265) is of type Unsigned32 and + contains the IANA "SMI Network Management Private Enterprise Codes" + [RFC3232] value assigned to a vendor other than the device vendor but + including the application vendor. This is used in the CER and CEA + messages in order to inform the peer that the sender supports (a + subset of) the vendor-specific AVPs defined by the vendor identified + in this AVP. The value of this AVP MUST NOT be set to zero. + Multiple instances of this AVP containing the same value SHOULD NOT + be sent. + +5.3.7. Product-Name AVP + + The Product-Name AVP (AVP Code 269) is of type UTF8String, and + contains the vendor assigned name for the product. The Product-Name + AVP SHOULD remain constant across firmware revisions for the same + product. + +5.4. Disconnecting Peer connections + + When a Diameter node disconnects one of its transport connections, + its peer cannot know the reason for the disconnect, and will most + likely assume that a connectivity problem occurred, or that the peer + has rebooted. In these cases, the peer may periodically attempt to + reconnect, as stated in Section 2.1. In the event that the + disconnect was a result of either a shortage of internal resources, + or simply that the node in question has no intentions of forwarding + any Diameter messages to the peer in the foreseeable future, a + periodic connection request would not be welcomed. The + Disconnection-Reason AVP contains the reason the Diameter node issued + the Disconnect-Peer-Request message. + + The Disconnect-Peer-Request message is used by a Diameter node to + inform its peer of its intent to disconnect the transport layer, and + that the peer shouldn't reconnect unless it has a valid reason to do + so (e.g., message to be forwarded). Upon receipt of the message, the + Disconnect-Peer-Answer is returned, which SHOULD contain an error if + messages have recently been forwarded, and are likely in flight, + which would otherwise cause a race condition. + + The receiver of the Disconnect-Peer-Answer initiates the transport + disconnect. The sender of the Disconnect-Peer-Answer should be able + to detect the transport closure and cleanup the connection. + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 65] + +Internet-Draft Diameter Base Protocol January 2011 + + +5.4.1. Disconnect-Peer-Request + + The Disconnect-Peer-Request (DPR), indicated by the Command-Code set + to 282 and the Command Flags' 'R' bit set, is sent to a peer to + inform its intentions to shutdown the transport connection. Upon + detection of a transport failure, this message MUST NOT be sent to an + alternate peer. + + Message Format + + <DPR> ::= < Diameter Header: 282, REQ > + { Origin-Host } + { Origin-Realm } + { Disconnect-Cause } + * [ AVP ] + +5.4.2. Disconnect-Peer-Answer + + The Disconnect-Peer-Answer (DPA), indicated by the Command-Code set + to 282 and the Command Flags' 'R' bit cleared, is sent as a response + to the Disconnect-Peer-Request message. Upon receipt of this + message, the transport connection is shutdown. + + Message Format + + <DPA> ::= < Diameter Header: 282 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Error-Message ] + [ Failed-AVP ] + * [ AVP ] + +5.4.3. Disconnect-Cause AVP + + The Disconnect-Cause AVP (AVP Code 273) is of type Enumerated. A + Diameter node MUST include this AVP in the Disconnect-Peer-Request + message to inform the peer of the reason for its intention to + shutdown the transport connection. The following values are + supported: + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 66] + +Internet-Draft Diameter Base Protocol January 2011 + + + REBOOTING 0 + A scheduled reboot is imminent. Receiver of DPR with above result + code MAY attempt reconnection. + + BUSY 1 + The peer's internal resources are constrained, and it has + determined that the transport connection needs to be closed. + Receiver of DPR with above result code SHOULD NOT attempt + reconnection. + + DO_NOT_WANT_TO_TALK_TO_YOU 2 + The peer has determined that it does not see a need for the + transport connection to exist, since it does not expect any + messages to be exchanged in the near future. Receiver of DPR + with above result code SHOULD NOT attempt reconnection. + +5.5. Transport Failure Detection + + Given the nature of the Diameter protocol, it is recommended that + transport failures be detected as soon as possible. Detecting such + failures will minimize the occurrence of messages sent to unavailable + agents, resulting in unnecessary delays, and will provide better + failover performance. The Device-Watchdog-Request and Device- + Watchdog-Answer messages, defined in this section, are used to pro- + actively detect transport failures. + +5.5.1. Device-Watchdog-Request + + The Device-Watchdog-Request (DWR), indicated by the Command-Code set + to 280 and the Command Flags' 'R' bit set, is sent to a peer when no + traffic has been exchanged between two peers (see Section 5.5.3). + Upon detection of a transport failure, this message MUST NOT be sent + to an alternate peer. + + Message Format + + <DWR> ::= < Diameter Header: 280, REQ > + { Origin-Host } + { Origin-Realm } + [ Origin-State-Id ] + * [ AVP ] + +5.5.2. Device-Watchdog-Answer + + The Device-Watchdog-Answer (DWA), indicated by the Command-Code set + to 280 and the Command Flags' 'R' bit cleared, is sent as a response + to the Device-Watchdog-Request message. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 67] + +Internet-Draft Diameter Base Protocol January 2011 + + + Message Format + + <DWA> ::= < Diameter Header: 280 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Error-Message ] + [ Failed-AVP ] + [ Origin-State-Id ] + * [ AVP ] + +5.5.3. Transport Failure Algorithm + + The transport failure algorithm is defined in [RFC3539]. All + Diameter implementations MUST support the algorithm defined in the + specification in order to be compliant to the Diameter base protocol. + +5.5.4. Failover and Failback Procedures + + In the event that a transport failure is detected with a peer, it is + necessary for all pending request messages to be forwarded to an + alternate agent, if possible. This is commonly referred to as + failover. + + In order for a Diameter node to perform failover procedures, it is + necessary for the node to maintain a pending message queue for a + given peer. When an answer message is received, the corresponding + request is removed from the queue. The Hop-by-Hop Identifier field + is used to match the answer with the queued request. + + When a transport failure is detected, if possible all messages in the + queue are sent to an alternate agent with the T flag set. On booting + a Diameter client or agent, the T flag is also set on any records + still remaining to be transmitted in non-volatile storage. An + example of a case where it is not possible to forward the message to + an alternate server is when the message has a fixed destination, and + the unavailable peer is the message's final destination (see + Destination-Host AVP). Such an error requires that the agent return + an answer message with the 'E' bit set and the Result-Code AVP set to + DIAMETER_UNABLE_TO_DELIVER. + + It is important to note that multiple identical requests or answers + MAY be received as a result of a failover. The End-to-End Identifier + field in the Diameter header along with the Origin-Host AVP MUST be + used to identify duplicate messages. + + As described in Section 2.1, a connection request should be + periodically attempted with the failed peer in order to re-establish + + + +Fajardo, et al. Expires July 24, 2011 [Page 68] + +Internet-Draft Diameter Base Protocol January 2011 + + + the transport connection. Once a connection has been successfully + established, messages can once again be forwarded to the peer. This + is commonly referred to as failback. + +5.6. Peer State Machine + + This section contains a finite state machine that MUST be observed by + all Diameter implementations. Each Diameter node MUST follow the + state machine described below when communicating with each peer. + Multiple actions are separated by commas, and may continue on + succeeding lines, as space requires. Similarly, state and next state + may also span multiple lines, as space requires. + + This state machine is closely coupled with the state machine + described in [RFC3539], which is used to open, close, failover, + probe, and reopen transport connections. Note in particular that + [RFC3539] requires the use of watchdog messages to probe connections. + For Diameter, DWR and DWA messages are to be used. + + I- is used to represent the initiator (connecting) connection, while + the R- is used to represent the responder (listening) connection. + The lack of a prefix indicates that the event or action is the same + regardless of the connection on which the event occurred. + + The stable states that a state machine may be in are Closed, I-Open + and R-Open; all other states are intermediate. Note that I-Open and + R-Open are equivalent except for whether the initiator or responder + transport connection is used for communication. + + A CER message is always sent on the initiating connection immediately + after the connection request is successfully completed. In the case + of an election, one of the two connections will shut down. The + responder connection will survive if the Origin-Host of the local + Diameter entity is higher than that of the peer; the initiator + connection will survive if the peer's Origin-Host is higher. All + subsequent messages are sent on the surviving connection. Note that + the results of an election on one peer are guaranteed to be the + inverse of the results on the other. + + For TLS/TCP and DTLS/SCTP usage, TLS/TCP and DTLS/SCTP handshake + SHOULD begin when both ends are in the closed state prior to any + Diameter message exchanges. The TLS/TCP and DTLS/SCTP connection + SHOULD be established before sending any CER or CEA message to secure + and protect the capabilities information of both peers. The TLS/TCP + and DTLS/SCTP connection SHOULD be disconnected when the state + machine moves to the closed state. When connecting to responders + that do not conform to this document (i.e. older Diameter + implementations that are not prepared to received TLS/TCP and DTLS/ + + + +Fajardo, et al. Expires July 24, 2011 [Page 69] + +Internet-Draft Diameter Base Protocol January 2011 + + + SCTP connections in the closed state), the initial TLS/TCP and DTLS/ + SCTP connection attempt will fail. The initiator MAY then attempt to + connect via TCP or SCTP and initiate the TLS/TCP and DTLS/SCTP + handshake when both ends are in the open state. If the handshake is + successful, all further messages will be sent via TLS/TCP and DTLS/ + SCTP. If the handshake fails, both ends move to the closed state. + + The state machine constrains only the behavior of a Diameter + implementation as seen by Diameter peers through events on the wire. + + Any implementation that produces equivalent results is considered + compliant. + + state event action next state + ----------------------------------------------------------------- + Closed Start I-Snd-Conn-Req Wait-Conn-Ack + R-Conn-CER R-Accept, R-Open + Process-CER, + R-Snd-CEA + + Wait-Conn-Ack I-Rcv-Conn-Ack I-Snd-CER Wait-I-CEA + I-Rcv-Conn-Nack Cleanup Closed + R-Conn-CER R-Accept, Wait-Conn-Ack/ + Process-CER Elect + Timeout Error Closed + + Wait-I-CEA I-Rcv-CEA Process-CEA I-Open + R-Conn-CER R-Accept, Wait-Returns + Process-CER, + Elect + I-Peer-Disc I-Disc Closed + I-Rcv-Non-CEA Error Closed + Timeout Error Closed + + Wait-Conn-Ack/ I-Rcv-Conn-Ack I-Snd-CER,Elect Wait-Returns + Elect I-Rcv-Conn-Nack R-Snd-CEA R-Open + R-Peer-Disc R-Disc Wait-Conn-Ack + R-Conn-CER R-Reject Wait-Conn-Ack/ + Elect + Timeout Error Closed + + Wait-Returns Win-Election I-Disc,R-Snd-CEA R-Open + I-Peer-Disc I-Disc, R-Open + R-Snd-CEA + I-Rcv-CEA R-Disc I-Open + R-Peer-Disc R-Disc Wait-I-CEA + R-Conn-CER R-Reject Wait-Returns + Timeout Error Closed + + + +Fajardo, et al. Expires July 24, 2011 [Page 70] + +Internet-Draft Diameter Base Protocol January 2011 + + + R-Open Send-Message R-Snd-Message R-Open + R-Rcv-Message Process R-Open + R-Rcv-DWR Process-DWR, R-Open + R-Snd-DWA + R-Rcv-DWA Process-DWA R-Open + R-Conn-CER R-Reject R-Open + Stop R-Snd-DPR Closing + R-Rcv-DPR R-Snd-DPA, Closed + R-Disc + R-Peer-Disc R-Disc Closed + + I-Open Send-Message I-Snd-Message I-Open + I-Rcv-Message Process I-Open + I-Rcv-DWR Process-DWR, I-Open + I-Snd-DWA + I-Rcv-DWA Process-DWA I-Open + R-Conn-CER R-Reject I-Open + Stop I-Snd-DPR Closing + I-Rcv-DPR I-Snd-DPA, Closed + I-Disc + I-Peer-Disc I-Disc Closed + + Closing I-Rcv-DPA I-Disc Closed + R-Rcv-DPA R-Disc Closed + Timeout Error Closed + I-Peer-Disc I-Disc Closed + R-Peer-Disc R-Disc Closed + +5.6.1. Incoming connections + + When a connection request is received from a Diameter peer, it is + not, in the general case, possible to know the identity of that peer + until a CER is received from it. This is because host and port + determine the identity of a Diameter peer; and the source port of an + incoming connection is arbitrary. Upon receipt of CER, the identity + of the connecting peer can be uniquely determined from Origin-Host. + + For this reason, a Diameter peer must employ logic separate from the + state machine to receive connection requests, accept them, and await + CER. Once CER arrives on a new connection, the Origin-Host that + identifies the peer is used to locate the state machine associated + with that peer, and the new connection and CER are passed to the + state machine as an R-Conn-CER event. + + The logic that handles incoming connections SHOULD close and discard + the connection if any message other than CER arrives, or if an + implementation-defined timeout occurs prior to receipt of CER. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 71] + +Internet-Draft Diameter Base Protocol January 2011 + + + Because handling of incoming connections up to and including receipt + of CER requires logic, separate from that of any individual state + machine associated with a particular peer, it is described separately + in this section rather than in the state machine above. + +5.6.2. Events + + Transitions and actions in the automaton are caused by events. In + this section, we will ignore the -I and -R prefix, since the actual + event would be identical, but would occur on one of two possible + connections. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 72] + +Internet-Draft Diameter Base Protocol January 2011 + + + Start The Diameter application has signaled that a + connection should be initiated with the peer. + + R-Conn-CER An acknowledgement is received stating that the + transport connection has been established, and the + associated CER has arrived. + + Rcv-Conn-Ack A positive acknowledgement is received confirming that + the transport connection is established. + + Rcv-Conn-Nack A negative acknowledgement was received stating that + the transport connection was not established. + + Timeout An application-defined timer has expired while waiting + for some event. + + Rcv-CER A CER message from the peer was received. + + Rcv-CEA A CEA message from the peer was received. + + Rcv-Non-CEA A message other than CEA from the peer was received. + + Peer-Disc A disconnection indication from the peer was received. + + Rcv-DPR A DPR message from the peer was received. + + Rcv-DPA A DPA message from the peer was received. + + Win-Election An election was held, and the local node was the + winner. + + Send-Message A message is to be sent. + + Rcv-Message A message other than CER, CEA, DPR, DPA, DWR or DWA + was received. + + Stop The Diameter application has signaled that a + connection should be terminated (e.g., on system + shutdown). + +5.6.3. Actions + + Actions in the automaton are caused by events and typically indicate + the transmission of packets and/or an action to be taken on the + connection. In this section we will ignore the I- and R-prefix, + since the actual action would be identical, but would occur on one of + two possible connections. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 73] + +Internet-Draft Diameter Base Protocol January 2011 + + + Snd-Conn-Req A transport connection is initiated with the peer. + + Accept The incoming connection associated with the R-Conn-CER + is accepted as the responder connection. + + Reject The incoming connection associated with the R-Conn-CER + is disconnected. + + Process-CER The CER associated with the R-Conn-CER is processed. + Snd-CER A CER message is sent to the peer. + + Snd-CEA A CEA message is sent to the peer. + + Cleanup If necessary, the connection is shutdown, and any + local resources are freed. + + Error The transport layer connection is disconnected, + either politely or abortively, in response to + an error condition. Local resources are freed. + + Process-CEA A received CEA is processed. + + Snd-DPR A DPR message is sent to the peer. + + Snd-DPA A DPA message is sent to the peer. + + Disc The transport layer connection is disconnected, + and local resources are freed. + + Elect An election occurs (see Section 5.6.4 for more + information). + + Snd-Message A message is sent. + + Snd-DWR A DWR message is sent. + + Snd-DWA A DWA message is sent. + + Process-DWR The DWR message is serviced. + + Process-DWA The DWA message is serviced. + + Process A message is serviced. + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 74] + +Internet-Draft Diameter Base Protocol January 2011 + + +5.6.4. The Election Process + + The election is performed on the responder. The responder compares + the Origin-Host received in the CER with its own Origin-Host as two + streams of octets. If the local Origin-Host lexicographically + succeeds the received Origin-Host a Win-Election event is issued + locally. Diameter identities are in ASCII form therefore the lexical + comparison is consistent with DNS case insensitivity where octets + that fall in the ASCII range 'a' through 'z' MUST compare equally to + their upper-case counterparts between 'A' and 'Z'. See Appendix D + for interactions between the Diameter protocol and Internationalized + Domain Name (IDNs). + + The winner of the election MUST close the connection it initiated. + Historically, maintaining the responder side of a connection was more + efficient than maintaining the initiator side. However, current + practices makes this distinction irrelevant. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 75] + +Internet-Draft Diameter Base Protocol January 2011 + + +6. Diameter message processing + + This section describes how Diameter requests and answers are created + and processed. + +6.1. Diameter Request Routing Overview + + A request is sent towards its final destination using a combination + of the Destination-Realm and Destination-Host AVPs, in one of these + three combinations: + + o a request that is not able to be proxied (such as CER) MUST NOT + contain either Destination-Realm or Destination-Host AVPs. + + o a request that needs to be sent to a home server serving a + specific realm, but not to a specific server (such as the first + request of a series of round-trips), MUST contain a Destination- + Realm AVP, but MUST NOT contain a Destination-Host AVP. For + Diameter clients, the value of the Destination-Realm AVP MAY be + extracted from the User-Name AVP, or other methods. + + o otherwise, a request that needs to be sent to a specific home + server among those serving a given realm, MUST contain both the + Destination-Realm and Destination-Host AVPs. + + The Destination-Host AVP is used as described above when the + destination of the request is fixed, which includes: + + o Authentication requests that span multiple round trips + + o A Diameter message that uses a security mechanism that makes use + of a pre-established session key shared between the source and the + final destination of the message. + + o Server initiated messages that MUST be received by a specific + Diameter client (e.g., access device), such as the Abort-Session- + Request message, which is used to request that a particular user's + session be terminated. + + Note that an agent can forward a request to a host described in the + Destination-Host AVP only if the host in question is included in its + peer table (see Section 2.7). Otherwise, the request is routed based + on the Destination-Realm only (see Sections 6.1.6). + + When a message is received, the message is processed in the following + order: + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 76] + +Internet-Draft Diameter Base Protocol January 2011 + + + o If the message is destined for the local host, the procedures + listed in Section 6.1.4 are followed. + + o If the message is intended for a Diameter peer with whom the local + host is able to directly communicate, the procedures listed in + Section 6.1.5 are followed. This is known as Request Forwarding. + + o The procedures listed in Section 6.1.6 are followed, which is + known as Request Routing. + + o If none of the above is successful, an answer is returned with the + Result-Code set to DIAMETER_UNABLE_TO_DELIVER, with the E-bit set. + + For routing of Diameter messages to work within an administrative + domain, all Diameter nodes within the realm MUST be peers. + + Note the processing rules contained in this section are intended to + be used as general guidelines to Diameter developers. Certain + implementations MAY use different methods than the ones described + here, and still comply with the protocol specification. See Section + 7 for more detail on error handling. + +6.1.1. Originating a Request + + When creating a request, in addition to any other procedures + described in the application definition for that specific request, + the following procedures MUST be followed: + + o the Command-Code is set to the appropriate value + + o the 'R' bit is set + + o the End-to-End Identifier is set to a locally unique value + + o the Origin-Host and Origin-Realm AVPs MUST be set to the + appropriate values, used to identify the source of the message + + o the Destination-Host and Destination-Realm AVPs MUST be set to the + appropriate values as described in Section 6.1. + +6.1.2. Sending a Request + + When sending a request, originated either locally, or as the result + of a forwarding or routing operation, the following procedures SHOULD + be followed: + + o The Hop-by-Hop Identifier SHOULD be set to a locally unique value. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 77] + +Internet-Draft Diameter Base Protocol January 2011 + + + o The message SHOULD be saved in the list of pending requests. + + Other actions to perform on the message based on the particular role + the agent is playing are described in the following sections. + +6.1.3. Receiving Requests + + A relay or proxy agent MUST check for forwarding loops when receiving + requests. A loop is detected if the server finds its own identity in + a Route-Record AVP. When such an event occurs, the agent MUST answer + with the Result-Code AVP set to DIAMETER_LOOP_DETECTED. + +6.1.4. Processing Local Requests + + A request is known to be for local consumption when one of the + following conditions occur: + + o The Destination-Host AVP contains the local host's identity, + + o The Destination-Host AVP is not present, the Destination-Realm AVP + contains a realm the server is configured to process locally, and + the Diameter application is locally supported, or + + o Both the Destination-Host and the Destination-Realm are not + present. + + When a request is locally processed, the rules in Section 6.2 should + be used to generate the corresponding answer. + +6.1.5. Request Forwarding + + Request forwarding is done using the Diameter Peer Table. The + Diameter peer table contains all of the peers that the local node is + able to directly communicate with. + + When a request is received, and the host encoded in the Destination- + Host AVP is one that is present in the peer table, the message SHOULD + be forwarded to the peer. + +6.1.6. Request Routing + + Diameter request message routing is done via realms and application + identifiers. A Diameter message that may be forwarded by Diameter + agents (proxies, redirect or relay agents) MUST include the target + realm in the Destination-Realm AVP. Request routing SHOULD rely on + the Destination-Realm AVP and the Application Id present in the + request message header to aid in the routing decision. The realm MAY + be retrieved from the User-Name AVP, which is in the form of a + + + +Fajardo, et al. Expires July 24, 2011 [Page 78] + +Internet-Draft Diameter Base Protocol January 2011 + + + Network Access Identifier (NAI). The realm portion of the NAI is + inserted in the Destination-Realm AVP. + + Diameter agents MAY have a list of locally supported realms and + applications, and MAY have a list of externally supported realms and + applications. When a request is received that includes a realm + and/or application that is not locally supported, the message is + routed to the peer configured in the Routing Table (see Section 2.7). + + Realm names and Application Ids are the minimum supported routing + criteria, additional information may be needed to support redirect + semantics. + +6.1.7. Predictive Loop Avoidance + + Before forwarding or routing a request, Diameter agents, in addition + to processing done in Section 6.1.3, SHOULD check for the presence of + candidate route's peer identity in any of the Route-Record AVPs. In + an event of the agent detecting the presence of a candidate route's + peer identity in a Route-Record AVP, the agent MUST ignore such route + for the Diameter request message and attempt alternate routes if any. + In case all the candidate routes are eliminated by the above + criteria, the agent SHOULD return DIAMETER_UNABLE_TO_DELIVER message. + +6.1.8. Redirecting Requests + + When a redirect agent receives a request whose routing entry is set + to REDIRECT, it MUST reply with an answer message with the 'E' bit + set, while maintaining the Hop-by-Hop Identifier in the header, and + include the Result-Code AVP to DIAMETER_REDIRECT_INDICATION. Each of + the servers associated with the routing entry are added in separate + Redirect-Host AVP. + + +------------------+ + | Diameter | + | Redirect Agent | + +------------------+ + ^ | 2. command + 'E' bit + 1. Request | | Result-Code = + [email protected] | | DIAMETER_REDIRECT_INDICATION + + | | Redirect-Host AVP(s) + | v + +-------------+ 3. Request +-------------+ + | example.com |------------->| example.net | + | Relay | | Diameter | + | Agent |<-------------| Server | + +-------------+ 4. Answer +-------------+ + + + + +Fajardo, et al. Expires July 24, 2011 [Page 79] + +Internet-Draft Diameter Base Protocol January 2011 + + + Figure 5: Diameter Redirect Agent + + The receiver of the answer message with the 'E' bit set, and the + Result-Code AVP set to DIAMETER_REDIRECT_INDICATION uses the hop-by- + hop field in the Diameter header to identify the request in the + pending message queue (see Section 5.3) that is to be redirected. If + no transport connection exists with the new agent, one is created, + and the request is sent directly to it. + + Multiple Redirect-Host AVPs are allowed. The receiver of the answer + message with the 'E' bit set selects exactly one of these hosts as + the destination of the redirected message. + + When the Redirect-Host-Usage AVP included in the answer message has a + non-zero value, a route entry for the redirect indications is created + and cached by the receiver. The redirect usage for such route entry + is set by the value of Redirect-Host-Usage AVP and the lifetime of + the cached route entry is set by Redirect-Max-Cache-Time AVP value. + + It is possible that multiple redirect indications can create multiple + cached route entries differing only in their redirect usage and the + peer to forward messages to. As an example, two(2) route entries + that are created by two(2) redirect indications results in two(2) + cached routes for the same realm and Application Id. However, one + has a redirect usage of ALL_SESSION where matching request will be + forwarded to one peer and the other has a redirect usage of ALL_REALM + where request are forwarded to another peer. Therefore, an incoming + request that matches the realm and Application Id of both routes will + need additional resolution. In such a case, a routing precedence + rule MUST be used against the redirect usage value to resolve the + contention. The precedence rule can be found in Section 6.13. + +6.1.9. Relaying and Proxying Requests + + A relay or proxy agent MUST append a Route-Record AVP to all requests + forwarded. The AVP contains the identity of the peer the request was + received from. + + The Hop-by-Hop identifier in the request is saved, and replaced with + a locally unique value. The source of the request is also saved, + which includes the IP address, port and protocol. + + A relay or proxy agent MAY include the Proxy-Info AVP in requests if + it requires access to any local state information when the + corresponding response is received. The Proxy-Info AVP has security + implications as state information is distribute to other entities. + As such, it is RECOMMMENDED to protect the content of the Proxy-Info + AVP with cryptographic mechanisms, for example by using a keyed + + + +Fajardo, et al. Expires July 24, 2011 [Page 80] + +Internet-Draft Diameter Base Protocol January 2011 + + + message digest. Such a mechanism, however, requires the management + of keys, although only locally at the Diameter server. Still, a full + description of the management of the keys used to protect the Proxy- + Info AVP is beyond the scope of this document. Below is a list of + commonly recommended: + + o The keys should be generated securely following the randomness + recommendations in [RFC4086]. + + o The keys and cryptographic protection algorithms should be at + least 128 bits in strength. + + o The keys should not be used for any other purpose than generating + and verifying tickets. + + o The keys should be changed regularly. + + o The keys should be changed if the ticket format or cryptographic + protection algorithms change. + + The message is then forwarded to the next hop, as identified in the + Routing Table. + + Figure 6 provides an example of message routing using the procedures + listed in these sections. + + (Origin-Host=nas.example.net) (Origin-Host=nas.example.net) + (Origin-Realm=example.net) (Origin-Realm=example.net) + (Destination-Realm=example.com) (Destination- + Realm=example.com) + (Route-Record=nas.example.net) + +------+ ------> +------+ ------> +------+ + | | (Request) | | (Request) | | + | NAS +-------------------+ DRL +-------------------+ HMS | + | | | | | | + +------+ <------ +------+ <------ +------+ + example.net (Answer) example.net (Answer) example.com + (Origin-Host=hms.example.com) (Origin-Host=hms.example.com) + (Origin-Realm=example.com) (Origin-Realm=example.com) + + Figure 6: Routing of Diameter messages + + Relay and proxy agents are not required to perform full inspection of + incoming messages. At a minimum, validation of the message header + and relevant routing AVPs has to be done when relaying messages. + Proxy agents may optionally perform more in-depth message validation + for applications it is interested in. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 81] + +Internet-Draft Diameter Base Protocol January 2011 + + +6.2. Diameter Answer Processing + + When a request is locally processed, the following procedures MUST be + applied to create the associated answer, in addition to any + additional procedures that MAY be discussed in the Diameter + application defining the command: + + o The same Hop-by-Hop identifier in the request is used in the + answer. + + o The local host's identity is encoded in the Origin-Host AVP. + + o The Destination-Host and Destination-Realm AVPs MUST NOT be + present in the answer message. + + o The Result-Code AVP is added with its value indicating success or + failure. + + o If the Session-Id is present in the request, it MUST be included + in the answer. + + o Any Proxy-Info AVPs in the request MUST be added to the answer + message, in the same order they were present in the request. + + o The 'P' bit is set to the same value as the one in the request. + + o The same End-to-End identifier in the request is used in the + answer. + + Note that the error messages (see Section 7.3) are also subjected to + the above processing rules. + +6.2.1. Processing received Answers + + A Diameter client or proxy MUST match the Hop-by-Hop Identifier in an + answer received against the list of pending requests. The + corresponding message should be removed from the list of pending + requests. It SHOULD ignore answers received that do not match a + known Hop-by-Hop Identifier. + +6.2.2. Relaying and Proxying Answers + + If the answer is for a request which was proxied or relayed, the + agent MUST restore the original value of the Diameter header's Hop- + by-Hop Identifier field. + + If the last Proxy-Info AVP in the message is targeted to the local + Diameter server, the AVP MUST be removed before the answer is + + + +Fajardo, et al. Expires July 24, 2011 [Page 82] + +Internet-Draft Diameter Base Protocol January 2011 + + + forwarded. + + If a relay or proxy agent receives an answer with a Result-Code AVP + indicating a failure, it MUST NOT modify the contents of the AVP. + Any additional local errors detected SHOULD be logged, but not + reflected in the Result-Code AVP. If the agent receives an answer + message with a Result-Code AVP indicating success, and it wishes to + modify the AVP to indicate an error, it MUST modify the Result-Code + AVP to contain the appropriate error in the message destined towards + the access device as well as include the Error-Reporting-Host AVP and + it MUST issue an STR on behalf of the access device towards the + Diameter server. + + The agent MUST then send the answer to the host that it received the + original request from. + +6.3. Origin-Host AVP + + The Origin-Host AVP (AVP Code 264) is of type DiameterIdentity, and + MUST be present in all Diameter messages. This AVP identifies the + endpoint that originated the Diameter message. Relay agents MUST NOT + modify this AVP. + + The value of the Origin-Host AVP is guaranteed to be unique within a + single host. + + Note that the Origin-Host AVP may resolve to more than one address as + the Diameter peer may support more than one address. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + +6.4. Origin-Realm AVP + + The Origin-Realm AVP (AVP Code 296) is of type DiameterIdentity. + This AVP contains the Realm of the originator of any Diameter message + and MUST be present in all messages. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + +6.5. Destination-Host AVP + + The Destination-Host AVP (AVP Code 293) is of type DiameterIdentity. + This AVP MUST be present in all unsolicited agent initiated messages, + MAY be present in request messages, and MUST NOT be present in Answer + messages. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 83] + +Internet-Draft Diameter Base Protocol January 2011 + + + The absence of the Destination-Host AVP will cause a message to be + sent to any Diameter server supporting the application within the + realm specified in Destination-Realm AVP. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + +6.6. Destination-Realm AVP + + The Destination-Realm AVP (AVP Code 283) is of type DiameterIdentity, + and contains the realm the message is to be routed to. The + Destination-Realm AVP MUST NOT be present in Answer messages. + Diameter Clients insert the realm portion of the User-Name AVP. + Diameter servers initiating a request message use the value of the + Origin-Realm AVP from a previous message received from the intended + target host (unless it is known a priori). When present, the + Destination-Realm AVP is used to perform message routing decisions. + + An ABNF for a request message that includes the Destination-Realm AVP + SHOULD list the Destination-Realm AVP as a required AVP (an AVP + indicated as {AVP}) otherwise the message is inherently a non- + routable message. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + +6.7. Routing AVPs + + The AVPs defined in this section are Diameter AVPs used for routing + purposes. These AVPs change as Diameter messages are processed by + agents. + +6.7.1. Route-Record AVP + + The Route-Record AVP (AVP Code 282) is of type DiameterIdentity. The + identity added in this AVP MUST be the same as the one received in + the Origin-Host of the Capabilities Exchange message. + +6.7.2. Proxy-Info AVP + + The Proxy-Info AVP (AVP Code 284) is of type Grouped. This AVP + contains the identity and local state information of the Diameter + node that creates and adds it to a message. The Grouped Data field + has the following ABNF grammar: + + Proxy-Info ::= < AVP Header: 284 > + { Proxy-Host } + { Proxy-State } + + + +Fajardo, et al. Expires July 24, 2011 [Page 84] + +Internet-Draft Diameter Base Protocol January 2011 + + + * [ AVP ] + +6.7.3. Proxy-Host AVP + + The Proxy-Host AVP (AVP Code 280) is of type DiameterIdentity. This + AVP contains the identity of the host that added the Proxy-Info AVP. + +6.7.4. Proxy-State AVP + + The Proxy-State AVP (AVP Code 33) is of type OctetString. It + contains state information that would otherwise be stored at the + Diameter entity that created it. As such, this AVP MUST be treated + as opaque data by other Diameter entities. + +6.8. Auth-Application-Id AVP + + The Auth-Application-Id AVP (AVP Code 258) is of type Unsigned32 and + is used in order to advertise support of the Authentication and + Authorization portion of an application (see Section 2.4). If + present in a message other than CER and CEA, the value of the Auth- + Application-Id AVP MUST match the Application Id present in the + Diameter message header. + +6.9. Acct-Application-Id AVP + + The Acct-Application-Id AVP (AVP Code 259) is of type Unsigned32 and + is used in order to advertise support of the Accounting portion of an + application (see Section 2.4). If present in a message other than + CER and CEA, the value of the Acct-Application-Id AVP MUST match the + Application Id present in the Diameter message header. + +6.10. Inband-Security-Id AVP + + The Inband-Security-Id AVP (AVP Code 299) is of type Unsigned32 and + is used in order to advertise support of the security portion of the + application. The use of this AVP in CER and CEA messages is no + longer recommended. Instead, discovery of a Diameter entities + security capabilities can be done either through static configuration + or via Diameter Peer Discovery described in Section 5.2. + + The following values are supported: + + + NO_INBAND_SECURITY 0 + + This peer does not support TLS/TCP and DTLS/SCTP. This is the + default value, if the AVP is omitted. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 85] + +Internet-Draft Diameter Base Protocol January 2011 + + + TLS 1 + + This node supports TLS/TCP and DTLS/SCTP security, as defined by + [RFC5246]. + +6.11. Vendor-Specific-Application-Id AVP + + The Vendor-Specific-Application-Id AVP (AVP Code 260) is of type + Grouped and is used to advertise support of a vendor-specific + Diameter Application. Exactly one instance of either Auth- + Application-Id or Acct-Application-Id AVP MUST be present. The + Application Id carried by either Auth-Application-Id or Acct- + Application-Id AVP MUST comply with vendor specific Application Id + assignment described in Sec 11.3. It MUST also match the Application + Id present in the Diameter header except when used in a CER or CEA + message. + + The Vendor-Id AVP is an informational AVP pertaining to the vendor + who may have authorship of the vendor-specific Diameter application. + It MUST NOT be used as a means of defining a completely separate + vendor-specific Application Id space. + + The Vendor-Specific-Application-Id AVP SHOULD be placed as close to + the Diameter header as possible. + + AVP Format + + <Vendor-Specific-Application-Id> ::= < AVP Header: 260 > + { Vendor-Id } + [ Auth-Application-Id ] + [ Acct-Application-Id ] + + A Vendor-Specific-Application-Id AVP MUST contain exactly one of + either Auth-Application-Id or Acct-Application-Id. If a Vendor- + Specific-Application-Id is received without any of these two AVPs, + then the recipient SHOULD issue an answer with a Result-Code set to + DIAMETER_MISSING_AVP. The answer SHOULD also include a Failed-AVP + which MUST contain an example of an Auth-Application-Id AVP and an + Acct-Application-Id AVP. + + If a Vendor-Specific-Application-Id is received that contains both + Auth-Application-Id and Acct-Application-Id, then the recipient MUST + issue an answer with Result-Code set to + DIAMETER_AVP_OCCURS_TOO_MANY_TIMES. The answer MUST also include a + Failed-AVP which MUST contain the received Auth-Application-Id AVP + and Acct-Application-Id AVP. + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 86] + +Internet-Draft Diameter Base Protocol January 2011 + + +6.12. Redirect-Host AVP + + The Redirect-Host AVP (AVP Code 292) is of type DiameterURI. One or + more of instances of this AVP MUST be present if the answer message's + 'E' bit is set and the Result-Code AVP is set to + DIAMETER_REDIRECT_INDICATION. + + Upon receiving the above, the receiving Diameter node SHOULD forward + the request directly to one of the hosts identified in these AVPs. + The server contained in the selected Redirect-Host AVP SHOULD be used + for all messages matching the criteria set by the Redirect-Host-Usage + AVP. + +6.13. Redirect-Host-Usage AVP + + The Redirect-Host-Usage AVP (AVP Code 261) is of type Enumerated. + This AVP MAY be present in answer messages whose 'E' bit is set and + the Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION. + + When present, this AVP provides a hints about how the routing entry + resulting from the Redirect-Host is to be used. The following values + are supported: + + + DONT_CACHE 0 + + The host specified in the Redirect-Host AVP SHOULD NOT be cached. + This is the default value. + + + ALL_SESSION 1 + + All messages within the same session, as defined by the same value + of the Session-ID AVP SHOULD be sent to the host specified in the + Redirect-Host AVP. + + + ALL_REALM 2 + + All messages destined for the realm requested SHOULD be sent to + the host specified in the Redirect-Host AVP. + + + REALM_AND_APPLICATION 3 + + All messages for the application requested to the realm specified + SHOULD be sent to the host specified in the Redirect-Host AVP. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 87] + +Internet-Draft Diameter Base Protocol January 2011 + + + ALL_APPLICATION 4 + + All messages for the application requested SHOULD be sent to the + host specified in the Redirect-Host AVP. + + + ALL_HOST 5 + + All messages that would be sent to the host that generated the + Redirect-Host SHOULD be sent to the host specified in the + Redirect- Host AVP. + + + ALL_USER 6 + + All messages for the user requested SHOULD be sent to the host + specified in the Redirect-Host AVP. + + + + When multiple cached routes are created by redirect indications and + they differ only in redirect usage and peers to forward requests to + (see Section 6.1.8), a precedence rule MUST be applied to the + redirect usage values of the cached routes during normal routing to + resolve contentions that may occur. The precedence rule is the order + that dictate which redirect usage should be considered before any + other as they appear. The order is as follows: + + + 1. ALL_SESSION + + 2. ALL_USER + + 3. REALM_AND_APPLICATION + + 4. ALL_REALM + + 5. ALL_APPLICATION + + 6. ALL_HOST + +6.14. Redirect-Max-Cache-Time AVP + + The Redirect-Max-Cache-Time AVP (AVP Code 262) is of type Unsigned32. + This AVP MUST be present in answer messages whose 'E' bit is set, the + Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION and the + Redirect-Host-Usage AVP set to a non-zero value. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 88] + +Internet-Draft Diameter Base Protocol January 2011 + + + This AVP contains the maximum number of seconds the peer and route + table entries, created as a result of the Redirect-Host, SHOULD be + cached. Note that once a host is no longer reachable, any associated + cache, peer and routing table entries MUST be deleted. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 89] + +Internet-Draft Diameter Base Protocol January 2011 + + +7. Error Handling + + There are two different types of errors in Diameter; protocol and + application errors. A protocol error is one that occurs at the base + protocol level, and MAY require per hop attention (e.g., message + routing error). Application errors, on the other hand, generally + occur due to a problem with a function specified in a Diameter + application (e.g., user authentication, missing AVP). + + Result-Code AVP values that are used to report protocol errors MUST + only be present in answer messages whose 'E' bit is set. When a + request message is received that causes a protocol error, an answer + message is returned with the 'E' bit set, and the Result-Code AVP is + set to the appropriate protocol error value. As the answer is sent + back towards the originator of the request, each proxy or relay agent + MAY take action on the message. + + 1. Request +---------+ Link Broken + +-------------------------->|Diameter |----///----+ + | +---------------------| | v + +------+--+ | 2. answer + 'E' set | Relay 2 | +--------+ + |Diameter |<-+ (Unable to Forward) +---------+ |Diameter| + | | | Home | + | Relay 1 |--+ +---------+ | Server | + +---------+ | 3. Request |Diameter | +--------+ + +-------------------->| | ^ + | Relay 3 |-----------+ + +---------+ + + Figure 7: Example of Protocol Error causing answer message + + Figure 7 provides an example of a message forwarded upstream by a + Diameter relay. When the message is received by Relay 2, and it + detects that it cannot forward the request to the home server, an + answer message is returned with the 'E' bit set and the Result-Code + AVP set to DIAMETER_UNABLE_TO_DELIVER. Given that this error falls + within the protocol error category, Relay 1 would take special + action, and given the error, attempt to route the message through its + alternate Relay 3. + + +---------+ 1. Request +---------+ 2. Request +---------+ + | Access |------------>|Diameter |------------>|Diameter | + | | | | | Home | + | Device |<------------| Relay |<------------| Server | + +---------+ 4. Answer +---------+ 3. Answer +---------+ + (Missing AVP) (Missing AVP) + + Figure 8: Example of Application Error Answer message + + + +Fajardo, et al. Expires July 24, 2011 [Page 90] + +Internet-Draft Diameter Base Protocol January 2011 + + + Figure 8 provides an example of a Diameter message that caused an + application error. When application errors occur, the Diameter + entity reporting the error clears the 'R' bit in the Command Flags, + and adds the Result-Code AVP with the proper value. Application + errors do not require any proxy or relay agent involvement, and + therefore the message would be forwarded back to the originator of + the request. + + In the case where the answer message itself contains errors, any + related session SHOULD be terminated by sending an STR or ASR + message. The Termination-Cause AVP in the STR MAY be filled with the + appropriate value to indicate the cause of the error. An application + MAY also send an application-specific request instead of STR or ASR + to signal the error in the case where no state is maintained or to + allow for some form of error recovery with the corresponding Diameter + entity. + + There are certain Result-Code AVP application errors that require + additional AVPs to be present in the answer. In these cases, the + Diameter node that sets the Result-Code AVP to indicate the error + MUST add the AVPs. Examples are: + + o A request with an unrecognized AVP is received with the 'M' bit + (Mandatory bit) set, causes an answer to be sent with the Result- + Code AVP set to DIAMETER_AVP_UNSUPPORTED, and the Failed-AVP AVP + containing the offending AVP. + + o A request with an AVP that is received with an unrecognized value + causes an answer to be returned with the Result-Code AVP set to + DIAMETER_INVALID_AVP_VALUE, with the Failed-AVP AVP containing the + AVP causing the error. + + o A received command which is missing AVP(s) that are defined as + required in the commands ABNF; examples are AVPs indicated as + {AVP}. The receiver issues an answer with the Result-Code set to + DIAMETER_MISSING_AVP, and creates an AVP with the AVP Code and + other fields set as expected in the missing AVP. The created AVP + is then added to the Failed- AVP AVP. + + The Result-Code AVP describes the error that the Diameter node + encountered in its processing. In case there are multiple errors, + the Diameter node MUST report only the first error it encountered + (detected possibly in some implementation dependent order). The + specific errors that can be described by this AVP are described in + the following section. + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 91] + +Internet-Draft Diameter Base Protocol January 2011 + + +7.1. Result-Code AVP + + The Result-Code AVP (AVP Code 268) is of type Unsigned32 and + indicates whether a particular request was completed successfully or + whether an error occurred. All Diameter answer messages in IETF + defined Diameter application specification MUST include one Result- + Code AVP. A non-successful Result-Code AVP (one containing a non + 2xxx value other than DIAMETER_REDIRECT_INDICATION) MUST include the + Error-Reporting-Host AVP if the host setting the Result-Code AVP is + different from the identity encoded in the Origin-Host AVP. + + + The Result-Code data field contains an IANA-managed 32-bit address + space representing errors (see Section 11.4). Diameter provides the + following classes of errors, all identified by the thousands digit in + the decimal notation: + + o 1xxx (Informational) + + o 2xxx (Success) + + o 3xxx (Protocol Errors) + + o 4xxx (Transient Failures) + + o 5xxx (Permanent Failure) + + A non-recognized class (one whose first digit is not defined in this + section) MUST be handled as a permanent failure. + +7.1.1. Informational + + Errors that fall within this category are used to inform the + requester that a request could not be satisfied, and additional + action is required on its part before access is granted. + + + DIAMETER_MULTI_ROUND_AUTH 1001 + + This informational error is returned by a Diameter server to + inform the access device that the authentication mechanism being + used requires multiple round trips, and a subsequent request needs + to be issued in order for access to be granted. + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 92] + +Internet-Draft Diameter Base Protocol January 2011 + + +7.1.2. Success + + Errors that fall within the Success category are used to inform a + peer that a request has been successfully completed. + + + DIAMETER_SUCCESS 2001 + + The request was successfully completed. + + DIAMETER_LIMITED_SUCCESS 2002 + + When returned, the request was successfully completed, but + additional processing is required by the application in order to + provide service to the user. + +7.1.3. Protocol Errors + + Errors that fall within the Protocol Error category SHOULD be treated + on a per-hop basis, and Diameter proxies MAY attempt to correct the + error, if it is possible. Note that these errors MUST only be used + in answer messages whose 'E' bit is set. This document omits some + error codes defined in [RFC3588]. To provide backward compatibility + with [RFC3588] implementations these error code values are not re- + used and hence the error codes values enumerated below are non- + sequential. + + + DIAMETER_UNABLE_TO_DELIVER 3002 + + This error is given when Diameter can not deliver the message to + the destination, either because no host within the realm + supporting the required application was available to process the + request, or because Destination-Host AVP was given without the + associated Destination-Realm AVP. + + + DIAMETER_REALM_NOT_SERVED 3003 + + The intended realm of the request is not recognized. + + + DIAMETER_TOO_BUSY 3004 + + When returned, a Diameter node SHOULD attempt to send the message + to an alternate peer. This error MUST only be used when a + specific server is requested, and it cannot provide the requested + service. + + + +Fajardo, et al. Expires July 24, 2011 [Page 93] + +Internet-Draft Diameter Base Protocol January 2011 + + + DIAMETER_LOOP_DETECTED 3005 + + An agent detected a loop while trying to get the message to the + intended recipient. The message MAY be sent to an alternate peer, + if one is available, but the peer reporting the error has + identified a configuration problem. + + + DIAMETER_REDIRECT_INDICATION 3006 + + A redirect agent has determined that the request could not be + satisfied locally and the initiator of the request SHOULD direct + the request directly to the server, whose contact information has + been added to the response. When set, the Redirect-Host AVP MUST + be present. + + + DIAMETER_APPLICATION_UNSUPPORTED 3007 + + A request was sent for an application that is not supported. + + + DIAMETER_INVALID_BIT_IN_HEADER 3011 + + This error is returned when a reserved bit in the Diameter header + is set to one (1) or the bits in the Diameter header defined in + Section 3 are set incorrectly. + + + DIAMETER_INVALID_MESSAGE_LENGTH 3012 + + This error is returned when a request is received with an invalid + message length. + + +7.1.4. Transient Failures + + Errors that fall within the transient failures category are used to + inform a peer that the request could not be satisfied at the time it + was received, but MAY be able to satisfy the request in the future. + Note that these errors MUST be used in answer messages whose 'E' bit + is not set. + + + DIAMETER_AUTHENTICATION_REJECTED 4001 + + The authentication process for the user failed, most likely due to + an invalid password used by the user. Further attempts MUST only + + + +Fajardo, et al. Expires July 24, 2011 [Page 94] + +Internet-Draft Diameter Base Protocol January 2011 + + + be tried after prompting the user for a new password. + + + DIAMETER_OUT_OF_SPACE 4002 + + A Diameter node received the accounting request but was unable to + commit it to stable storage due to a temporary lack of space. + + + ELECTION_LOST 4003 + + The peer has determined that it has lost the election process and + has therefore disconnected the transport connection. + + +7.1.5. Permanent Failures + + Errors that fall within the permanent failures category are used to + inform the peer that the request failed, and should not be attempted + again. Note that these errors SHOULD be used in answer messages + whose 'E' bit is not set. In error conditions where it is not + possible or efficient to compose application-specific answer grammar + then answer messages with E-bit set and complying to the grammar + described in 7.2 MAY also be used for permanent errors. + + To provide backward compatibility with existing implementations that + follow [RFC3588], some of the error values that have previously been + used in this category by [RFC3588] will not be re-used. Therefore + the error values enumerated here may be non-sequential. + + + DIAMETER_AVP_UNSUPPORTED 5001 + + The peer received a message that contained an AVP that is not + recognized or supported and was marked with the Mandatory bit. A + Diameter message with this error MUST contain one or more Failed- + AVP AVP containing the AVPs that caused the failure. + + + DIAMETER_UNKNOWN_SESSION_ID 5002 + + The request contained an unknown Session-Id. + + + DIAMETER_AUTHORIZATION_REJECTED 5003 + + A request was received for which the user could not be authorized. + This error could occur if the service requested is not permitted + + + +Fajardo, et al. Expires July 24, 2011 [Page 95] + +Internet-Draft Diameter Base Protocol January 2011 + + + to the user. + + + DIAMETER_INVALID_AVP_VALUE 5004 + + The request contained an AVP with an invalid value in its data + portion. A Diameter message indicating this error MUST include + the offending AVPs within a Failed-AVP AVP. + + + DIAMETER_MISSING_AVP 5005 + + The request did not contain an AVP that is required by the Command + Code definition. If this value is sent in the Result-Code AVP, a + Failed-AVP AVP SHOULD be included in the message. The Failed-AVP + AVP MUST contain an example of the missing AVP complete with the + Vendor-Id if applicable. The value field of the missing AVP + should be of correct minimum length and contain zeroes. + + + DIAMETER_RESOURCES_EXCEEDED 5006 + + A request was received that cannot be authorized because the user + has already expended allowed resources. An example of this error + condition is a user that is restricted to one dial-up PPP port, + attempts to establish a second PPP connection. + + + DIAMETER_CONTRADICTING_AVPS 5007 + + The Home Diameter server has detected AVPs in the request that + contradicted each other, and is not willing to provide service to + the user. The Failed-AVP AVPs MUST be present which contains the + AVPs that contradicted each other. + + + DIAMETER_AVP_NOT_ALLOWED 5008 + + A message was received with an AVP that MUST NOT be present. The + Failed-AVP AVP MUST be included and contain a copy of the + offending AVP. + + + DIAMETER_AVP_OCCURS_TOO_MANY_TIMES 5009 + + A message was received that included an AVP that appeared more + often than permitted in the message definition. The Failed-AVP + AVP MUST be included and contain a copy of the first instance of + + + +Fajardo, et al. Expires July 24, 2011 [Page 96] + +Internet-Draft Diameter Base Protocol January 2011 + + + the offending AVP that exceeded the maximum number of occurrences + + + DIAMETER_NO_COMMON_APPLICATION 5010 + + This error is returned by a Diameter node that receives a CER + whereby no applications are common between the CER sending peer + and the CER receiving peer. + + + DIAMETER_UNSUPPORTED_VERSION 5011 + + This error is returned when a request was received, whose version + number is unsupported. + + + DIAMETER_UNABLE_TO_COMPLY 5012 + + This error is returned when a request is rejected for unspecified + reasons. + + + DIAMETER_INVALID_AVP_LENGTH 5014 + + The request contained an AVP with an invalid length. A Diameter + message indicating this error MUST include the offending AVPs + within a Failed-AVP AVP. In cases where the erroneous AVP length + value exceeds the message length or is less than the minimum AVP + header length, it is sufficient to include the offending AVP + header and a zero filled payload of the minimum required length + for the payloads data type. If the AVP is a grouped AVP, the + grouped AVP header with an empty payload would be sufficient to + indicate the offending AVP. In the case where the offending AVP + header cannot be fully decoded when the AVP length is less than + the minimum AVP header length, it is sufficient to include an + offending AVP header that is formulated by padding the incomplete + AVP header with zero up to the minimum AVP header length. + + + DIAMETER_NO_COMMON_SECURITY 5017 + + This error is returned when a CER message is received, and there + are no common security mechanisms supported between the peers. A + Capabilities-Exchange-Answer (CEA) MUST be returned with the + Result-Code AVP set to DIAMETER_NO_COMMON_SECURITY. + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 97] + +Internet-Draft Diameter Base Protocol January 2011 + + + DIAMETER_UNKNOWN_PEER 5018 + + A CER was received from an unknown peer. + + + DIAMETER_COMMAND_UNSUPPORTED 5019 + + This error code is used when a Diameter entity receives a message + with a Command Code that it does not support. + + + DIAMETER_INVALID_HDR_BITS 5020 + + A request was received whose bits in the Diameter header were + either set to an invalid combination, or to a value that is + inconsistent with the command code's definition. + + + DIAMETER_INVALID_AVP_BITS 5021 + + A request was received that included an AVP whose flag bits are + set to an unrecognized value, or that is inconsistent with the + AVP's definition. + + +7.2. Error Bit + + The 'E' (Error Bit) in the Diameter header is set when the request + caused a protocol-related error (see Section 7.1.3). A message with + the 'E' bit MUST NOT be sent as a response to an answer message. + Note that a message with the 'E' bit set is still subjected to the + processing rules defined in Section 6.2. When set, the answer + message will not conform to the ABNF specification for the command, + and will instead conform to the following ABNF: + + Message Format + + <answer-message> ::= < Diameter Header: code, ERR [PXY] > + 0*1< Session-Id > + { Origin-Host } + { Origin-Realm } + { Result-Code } + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + [ Failed-AVP ] + [ Experimental-Result ] + * [ Proxy-Info ] + + + +Fajardo, et al. Expires July 24, 2011 [Page 98] + +Internet-Draft Diameter Base Protocol January 2011 + + + * [ AVP ] + + Note that the code used in the header is the same than the one found + in the request message, but with the 'R' bit cleared and the 'E' bit + set. The 'P' bit in the header is set to the same value as the one + found in the request message. + +7.3. Error-Message AVP + + The Error-Message AVP (AVP Code 281) is of type UTF8String. It MAY + accompany a Result-Code AVP as a human readable error message. The + Error-Message AVP is not intended to be useful in an environment + where error messages are processed automatically. It SHOULD NOT be + expected that the content of this AVP is parsed by network entities. + +7.4. Error-Reporting-Host AVP + + The Error-Reporting-Host AVP (AVP Code 294) is of type + DiameterIdentity. This AVP contains the identity of the Diameter + host that sent the Result-Code AVP to a value other than 2001 + (Success), only if the host setting the Result-Code is different from + the one encoded in the Origin-Host AVP. This AVP is intended to be + used for troubleshooting purposes, and MUST be set when the Result- + Code AVP indicates a failure. + +7.5. Failed-AVP AVP + + The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides + debugging information in cases where a request is rejected or not + fully processed due to erroneous information in a specific AVP. The + value of the Result-Code AVP will provide information on the reason + for the Failed-AVP AVP. A Diameter message SHOULD contain only one + Failed-AVP that corresponds to the error indicated by the Result-Code + AVP. For practical purposes, this Failed-AVP would typically refer + to the first AVP processing error that a Diameter node encounters. + + The possible reasons for this AVP are the presence of an improperly + constructed AVP, an unsupported or unrecognized AVP, an invalid AVP + value, the omission of a required AVP, the presence of an explicitly + excluded AVP (see tables in Section 10), or the presence of two or + more occurrences of an AVP which is restricted to 0, 1, or 0-1 + occurrences. + + A Diameter message SHOULD contain one Failed-AVP AVP, containing the + entire AVP that could not be processed successfully. If the failure + reason is omission of a required AVP, an AVP with the missing AVP + code, the missing vendor id, and a zero filled payload of the minimum + required length for the omitted AVP will be added. If the failure + + + +Fajardo, et al. Expires July 24, 2011 [Page 99] + +Internet-Draft Diameter Base Protocol January 2011 + + + reason is an invalid AVP length where the reported length is less + than the minimum AVP header length or greater than the reported + message length, a copy of the offending AVP header and a zero filled + payload of the minimum required length SHOULD be added. + + In the case where the offending AVP is embedded within a grouped AVP, + the Failed-AVP MAY contain the grouped AVP which in turn contains the + single offending AVP. The same method MAY be employed if the grouped + AVP itself is embedded in yet another grouped AVP and so on. In this + case, the Failed-AVP MAY contain the grouped AVP hierarchy up to the + single offending AVP. This enables the recipient to detect the + location of the offending AVP when embedded in a group. + + AVP Format + + <Failed-AVP> ::= < AVP Header: 279 > + 1* {AVP} + +7.6. Experimental-Result AVP + + The Experimental-Result AVP (AVP Code 297) is of type Grouped, and + indicates whether a particular vendor-specific request was completed + successfully or whether an error occurred. This AVP has the + following structure: + + AVP Format + + Experimental-Result ::= < AVP Header: 297 > + { Vendor-Id } + { Experimental-Result-Code } + + The Vendor-Id AVP (see Section 5.3.3) in this grouped AVP identifies + the vendor responsible for the assignment of the result code which + follows. All Diameter answer messages defined in vendor-specific + applications MUST include either one Result-Code AVP or one + Experimental-Result AVP. + +7.7. Experimental-Result-Code AVP + + The Experimental-Result-Code AVP (AVP Code 298) is of type Unsigned32 + and contains a vendor-assigned value representing the result of + processing the request. + + It is recommended that vendor-specific result codes follow the same + conventions given for the Result-Code AVP regarding the different + types of result codes and the handling of errors (for non 2xxx + values). + + + + +Fajardo, et al. Expires July 24, 2011 [Page 100] + +Internet-Draft Diameter Base Protocol January 2011 + + +8. Diameter User Sessions + + In general, Diameter can provide two different types of services to + applications. The first involves authentication and authorization, + and can optionally make use of accounting. The second only makes use + of accounting. + + When a service makes use of the authentication and/or authorization + portion of an application, and a user requests access to the network, + the Diameter client issues an auth request to its local server. The + auth request is defined in a service-specific Diameter application + (e.g., NASREQ). The request contains a Session-Id AVP, which is used + in subsequent messages (e.g., subsequent authorization, accounting, + etc) relating to the user's session. The Session-Id AVP is a means + for the client and servers to correlate a Diameter message with a + user session. + + When a Diameter server authorizes a user to use network resources for + a finite amount of time, and it is willing to extend the + authorization via a future request, it MUST add the Authorization- + Lifetime AVP to the answer message. The Authorization-Lifetime AVP + defines the maximum number of seconds a user MAY make use of the + resources before another authorization request is expected by the + server. The Auth-Grace-Period AVP contains the number of seconds + following the expiration of the Authorization-Lifetime, after which + the server will release all state information related to the user's + session. Note that if payment for services is expected by the + serving realm from the user's home realm, the Authorization-Lifetime + AVP, combined with the Auth-Grace-Period AVP, implies the maximum + length of the session the home realm is willing to be fiscally + responsible for. Services provided past the expiration of the + Authorization-Lifetime and Auth-Grace-Period AVPs are the + responsibility of the access device. Of course, the actual cost of + services rendered is clearly outside the scope of the protocol. + + An access device that does not expect to send a re-authorization or a + session termination request to the server MAY include the Auth- + Session-State AVP with the value set to NO_STATE_MAINTAINED as a hint + to the server. If the server accepts the hint, it agrees that since + no session termination message will be received once service to the + user is terminated, it cannot maintain state for the session. If the + answer message from the server contains a different value in the + Auth-Session-State AVP (or the default value if the AVP is absent), + the access device MUST follow the server's directives. Note that the + value NO_STATE_MAINTAINED MUST NOT be set in subsequent re- + authorization requests and answers. + + The base protocol does not include any authorization request + + + +Fajardo, et al. Expires July 24, 2011 [Page 101] + +Internet-Draft Diameter Base Protocol January 2011 + + + messages, since these are largely application-specific and are + defined in a Diameter application document. However, the base + protocol does define a set of messages that are used to terminate + user sessions. These are used to allow servers that maintain state + information to free resources. + + When a service only makes use of the Accounting portion of the + Diameter protocol, even in combination with an application, the + Session-Id is still used to identify user sessions. However, the + session termination messages are not used, since a session is + signaled as being terminated by issuing an accounting stop message. + + Diameter may also be used for services that cannot be easily + categorized as authentication, authorization or accounting (e.g., + certain 3GPP IMS interfaces). In such cases, the finite state + machine defined in subsequent sections may not be applicable. + Therefore, the applications itself MAY need to define its own finite + state machine. However, such application-specific state machines + SHOULD follow the general state machine framework outlined in this + document such as the use of Session-Id AVPs and the use of STR/STA, + ASR/ASA messages for stateful sessions. + +8.1. Authorization Session State Machine + + This section contains a set of finite state machines, representing + the life cycle of Diameter sessions, and which MUST be observed by + all Diameter implementations that make use of the authentication + and/or authorization portion of a Diameter application. The term + Service-Specific below refers to a message defined in a Diameter + application (e.g., Mobile IPv4, NASREQ). + + There are four different authorization session state machines + supported in the Diameter base protocol. The first two describe a + session in which the server is maintaining session state, indicated + by the value of the Auth-Session-State AVP (or its absence). One + describes the session from a client perspective, the other from a + server perspective. The second two state machines are used when the + server does not maintain session state. Here again, one describes + the session from a client perspective, the other from a server + perspective. + + When a session is moved to the Idle state, any resources that were + allocated for the particular session must be released. Any event not + listed in the state machines MUST be considered as an error + condition, and an answer, if applicable, MUST be returned to the + originator of the message. + + In the case that an application does not support re-auth, the state + + + +Fajardo, et al. Expires July 24, 2011 [Page 102] + +Internet-Draft Diameter Base Protocol January 2011 + + + transitions related to server-initiated re-auth when both client and + server session maintains state (e.g., Send RAR, Pending, Receive RAA) + MAY be ignored. + + In the state table, the event 'Failure to send X' means that the + Diameter agent is unable to send command X to the desired + destination. This could be due to the peer being down, or due to the + peer sending back a transient failure or temporary protocol error + notification DIAMETER_TOO_BUSY or DIAMETER_LOOP_DETECTED in the + Result-Code AVP of the corresponding Answer command. The event 'X + successfully sent' is the complement of 'Failure to send X'. + + The following state machine is observed by a client when state is + maintained on the server: + + CLIENT, STATEFUL + State Event Action New State + --------------------------------------------------------------- + Idle Client or Device Requests Send Pending + access service + specific + auth req + + Idle ASR Received Send ASA Idle + for unknown session with + Result-Code = + UNKNOWN_ + SESSION_ID + + Idle RAR Received Send RAA Idle + for unknown session with + Result-Code = + UNKNOWN_ + SESSION_ID + + Pending Successful Service-specific Grant Open + authorization answer Access + received with default + Auth-Session-State value + + Pending Successful Service-specific Sent STR Discon + authorization answer received + but service not provided + + Pending Error processing successful Sent STR Discon + Service-specific authorization + answer + + + + +Fajardo, et al. Expires July 24, 2011 [Page 103] + +Internet-Draft Diameter Base Protocol January 2011 + + + Pending Failed Service-specific Cleanup Idle + authorization answer received + + Open User or client device Send Open + requests access to service service + specific + auth req + + Open Successful Service-specific Provide Open + authorization answer received Service + + Open Failed Service-specific Discon. Idle + authorization answer user/device + received. + + Open RAR received and client will Send RAA Open + perform subsequent re-auth with + Result-Code = + SUCCESS + + Open RAR received and client will Send RAA Idle + not perform subsequent with + re-auth Result-Code != + SUCCESS, + Discon. + user/device + + Open Session-Timeout Expires on Send STR Discon + Access Device + + Open ASR Received, Send ASA Discon + client will comply with + with request to end the Result-Code = + session = SUCCESS, + Send STR. + + Open ASR Received, Send ASA Open + client will not comply with + with request to end the Result-Code != + session != SUCCESS + + Open Authorization-Lifetime + Send STR Discon + Auth-Grace-Period expires on + access device + + Discon ASR Received Send ASA Discon + + Discon STA Received Discon. Idle + + + +Fajardo, et al. Expires July 24, 2011 [Page 104] + +Internet-Draft Diameter Base Protocol January 2011 + + + user/device + + The following state machine is observed by a server when it is + maintaining state for the session: + + SERVER, STATEFUL + State Event Action New State + --------------------------------------------------------------- + Idle Service-specific authorization Send Open + request received, and successful + user is authorized serv. + specific + answer + + Idle Service-specific authorization Send Idle + request received, and failed serv. + user is not authorized specific + answer + + Open Service-specific authorization Send Open + request received, and user successful + is authorized serv. specific + answer + + Open Service-specific authorization Send Idle + request received, and user failed serv. + is not authorized specific + answer, + Cleanup + + Open Home server wants to confirm Send RAR Pending + authentication and/or + authorization of the user + + Pending Received RAA with a failed Cleanup Idle + Result-Code + + Pending Received RAA with Result-Code Update Open + = SUCCESS session + + Open Home server wants to Send ASR Discon + terminate the service + + Open Authorization-Lifetime (and Cleanup Idle + Auth-Grace-Period) expires + on home server. + + Open Session-Timeout expires on Cleanup Idle + + + +Fajardo, et al. Expires July 24, 2011 [Page 105] + +Internet-Draft Diameter Base Protocol January 2011 + + + home server + + Discon Failure to send ASR Wait, Discon + resend ASR + + Discon ASR successfully sent and Cleanup Idle + ASA Received with Result-Code + + Not ASA Received None No Change. + Discon + + Any STR Received Send STA, Idle + Cleanup. + + The following state machine is observed by a client when state is not + maintained on the server: + + CLIENT, STATELESS + State Event Action New State + --------------------------------------------------------------- + Idle Client or Device Requests Send Pending + access service + specific + auth req + + Pending Successful Service-specific Grant Open + authorization answer Access + received with Auth-Session- + State set to + NO_STATE_MAINTAINED + + Pending Failed Service-specific Cleanup Idle + authorization answer + received + + Open Session-Timeout Expires on Discon. Idle + Access Device user/device + + Open Service to user is terminated Discon. Idle + user/device + + The following state machine is observed by a server when it is not + maintaining state for the session: + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 106] + +Internet-Draft Diameter Base Protocol January 2011 + + + SERVER, STATELESS + State Event Action New State + --------------------------------------------------------------- + Idle Service-specific authorization Send serv. Idle + request received, and specific + successfully processed answer + +8.2. Accounting Session State Machine + + The following state machines MUST be supported for applications that + have an accounting portion or that require only accounting services. + The first state machine is to be observed by clients. + + See Section 9.7 for Accounting Command Codes and Section 9.8 for + Accounting AVPs. + + The server side in the accounting state machine depends in some cases + on the particular application. The Diameter base protocol defines a + default state machine that MUST be followed by all applications that + have not specified other state machines. This is the second state + machine in this section described below. + + The default server side state machine requires the reception of + accounting records in any order and at any time, and does not place + any standards requirement on the processing of these records. + Implementations of Diameter may perform checking, ordering, + correlation, fraud detection, and other tasks based on these records. + AVPs may need to be inspected as a part of these tasks. The tasks + can happen either immediately after record reception or in a post- + processing phase. However, as these tasks are typically application + or even policy dependent, they are not standardized by the Diameter + specifications. Applications MAY define requirements on when to + accept accounting records based on the used value of Accounting- + Realtime-Required AVP, credit limits checks, and so on. + + However, the Diameter base protocol defines one optional server side + state machine that MAY be followed by applications that require + keeping track of the session state at the accounting server. Note + that such tracking is incompatible with the ability to sustain long + duration connectivity problems. Therefore, the use of this state + machine is recommended only in applications where the value of the + Accounting-Realtime-Required AVP is DELIVER_AND_GRANT, and hence + accounting connectivity problems are required to cause the serviced + user to be disconnected. Otherwise, records produced by the client + may be lost by the server which no longer accepts them after the + connectivity is re-established. This state machine is the third + state machine in this section. The state machine is supervised by a + supervision session timer Ts, which the value should be reasonably + + + +Fajardo, et al. Expires July 24, 2011 [Page 107] + +Internet-Draft Diameter Base Protocol January 2011 + + + higher than the Acct_Interim_Interval value. Ts MAY be set to two + times the value of the Acct_Interim_Interval so as to avoid the + accounting session in the Diameter server to change to Idle state in + case of short transient network failure. + + Any event not listed in the state machines MUST be considered as an + error condition, and a corresponding answer, if applicable, MUST be + returned to the originator of the message. + + In the state table, the event 'Failure to send' means that the + Diameter client is unable to communicate with the desired + destination. This could be due to the peer being down, or due to the + peer sending back a transient failure or temporary protocol error + notification DIAMETER_OUT_OF_SPACE, DIAMETER_TOO_BUSY, or + DIAMETER_LOOP_DETECTED in the Result-Code AVP of the Accounting + Answer command. + + The event 'Failed answer' means that the Diameter client received a + non-transient failure notification in the Accounting Answer command. + + Note that the action 'Disconnect user/dev' MUST have an effect also + to the authorization session state table, e.g., cause the STR message + to be sent, if the given application has both authentication/ + authorization and accounting portions. + + The states PendingS, PendingI, PendingL, PendingE and PendingB stand + for pending states to wait for an answer to an accounting request + related to a Start, Interim, Stop, Event or buffered record, + respectively. + + CLIENT, ACCOUNTING + State Event Action New State + --------------------------------------------------------------- + Idle Client or device requests Send PendingS + access accounting + start req. + + Idle Client or device requests Send PendingE + a one-time service accounting + event req + + Idle Records in storage Send PendingB + record + + PendingS Successful accounting Open + start answer received + + PendingS Failure to send and buffer Store Open + + + +Fajardo, et al. Expires July 24, 2011 [Page 108] + +Internet-Draft Diameter Base Protocol January 2011 + + + space available and realtime Start + not equal to DELIVER_AND_GRANT Record + + PendingS Failure to send and no buffer Open + space available and realtime + equal to GRANT_AND_LOSE + + PendingS Failure to send and no Disconnect Idle + buffer space available and user/dev + realtime not equal to + GRANT_AND_LOSE + + PendingS Failed accounting start answer Open + received and realtime equal + to GRANT_AND_LOSE + + PendingS Failed accounting start answer Disconnect Idle + received and realtime not user/dev + equal to GRANT_AND_LOSE + + PendingS User service terminated Store PendingS + stop + record + + Open Interim interval elapses Send PendingI + accounting + interim + record + Open User service terminated Send PendingL + accounting + stop req. + + PendingI Successful accounting interim Open + answer received + + PendingI Failure to send and (buffer Store Open + space available or old interim + record can be overwritten) record + and realtime not equal to + DELIVER_AND_GRANT + + PendingI Failure to send and no buffer Open + space available and realtime + equal to GRANT_AND_LOSE + + + PendingI Failure to send and no Disconnect Idle + buffer space available and user/dev + + + +Fajardo, et al. Expires July 24, 2011 [Page 109] + +Internet-Draft Diameter Base Protocol January 2011 + + + realtime not equal to + GRANT_AND_LOSE + + PendingI Failed accounting interim Open + answer received and realtime + equal to GRANT_AND_LOSE + + PendingI Failed accounting interim Disconnect Idle + answer received and user/dev + realtime not equal to + GRANT_AND_LOSE + + PendingI User service terminated Store PendingI + stop + record + PendingE Successful accounting Idle + event answer received + + PendingE Failure to send and buffer Store Idle + space available event + record + + PendingE Failure to send and no buffer Idle + space available + + PendingE Failed accounting event answer Idle + received + + PendingB Successful accounting answer Delete Idle + received record + + PendingB Failure to send Idle + + PendingB Failed accounting answer Delete Idle + received record + + PendingL Successful accounting Idle + stop answer received + + PendingL Failure to send and buffer Store Idle + space available stop + record + + PendingL Failure to send and no buffer Idle + space available + + PendingL Failed accounting stop answer Idle + received + + + +Fajardo, et al. Expires July 24, 2011 [Page 110] + +Internet-Draft Diameter Base Protocol January 2011 + + + SERVER, STATELESS ACCOUNTING + State Event Action New State + --------------------------------------------------------------- + + Idle Accounting start request Send Idle + received, and successfully accounting + processed. start + answer + + Idle Accounting event request Send Idle + received, and successfully accounting + processed. event + answer + + Idle Interim record received, Send Idle + and successfully processed. accounting + interim + answer + + Idle Accounting stop request Send Idle + received, and successfully accounting + processed stop answer + + Idle Accounting request received, Send Idle + no space left to store accounting + records answer, + Result-Code = + OUT_OF_ + SPACE + + SERVER, STATEFUL ACCOUNTING + State Event Action New State + --------------------------------------------------------------- + + Idle Accounting start request Send Open + received, and successfully accounting + processed. start + answer, + Start Ts + + Idle Accounting event request Send Idle + received, and successfully accounting + processed. event + answer + + Idle Accounting request received, Send Idle + no space left to store accounting + records answer, + + + +Fajardo, et al. Expires July 24, 2011 [Page 111] + +Internet-Draft Diameter Base Protocol January 2011 + + + Result-Code = + OUT_OF_ + SPACE + + Open Interim record received, Send Open + and successfully processed. accounting + interim + answer, + Restart Ts + + Open Accounting stop request Send Idle + received, and successfully accounting + processed stop answer, + Stop Ts + + Open Accounting request received, Send Idle + no space left to store accounting + records answer, + Result-Code = + OUT_OF_ + SPACE, + Stop Ts + + Open Session supervision timer Ts Stop Ts Idle + expired + +8.3. Server-Initiated Re-Auth + + A Diameter server may initiate a re-authentication and/or re- + authorization service for a particular session by issuing a Re-Auth- + Request (RAR). + + For example, for pre-paid services, the Diameter server that + originally authorized a session may need some confirmation that the + user is still using the services. + + An access device that receives a RAR message with Session-Id equal to + a currently active session MUST initiate a re-auth towards the user, + if the service supports this particular feature. Each Diameter + application MUST state whether server-initiated re-auth is supported, + since some applications do not allow access devices to prompt the + user for re-auth. + +8.3.1. Re-Auth-Request + + The Re-Auth-Request (RAR), indicated by the Command-Code set to 258 + and the message flags' 'R' bit set, may be sent by any server to the + access device that is providing session service, to request that the + + + +Fajardo, et al. Expires July 24, 2011 [Page 112] + +Internet-Draft Diameter Base Protocol January 2011 + + + user be re-authenticated and/or re-authorized. + + + Message Format + + <RAR> ::= < 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-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.3.2. Re-Auth-Answer + + The Re-Auth-Answer (RAA), indicated by the Command-Code set to 258 + and the message flags' 'R' bit clear, is sent in response to the RAR. + The Result-Code AVP MUST be present, and indicates the disposition of + the request. + + A successful RAA message MUST be followed by an application-specific + authentication and/or authorization message. + + + Message Format + + <RAA> ::= < Diameter Header: 258, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + + + +Fajardo, et al. Expires July 24, 2011 [Page 113] + +Internet-Draft Diameter Base Protocol January 2011 + + +8.4. Session Termination + + It is necessary for a Diameter server that authorized a session, for + which it is maintaining state, to be notified when that session is no + longer active, both for tracking purposes as well as to allow + stateful agents to release any resources that they may have provided + for the user's session. For sessions whose state is not being + maintained, this section is not used. + + When a user session that required Diameter authorization terminates, + the access device that provided the service MUST issue a Session- + Termination-Request (STR) message to the Diameter server that + authorized the service, to notify it that the session is no longer + active. An STR MUST be issued when a user session terminates for any + reason, including user logoff, expiration of Session-Timeout, + administrative action, termination upon receipt of an Abort-Session- + Request (see below), orderly shutdown of the access device, etc. + + The access device also MUST issue an STR for a session that was + authorized but never actually started. This could occur, for + example, due to a sudden resource shortage in the access device, or + because the access device is unwilling to provide the type of service + requested in the authorization, or because the access device does not + support a mandatory AVP returned in the authorization, etc. + + It is also possible that a session that was authorized is never + actually started due to action of a proxy. For example, a proxy may + modify an authorization answer, converting the result from success to + failure, prior to forwarding the message to the access device. If + the answer did not contain an Auth-Session-State AVP with the value + NO_STATE_MAINTAINED, a proxy that causes an authorized session not to + be started MUST issue an STR to the Diameter server that authorized + the session, since the access device has no way of knowing that the + session had been authorized. + + A Diameter server that receives an STR message MUST clean up + resources (e.g., session state) associated with the Session-Id + specified in the STR, and return a Session-Termination-Answer. + + A Diameter server also MUST clean up resources when the Session- + Timeout expires, or when the Authorization-Lifetime and the Auth- + Grace-Period AVPs expires without receipt of a re-authorization + request, regardless of whether an STR for that session is received. + The access device is not expected to provide service beyond the + expiration of these timers; thus, expiration of either of these + timers implies that the access device may have unexpectedly shut + down. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 114] + +Internet-Draft Diameter Base Protocol January 2011 + + +8.4.1. Session-Termination-Request + + The Session-Termination-Request (STR), indicated by the Command-Code + set to 275 and the Command Flags' 'R' bit set, is sent by a Diameter + client or by a Diameter proxy to inform the Diameter Server that an + authenticated and/or authorized session is being terminated. + + + Message Format + + <STR> ::= < Diameter Header: 275, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Termination-Cause } + [ User-Name ] + [ Destination-Host ] + * [ Class ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.4.2. Session-Termination-Answer + + The Session-Termination-Answer (STA), indicated by the Command-Code + set to 275 and the message flags' 'R' bit clear, is sent by the + Diameter Server to acknowledge the notification that the session has + been terminated. The Result-Code AVP MUST be present, and MAY + contain an indication that an error occurred while servicing the STR. + + Upon sending or receipt of the STA, the Diameter Server MUST release + all resources for the session indicated by the Session-Id AVP. Any + intermediate server in the Proxy-Chain MAY also release any + resources, if necessary. + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 115] + +Internet-Draft Diameter Base Protocol January 2011 + + + Message Format + + <STA> ::= < Diameter Header: 275, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + * [ Class ] + [ Error-Message ] + [ Error-Reporting-Host ] + [ Failed-AVP ] + [ Origin-State-Id ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + +8.5. Aborting a Session + + A Diameter server may request that the access device stop providing + service for a particular session by issuing an Abort-Session-Request + (ASR). + + For example, the Diameter server that originally authorized the + session may be required to cause that session to be stopped for lack + of credit or other reasons that were not anticipated when the session + was first authorized. + + An access device that receives an ASR with Session-ID equal to a + currently active session MAY stop the session. Whether the access + device stops the session or not is implementation- and/or + configuration-dependent. For example, an access device may honor + ASRs from certain agents only. In any case, the access device MUST + respond with an Abort-Session-Answer, including a Result-Code AVP to + indicate what action it took. + +8.5.1. Abort-Session-Request + + The Abort-Session-Request (ASR), indicated by the Command-Code set to + 274 and the message flags' 'R' bit set, may be sent by any Diameter + server or any Diameter proxy to the access device that is providing + session service, to request that the session identified by the + Session-Id be stopped. + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 116] + +Internet-Draft Diameter Base Protocol January 2011 + + + Message Format + + <ASR> ::= < Diameter Header: 274, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + [ User-Name ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.5.2. Abort-Session-Answer + + The Abort-Session-Answer (ASA), indicated by the Command-Code set to + 274 and the message flags' 'R' bit clear, is sent in response to the + ASR. The Result-Code AVP MUST be present, and indicates the + disposition of the request. + + If the session identified by Session-Id in the ASR was successfully + terminated, Result-Code is set to DIAMETER_SUCCESS. If the session + is not currently active, Result-Code is set to + DIAMETER_UNKNOWN_SESSION_ID. If the access device does not stop the + session for any other reason, Result-Code is set to + DIAMETER_UNABLE_TO_COMPLY. + + + Message Format + + <ASA> ::= < Diameter Header: 274, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + + + +Fajardo, et al. Expires July 24, 2011 [Page 117] + +Internet-Draft Diameter Base Protocol January 2011 + + +8.6. Inferring Session Termination from Origin-State-Id + + The Origin-State-Id is used to allow detection of terminated sessions + for which no STR would have been issued, due to unanticipated + shutdown of an access device. + + A Diameter client or access device increments the value of the + Origin-State-Id every time it is started or powered-up. The new + Origin-State-Id is then sent in the CER/CEA message immediately upon + connection to the server. The Diameter server receiving the new + Origin-State-Id can determine whether the sending Diameter client had + abruptly shutdown by comparing the old value of the Origin-State-Id + it has kept for that specific client is less than the new value and + whether it has un-terminated sessions originating from that client. + + An access device can also include the Origin-State-Id in request + messages other than CER if there are relays or proxies in between the + access device and the server. In this case, however, the server + cannot discover that the access device has been restarted unless and + until it receives a new request from it. Therefore this mechanism is + more opportunistic across proxies and relays. + + The Diameter server may assume that all sessions that were active + prior to detection of a client restart have been terminated. The + Diameter server MAY clean up all session state associated with such + lost sessions, and MAY also issues STRs for all such lost sessions + that were authorized on upstream servers, to allow session state to + be cleaned up globally. + +8.7. Auth-Request-Type AVP + + The Auth-Request-Type AVP (AVP Code 274) is of type Enumerated and is + included in application-specific auth requests to inform the peers + whether a user is to be authenticated only, authorized only or both. + Note any value other than both MAY cause RADIUS interoperability + issues. The following values are defined: + + + AUTHENTICATE_ONLY 1 + + The request being sent is for authentication only, and MUST + contain the relevant application specific authentication AVPs that + are needed by the Diameter server to authenticate the user. + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 118] + +Internet-Draft Diameter Base Protocol January 2011 + + + AUTHORIZE_ONLY 2 + + The request being sent is for authorization only, and MUST contain + the application-specific authorization AVPs that are necessary to + identify the service being requested/offered. + + + AUTHORIZE_AUTHENTICATE 3 + + The request contains a request for both authentication and + authorization. The request MUST include both the relevant + application-specific authentication information, and authorization + information necessary to identify the service being requested/ + offered. + + +8.8. Session-Id AVP + + The Session-Id AVP (AVP Code 263) is of type UTF8String and is used + to identify a specific session (see Section 8). All messages + pertaining to a specific session MUST include only one Session-Id AVP + and the same value MUST be used throughout the life of a session. + When present, the Session-Id SHOULD appear immediately following the + Diameter Header (see Section 3). + + The Session-Id MUST be globally and eternally unique, as it is meant + to uniquely identify a user session without reference to any other + information, and may be needed to correlate historical authentication + information with accounting information. The Session-Id includes a + mandatory portion and an implementation-defined portion; a + recommended format for the implementation-defined portion is outlined + below. + + The Session-Id MUST begin with the sender's identity encoded in the + DiameterIdentity type (see Section 4.4). The remainder of the + Session-Id is delimited by a ";" character, and MAY be any sequence + that the client can guarantee to be eternally unique; however, the + following format is recommended, (square brackets [] indicate an + optional element): + + <DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>] + + <high 32 bits> and <low 32 bits> are decimal representations of the + high and low 32 bits of a monotonically increasing 64-bit value. The + 64-bit value is rendered in two part to simplify formatting by 32-bit + processors. At startup, the high 32 bits of the 64-bit value MAY be + initialized to the time in NTP format [RFC5905], and the low 32 bits + MAY be initialized to zero. This will for practical purposes + + + +Fajardo, et al. Expires July 24, 2011 [Page 119] + +Internet-Draft Diameter Base Protocol January 2011 + + + eliminate the possibility of overlapping Session-Ids after a reboot, + assuming the reboot process takes longer than a second. + Alternatively, an implementation MAY keep track of the increasing + value in non-volatile memory. + + + <optional value> is implementation specific but may include a modem's + device Id, a layer 2 address, timestamp, etc. + + Example, in which there is no optional value: + + accesspoint7.example.com;1876543210;523 + + Example, in which there is an optional value: + + accesspoint7.example.com;1876543210;523;[email protected] + + The Session-Id is created by the Diameter application initiating the + session, which in most cases is done by the client. Note that a + Session-Id MAY be used for both the authentication, authorization and + accounting commands of a given application. + +8.9. Authorization-Lifetime AVP + + The Authorization-Lifetime AVP (AVP Code 291) is of type Unsigned32 + and contains the maximum number of seconds of service to be provided + to the user before the user is to be re-authenticated and/or re- + authorized. Care should be taken when the Authorization- Lifetime + value is determined, since a low, non-zero, value could create + significant Diameter traffic, which could congest both the network + and the agents. + + A value of zero (0) means that immediate re-auth is necessary by the + access device. The absence of this AVP, or a value of all ones + (meaning all bits in the 32 bit field are set to one) means no re- + auth is expected. + + If both this AVP and the Session-Timeout AVP are present in a + message, the value of the latter MUST NOT be smaller than the + Authorization-Lifetime AVP. + + An Authorization-Lifetime AVP MAY be present in re-authorization + messages, and contains the number of seconds the user is authorized + to receive service from the time the re-auth answer message is + received by the access device. + + This AVP MAY be provided by the client as a hint of the maximum + lifetime that it is willing to accept. The server MUST return a + + + +Fajardo, et al. Expires July 24, 2011 [Page 120] + +Internet-Draft Diameter Base Protocol January 2011 + + + value that is equal to, or smaller, than the one provided by the + client. + +8.10. Auth-Grace-Period AVP + + The Auth-Grace-Period AVP (AVP Code 276) is of type Unsigned32 and + contains the number of seconds the Diameter server will wait + following the expiration of the Authorization-Lifetime AVP before + cleaning up resources for the session. + +8.11. Auth-Session-State AVP + + The Auth-Session-State AVP (AVP Code 277) is of type Enumerated and + specifies whether state is maintained for a particular session. The + client MAY include this AVP in requests as a hint to the server, but + the value in the server's answer message is binding. The following + values are supported: + + + STATE_MAINTAINED 0 + + This value is used to specify that session state is being + maintained, and the access device MUST issue a session termination + message when service to the user is terminated. This is the + default value. + + + NO_STATE_MAINTAINED 1 + + This value is used to specify that no session termination messages + will be sent by the access device upon expiration of the + Authorization-Lifetime. + + +8.12. Re-Auth-Request-Type AVP + + The Re-Auth-Request-Type AVP (AVP Code 285) is of type Enumerated and + is included in application-specific auth answers to inform the client + of the action expected upon expiration of the Authorization-Lifetime. + If the answer message contains an Authorization-Lifetime AVP with a + positive value, the Re-Auth-Request-Type AVP MUST be present in an + answer message. The following values are defined: + + + AUTHORIZE_ONLY 0 + + An authorization only re-auth is expected upon expiration of the + Authorization-Lifetime. This is the default value if the AVP is + + + +Fajardo, et al. Expires July 24, 2011 [Page 121] + +Internet-Draft Diameter Base Protocol January 2011 + + + not present in answer messages that include the Authorization- + Lifetime. + + + AUTHORIZE_AUTHENTICATE 1 + + An authentication and authorization re-auth is expected upon + expiration of the Authorization-Lifetime. + + +8.13. Session-Timeout AVP + + The Session-Timeout AVP (AVP Code 27) [RFC2865] is of type Unsigned32 + and contains the maximum number of seconds of service to be provided + to the user before termination of the session. When both the + Session-Timeout and the Authorization-Lifetime AVPs are present in an + answer message, the former MUST be equal to or greater than the value + of the latter. + + A session that terminates on an access device due to the expiration + of the Session-Timeout MUST cause an STR to be issued, unless both + the access device and the home server had previously agreed that no + session termination messages would be sent (see Section 8.11). + + A Session-Timeout AVP MAY be present in a re-authorization answer + message, and contains the remaining number of seconds from the + beginning of the re-auth. + + A value of zero, or the absence of this AVP, means that this session + has an unlimited number of seconds before termination. + + This AVP MAY be provided by the client as a hint of the maximum + timeout that it is willing to accept. However, the server MAY return + a value that is equal to, or smaller, than the one provided by the + client. + +8.14. User-Name AVP + + The User-Name AVP (AVP Code 1) [RFC2865] is of type UTF8String, which + contains the User-Name, in a format consistent with the NAI + specification [RFC4282]. + +8.15. Termination-Cause AVP + + The Termination-Cause AVP (AVP Code 295) is of type Enumerated, and + is used to indicate the reason why a session was terminated on the + access device. The following values are defined: + + + + +Fajardo, et al. Expires July 24, 2011 [Page 122] + +Internet-Draft Diameter Base Protocol January 2011 + + + DIAMETER_LOGOUT 1 + + The user initiated a disconnect + + + DIAMETER_SERVICE_NOT_PROVIDED 2 + + This value is used when the user disconnected prior to the receipt + of the authorization answer message. + + + DIAMETER_BAD_ANSWER 3 + + This value indicates that the authorization answer received by the + access device was not processed successfully. + + + DIAMETER_ADMINISTRATIVE 4 + + The user was not granted access, or was disconnected, due to + administrative reasons, such as the receipt of a Abort-Session- + Request message. + + + DIAMETER_LINK_BROKEN 5 + + The communication to the user was abruptly disconnected. + + + DIAMETER_AUTH_EXPIRED 6 + + The user's access was terminated since its authorized session time + has expired. + + + DIAMETER_USER_MOVED 7 + + The user is receiving services from another access device. + + + DIAMETER_SESSION_TIMEOUT 8 + + The user's session has timed out, and service has been terminated. + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 123] + +Internet-Draft Diameter Base Protocol January 2011 + + +8.16. Origin-State-Id AVP + + The Origin-State-Id AVP (AVP Code 278), of type Unsigned32, is a + monotonically increasing value that is advanced whenever a Diameter + entity restarts with loss of previous state, for example upon reboot. + Origin-State-Id MAY be included in any Diameter message, including + CER. + + A Diameter entity issuing this AVP MUST create a higher value for + this AVP each time its state is reset. A Diameter entity MAY set + Origin-State-Id to the time of startup, or it MAY use an incrementing + counter retained in non-volatile memory across restarts. + + The Origin-State-Id, if present, MUST reflect the state of the entity + indicated by Origin-Host. If a proxy modifies Origin-Host, it MUST + either remove Origin-State-Id or modify it appropriately as well. + Typically, Origin-State-Id is used by an access device that always + starts up with no active sessions; that is, any session active prior + to restart will have been lost. By including Origin-State-Id in a + message, it allows other Diameter entities to infer that sessions + associated with a lower Origin-State-Id are no longer active. If an + access device does not intend for such inferences to be made, it MUST + either not include Origin-State-Id in any message, or set its value + to 0. + +8.17. Session-Binding AVP + + The Session-Binding AVP (AVP Code 270) is of type Unsigned32, and MAY + be present in application-specific authorization answer messages. If + present, this AVP MAY inform the Diameter client that all future + application-specific re-auth and Session-Termination-Request messages + for this session MUST be sent to the same authorization server. + + This field is a bit mask, and the following bits have been defined: + + + RE_AUTH 1 + + When set, future re-auth messages for this session MUST NOT + include the Destination-Host AVP. When cleared, the default + value, the Destination-Host AVP MUST be present in all re-auth + messages for this session. + + + STR 2 + + When set, the STR message for this session MUST NOT include the + Destination-Host AVP. When cleared, the default value, the + + + +Fajardo, et al. Expires July 24, 2011 [Page 124] + +Internet-Draft Diameter Base Protocol January 2011 + + + Destination-Host AVP MUST be present in the STR message for this + session. + + + ACCOUNTING 4 + + When set, all accounting messages for this session MUST NOT + include the Destination-Host AVP. When cleared, the default + value, the Destination-Host AVP, if known, MUST be present in all + accounting messages for this session. + + +8.18. Session-Server-Failover AVP + + The Session-Server-Failover AVP (AVP Code 271) is of type Enumerated, + and MAY be present in application-specific authorization answer + messages that either do not include the Session-Binding AVP or + include the Session-Binding AVP with any of the bits set to a zero + value. If present, this AVP MAY inform the Diameter client that if a + re-auth or STR message fails due to a delivery problem, the Diameter + client SHOULD issue a subsequent message without the Destination-Host + AVP. When absent, the default value is REFUSE_SERVICE. + + The following values are supported: + + + REFUSE_SERVICE 0 + + If either the re-auth or the STR message delivery fails, terminate + service with the user, and do not attempt any subsequent attempts. + + + TRY_AGAIN 1 + + If either the re-auth or the STR message delivery fails, resend + the failed message without the Destination-Host AVP present. + + + ALLOW_SERVICE 2 + + If re-auth message delivery fails, assume that re-authorization + succeeded. If STR message delivery fails, terminate the session. + + + TRY_AGAIN_ALLOW_SERVICE 3 + + If either the re-auth or the STR message delivery fails, resend + the failed message without the Destination-Host AVP present. If + + + +Fajardo, et al. Expires July 24, 2011 [Page 125] + +Internet-Draft Diameter Base Protocol January 2011 + + + the second delivery fails for re-auth, assume re-authorization + succeeded. If the second delivery fails for STR, terminate the + session. + + +8.19. Multi-Round-Time-Out AVP + + The Multi-Round-Time-Out AVP (AVP Code 272) is of type Unsigned32, + and SHOULD be present in application-specific authorization answer + messages whose Result-Code AVP is set to DIAMETER_MULTI_ROUND_AUTH. + This AVP contains the maximum number of seconds that the access + device MUST provide the user in responding to an authentication + request. + +8.20. Class AVP + + The Class AVP (AVP Code 25) is of type OctetString and is used by + Diameter servers to return state information to the access device. + When one or more Class AVPs are present in application-specific + authorization answer messages, they MUST be present in subsequent re- + authorization, session termination and accounting messages. Class + AVPs found in a re-authorization answer message override the ones + found in any previous authorization answer message. Diameter server + implementations SHOULD NOT return Class AVPs that require more than + 4096 bytes of storage on the Diameter client. A Diameter client that + receives Class AVPs whose size exceeds local available storage MUST + terminate the session. + +8.21. Event-Timestamp AVP + + The Event-Timestamp (AVP Code 55) is of type Time, and MAY be + included in an Accounting-Request and Accounting-Answer messages to + record the time that the reported event occurred, in seconds since + January 1, 1900 00:00 UTC. + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 126] + +Internet-Draft Diameter Base Protocol January 2011 + + +9. Accounting + + This accounting protocol is based on a server directed model with + capabilities for real-time delivery of accounting information. + Several fault resilience methods [RFC2975] have been built in to the + protocol in order minimize loss of accounting data in various fault + situations and under different assumptions about the capabilities of + the used devices. + +9.1. Server Directed Model + + The server directed model means that the device generating the + accounting data gets information from either the authorization server + (if contacted) or the accounting server regarding the way accounting + data shall be forwarded. This information includes accounting record + timeliness requirements. + + As discussed in [RFC2975], real-time transfer of accounting records + is a requirement, such as the need to perform credit limit checks and + fraud detection. Note that batch accounting is not a requirement, + and is therefore not supported by Diameter. Should batched + accounting be required in the future, a new Diameter application will + need to be created, or it could be handled using another protocol. + Note, however, that even if at the Diameter layer accounting requests + are processed one by one, transport protocols used under Diameter + typically batch several requests in the same packet under heavy + traffic conditions. This may be sufficient for many applications. + + The authorization server (chain) directs the selection of proper + transfer strategy, based on its knowledge of the user and + relationships of roaming partnerships. The server (or agents) uses + the Acct-Interim-Interval and Accounting-Realtime-Required AVPs to + control the operation of the Diameter peer operating as a client. + The Acct-Interim-Interval AVP, when present, instructs the Diameter + node acting as a client to produce accounting records continuously + even during a session. Accounting-Realtime-Required AVP is used to + control the behavior of the client when the transfer of accounting + records from the Diameter client is delayed or unsuccessful. + + The Diameter accounting server MAY override the interim interval or + the realtime requirements by including the Acct-Interim-Interval or + Accounting-Realtime-Required AVP in the Accounting-Answer message. + When one of these AVPs is present, the latest value received SHOULD + be used in further accounting activities for the same session. + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 127] + +Internet-Draft Diameter Base Protocol January 2011 + + +9.2. Protocol Messages + + A Diameter node that receives a successful authentication and/or + authorization messages from the Diameter server SHOULD collect + accounting information for the session. The Accounting-Request + message is used to transmit the accounting information to the + Diameter server, which MUST reply with the Accounting-Answer message + to confirm reception. The Accounting-Answer message includes the + Result-Code AVP, which MAY indicate that an error was present in the + accounting message. The value of the Accounting-Realtime-Required + AVP received earlier for the session in question may indicate that + the user's session has to be terminated when a rejected Accounting- + Request message was received. + +9.3. Accounting Application Extension and Requirements + + Each Diameter application (e.g., NASREQ, MobileIP), SHOULD define + their Service-Specific AVPs that MUST be present in the Accounting- + Request message in a section entitled "Accounting AVPs". The + application MUST assume that the AVPs described in this document will + be present in all Accounting messages, so only their respective + service-specific AVPs need to be defined in that section. + + Applications have the option of using one or both of the following + accounting application extension models: + + Split Accounting Service + + The accounting message will carry the Application Id of the + Diameter base accounting application (see Section 2.4). + Accounting messages may be routed to Diameter nodes other than the + corresponding Diameter application. These nodes might be + centralized accounting servers that provide accounting service for + multiple different Diameter applications. These nodes MUST + advertise the Diameter base accounting Application Id during + capabilities exchange. + + + Coupled Accounting Service + + The accounting messages will carry the Application Id of the + application that is using it. The application itself will process + the received accounting records or forward them to an accounting + server. There is no accounting application advertisement required + during capabilities exchange and the accounting messages will be + routed the same as any of the other application messages. + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 128] + +Internet-Draft Diameter Base Protocol January 2011 + + + In cases where an application does not define its own accounting + service, it is preferred that the split accounting model be used. + +9.4. Fault Resilience + + Diameter Base protocol mechanisms are used to overcome small message + loss and network faults of temporary nature. + + Diameter peers acting as clients MUST implement the use of failover + to guard against server failures and certain network failures. + Diameter peers acting as agents or related off-line processing + systems MUST detect duplicate accounting records caused by the + sending of same record to several servers and duplication of messages + in transit. This detection MUST be based on the inspection of the + Session-Id and Accounting-Record-Number AVP pairs. Appendix C + discusses duplicate detection needs and implementation issues. + + Diameter clients MAY have non-volatile memory for the safe storage of + accounting records over reboots or extended network failures, network + partitions, and server failures. If such memory is available, the + client SHOULD store new accounting records there as soon as the + records are created and until a positive acknowledgement of their + reception from the Diameter Server has been received. Upon a reboot, + the client MUST starting sending the records in the non-volatile + memory to the accounting server with appropriate modifications in + termination cause, session length, and other relevant information in + the records. + + A further application of this protocol may include AVPs to control + how many accounting records may at most be stored in the Diameter + client without committing them to the non-volatile memory or + transferring them to the Diameter server. + + The client SHOULD NOT remove the accounting data from any of its + memory areas before the correct Accounting-Answer has been received. + The client MAY remove oldest, undelivered or yet unacknowledged + accounting data if it runs out of resources such as memory. It is an + implementation dependent matter for the client to accept new sessions + under this condition. + +9.5. Accounting Records + + In all accounting records, the Session-Id AVP MUST be present; the + User-Name AVP MUST be present if it is available to the Diameter + client. + + Different types of accounting records are sent depending on the + actual type of accounted service and the authorization server's + + + +Fajardo, et al. Expires July 24, 2011 [Page 129] + +Internet-Draft Diameter Base Protocol January 2011 + + + directions for interim accounting. If the accounted service is a + one-time event, meaning that the start and stop of the event are + simultaneous, then the Accounting-Record-Type AVP MUST be present and + set to the value EVENT_RECORD. + + If the accounted service is of a measurable length, then the AVP MUST + use the values START_RECORD, STOP_RECORD, and possibly, + INTERIM_RECORD. If the authorization server has not directed interim + accounting to be enabled for the session, two accounting records MUST + be generated for each service of type session. When the initial + Accounting-Request for a given session is sent, the Accounting- + Record-Type AVP MUST be set to the value START_RECORD. When the last + Accounting-Request is sent, the value MUST be STOP_RECORD. + + If the authorization server has directed interim accounting to be + enabled, the Diameter client MUST produce additional records between + the START_RECORD and STOP_RECORD, marked INTERIM_RECORD. The + production of these records is directed by Acct-Interim-Interval as + well as any re-authentication or re-authorization of the session. + The Diameter client MUST overwrite any previous interim accounting + records that are locally stored for delivery, if a new record is + being generated for the same session. This ensures that only one + pending interim record can exist on an access device for any given + session. + + A particular value of Accounting-Sub-Session-Id MUST appear only in + one sequence of accounting records from a DIAMETER client, except for + the purposes of retransmission. The one sequence that is sent MUST + be either one record with Accounting-Record-Type AVP set to the value + EVENT_RECORD, or several records starting with one having the value + START_RECORD, followed by zero or more INTERIM_RECORD and a single + STOP_RECORD. A particular Diameter application specification MUST + define the type of sequences that MUST be used. + +9.6. Correlation of Accounting Records + + If an application uses accounting messages, it can correlate + accounting records with a specific application session by using the + Session-Id of the particular application session in the accounting + messages. Accounting messages MAY also use a different Session-Id + from that of the application sessions in which case other session + related information is needed to perform correlation. + + In cases where an application requires multiple accounting sub- + session, an Accounting-Sub-Session-Id AVP is used to differentiate + each sub-session. The Session-Id would remain constant for all sub- + sessions and is be used to correlate all the sub-sessions to a + particular application session. Note that receiving a STOP_RECORD + + + +Fajardo, et al. Expires July 24, 2011 [Page 130] + +Internet-Draft Diameter Base Protocol January 2011 + + + with no Accounting-Sub-Session-Id AVP when sub-sessions were + originally used in the START_RECORD messages implies that all sub- + sessions are terminated. + + There are also cases where an application needs to correlate multiple + application sessions into a single accounting record; the accounting + record may span multiple different Diameter applications and sessions + used by the same user at a given time. In such cases, the Acct- + Multi-Session-Id AVP is used. The Acct-Multi-Session-Id AVP SHOULD + be signaled by the server to the access device (typically during + authorization) when it determines that a request belongs to an + existing session. The access device MUST then include the Acct- + Multi-Session-Id AVP in all subsequent accounting messages. + + The Acct-Multi-Session-Id AVP MAY include the value of the original + Session-Id. It's contents are implementation specific, but MUST be + globally unique across other Acct-Multi-Session-Id, and MUST NOT + change during the life of a session. + + A Diameter application document MUST define the exact concept of a + session that is being accounted, and MAY define the concept of a + multi-session. For instance, the NASREQ DIAMETER application treats + a single PPP connection to a Network Access Server as one session, + and a set of Multilink PPP sessions as one multi-session. + +9.7. Accounting Command-Codes + + This section defines Command-Code values that MUST be supported by + all Diameter implementations that provide Accounting services. + +9.7.1. Accounting-Request + + The Accounting-Request (ACR) command, indicated by the Command-Code + field set to 271 and the Command Flags' 'R' bit set, is sent by a + Diameter node, acting as a client, in order to exchange accounting + information with a peer. + + The AVP listed below SHOULD include service-specific accounting AVPs, + as described in Section 9.3. + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 131] + +Internet-Draft Diameter Base Protocol January 2011 + + + Message Format + + <ACR> ::= < 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 ] + [ Destination-Host ] + [ Accounting-Sub-Session-Id ] + [ Acct-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Acct-Interim-Interval ] + [ Accounting-Realtime-Required ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +9.7.2. Accounting-Answer + + The Accounting-Answer (ACA) command, indicated by the Command-Code + field set to 271 and the Command Flags' 'R' bit cleared, is used to + acknowledge an Accounting-Request command. The Accounting-Answer + command contains the same Session-Id as the corresponding request. + + Only the target Diameter Server, known as the home Diameter Server, + SHOULD respond with the Accounting-Answer command. + + The AVP listed below SHOULD include service-specific accounting AVPs, + as described in Section 9.3. + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 132] + +Internet-Draft Diameter Base Protocol January 2011 + + + Message Format + + <ACA> ::= < 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 ] + [ Error-Message ] + [ Error-Reporting-Host ] + [ Failed-AVP ] + [ Acct-Interim-Interval ] + [ Accounting-Realtime-Required ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Proxy-Info ] + * [ AVP ] + +9.8. Accounting AVPs + + This section contains AVPs that describe accounting usage information + related to a specific session. + +9.8.1. Accounting-Record-Type AVP + + The Accounting-Record-Type AVP (AVP Code 480) is of type Enumerated + and contains the type of accounting record being sent. The following + values are currently defined for the Accounting-Record-Type AVP: + + + EVENT_RECORD 1 + + An Accounting Event Record is used to indicate that a one-time + event has occurred (meaning that the start and end of the event + are simultaneous). This record contains all information relevant + to the service, and is the only record of the service. + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 133] + +Internet-Draft Diameter Base Protocol January 2011 + + + START_RECORD 2 + + An Accounting Start, Interim, and Stop Records are used to + indicate that a service of a measurable length has been given. An + Accounting Start Record is used to initiate an accounting session, + and contains accounting information that is relevant to the + initiation of the session. + + + INTERIM_RECORD 3 + + An Interim Accounting Record contains cumulative accounting + information for an existing accounting session. Interim + Accounting Records SHOULD be sent every time a re-authentication + or re-authorization occurs. Further, additional interim record + triggers MAY be defined by application-specific Diameter + applications. The selection of whether to use INTERIM_RECORD + records is done by the Acct-Interim-Interval AVP. + + + STOP_RECORD 4 + + An Accounting Stop Record is sent to terminate an accounting + session and contains cumulative accounting information relevant to + the existing session. + + +9.8.2. Acct-Interim-Interval AVP + + The Acct-Interim-Interval AVP (AVP Code 85) is of type Unsigned32 and + is sent from the Diameter home authorization server to the Diameter + client. The client uses information in this AVP to decide how and + when to produce accounting records. With different values in this + AVP, service sessions can result in one, two, or two+N accounting + records, based on the needs of the home-organization. The following + accounting record production behavior is directed by the inclusion of + this AVP: + + + 1. The omission of the Acct-Interim-Interval AVP or its inclusion + with Value field set to 0 means that EVENT_RECORD, START_RECORD, + and STOP_RECORD are produced, as appropriate for the service. + + + 2. The inclusion of the AVP with Value field set to a non-zero value + means that INTERIM_RECORD records MUST be produced between the + START_RECORD and STOP_RECORD records. The Value field of this + AVP is the nominal interval between these records in seconds. + + + +Fajardo, et al. Expires July 24, 2011 [Page 134] + +Internet-Draft Diameter Base Protocol January 2011 + + + The Diameter node that originates the accounting information, + known as the client, MUST produce the first INTERIM_RECORD record + roughly at the time when this nominal interval has elapsed from + the START_RECORD, the next one again as the interval has elapsed + once more, and so on until the session ends and a STOP_RECORD + record is produced. + + The client MUST ensure that the interim record production times + are randomized so that large accounting message storms are not + created either among records or around a common service start + time. + +9.8.3. Accounting-Record-Number AVP + + The Accounting-Record-Number AVP (AVP Code 485) is of type Unsigned32 + and identifies this record within one session. As Session-Id AVPs + are globally unique, the combination of Session-Id and Accounting- + Record-Number AVPs is also globally unique, and can be used in + matching accounting records with confirmations. An easy way to + produce unique numbers is to set the value to 0 for records of type + EVENT_RECORD and START_RECORD, and set the value to 1 for the first + INTERIM_RECORD, 2 for the second, and so on until the value for + STOP_RECORD is one more than for the last INTERIM_RECORD. + +9.8.4. Acct-Session-Id AVP + + The Acct-Session-Id AVP (AVP Code 44) is of type OctetString is only + used when RADIUS/Diameter translation occurs. This AVP contains the + contents of the RADIUS Acct-Session-Id attribute. + +9.8.5. Acct-Multi-Session-Id AVP + + The Acct-Multi-Session-Id AVP (AVP Code 50) is of type UTF8String, + following the format specified in Section 8.8. The Acct-Multi- + Session-Id AVP is used to link together multiple related accounting + sessions, where each session would have a unique Session-Id, but the + same Acct-Multi-Session-Id AVP. This AVP MAY be returned by the + Diameter server in an authorization answer, and MUST be used in all + accounting messages for the given session. + +9.8.6. Accounting-Sub-Session-Id AVP + + The Accounting-Sub-Session-Id AVP (AVP Code 287) is of type + Unsigned64 and contains the accounting sub-session identifier. The + combination of the Session-Id and this AVP MUST be unique per sub- + session, and the value of this AVP MUST be monotonically increased by + one for all new sub-sessions. The absence of this AVP implies no + sub-sessions are in use, with the exception of an Accounting-Request + + + +Fajardo, et al. Expires July 24, 2011 [Page 135] + +Internet-Draft Diameter Base Protocol January 2011 + + + whose Accounting-Record-Type is set to STOP_RECORD. A STOP_RECORD + message with no Accounting-Sub-Session-Id AVP present will signal the + termination of all sub-sessions for a given Session-Id. + +9.8.7. Accounting-Realtime-Required AVP + + The Accounting-Realtime-Required AVP (AVP Code 483) is of type + Enumerated and is sent from the Diameter home authorization server to + the Diameter client or in the Accounting-Answer from the accounting + server. The client uses information in this AVP to decide what to do + if the sending of accounting records to the accounting server has + been temporarily prevented due to, for instance, a network problem. + + + DELIVER_AND_GRANT 1 + + The AVP with Value field set to DELIVER_AND_GRANT means that the + service MUST only be granted as long as there is a connection to + an accounting server. Note that the set of alternative accounting + servers are treated as one server in this sense. Having to move + the accounting record stream to a backup server is not a reason to + discontinue the service to the user. + + + GRANT_AND_STORE 2 + + The AVP with Value field set to GRANT_AND_STORE means that service + SHOULD be granted if there is a connection, or as long as records + can still be stored as described in Section 9.4. + + This is the default behavior if the AVP isn't included in the + reply from the authorization server. + + + GRANT_AND_LOSE 3 + + The AVP with Value field set to GRANT_AND_LOSE means that service + SHOULD be granted even if the records cannot be delivered or + stored. + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 136] + +Internet-Draft Diameter Base Protocol January 2011 + + +10. AVP Occurrence Table + + The following tables presents the AVPs defined in this document, and + specifies in which Diameter messages they MAY be present or not. + AVPs that occur only inside a Grouped AVP are not shown in this + table. + + The table uses the following symbols: + + + 0 The AVP MUST NOT be present in the message. + + 0+ Zero or more instances of the AVP MAY be present in the + message. + + 0-1 Zero or one instance of the AVP MAY be present in the message. + It is considered an error if there are more than one instance of + the AVP. + + 1 One instance of the AVP MUST be present in the message. + + 1+ At least one instance of the AVP MUST be present in the + message. + +10.1. Base Protocol Command AVP Table + + The table in this section is limited to the non-accounting Command + Codes defined in this specification. + + +-----------------------------------------------+ + | Command-Code | + +---+---+---+---+---+---+---+---+---+---+---+---+ + Attribute Name |CER|CEA|DPR|DPA|DWR|DWA|RAR|RAA|ASR|ASA|STR|STA| + --------------------+---+---+---+---+---+---+---+---+---+---+---+---+ + Acct-Interim- |0 |0 |0 |0 |0 |0 |0-1|0 |0 |0 |0 |0 | + Interval | | | | | | | | | | | | | + Accounting-Realtime-|0 |0 |0 |0 |0 |0 |0-1|0 |0 |0 |0 |0 | + Required | | | | | | | | | | | | | + Acct-Application-Id |0+ |0+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Auth-Application-Id |0+ |0+ |0 |0 |0 |0 |1 |0 |1 |0 |1 |0 | + Auth-Grace-Period |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Auth-Request-Type |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Auth-Session-State |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Authorization- |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Lifetime | | | | | | | | | | | | | + Class |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0+ |0+ | + Destination-Host |0 |0 |0 |0 |0 |0 |1 |0 |1 |0 |0-1|0 | + Destination-Realm |0 |0 |0 |0 |0 |0 |1 |0 |1 |0 |1 |0 | + + + +Fajardo, et al. Expires July 24, 2011 [Page 137] + +Internet-Draft Diameter Base Protocol January 2011 + + + Disconnect-Cause |0 |0 |1 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Error-Message |0 |0-1|0 |0-1|0 |0-1|0 |0-1|0 |0-1|0 |0-1| + Error-Reporting-Host|0 |0 |0 |0 |0 |0 |0 |0-1|0 |0-1|0 |0-1| + Failed-AVP |0 |0+ |0 |0+ |0 |0+ |0 |0+ |0 |0+ |0 |0+ | + Firmware-Revision |0-1|0-1|0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Host-IP-Address |1+ |1+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Inband-Security-Id |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Multi-Round-Time-Out|0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Origin-Host |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 | + Origin-Realm |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 | + Origin-State-Id |0-1|0-1|0 |0 |0-1|0-1|0-1|0-1|0-1|0-1|0-1|0-1| + Product-Name |1 |1 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Proxy-Info |0 |0 |0 |0 |0 |0 |0+ |0+ |0+ |0+ |0+ |0+ | + Redirect-Host |0 |0 |0 |0 |0 |0 |0 |0+ |0 |0+ |0 |0+ | + Redirect-Host-Usage |0 |0 |0 |0 |0 |0 |0 |0-1|0 |0-1|0 |0-1| + Redirect-Max-Cache- |0 |0 |0 |0 |0 |0 |0 |0-1|0 |0-1|0 |0-1| + Time | | | | | | | | | | | | | + Result-Code |0 |1 |0 |1 |0 |1 |0 |1 |0 |1 |0 |1 | + Re-Auth-Request-Type|0 |0 |0 |0 |0 |0 |1 |0 |0 |0 |0 |0 | + Route-Record |0 |0 |0 |0 |0 |0 |0+ |0 |0+ |0 |0+ |0 | + Session-Binding |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Session-Id |0 |0 |0 |0 |0 |0 |1 |1 |1 |1 |1 |1 | + Session-Server- |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Failover | | | | | | | | | | | | | + Session-Timeout |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Supported-Vendor-Id |0+ |0+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Termination-Cause |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |1 |0 | + User-Name |0 |0 |0 |0 |0 |0 |0-1|0-1|0-1|0-1|0-1|0-1| + Vendor-Id |1 |1 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Vendor-Specific- |0+ |0+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Application-Id | | | | | | | | | | | | | + --------------------+---+---+---+---+---+---+---+---+---+---+---+---+ + +10.2. Accounting AVP Table + + The table in this section is used to represent which AVPs defined in + this document are to be present in the Accounting messages. These + AVP occurrence requirements are guidelines, which may be expanded, + and/or overridden by application-specific requirements in the + Diameter applications documents. + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 138] + +Internet-Draft Diameter Base Protocol January 2011 + + + +-----------+ + | Command | + | Code | + +-----+-----+ + Attribute Name | ACR | ACA | + ------------------------------+-----+-----+ + Acct-Interim-Interval | 0-1 | 0-1 | + Acct-Multi-Session-Id | 0-1 | 0-1 | + Accounting-Record-Number | 1 | 1 | + Accounting-Record-Type | 1 | 1 | + Acct-Session-Id | 0-1 | 0-1 | + Accounting-Sub-Session-Id | 0-1 | 0-1 | + Accounting-Realtime-Required | 0-1 | 0-1 | + Acct-Application-Id | 0-1 | 0-1 | + Auth-Application-Id | 0 | 0 | + Class | 0+ | 0+ | + Destination-Host | 0-1 | 0 | + Destination-Realm | 1 | 0 | + Error-Reporting-Host | 0 | 0+ | + Event-Timestamp | 0-1 | 0-1 | + Origin-Host | 1 | 1 | + Origin-Realm | 1 | 1 | + Proxy-Info | 0+ | 0+ | + Route-Record | 0+ | 0 | + Result-Code | 0 | 1 | + Session-Id | 1 | 1 | + Termination-Cause | 0 | 0 | + User-Name | 0-1 | 0-1 | + Vendor-Specific-Application-Id| 0-1 | 0-1 | + ------------------------------+-----+-----+ + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 139] + +Internet-Draft Diameter Base Protocol January 2011 + + +11. IANA Considerations + + This section provides guidance to the Internet Assigned Numbers + Authority (IANA) regarding registration of values related to the + Diameter protocol, in accordance with BCP 26 [RFC5226]. The policies + and procedures for the IANA put in place by [RFC3588] applies here. + The criteria used by the IANA for assignment of numbers within this + namespace remains the same unless otherwise stated in this section. + Existing assignments remains the same unless explicitly updated or + deprecated in this secion. + +11.1. Changes to AVP Header Allocation + + For AVP Headers, the only change is the AVP code block allocations. + Block allocation (release of more than 3 at a time for a given + purpose) now only require IETF Review as opposed to an IETF + Consensus. + +11.2. Diameter Header + + For the Diameter Header, the command code namespace allocation has + changed. The new allocation rules are as follows: + + The command code values 256 - 8,388,607 (0x100 to 0x7fffff) are + for permanent, standard commands, allocated by IETF Review + [RFC5226]. + + The values 8,388,608 - 16,777,213 (0x800000 - 0xfffffd) are + reserved for vendor-specific command codes, to be allocated on a + First Come, First Served basis by IANA [RFC5226]. The request to + IANA for a Vendor-Specific Command Code SHOULD include a reference + to a publicly available specification which documents the command + in sufficient detail to aid in interoperability between + independent implementations. If the specification cannot be made + publicly available, the request for a vendor-specific command code + MUST include the contact information of persons and/or entities + responsible for authoring and maintaining the command. + +11.3. AVP Values + + For AVP values, the Experimental-Result-Code AVP value allocation has + been added. The new rule is as follows: + +11.3.1. Experimental-Result-Code AVP + + Values for this AVP are purely local to the indicated vendor, and no + IANA registry is maintained for them. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 140] + +Internet-Draft Diameter Base Protocol January 2011 + + +11.4. Diameter TCP, SCTP, TLS/TCP and DTLS/SCTP Port Numbers + + Updated port number assignments are described in this section. The + IANA has assigned port number 3868 for TCP and SCTP. The port number + [TBD] has been assigned for TLS/TCP and DTLS/SCTP. + +11.5. S-NAPTR Parameters + + This document registers a new S-NAPTR Application Service Tag value + of "aaa". + + This document also registers the following S-NAPTR Application + Protocol Tags: + + Tag | Protocol + -------------------|--------- + diameter.tcp | TCP + diameter.sctp | SCTP + diameter.tls.tcp | TLS/TCP + diameter.dtls.sctp | DTLS/SCTP + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 141] + +Internet-Draft Diameter Base Protocol January 2011 + + +12. Diameter protocol related configurable parameters + + This section contains the configurable parameters that are found + throughout this document: + + Diameter Peer + + A Diameter entity MAY communicate with peers that are statically + configured. A statically configured Diameter peer would require + that either the IP address or the fully qualified domain name + (FQDN) be supplied, which would then be used to resolve through + DNS. + + Routing Table + + A Diameter proxy server routes messages based on the realm portion + of a Network Access Identifier (NAI). The server MUST have a + table of Realm Names, and the address of the peer to which the + message must be forwarded to. The routing table MAY also include + a "default route", which is typically used for all messages that + cannot be locally processed. + + Tc timer + + The Tc timer controls the frequency that transport connection + attempts are done to a peer with whom no active transport + connection exists. The recommended value is 30 seconds. + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 142] + +Internet-Draft Diameter Base Protocol January 2011 + + +13. Security Considerations + + The Diameter base protocol messages SHOULD be secured by using TLS + [RFC5246] or DTLS/SCTP [RFC6083]. Additional security mechanisms + such as IPsec [RFC4301] MAY also be deployed to secure connections + between peers. However, all Diameter base protocol implementations + MUST support the use of TLS/TCP and DTLS/SCTP and the Diameter + protocol MUST NOT be used without any security mechanism. + + If a Diameter connection is to be protected via TLS/TCP and DTLS/SCTP + or IPsec, then TLS/TCP and DTLS/SCTP or IPsec/IKE SHOULD begin prior + to any Diameter message exchange. All security parameters for TLS/ + TCP and DTLS/SCTP or IPsec are configured independent of the Diameter + protocol. All Diameter message will be sent through the TLS/TCP and + DTLS/SCTP or IPsec connection after a successful setup. + + For TLS/TCP and DTLS/SCTP connections to be established in the open + state, the CER/CEA exchange MUST include an Inband-Security-ID AVP + with a value of TLS/TCP and DTLS/SCTP. The TLS/TCP and DTLS/SCTP + handshake will begin when both ends successfully reached the open + state, after completion of the CER/CEA exchange. If the TLS/TCP and + DTLS/SCTP handshake is successful, all further messages will be sent + via TLS/TCP and DTLS/SCTP. If the handshake fails, both ends move to + the closed state. See Sections 13.1 for more details. + +13.1. TLS/TCP and DTLS/SCTP Usage + + Diameter nodes using TLS/TCP and DTLS/SCTP for security MUST mutually + authenticate as part of TLS/TCP and DTLS/SCTP session establishment. + In order to ensure mutual authentication, the Diameter node acting as + TLS/TCP and DTLS/SCTP server MUST request a certificate from the + Diameter node acting as TLS/TCP and DTLS/SCTP client, and the + Diameter node acting as TLS/TCP and DTLS/SCTP client MUST be prepared + to supply a certificate on request. + + Diameter nodes MUST be able to negotiate the following TLS/TCP and + DTLS/SCTP cipher suites: + + TLS_RSA_WITH_RC4_128_MD5 + TLS_RSA_WITH_RC4_128_SHA + TLS_RSA_WITH_3DES_EDE_CBC_SHA + + Diameter nodes SHOULD be able to negotiate the following TLS/TCP and + DTLS/SCTP cipher suite: + + TLS_RSA_WITH_AES_128_CBC_SHA + + Diameter nodes MAY negotiate other TLS/TCP and DTLS/SCTP cipher + + + +Fajardo, et al. Expires July 24, 2011 [Page 143] + +Internet-Draft Diameter Base Protocol January 2011 + + + suites. + +13.2. Peer-to-Peer Considerations + + As with any peer-to-peer protocol, proper configuration of the trust + model within a Diameter peer is essential to security. When + certificates are used, it is necessary to configure the root + certificate authorities trusted by the Diameter peer. These root CAs + are likely to be unique to Diameter usage and distinct from the root + CAs that might be trusted for other purposes such as Web browsing. + In general, it is expected that those root CAs will be configured so + as to reflect the business relationships between the organization + hosting the Diameter peer and other organizations. As a result, a + Diameter peer will typically not be configured to allow connectivity + with any arbitrary peer. With certificate authentication, Diameter + peers may not be known beforehand and therefore peer discovery may be + required. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 144] + +Internet-Draft Diameter Base Protocol January 2011 + + +14. References + +14.1. Normative References + + [FLOATPOINT] + Institute of Electrical and Electronics Engineers, "IEEE + Standard for Binary Floating-Point Arithmetic, ANSI/IEEE + Standard 754-1985", August 1985. + + [IANAADFAM] + IANA,, "Address Family Numbers", + http://www.iana.org/assignments/address-family-numbers. + + [RADTYPE] IANA,, "RADIUS Types", + http://www.iana.org/assignments/radius-types. + + [RFC791] Postel, J., "Internet Protocol", RFC 791, September 1981. + + [RFC793] Postel, J., "Transmission Control Protocol", RFC 793, + January 1981. + + [RFC3539] Aboba, B. and J. Wood, "Authentication, Authorization and + Accounting (AAA) Transport Profile", RFC 3539, June 2003. + + [RFC4004] Calhoun, P., Johansson, T., Perkins, C., Hiller, T., and + P. McCann, "Diameter Mobile IPv4 Application", RFC 4004, + August 2005. + + [RFC4005] Calhoun, P., Zorn, G., Spence, D., and D. Mitton, + "Diameter Network Access Server Application", RFC 4005, + August 2005. + + [RFC4006] Hakala, H., Mattila, L., Koskinen, J-P., Stura, M., and J. + Loughney, "Diameter Credit-Control Application", RFC 4006, + August 2005. + + [RFC5234] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", STD 68, RFC 5234, January 2008. + + [RFC3588] Calhoun, P., Loughney, J., Guttman, E., Zorn, G., and J. + Arkko, "Diameter Base Protocol", RFC 3588, September 2003. + + [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing an + IANA Considerations Section in RFCs", BCP 26, RFC 5226, + May 2008. + + [RFC4291] Hinden, R. and S. Deering, "IP Version 6 Addressing + Architecture", RFC 4291, February 2006. + + + +Fajardo, et al. Expires July 24, 2011 [Page 145] + +Internet-Draft Diameter Base Protocol January 2011 + + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC4282] Aboba, B., Beadles, M., Arkko, J., and P. Eronen, "The + Network Access Identifier", RFC 4282, December 2005. + + [RFC4086] Eastlake, D., Schiller, J., and S. Crocker, "Randomness + Requirements for Security", BCP 106, RFC 4086, June 2005. + + [RFC4960] Stewart, R., "Stream Control Transmission Protocol", + RFC 4960, September 2007. + + [RFC3958] Daigle, L. and A. Newton, "Domain-Based Application + Service Location Using SRV RRs and the Dynamic Delegation + Discovery Service (DDDS)", RFC 3958, January 2005. + + [RFC5246] Dierks, T. and E. Rescorla, "The Transport Layer Security + (TLS) Protocol Version 1.2", RFC 5246, August 2008. + + [RFC3986] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform + Resource Identifier (URI): Generic Syntax", STD 66, + RFC 3986, January 2005. + + [RFC3629] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", STD 63, RFC 3629, November 2003. + + [RFC5890] Klensin, J., "Internationalized Domain Names for + Applications (IDNA): Definitions and Document Framework", + RFC 5890, August 2010. + + [RFC5891] Klensin, J., "Internationalized Domain Names in + Applications (IDNA): Protocol", RFC 5891, August 2010. + + [RFC3492] Costello, A., "Punycode: A Bootstring encoding of Unicode + for Internationalized Domain Names in Applications + (IDNA)", RFC 3492, March 2003. + + [RFC5729] Korhonen, J., Jones, M., Morand, L., and T. Tsou, + "Clarifications on the Routing of Diameter Requests Based + on the Username and the Realm", RFC 5729, December 2009. + + [RFC4347] Rescorla, E. and N. Modadugu, "Datagram Transport Layer + Security", RFC 4347, April 2006. + + [RFC6083] Tuexen, M., Seggelmann, R., and E. Rescorla, "Datagram + Transport Layer Security (DTLS) for Stream Control + Transmission Protocol (SCTP)", RFC 6083, January 2011. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 146] + +Internet-Draft Diameter Base Protocol January 2011 + + +14.2. Informational References + + [RFC2989] Aboba, B., Calhoun, P., Glass, S., Hiller, T., McCann, P., + Shiino, H., Walsh, P., Zorn, G., Dommety, G., Perkins, C., + Patil, B., Mitton, D., Manning, S., Beadles, M., Chen, X., + Sivalingham, S., Hameed, A., Munson, M., Jacobs, S., Lim, + B., Hirschman, B., Hsu, R., Koo, H., Lipford, M., + Campbell, E., Xu, Y., Baba, S., and E. Jaques, "Criteria + for Evaluating AAA Protocols for Network Access", + RFC 2989, November 2000. + + [RFC2975] Aboba, B., Arkko, J., and D. Harrington, "Introduction to + Accounting Management", RFC 2975, October 2000. + + [RFC3232] Reynolds, J., "Assigned Numbers: RFC 1700 is Replaced by + an On-line Database", RFC 3232, January 2002. + + [RFC5176] Chiba, M., Dommety, G., Eklund, M., Mitton, D., and B. + Aboba, "Dynamic Authorization Extensions to Remote + Authentication Dial In User Service (RADIUS)", RFC 5176, + January 2008. + + [RFC1661] Simpson, W., "The Point-to-Point Protocol (PPP)", STD 51, + RFC 1661, July 1994. + + [RFC2866] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000. + + [RFC2869] Rigney, C., Willats, W., and P. Calhoun, "RADIUS + Extensions", RFC 2869, June 2000. + + [RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson, + "Remote Authentication Dial In User Service (RADIUS)", + RFC 2865, June 2000. + + [RFC3162] Aboba, B., Zorn, G., and D. Mitton, "RADIUS and IPv6", + RFC 3162, August 2001. + + [RFC4301] Kent, S. and K. Seo, "Security Architecture for the + Internet Protocol", RFC 4301, December 2005. + + [RFC5905] Mills, D., Martin, J., Burbank, J., and W. Kasch, "Network + Time Protocol Version 4: Protocol and Algorithms + Specification", RFC 5905, June 2010. + + [RFC1492] Finseth, C., "An Access Control Protocol, Sometimes Called + TACACS", RFC 1492, July 1993. + + [RFC4690] Klensin, J., Faltstrom, P., Karp, C., and IAB, "Review and + + + +Fajardo, et al. Expires July 24, 2011 [Page 147] + +Internet-Draft Diameter Base Protocol January 2011 + + + Recommendations for Internationalized Domain Names + (IDNs)", RFC 4690, September 2006. + + [RFC5461] Gont, F., "TCP's Reaction to Soft Errors", RFC 5461, + February 2009. + + [RFC5927] Gont, F., "ICMP Attacks against TCP", RFC 5927, July 2010. + + [RFC3692] Narten, T., "Assigning Experimental and Testing Numbers + Considered Useful", BCP 82, RFC 3692, January 2004. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 148] + +Internet-Draft Diameter Base Protocol January 2011 + + +Appendix A. Acknowledgements + +A.1. RFC3588bis + + The authors would like to thank the following people that have + provided proposals and contributions to this document: + + To Vishnu Ram and Satendra Gera for their contributions on + Capabilities Updates, Predictive Loop Avoidance as well as many other + technical proposals. To Tolga Asveren for his insights and + contributions on almost all of the proposed solutions incorporated + into this document. To Timothy Smith for helping on the Capabilities + Updates and other topics. To Tony Zhang for providing fixes to loop + holes on composing Failed-AVPs as well as many other issues and + topics. To Jan Nordqvist for clearly stating the usage of + Application Ids. To Anders Kristensen for providing needed technical + opinions. To David Frascone for providing invaluable review of the + document. To Mark Jones for providing clarifying text on vendor + command codes and other vendor specific indicators. + + Special thanks to the Diameter extensibility design team which helped + resolve the tricky question of mandatory AVPs and ABNF semantics. + The members of this team are as follows: + + Avi Lior, Jari Arkko, Glen Zorn, Lionel Morand, Mark Jones, Tolga + Asveren Jouni Korhonen, Glenn McGregor. + + Special thanks also to people who have provided invaluable comments + and inputs especially in resolving controversial issues: + + Glen Zorn, Yoshihiro Ohba, Marco Stura, and Pasi Eronen. + + Finally, we would like to thank the original authors of this + document: + + Pat Calhoun, John Loughney, Jari Arkko, Erik Guttman and Glen Zorn. + + Their invaluable knowledge and experience has given us a robust and + flexible AAA protocol that many people have seen great value in + adopting. We greatly appreciate their support and stewardship for + the continued improvements of Diameter as a protocol. We would also + like to extend our gratitude to folks aside from the authors who have + assisted and contributed to the original version of this document. + Their efforts significantly contributed to the success of Diameter. + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 149] + +Internet-Draft Diameter Base Protocol January 2011 + + +A.2. RFC3588 + + The authors would like to thank Nenad Trifunovic, Tony Johansson and + Pankaj Patel for their participation in the pre-IETF Document Reading + Party. Allison Mankin, Jonathan Wood and Bernard Aboba provided + invaluable assistance in working out transport issues, and similarly + with Steven Bellovin in the security area. + + Paul Funk and David Mitton were instrumental in getting the Peer + State Machine correct, and our deep thanks go to them for their time. + + Text in this document was also provided by Paul Funk, Mark Eklund, + Mark Jones and Dave Spence. Jacques Caron provided many great + comments as a result of a thorough review of the spec. + + The authors would also like to acknowledge the following people for + their contribution in the development of the Diameter protocol: + + Allan C. Rubens, Haseeb Akhtar, William Bulley, Stephen Farrell, + David Frascone, Daniel C. Fox, Lol Grant, Ignacio Goyret, Nancy + Greene, Peter Heitman, Fredrik Johansson, Mark Jones, Martin Julien, + Bob Kopacz, Paul Krumviede, Fergal Ladley, Ryan Moats, Victor Muslin, + Kenneth Peirce, John Schnizlein, Sumit Vakil, John R. Vollbrecht and + Jeff Weisberg. + + Finally, Pat Calhoun would like to thank Sun Microsystems since most + of the effort put into this document was done while he was in their + employ. + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 150] + +Internet-Draft Diameter Base Protocol January 2011 + + +Appendix B. S-NAPTR Example + + As an example, consider a client that wishes to resolve aaa: + example1.com. The client performs a NAPTR query for that domain, and + the following NAPTR records are returned: + + ;; order pref flags service regexp replacement + IN NAPTR 50 50 "s" "aaa:diameter.tls.tcp" "" + _diameter._tls.example1.com + IN NAPTR 100 50 "s" "aaa:diameter.tcp" "" + _aaa._tcp.example1.com + IN NAPTR 150 50 "s" "aaa:diameter.sctp" "" + _diameter._sctp.example1.com + + This indicates that the server supports TLS, TCP and SCTP in that + order. If the client supports TLS, TLS will be used, targeted to a + host determined by an SRV lookup of _diameter._tls.example1.com. + That lookup would return: + + ;; Priority Weight Port Target + IN SRV 0 1 5060 server1.example1.com + IN SRV 0 2 5060 server2.example1.com + + As an alternative example, a client that wishes to resolve aaa: + example2.com. The client performs a NAPTR query for that domain, and + the following NAPTR records are returned: + + ;; order pref flags service regexp replacement + IN NAPTR 150 50 "a" "aaa:diameter.tls.tcp" "" + server1.example2.com + IN NAPTR 150 50 "a" "aaa:diameter.tls.tcp" "" + server2.example2.com + + This indicates that the server supports TCP available at the returned + host names. + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 151] + +Internet-Draft Diameter Base Protocol January 2011 + + +Appendix C. Duplicate Detection + + As described in Section 9.4, accounting record duplicate detection is + based on session identifiers. Duplicates can appear for various + reasons: + + o Failover to an alternate server. Where close to real-time + performance is required, failover thresholds need to be kept low + and this may lead to an increased likelihood of duplicates. + Failover can occur at the client or within Diameter agents. + + o Failure of a client or agent after sending of a record from non- + volatile memory, but prior to receipt of an application layer ACK + and deletion of the record. record to be sent. This will result + in retransmission of the record soon after the client or agent has + rebooted. + + o Duplicates received from RADIUS gateways. Since the + retransmission behavior of RADIUS is not defined within [RFC2865], + the likelihood of duplication will vary according to the + implementation. + + o Implementation problems and misconfiguration. + + The T flag is used as an indication of an application layer + retransmission event, e.g., due to failover to an alternate server. + It is defined only for request messages sent by Diameter clients or + agents. For instance, after a reboot, a client may not know whether + it has already tried to send the accounting records in its non- + volatile memory before the reboot occurred. Diameter servers MAY use + the T flag as an aid when processing requests and detecting duplicate + messages. However, servers that do this MUST ensure that duplicates + are found even when the first transmitted request arrives at the + server after the retransmitted request. It can be used only in cases + where no answer has been received from the Server for a request and + the request is sent again, (e.g., due to a failover to an alternate + peer, due to a recovered primary peer or due to a client re-sending a + stored record from non-volatile memory such as after reboot of a + client or agent). + + In some cases the Diameter accounting server can delay the duplicate + detection and accounting record processing until a post-processing + phase takes place. At that time records are likely to be sorted + according to the included User-Name and duplicate elimination is easy + in this case. In other situations it may be necessary to perform + real-time duplicate detection, such as when credit limits are imposed + or real-time fraud detection is desired. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 152] + +Internet-Draft Diameter Base Protocol January 2011 + + + In general, only generation of duplicates due to failover or re- + sending of records in non-volatile storage can be reliably detected + by Diameter clients or agents. In such cases the Diameter client or + agents can mark the message as possible duplicate by setting the T + flag. Since the Diameter server is responsible for duplicate + detection, it can choose to make use of the T flag or not, in order + to optimize duplicate detection. Since the T flag does not affect + interoperability, and may not be needed by some servers, generation + of the T flag is REQUIRED for Diameter clients and agents, but MAY be + implemented by Diameter servers. + + As an example, it can be usually be assumed that duplicates appear + within a time window of longest recorded network partition or device + fault, perhaps a day. So only records within this time window need + to be looked at in the backward direction. Secondly, hashing + techniques or other schemes, such as the use of the T flag in the + received messages, may be used to eliminate the need to do a full + search even in this set except for rare cases. + + The following is an example of how the T flag may be used by the + server to detect duplicate requests. + + + A Diameter server MAY check the T flag of the received message to + determine if the record is a possible duplicate. If the T flag is + set in the request message, the server searches for a duplicate + within a configurable duplication time window backward and + forward. This limits database searching to those records where + the T flag is set. In a well run network, network partitions and + device faults will presumably be rare events, so this approach + represents a substantial optimization of the duplicate detection + process. During failover, it is possible for the original record + to be received after the T flag marked record, due to differences + in network delays experienced along the path by the original and + duplicate transmissions. The likelihood of this occurring + increases as the failover interval is decreased. In order to be + able to detect out of order duplicates, the Diameter server should + use backward and forward time windows when performing duplicate + checking for the T flag marked request. For example, in order to + allow time for the original record to exit the network and be + recorded by the accounting server, the Diameter server can delay + processing records with the T flag set until a time period + TIME_WAIT + RECORD_PROCESSING_TIME has elapsed after the closing + of the original transport connection. After this time period has + expired, then it may check the T flag marked records against the + database with relative assurance that the original records, if + sent, have been received and recorded. + + + + +Fajardo, et al. Expires July 24, 2011 [Page 153] + +Internet-Draft Diameter Base Protocol January 2011 + + +Appendix D. Internationalized Domain Names + + To be compatible with the existing DNS infrastructure and simplify + host and domain name comparison, Diameter identities (FQDNs) are + represented in ASCII form. This allows the Diameter protocol to fall + in-line with the DNS strategy of being transparent from the effects + of Internationalized Domain Names (IDNs) by following the + recommendations in [RFC4690] and [RFC5890]. Applications that + provide support for IDNs outside of the Diameter protocol but + interacting with it SHOULD use the representation and conversion + framework described in [RFC5890], [RFC5891] and [RFC3492]. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 154] + +Internet-Draft Diameter Base Protocol January 2011 + + +Authors' Addresses + + Victor Fajardo (editor) + Telcordia Technologies + One Telcordia Drive, 1S-222 + Piscataway, NJ 08854 + USA + + Phone: +1-908-421-1845 + Email: [email protected] + + + Jari Arkko + Ericsson Research + 02420 Jorvas + Finland + + Phone: +358 40 5079256 + Email: [email protected] + + + John Loughney + Nokia Research Center + 955 Page Mill Road + Palo Alto, CA 94304 + US + + Phone: +1-650-283-8068 + Email: [email protected] + + + Glenn Zorn + Network Zen + 1310 East Thomas Street + Seattle, WA 98102 + US + + Phone: + Email: [email protected] + + + + + + + + + + + + +Fajardo, et al. Expires July 24, 2011 [Page 155] + + diff --git a/lib/diameter/doc/standard/rfc3124.txt b/lib/diameter/doc/standard/rfc3124.txt new file mode 100644 index 0000000000..db57bc370f --- /dev/null +++ b/lib/diameter/doc/standard/rfc3124.txt @@ -0,0 +1,1235 @@ + + + + + + +Network Working Group H. Balakrishnan +Request for Comments: 3124 MIT LCS +Category: Standards Track S. Seshan + CMU + June 2001 + + + The Congestion Manager + + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2001). All Rights Reserved. + +Abstract + + This document describes the Congestion Manager (CM), an end-system + module that: + + (i) Enables an ensemble of multiple concurrent streams from a sender + destined to the same receiver and sharing the same congestion + properties to perform proper congestion avoidance and control, and + + (ii) Allows applications to easily adapt to network congestion. + +1. Conventions used in this document: + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC-2119 [Bradner97]. + + STREAM + + A group of packets that all share the same source and destination + IP address, IP type-of-service, transport protocol, and source and + destination transport-layer port numbers. + + + + + + + +Balakrishnan, et. al. Standards Track [Page 1] + +RFC 3124 The Congestion Manager June 2001 + + + MACROFLOW + + A group of CM-enabled streams that all use the same congestion + management and scheduling algorithms, and share congestion state + information. Currently, streams destined to different receivers + belong to different macroflows. Streams destined to the same + receiver MAY belong to different macroflows. When the Congestion + Manager is in use, streams that experience identical congestion + behavior and use the same congestion control algorithm SHOULD + belong to the same macroflow. + + APPLICATION + + Any software module that uses the CM. This includes user-level + applications such as Web servers or audio/video servers, as well + as in-kernel protocols such as TCP [Postel81] that use the CM for + congestion control. + + WELL-BEHAVED APPLICATION + + An application that only transmits when allowed by the CM and + accurately accounts for all data that it has sent to the receiver + by informing the CM using the CM API. + + PATH MAXIMUM TRANSMISSION UNIT (PMTU) + + The size of the largest packet that the sender can transmit + without it being fragmented en route to the receiver. It includes + the sizes of all headers and data except the IP header. + + CONGESTION WINDOW (cwnd) + + A CM state variable that modulates the amount of outstanding data + between sender and receiver. + + OUTSTANDING WINDOW (ownd) + + The number of bytes that has been transmitted by the source, but + not known to have been either received by the destination or lost + in the network. + + INITIAL WINDOW (IW) + + The size of the sender's congestion window at the beginning of a + macroflow. + + + + + + +Balakrishnan, et. al. Standards Track [Page 2] + +RFC 3124 The Congestion Manager June 2001 + + + DATA TYPE SYNTAX + + We use "u64" for unsigned 64-bit, "u32" for unsigned 32-bit, "u16" + for unsigned 16-bit, "u8" for unsigned 8-bit, "i32" for signed + 32-bit, "i16" for signed 16-bit quantities, "float" for IEEE + floating point values. The type "void" is used to indicate that + no return value is expected from a call. Pointers are referred to + using "*" syntax, following C language convention. + + We emphasize that all the API functions described in this document + are "abstract" calls and that conformant CM implementations may + differ in specific implementation details. + +2. Introduction + + The framework described in this document integrates congestion + management across all applications and transport protocols. The CM + maintains congestion parameters (available aggregate and per-stream + bandwidth, per-receiver round-trip times, etc.) and exports an API + that enables applications to learn about network characteristics, + pass information to the CM, share congestion information with each + other, and schedule data transmissions. This document focuses on + applications and transport protocols with their own independent per- + byte or per-packet sequence number information, and does not require + modifications to the receiver protocol stack. However, the receiving + application must provide feedback to the sending application about + received packets and losses, and the latter is expected to use the CM + API to update CM state. This document does not address networks with + reservations or service differentiation. + + The CM is an end-system module that enables an ensemble of multiple + concurrent streams to perform stable congestion avoidance and + control, and allows applications to easily adapt their transmissions + to prevailing network conditions. It integrates congestion + management across all applications and transport protocols. It + maintains congestion parameters (available aggregate and per-stream + bandwidth, per-receiver round-trip times, etc.) and exports an API + that enables applications to learn about network characteristics, + pass information to the CM, share congestion information with each + other, and schedule data transmissions. When the CM is used, all + data transmissions subject to the CM must be done with the explicit + consent of the CM via this API to ensure proper congestion behavior. + + Systems MAY choose to use CM, and if so they MUST follow this + specification. + + This document focuses on applications and networks where the + following conditions hold: + + + +Balakrishnan, et. al. Standards Track [Page 3] + +RFC 3124 The Congestion Manager June 2001 + + + 1. Applications are well-behaved with their own independent + per-byte or per-packet sequence number information, and use the + CM API to update internal state in the CM. + + 2. Networks are best-effort without service discrimination or + reservations. In particular, it does not address situations + where different streams between the same pair of hosts traverse + paths with differing characteristics. + + The Congestion Manager framework can be extended to support + applications that do not provide their own feedback and to + differentially-served networks. These extensions will be addressed + in later documents. + + The CM is motivated by two main goals: + + (i) Enable efficient multiplexing. Increasingly, the trend on the + Internet is for unicast data senders (e.g., Web servers) to transmit + heterogeneous types of data to receivers, ranging from unreliable + real-time streaming content to reliable Web pages and applets. As a + result, many logically different streams share the same path between + sender and receiver. For the Internet to remain stable, each of + these streams must incorporate control protocols that safely probe + for spare bandwidth and react to congestion. Unfortunately, these + concurrent streams typically compete with each other for network + resources, rather than share them effectively. Furthermore, they do + not learn from each other about the state of the network. Even if + they each independently implement congestion control (e.g., a group + of TCP connections each implementing the algorithms in [Jacobson88, + Allman99]), the ensemble of streams tends to be more aggressive in + the face of congestion than a single TCP connection implementing + standard TCP congestion control and avoidance [Balakrishnan98]. + + (ii) Enable application adaptation to congestion. Increasingly, + popular real-time streaming applications run over UDP using their own + user-level transport protocols for good application performance, but + in most cases today do not adapt or react properly to network + congestion. By implementing a stable control algorithm and exposing + an adaptation API, the CM enables easy application adaptation to + congestion. Applications adapt the data they transmit to the current + network conditions. + + The CM framework builds on recent work on TCP control block sharing + [Touch97], integrated TCP congestion control (TCP-Int) + [Balakrishnan98] and TCP sessions [Padmanabhan98]. [Touch97] + advocates the sharing of some of the state in the TCP control block + to improve transient transport performance and describes sharing + across an ensemble of TCP connections. [Balakrishnan98], + + + +Balakrishnan, et. al. Standards Track [Page 4] + +RFC 3124 The Congestion Manager June 2001 + + + [Padmanabhan98], and [Eggert00] describe several experiments that + quantify the benefits of sharing congestion state, including improved + stability in the face of congestion and better loss recovery. + Integrating loss recovery across concurrent connections significantly + improves performance because losses on one connection can be detected + by noticing that later data sent on another connection has been + received and acknowledged. The CM framework extends these ideas in + two significant ways: (i) it extends congestion management to non-TCP + streams, which are becoming increasingly common and often do not + implement proper congestion management, and (ii) it provides an API + for applications to adapt their transmissions to current network + conditions. For an extended discussion of the motivation for the CM, + its architecture, API, and algorithms, see [Balakrishnan99]; for a + description of an implementation and performance results, see + [Andersen00]. + + The resulting end-host protocol architecture at the sender is shown + in Figure 1. The CM helps achieve network stability by implementing + stable congestion avoidance and control algorithms that are "TCP- + friendly" [Mahdavi98] based on algorithms described in [Allman99]. + However, it does not attempt to enforce proper congestion behavior + for all applications (but it does not preclude a policer on the host + that performs this task). Note that while the policer at the end- + host can use CM, the network has to be protected against compromises + to the CM and the policer at the end hosts, a task that requires + router machinery [Floyd99a]. We do not address this issue further in + this document. + + + + + + + + + + + + + + + + + + + + + + + + +Balakrishnan, et. al. Standards Track [Page 5] + +RFC 3124 The Congestion Manager June 2001 + + + |--------| |--------| |--------| |--------| |--------------| + | HTTP | | FTP | | RTP 1 | | RTP 2 | | | + |--------| |--------| |--------| |--------| | | + | | | ^ | ^ | | + | | | | | | | Scheduler | + | | | | | | |---| | | + | | | |-------|--+->| | | | + | | | | | |<--| | + v v v v | | |--------------| + |--------| |--------| |-------------| | | ^ + | TCP 1 | | TCP 2 | | UDP 1 | | A | | + |--------| |--------| |-------------| | | | + ^ | ^ | | | | |--------------| + | | | | | | P |-->| | + | | | | | | | | | + |---|------+---|--------------|------->| | | Congestion | + | | | | I | | | + v v v | | | Controller | + |-----------------------------------| | | | | + | IP |-->| | | | + |-----------------------------------| | | |--------------| + |---| + + Figure 1 + + The key components of the CM framework are (i) the API, (ii) the + congestion controller, and (iii) the scheduler. The API is (in part) + motivated by the requirements of application-level framing (ALF) + [Clark90], and is described in Section 4. The CM internals (Section + 5) include a congestion controller (Section 5.1) and a scheduler to + orchestrate data transmissions between concurrent streams in a + macroflow (Section 5.2). The congestion controller adjusts the + aggregate transmission rate between sender and receiver based on its + estimate of congestion in the network. It obtains feedback about its + past transmissions from applications themselves via the API. The + scheduler apportions available bandwidth amongst the different + streams within each macroflow and notifies applications when they are + permitted to send data. This document focuses on well-behaved + applications; a future one will describe the sender-receiver protocol + and header formats that will handle applications that do not + incorporate their own feedback to the CM. + +3. CM API + + By convention, the IETF does not treat Application Programming + Interfaces as standards track. However, it is considered important + to have the CM API and CM algorithm requirements in one coherent + document. The following section on the CM API uses the terms MUST, + + + +Balakrishnan, et. al. Standards Track [Page 6] + +RFC 3124 The Congestion Manager June 2001 + + + SHOULD, etc., but the terms are meant to apply within the context of + an implementation of the CM API. The section does not apply to + congestion control implementations in general, only to those + implementations offering the CM API. + + Using the CM API, streams can determine their share of the available + bandwidth, request and have their data transmissions scheduled, + inform the CM about successful transmissions, and be informed when + the CM's estimate of path bandwidth changes. Thus, the CM frees + applications from having to maintain information about the state of + congestion and available bandwidth along any path. + + The function prototypes below follow standard C language convention. + We emphasize that these API functions are abstract calls and + conformant CM implementations may differ in specific details, as long + as equivalent functionality is provided. + + When a new stream is created by an application, it passes some + information to the CM via the cm_open(stream_info) API call. + Currently, stream_info consists of the following information: (i) the + source IP address, (ii) the source port, (iii) the destination IP + address, (iv) the destination port, and (v) the IP protocol number. + +3.1 State maintenance + + 1. Open: All applications MUST call cm_open(stream_info) before + using the CM API. This returns a handle, cm_streamid, for the + application to use for all further CM API invocations for that + stream. If the returned cm_streamid is -1, then the cm_open() + failed and that stream cannot use the CM. + + All other calls to the CM for a stream use the cm_streamid + returned from the cm_open() call. + + 2. Close: When a stream terminates, the application SHOULD invoke + cm_close(cm_streamid) to inform the CM about the termination + of the stream. + + 3. Packet size: cm_mtu(cm_streamid) returns the estimated PMTU of + the path between sender and receiver. Internally, this + information SHOULD be obtained via path MTU discovery + [Mogul90]. It MAY be statically configured in the absence of + such a mechanism. + + + + + + + + +Balakrishnan, et. al. Standards Track [Page 7] + +RFC 3124 The Congestion Manager June 2001 + + +3.2 Data transmission + + The CM accommodates two types of adaptive senders, enabling + applications to dynamically adapt their content based on prevailing + network conditions, and supporting ALF-based applications. + + 1. Callback-based transmission. The callback-based transmission API + puts the stream in firm control of deciding what to transmit at each + point in time. To achieve this, the CM does not buffer any data; + instead, it allows streams the opportunity to adapt to unexpected + network changes at the last possible instant. Thus, this enables + streams to "pull out" and repacketize data upon learning about any + rate change, which is hard to do once the data has been buffered. + The CM must implement a cm_request(i32 cm_streamid) call for streams + wishing to send data in this style. After some time, depending on + the rate, the CM MUST invoke a callback using cmapp_send(), which is + a grant for the stream to send up to PMTU bytes. The callback-style + API is the recommended choice for ALF-based streams. Note that + cm_request() does not take the number of bytes or MTU-sized units as + an argument; each call to cm_request() is an implicit request for + sending up to PMTU bytes. The CM MAY provide an alternate interface, + cm_request(int k). The cmapp_send callback for this request is + granted the right to send up to k PMTU sized segments. Section 4.3 + discusses the time duration for which the transmission grant is + valid, while Section 5.2 describes how these requests are scheduled + and callbacks made. + + 2. Synchronous-style. The above callback-based API accommodates a + class of ALF streams that are "asynchronous." Asynchronous + transmitters do not transmit based on a periodic clock, but do so + triggered by asynchronous events like file reads or captured frames. + On the other hand, there are many streams that are "synchronous" + transmitters, which transmit periodically based on their own internal + timers (e.g., an audio senders that sends at a constant sampling + rate). While CM callbacks could be configured to periodically + interrupt such transmitters, the transmit loop of such applications + is less affected if they retain their original timer-based loop. In + addition, it complicates the CM API to have a stream express the + periodicity and granularity of its callbacks. Thus, the CM MUST + export an API that allows such streams to be informed of changes in + rates using the cmapp_update(u64 newrate, u32 srtt, u32 rttdev) + callback function, where newrate is the new rate in bits per second + for this stream, srtt is the current smoothed round trip time + estimate in microseconds, and rttdev is the smoothed linear deviation + in the round-trip time estimate calculated using the same algorithm + as in TCP [Paxson00]. The newrate value reports an instantaneous + rate calculated, for example, by taking the ratio of cwnd and srtt, + and dividing by the fraction of that ratio allocated to the stream. + + + +Balakrishnan, et. al. Standards Track [Page 8] + +RFC 3124 The Congestion Manager June 2001 + + + In response, the stream MUST adapt its packet size or change its + timer interval to conform to (i.e., not exceed) the allowed rate. Of + course, it may choose not to use all of this rate. Note that the CM + is not on the data path of the actual transmission. + + To avoid unnecessary cmapp_update() callbacks that the application + will only ignore, the CM MUST provide a cm_thresh(float + rate_downthresh, float rate_upthresh, float rtt_downthresh, float + rtt_upthresh) function that a stream can use at any stage in its + execution. In response, the CM SHOULD invoke the callback only when + the rate decreases to less than (rate_downthresh * lastrate) or + increases to more than (rate_upthresh * lastrate), where lastrate is + the rate last notified to the stream, or when the round-trip time + changes correspondingly by the requisite thresholds. This + information is used as a hint by the CM, in the sense the + cmapp_update() can be called even if these conditions are not met. + + The CM MUST implement a cm_query(i32 cm_streamid, u64* rate, u32* + srtt, u32* rttdev) to allow an application to query the current CM + state. This sets the rate variable to the current rate estimate in + bits per second, the srtt variable to the current smoothed round-trip + time estimate in microseconds, and rttdev to the mean linear + deviation. If the CM does not have valid estimates for the + macroflow, it fills in negative values for the rate, srtt, and + rttdev. + + Note that a stream can use more than one of the above transmission + APIs at the same time. In particular, the knowledge of sustainable + rate is useful for asynchronous streams as well as synchronous ones; + e.g., an asynchronous Web server disseminating images using TCP may + use cmapp_send() to schedule its transmissions and cmapp_update() to + decide whether to send a low-resolution or high-resolution image. A + TCP implementation using the CM is described in Section 6.1.1, where + the benefit of the cm_request() callback API for TCP will become + apparent. + + The reader will notice that the basic CM API does not provide an + interface for buffered congestion-controlled transmissions. This is + intentional, since this transmission mode can be implemented using + the callback-based primitive. Section 6.1.2 describes how + congestion-controlled UDP sockets may be implemented using the CM + API. + +3.3 Application notification + + When a stream receives feedback from receivers, it MUST use + cm_update(i32 cm_streamid, u32 nrecd, u32 nlost, u8 lossmode, i32 + rtt) to inform the CM about events such as congestion losses, + + + +Balakrishnan, et. al. Standards Track [Page 9] + +RFC 3124 The Congestion Manager June 2001 + + + successful receptions, type of loss (timeout event, Explicit + Congestion Notification [Ramakrishnan99], etc.) and round-trip time + samples. The nrecd parameter indicates how many bytes were + successfully received by the receiver since the last cm_update call, + while the nrecd parameter identifies how many bytes were received + were lost during the same time period. The rtt value indicates the + round-trip time measured during the transmission of these bytes. The + rtt value must be set to -1 if no valid round-trip sample was + obtained by the application. The lossmode parameter provides an + indicator of how a loss was detected. A value of CM_NO_FEEDBACK + indicates that the application has received no feedback for all its + outstanding data, and is reporting this to the CM. For example, a + TCP that has experienced a timeout would use this parameter to inform + the CM of this. A value of CM_LOSS_FEEDBACK indicates that the + application has experienced some loss, which it believes to be due to + congestion, but not all outstanding data has been lost. For example, + a TCP segment loss detected using duplicate (selective) + acknowledgments or other data-driven techniques fits this category. + A value of CM_EXPLICIT_CONGESTION indicates that the receiver echoed + an explicit congestion notification message. Finally, a value of + CM_NO_CONGESTION indicates that no congestion-related loss has + occurred. The lossmode parameter MUST be reported as a bit-vector + where the bits correspond to CM_NO_FEEDBACK, CM_LOSS_FEEDBACK, + CM_EXPLICIT_CONGESTION, and CM_NO_CONGESTION. Note that over links + (paths) that experience losses for reasons other than congestion, an + application SHOULD inform the CM of losses, with the CM_NO_CONGESTION + field set. + + cm_notify(i32 cm_streamid, u32 nsent) MUST be called when data is + transmitted from the host (e.g., in the IP output routine) to inform + the CM that nsent bytes were just transmitted on a given stream. + This allows the CM to update its estimate of the number of + outstanding bytes for the macroflow and for the stream. + + A cmapp_send() grant from the CM to an application is valid only for + an expiration time, equal to the larger of the round-trip time and an + implementation-dependent threshold communicated as an argument to the + cmapp_send() callback function. The application MUST NOT send data + based on this callback after this time has expired. Furthermore, if + the application decides not to send data after receiving this + callback, it SHOULD call cm_notify(stream_info, 0) to allow the CM to + permit other streams in the macroflow to transmit data. The CM + congestion controller MUST be robust to applications forgetting to + invoke cm_notify(stream_info, 0) correctly, or applications that + crash or disappear after having made a cm_request() call. + + + + + + +Balakrishnan, et. al. Standards Track [Page 10] + +RFC 3124 The Congestion Manager June 2001 + + +3.4 Querying + + If applications wish to learn about per-stream available bandwidth + and round-trip time, they can use the CM's cm_query(i32 cm_streamid, + i64* rate, i32* srtt, i32* rttdev) call, which fills in the desired + quantities. If the CM does not have valid estimates for the + macroflow, it fills in negative values for the rate, srtt, and + rttdev. + +3.5 Sharing granularity + + One of the decisions the CM needs to make is the granularity at which + a macroflow is constructed, by deciding which streams belong to the + same macroflow and share congestion information. The API provides + two functions that allow applications to decide which of their + streams ought to belong to the same macroflow. + + cm_getmacroflow(i32 cm_streamid) returns a unique i32 macroflow + identifier. cm_setmacroflow(i32 cm_macroflowid, i32 cm_streamid) + sets the macroflow of the stream cm_streamid to cm_macroflowid. If + the cm_macroflowid that is passed to cm_setmacroflow() is -1, then a + new macroflow is constructed and this is returned to the caller. + Each call to cm_setmacroflow() overrides the previous macroflow + association for the stream, should one exist. + + The default suggested aggregation method is to aggregate by + destination IP address; i.e., all streams to the same destination + address are aggregated to a single macroflow by default. The + cm_getmacroflow() and cm_setmacroflow() calls can then be used to + change this as needed. We do note that there are some cases where + this may not be optimal, even over best-effort networks. For + example, when a group of receivers are behind a NAT device, the + sender will see them all as one address. If the hosts behind the NAT + are in fact connected over different bottleneck links, some of those + hosts could see worse performance than before. It is possible to + detect such hosts when using delay and loss estimates, although the + specific mechanisms for doing so are beyond the scope of this + document. + + The objective of this interface is to set up sharing of groups not + sharing policy of relative weights of streams in a macroflow. The + latter requires the scheduler to provide an interface to set sharing + policy. However, because we want to support many different + schedulers (each of which may need different information to set + policy), we do not specify a complete API to the scheduler (but see + + + + + + +Balakrishnan, et. al. Standards Track [Page 11] + +RFC 3124 The Congestion Manager June 2001 + + + Section 5.2). A later guideline document is expected to describe a + few simple schedulers (e.g., weighted round-robin, hierarchical + scheduling) and the API they export to provide relative + prioritization. + +4. CM internals + + This section describes the internal components of the CM. It + includes a Congestion Controller and a Scheduler, with well-defined, + abstract interfaces exported by them. + +4.1 Congestion controller + + Associated with each macroflow is a congestion control algorithm; the + collection of all these algorithms comprises the congestion + controller of the CM. The control algorithm decides when and how + much data can be transmitted by a macroflow. It uses application + notifications (Section 4.3) from concurrent streams on the same + macroflow to build up information about the congestion state of the + network path used by the macroflow. + + The congestion controller MUST implement a "TCP-friendly" [Mahdavi98] + congestion control algorithm. Several macroflows MAY (and indeed, + often will) use the same congestion control algorithm but each + macroflow maintains state about the network used by its streams. + + The congestion control module MUST implement the following abstract + interfaces. We emphasize that these are not directly visible to + applications; they are within the context of a macroflow, and are + different from the CM API functions of Section 4. + + - void query(u64 *rate, u32 *srtt, u32 *rttdev): This function + returns the estimated rate (in bits per second) and smoothed + round trip time (in microseconds) for the macroflow. + + - void notify(u32 nsent): This function MUST be used to notify the + congestion control module whenever data is sent by an + application. The nsent parameter indicates the number of bytes + just sent by the application. + + - void update(u32 nsent, u32 nrecd, u32 rtt, u32 lossmode): This + function is called whenever any of the CM streams associated with + a macroflow identifies that data has reached the receiver or has + been lost en route. The nrecd parameter indicates the number of + bytes that have just arrived at the receiver. The nsent + parameter is the sum of the number of bytes just received and the + + + + + +Balakrishnan, et. al. Standards Track [Page 12] + +RFC 3124 The Congestion Manager June 2001 + + + number of bytes identified as lost en route. The rtt parameter is + the estimated round trip time in microseconds during the + transfer. The lossmode parameter provides an indicator of how a + loss was detected (section 4.3). + + Although these interfaces are not visible to applications, the + congestion controller MUST implement these abstract interfaces to + provide for modular inter-operability with different separately- + developed schedulers. + + The congestion control module MUST also call the associated + scheduler's schedule function (section 5.2) when it believes that the + current congestion state allows an MTU-sized packet to be sent. + +4.2 Scheduler + + While it is the responsibility of the congestion control module to + determine when and how much data can be transmitted, it is the + responsibility of a macroflow's scheduler module to determine which + of the streams should get the opportunity to transmit data. + + The Scheduler MUST implement the following interfaces: + + - void schedule(u32 num_bytes): When the congestion control module + determines that data can be sent, the schedule() routine MUST be + called with no more than the number of bytes that can be sent. + In turn, the scheduler MAY call the cmapp_send() function that CM + applications must provide. + + - float query_share(i32 cm_streamid): This call returns the + described stream's share of the total bandwidth available to the + macroflow. This call combined with the query call of the + congestion controller provides the information to satisfy an + application's cm_query() request. + + - void notify(i32 cm_streamid, u32 nsent): This interface is used + to notify the scheduler module whenever data is sent by a CM + application. The nsent parameter indicates the number of bytes + just sent by the application. + + The Scheduler MAY implement many additional interfaces. As + experience with CM schedulers increases, future documents may + make additions and/or changes to some parts of the scheduler + API. + + + + + + + +Balakrishnan, et. al. Standards Track [Page 13] + +RFC 3124 The Congestion Manager June 2001 + + +5. Examples + +5.1 Example applications + + This section describes three possible uses of the CM API by + applications. We describe two asynchronous applications---an + implementation of a TCP sender and an implementation of congestion- + controlled UDP sockets, and a synchronous application---a streaming + audio server. More details of these applications and CM + implementation optimizations for efficient operation are described in + [Andersen00]. + + All applications that use the CM MUST incorporate feedback from the + receiver. For example, it must periodically (typically once or twice + per round trip time) determine how many of its packets arrived at the + receiver. When the source gets this feedback, it MUST use + cm_update() to inform the CM of this new information. This results + in the CM updating ownd and may result in the CM changing its + estimates and calling cmapp_update() of the streams of the macroflow. + + The protocols in this section are examples and suggestions for + implementation, rather than requirements for any conformant + implementation. + +5.1.1 TCP + + A TCP implementation that uses CM should use the cmapp_send() + callback API. TCP only identifies which data it should send upon the + arrival of an acknowledgement or expiration of a timer. As a result, + it requires tight control over when and if new data or + retransmissions are sent. + + When TCP either connects to or accepts a connection from another + host, it performs a cm_open() call to associate the TCP connection + with a cm_streamid. + + Once a connection is established, the CM is used to control the + transmission of outgoing data. The CM eliminates the need for + tracking and reacting to congestion in TCP, because the CM and its + transmission API ensure proper congestion behavior. Loss recovery is + still performed by TCP based on fast retransmissions and recovery as + well as timeouts. In addition, TCP is also modified to have its own + outstanding window (tcp_ownd) estimate. Whenever data segments are + sent from its cmapp_send() callback, TCP updates its tcp_ownd value. + The ownd variable is also updated after each cm_update() call. TCP + also maintains a count of the number of outstanding segments + (pkt_cnt). At any time, TCP can calculate the average packet size + (avg_pkt_size) as tcp_ownd/pkt_cnt. The avg_pkt_size is used by TCP + + + +Balakrishnan, et. al. Standards Track [Page 14] + +RFC 3124 The Congestion Manager June 2001 + + + to help estimate the amount of outstanding data. Note that this is + not needed if the SACK option is used on the connection, since this + information is explicitly available. + + The TCP output routines are modified as follows: + + 1. All congestion window (cwnd) checks are removed. + + 2. When application data is available. The TCP output routines + perform all non-congestion checks (Nagle algorithm, receiver- + advertised window check, etc). If these checks pass, the output + routine queues the data and calls cm_request() for the stream. + + 3. If incoming data or timers result in a loss being detected, the + retransmission is also placed in a queue and cm_request() is + called for the stream. + + 4. The cmapp_send() callback for TCP is set to an output routine. + If any retransmission is enqueued, the routine outputs the + retransmission. Otherwise, the routine outputs as much new data + as the TCP connection state allows. However, the cmapp_send() + never sends more than a single segment per call. This routine + arranges for the other output computations to be done, such as + header and options computations. + + The IP output routine on the host calls cm_notify() when the packets + are actually sent out. Because it does not know which cm_streamid is + responsible for the packet, cm_notify() takes the stream_info as + argument (see Section 4 for what the stream_info should contain). + Because cm_notify() reports the IP payload size, TCP keeps track of + the total header size and incorporates these updates. + + The TCP input routines are modified as follows: + + 1. RTT estimation is done as normal using either timestamps or + Karn's algorithm. Any rtt estimate that is generated is passed to + CM via the cm_update call. + + 2. All cwnd and slow start threshold (ssthresh) updates are + removed. + + 3. Upon the arrival of an ack for new data, TCP computes the value + of in_flight (the amount of data in flight) as snd_max-ack-1 + (i.e., MAX Sequence Sent - Current Ack - 1). TCP then calls + cm_update(streamid, tcp_ownd - in_flight, 0, CM_NO_CONGESTION, + rtt). + + + + + +Balakrishnan, et. al. Standards Track [Page 15] + +RFC 3124 The Congestion Manager June 2001 + + + 4. Upon the arrival of a duplicate acknowledgement, TCP must check + its dupack count (dup_acks) to determine its action. If dup_acks + < 3, the TCP does nothing. If dup_acks == 3, TCP assumes that a + packet was lost and that at least 3 packets arrived to generate + these duplicate acks. Therefore, it calls cm_update(streamid, 4 * + avg_pkt_size, 3 * avg_pkt_size, CM_LOSS_FEEDBACK, rtt). The + average packet size is used since the acknowledgments do not + indicate exactly how much data has reached the other end. Most + TCP implementations interpret a duplicate ACK as an indication + that a full MSS has reached its destination. Once a new ACK is + received, these TCP sender implementations may resynchronize with + TCP receiver. The CM API does not provide a mechanism for TCP to + pass information from this resynchronization. Therefore, TCP can + only infer the arrival of an avg_pkt_size amount of data from each + duplicate ack. TCP also enqueues a retransmission of the lost + segment and calls cm_request(). If dup_acks > 3, TCP assumes that + a packet has reached the other end and caused this ack to be sent. + As a result, it calls cm_update(streamid, avg_pkt_size, + avg_pkt_size, CM_NO_CONGESTION, rtt). + + 5. Upon the arrival of a partial acknowledgment (one that does not + exceed the highest segment transmitted at the time the loss + occurred, as defined in [Floyd99b]), TCP assumes that a packet was + lost and that the retransmitted packet has reached the recipient. + Therefore, it calls cm_update(streamid, 2 * avg_pkt_size, + avg_pkt_size, CM_NO_CONGESTION, rtt). CM_NO_CONGESTION is used + since the loss period has already been reported. TCP also + enqueues a retransmission of the lost segment and calls + cm_request(). + + When the TCP retransmission timer expires, the sender identifies that + a segment has been lost and calls cm_update(streamid, avg_pkt_size, + 0, CM_NO_FEEDBACK, 0) to signify that no feedback has been received + from the receiver and that one segment is sure to have "left the + pipe." TCP also enqueues a retransmission of the lost segment and + calls cm_request(). + +5.1.2 Congestion-controlled UDP + + Congestion-controlled UDP is a useful CM application, which we + describe in the context of Berkeley sockets [Stevens94]. They + provide the same functionality as standard Berkeley UDP sockets, but + instead of immediately sending the data from the kernel packet queue + to lower layers for transmission, the buffered socket implementation + makes calls to the API exported by the CM inside the kernel and gets + callbacks from the CM. When a CM UDP socket is created, it is bound + to a particular stream. Later, when data is added to the packet + queue, cm_request() is called on the stream associated with the + + + +Balakrishnan, et. al. Standards Track [Page 16] + +RFC 3124 The Congestion Manager June 2001 + + + socket. When the CM schedules this stream for transmission, it calls + udp_ccappsend() in the UDP module. This function transmits one MTU + from the packet queue, and schedules the transmission of any + remaining packets. The in-kernel implementation of the CM UDP API + should not require any additional data copies and should support all + standard UDP options. Modifying existing applications to use + congestion-controlled UDP requires the implementation of a new socket + option on the socket. To work correctly, the sender must obtain + feedback about congestion. This can be done in at least two ways: + (i) the UDP receiver application can provide feedback to the sender + application, which will inform the CM of network conditions using + cm_update(); (ii) the UDP receiver implementation can provide + feedback to the sending UDP. Note that this latter alternative + requires changes to the receiver's network stack and the sender UDP + cannot assume that all receivers support this option without explicit + negotiation. + +5.1.3 Audio server + + A typical audio application often has access to the sample in a + multitude of data rates and qualities. The objective of the + application is then to deliver the highest possible quality of audio + (typically the highest data rate) its clients. The selection of + which version of audio to transmit should be based on the current + congestion state of the network. In addition, the source will want + audio delivered to its users at a consistent sampling rate. As a + result, it must send data a regular rate, minimizing delaying + transmissions and reducing buffering before playback. To meet these + requirements, this application can use the synchronous sender API + (Section 4.2). + + When the source first starts, it uses the cm_query() call to get an + initial estimate of network bandwidth and delay. If some other + streams on that macroflow have already been active, then it gets an + initial estimate that is valid; otherwise, it gets negative values, + which it ignores. It then chooses an encoding that does not exceed + these estimates (or, in the case of an invalid estimate, uses + application-specific initial values) and begins transmitting data. + The application also implements the cmapp_update() callback. When + the CM determines that network characteristics have changed, it calls + the application's cmapp_update() function and passes it a new rate + and round-trip time estimate. The application must change its choice + of audio encoding to ensure that it does not exceed these new + estimates. + + + + + + + +Balakrishnan, et. al. Standards Track [Page 17] + +RFC 3124 The Congestion Manager June 2001 + + +5.2 Example congestion control module + + To illustrate the responsibilities of a congestion control module, + the following describes some of the actions of a simple TCP-like + congestion control module that implements Additive Increase + Multiplicative Decrease congestion control (AIMD_CC): + + - query(): AIMD_CC returns the current congestion window (cwnd) + divided by the smoothed rtt (srtt) as its bandwidth estimate. It + returns the smoothed rtt estimate as srtt. + + - notify(): AIMD_CC adds the number of bytes sent to its + outstanding data window (ownd). + + - update(): AIMD_CC subtracts nsent from ownd. If the value of rtt + is non-zero, AIMD_CC updates srtt using the TCP srtt calculation. + If the update indicates that data has been lost, AIMD_CC sets + cwnd to 1 MTU if the loss_mode is CM_NO_FEEDBACK and to cwnd/2 + (with a minimum of 1 MTU) if the loss_mode is CM_LOSS_FEEDBACK or + CM_EXPLICIT_CONGESTION. AIMD_CC also sets its internal ssthresh + variable to cwnd/2. If no loss had occurred, AIMD_CC mimics TCP + slow start and linear growth modes. It increments cwnd by nsent + when cwnd < ssthresh (bounded by a maximum of ssthresh-cwnd) and + by nsent * MTU/cwnd when cwnd > ssthresh. + + - When cwnd or ownd are updated and indicate that at least one MTU + may be transmitted, AIMD_CC calls the CM to schedule a + transmission. + +5.3 Example Scheduler Module + + To clarify the responsibilities of a scheduler module, the following + describes some of the actions of a simple round robin scheduler + module (RR_sched): + + - schedule(): RR_sched schedules as many streams as possible in round + robin fashion. + + - query_share(): RR_sched returns 1/(number of streams in macroflow). + + - notify(): RR_sched does nothing. Round robin scheduling is not + affected by the amount of data sent. + +6. Security Considerations + + The CM provides many of the same services that the congestion control + in TCP provides. As such, it is vulnerable to many of the same + security problems. For example, incorrect reports of losses and + + + +Balakrishnan, et. al. Standards Track [Page 18] + +RFC 3124 The Congestion Manager June 2001 + + + transmissions will give the CM an inaccurate picture of the network's + congestion state. By giving CM a high estimate of congestion, an + attacker can degrade the performance observed by applications. For + example, a stream on a host can arbitrarily slow down any other + stream on the same macroflow, a form of denial of service. + + The more dangerous form of attack occurs when an application gives + the CM a low estimate of congestion. This would cause CM to be + overly aggressive and allow data to be sent much more quickly than + sound congestion control policies would allow. + + [Touch97] describes a number of the security problems that arise with + congestion information sharing. An additional vulnerability (not + covered by [Touch97])) occurs because applications have access + through the CM API to control shared state that will affect other + applications on the same computer. For instance, a poorly designed, + possibly a compromised, or intentionally malicious UDP application + could misuse cm_update() to cause starvation and/or too-aggressive + behavior of others in the macroflow. + +7. References + + [Allman99] Allman, M. and Paxson, V., "TCP Congestion + Control", RFC 2581, April 1999. + + [Andersen00] Balakrishnan, H., System Support for Bandwidth + Management and Content Adaptation in Internet + Applications, Proc. 4th Symp. on Operating Systems + Design and Implementation, San Diego, CA, October + 2000. Available from + http://nms.lcs.mit.edu/papers/cm-osdi2000.html + + [Balakrishnan98] Balakrishnan, H., Padmanabhan, V., Seshan, S., + Stemm, M., and Katz, R., "TCP Behavior of a Busy + Web Server: Analysis and Improvements," Proc. IEEE + INFOCOM, San Francisco, CA, March 1998. + + [Balakrishnan99] Balakrishnan, H., Rahul, H., and Seshan, S., "An + Integrated Congestion Management Architecture for + Internet Hosts," Proc. ACM SIGCOMM, Cambridge, MA, + September 1999. + + [Bradner96] Bradner, S., "The Internet Standards Process --- + Revision 3", BCP 9, RFC 2026, October 1996. + + [Bradner97] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + + + +Balakrishnan, et. al. Standards Track [Page 19] + +RFC 3124 The Congestion Manager June 2001 + + + [Clark90] Clark, D. and Tennenhouse, D., "Architectural + Consideration for a New Generation of Protocols", + Proc. ACM SIGCOMM, Philadelphia, PA, September + 1990. + + [Eggert00] Eggert, L., Heidemann, J., and Touch, J., "Effects + of Ensemble TCP," ACM Computer Comm. Review, + January 2000. + + [Floyd99a] Floyd, S. and Fall, K.," Promoting the Use of End- + to-End Congestion Control in the Internet," + IEEE/ACM Trans. on Networking, 7(4), August 1999, + pp. 458-472. + + [Floyd99b] Floyd, S. and T. Henderson,"The New Reno + Modification to TCP's Fast Recovery Algorithm," RFC + 2582, April 1999. + + [Jacobson88] Jacobson, V., "Congestion Avoidance and Control," + Proc. ACM SIGCOMM, Stanford, CA, August 1988. + + [Mahdavi98] Mahdavi, J. and Floyd, S., "The TCP Friendly + Website," + http://www.psc.edu/networking/tcp_friendly.html + + [Mogul90] Mogul, J. and S. Deering, "Path MTU Discovery," RFC + 1191, November 1990. + + [Padmanabhan98] Padmanabhan, V., "Addressing the Challenges of Web + Data Transport," PhD thesis, Univ. of California, + Berkeley, December 1998. + + [Paxson00] Paxson, V. and M. Allman, "Computing TCP's + Retransmission Timer", RFC 2988, November 2000. + + [Postel81] Postel, J., Editor, "Transmission Control + Protocol", STD 7, RFC 793, September 1981. + + [Ramakrishnan99] Ramakrishnan, K. and Floyd, S., "A Proposal to Add + Explicit Congestion Notification (ECN) to IP," RFC + 2481, January 1999. + + + [Stevens94] Stevens, W., TCP/IP Illustrated, Volume 1. + Addison-Wesley, Reading, MA, 1994. + + [Touch97] Touch, J., "TCP Control Block Interdependence", RFC + 2140, April 1997. + + + +Balakrishnan, et. al. Standards Track [Page 20] + +RFC 3124 The Congestion Manager June 2001 + + +8. Acknowledgments + + We thank David Andersen, Deepak Bansal, and Dorothy Curtis for their + work on the CM design and implementation. We thank Vern Paxson for + his detailed comments, feedback, and patience, and Sally Floyd, Mark + Handley, and Steven McCanne for useful feedback on the CM + architecture. Allison Mankin and Joe Touch provided several useful + comments on previous drafts of this document. + +9. Authors' Addresses + + Hari Balakrishnan + Laboratory for Computer Science + 200 Technology Square + Massachusetts Institute of Technology + Cambridge, MA 02139 + + EMail: [email protected] + Web: http://nms.lcs.mit.edu/~hari/ + + + Srinivasan Seshan + School of Computer Science + Carnegie Mellon University + 5000 Forbes Ave. + Pittsburgh, PA 15213 + + EMail: [email protected] + Web: http://www.cs.cmu.edu/~srini/ + + + + + + + + + + + + + + + + + + + + + + +Balakrishnan, et. al. Standards Track [Page 21] + +RFC 3124 The Congestion Manager June 2001 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2001). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Balakrishnan, et. al. Standards Track [Page 22] + diff --git a/lib/diameter/doc/standard/rfc3539.txt b/lib/diameter/doc/standard/rfc3539.txt new file mode 100644 index 0000000000..0b18625cc5 --- /dev/null +++ b/lib/diameter/doc/standard/rfc3539.txt @@ -0,0 +1,2299 @@ + + + + + + +Network Working Group B. Aboba +Request for Comments: 3539 Microsoft +Category: Standards Track J. Wood + Sun Microsystems, Inc. + June 2003 + + + Authentication, Authorization and Accounting (AAA) Transport Profile + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + This document discusses transport issues that arise within protocols + for Authentication, Authorization and Accounting (AAA). It also + provides recommendations on the use of transport by AAA protocols. + This includes usage of standards-track RFCs as well as experimental + proposals. + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 2 + 1.1. Requirements Language. . . . . . . . . . . . . . . . . . 2 + 1.2. Terminology. . . . . . . . . . . . . . . . . . . . . . . 2 + 2. Issues in Transport Usage. . . . . . . . . . . . . . . . . . . 5 + 2.1. Application-driven Versus Network-driven . . . . . . . . 5 + 2.2. Slow Failover. . . . . . . . . . . . . . . . . . . . . . 6 + 2.3. Use of Nagle Algorithm . . . . . . . . . . . . . . . . . 7 + 2.4. Multiple Connections . . . . . . . . . . . . . . . . . . 7 + 2.5. Duplicate Detection. . . . . . . . . . . . . . . . . . . 8 + 2.6. Invalidation of Transport Parameter Estimates. . . . . . 8 + 2.7. Inability to use Fast Re-Transmit. . . . . . . . . . . . 9 + 2.8. Congestion Avoidance . . . . . . . . . . . . . . . . . . 9 + 2.9. Delayed Acknowledgments. . . . . . . . . . . . . . . . . 11 + 2.10. Premature Failover . . . . . . . . . . . . . . . . . . . 11 + 2.11. Head of Line Blocking. . . . . . . . . . . . . . . . . . 11 + 2.12. Connection Load Balancing. . . . . . . . . . . . . . . . 12 + + + + +Aboba & Wood Standards Track [Page 1] + +RFC 3539 AAA Transport Profile June 2003 + + + 3. AAA Transport Profile. . . . . . . . . . . . . . . . . . . . . 12 + 3.1. Transport Mappings . . . . . . . . . . . . . . . . . . . 12 + 3.2. Use of Nagle Algorithm . . . . . . . . . . . . . . . . . 12 + 3.3. Multiple Connections . . . . . . . . . . . . . . . . . . 13 + 3.4. Application Layer Watchdog . . . . . . . . . . . . . . . 13 + 3.5. Duplicate Detection. . . . . . . . . . . . . . . . . . . 19 + 3.6. Invalidation of Transport Parameter Estimates. . . . . . 20 + 3.7. Inability to use Fast Re-Transmit. . . . . . . . . . . . 21 + 3.8. Head of Line Blocking. . . . . . . . . . . . . . . . . . 22 + 3.9. Congestion Avoidance . . . . . . . . . . . . . . . . . . 23 + 3.10. Premature Failover . . . . . . . . . . . . . . . . . . . 24 + 4. Security Considerations. . . . . . . . . . . . . . . . . . . . 24 + 5. IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 25 + 6. References . . . . . . . . . . . . . . . . . . . . . . . . . . 25 + 6.1. Normative References . . . . . . . . . . . . . . . . . . 25 + 6.2. Informative References . . . . . . . . . . . . . . . . . 26 + Appendix A - Detailed Watchdog Algorithm Description . . . . . . . 28 + Appendix B - AAA Agents. . . . . . . . . . . . . . . . . . . . . . 33 + B.1. Relays and Proxies . . . . . . . . . . . . . . . . . . . 33 + B.2. Re-directs . . . . . . . . . . . . . . . . . . . . . . . 35 + B.3. Store and Forward Proxies. . . . . . . . . . . . . . . . 36 + B.4. Transport Layer Proxies. . . . . . . . . . . . . . . . . 38 + Intellectual Property Statement. . . . . . . . . . . . . . . . . . 39 + Acknowledgments. . . . . . . . . . . . . . . . . . . . . . . . . . 39 + Author Addresses . . . . . . . . . . . . . . . . . . . . . . . . . 40 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 41 + +1. Introduction + + This document discusses transport issues that arise within protocols + for Authentication, Authorization and Accounting (AAA). It also + provides recommendations on the use of transport by AAA protocols. + This includes usage of standards-track RFCs as well as experimental + proposals. + +1.1. Requirements Language + + In this document, the key words "MAY", "MUST, "MUST NOT", "optional", + "recommended", "SHOULD", and "SHOULD NOT", are to be interpreted as + described in [RFC2119]. + +1.2. Terminology + + Accounting + The act of collecting information on resource usage for the + purpose of trend analysis, auditing, billing, or cost + allocation. + + + + +Aboba & Wood Standards Track [Page 2] + +RFC 3539 AAA Transport Profile June 2003 + + + Administrative Domain + An internet, or a collection of networks, computers, and + databases under a common administration. + + Agent A AAA agent is an intermediary that communicates with AAA + clients and servers. Several types of AAA agents exist, + including Relays, Re-directs, and Proxies. + + Application-driven transport + Transport behavior is said to be "application-driven" when + the rate at which messages are sent is limited by the rate + at which the application generates data, rather than by the + size of the congestion window. In the most extreme case, + the time between transactions exceeds the round-trip time + between sender and receiver, implying that the application + operates with an effective congestion window of one. AAA + transport is typically application driven. + + Attribute Value Pair (AVP) + The variable length concatenation of a unique Attribute + (represented by an integer) and a Value containing the + actual value identified by the attribute. + + Authentication + The act of verifying a claimed identity, in the form of a + pre-existing label from a mutually known name space, as the + originator of a message (message authentication) or as the + end-point of a channel (entity authentication). + + Authorization + The act of determining if a particular right, such as + access to some resource, can be granted to the presenter of + a particular credential. + + Billing The act of preparing an invoice. + + Network Access Identifier + The Network Access Identifier (NAI) is the userID submitted + by the host during network access authentication. In + roaming, the purpose of the NAI is to identify the user as + well as to assist in the routing of the authentication + request. The NAI may not necessarily be the same as the + user's e-mail address or the user-ID submitted in an + application layer authentication. + + + + + + + +Aboba & Wood Standards Track [Page 3] + +RFC 3539 AAA Transport Profile June 2003 + + + Network Access Server (NAS) + A Network Access Server (NAS) is a device that hosts + connect to in order to get access to the network. + + Proxy In addition to forwarding requests and responses, proxies + enforce policies relating to resource usage and + provisioning. This is typically accomplished by tracking + the state of NAS devices. While proxies typically do not + respond to client Requests prior to receiving a Response + from the server, they may originate Reject messages in + cases where policies are violated. As a result, proxies + need to understand the semantics of the messages passing + through them, and may not support all extensions. + + Local Proxy + A Local Proxy is a proxy that exists within the same + administrative domain as the network device (e.g. NAS) that + issued the AAA request. Typically a local proxy is used to + multiplex AAA messages to and from a large number of + network devices, and may implement policy. + + Store and forward proxy + Store and forward proxies distinguish themselves from other + proxy species by sending a reply to the NAS prior to + proxying the request to the server. As a result, store and + forward proxies need to implement AAA client and server + functionality for the messages that they handle. Store and + Forward proxies also typically keep state on conversations + in progress in order to assure delivery of proxied Requests + and Responses. While store and forward proxies are most + frequently deployed for accounting, they also can be used + to implement authentication/authorization policy. + + Network-driven transport + Transport behavior is said to be "network driven" when the + rate at which messages are sent is limited by the + congestion window, not by the rate at which the application + can generate data. File transfer is an example of an + application where transport is network driven. + + Re-direct Rather than forwarding Requests and Responses between + clients and servers, Re-directs refer clients to servers + and allow them to communicate directly. Since Re-directs + do not sit in the forwarding path, they do not alter any + AVPs transitting between client and server. Re-directs do + not originate messages and are capable of handling any + message type. A Re-direct may be configured only to re- + direct messages of certain types, while acting as a Relay + + + +Aboba & Wood Standards Track [Page 4] + +RFC 3539 AAA Transport Profile June 2003 + + + or Proxy for other types. As with Relays, re-directs do + not keep state with respect to conversations or NAS + resources. + + Relay Relays forward requests and responses based on routing- + related AVPs and domain forwarding table entries. Since + relays do not enforce policies, they do not examine or + alter non-routing AVPs. As a result, relays never + originate messages, do not need to understand the semantics + of messages or non-routing AVPs, and are capable of + handling any extension or message type. Since relays make + decisions based on information in routing AVPs and domain + forwarding tables they do not keep state on NAS resource + usage or conversations in progress. + +2. Issues in AAA Transport Usage + + Issues that arise in AAA transport usage include: + + Application-driven versus network-driven + Slow failover + Use of Nagle Algorithm + Multiple connections + Duplicate detection + Invalidation of transport parameter estimates + Inability to use fast re-transmit + Congestion avoidance + Delayed acknowledgments + Premature Failover + Head of line blocking + Connection load balancing + + We discuss each of these issues in turn. + +2.1. Application-driven versus Network-driven + + AAA transport behavior is typically application rather than network + driven. This means that the rate at which messages are sent is + typically limited by how quickly they are generated by the + application, rather than by the size of the congestion window. + + For example, let us assume a 48-port NAS with an average session time + of 20 minutes. This device will, on average, send only 144 + authentication/authorization requests/hour, and an equivalent number + of accounting requests. This represents an average inter-packet + spacing of 25 seconds, which is much larger than the Round Trip Time + (RTT) in most networks. + + + + +Aboba & Wood Standards Track [Page 5] + +RFC 3539 AAA Transport Profile June 2003 + + + Even on much larger NAS devices, the inter-packet spacing is often + larger than the RTT. For example, consider a 2048-port NAS with an + average session time of 10 minutes. It will on average send 3.4 + authentication/authorization requests/second, and an equivalent + number of accounting requests. This translates to an average inter- + packet spacing of 293 ms. + + However, even where transport behavior is largely application-driven, + periods of network-driven behavior can occur. For example, after a + NAS reboot, previously stored accounting records may be sent to the + accounting server in rapid succession. Similarly, after recovery + from a power failure, users may respond with a large number of + simultaneous logins. In both cases, AAA messages may be generated + more quickly than the network will allow them to be sent, and a queue + will build up. + + Network congestion can occur when transport behavior is network- + driven or application-driven. For example, while a single NAS may + not send substantial AAA traffic, many NASes may communicate with a + single AAA proxy or server. As a result, routers close to a heavily + loaded proxy or server may experience congestion, even though traffic + from each individual NAS is light. Such "convergent congestion" can + result in dropped packets in routers near the AAA server, or even + within the AAA server itself. + + Let us consider what happens when 10,000 48-ports NASes, each with an + average session time of 20 minutes, are configured with the same AAA + agent or server. The unfortunate proxy or server would receive 400 + authentication/authorization requests/second and an equivalent number + of accounting requests. For 1000 octet requests, this would generate + 6.4 Mbps of incoming traffic at the AAA agent or server. + + While this transaction load is within the capabilities of the fastest + AAA agents and servers, implementations exist that cannot handle such + a high load. Thus high queuing delays and/or dropped packets may be + experienced at the agent or server, even if routers on the path are + not congested. Thus, a well designed AAA protocol needs to be able + to handle congestion occurring at the AAA server, as well as + congestion experienced within the network. + +2.2. Slow Failover + + Where TCP [RFC793] is used as the transport, AAA implementations will + experience very slow fail over times if they wait until a TCP + connection times out before resending on another connection. This is + not an issue for SCTP [RFC2960], which supports endpoint and path + failure detection. As described in section 8 of [RFC2960], when the + number of retransmissions exceeds the maximum + + + +Aboba & Wood Standards Track [Page 6] + +RFC 3539 AAA Transport Profile June 2003 + + + ("Association.Max.Retrans"), the peer endpoint is considered + unreachable, the association enters the CLOSED state, and the failure + is reported to the application. This enables more rapid failure + detection. + +2.3. Use of Nagle Algorithm + + AAA protocol messages are often smaller than the maximum segment size + (MSS). While exceptions occur when certificate-based authentication + messages are issued or where a low path MTU is found, typically AAA + protocol messages are less than 1000 octets. Therefore, when using + TCP [RFC793], the total packet count and associated network overhead + can be reduced by combining multiple AAA messages within a single + packet. + + Where AAA runs over TCP and transport behavior is network-driven, + such as after a reboot when many users login simultaneously, or many + stored accounting records need to be sent, the Nagle algorithm will + result in "transport layer batching" of AAA messages. While this + does not reduce the work required by the application in parsing + packets and responding to the messages, it does reduce the number of + packets processed by routers along the path. The Nagle algorithm is + not used with SCTP. + + Where AAA transport is application-driven, the NAS will typically + receive a reply from the home server prior to having another request + to send. This implies, for example, that accounting requests will + typically be sent individually rather than being batched by the + transport layer. As a result, within the application-driven regime, + the Nagle algorithm [RFC896] is ineffective. + +2.4. Multiple Connections + + Since the RADIUS [RFC2865] Identifier field is a single octet, a + maximum of 256 requests can be in progress between two endpoints + described by a 5-tuple: (Client IP address, Client port, UDP, Server + IP address, Server port). In order to get around this limitation, + RADIUS clients have utilized more than one sending port, sometimes + even going to the extreme of using a different UDP source port for + each NAS port. + + Were this behavior to be extended to AAA protocols operating over + reliable transport, the result would be multiplication of the + effective slow-start ramp-up by the number of connections. For + example, if a AAA client had ten connections open to a AAA agent, and + used a per-connection initial window [RFC3390] of 2, then the + + + + + +Aboba & Wood Standards Track [Page 7] + +RFC 3539 AAA Transport Profile June 2003 + + + effective initial window would be 20. This is inappropriate, since + it would permit the AAA client to send a large burst of packets into + the network. + +2.5. Duplicate Detection + + Where a AAA client maintains connections to multiple AAA agents or + servers, and where failover/failback or connection load balancing is + supported, it is possible for multiple agents or servers to receive + duplicate copies of the same transaction. A transaction may be sent + on another connection before expiration of the "time wait" interval + necessary to guarantee that all packets sent on the original + connection have left the network. Therefore it is conceivable that + transactions sent on the alternate connection will arrive before + those sent on the failed connection. As a result, AAA agents and + servers MUST be prepared to handle duplicates, and MUST assume that + duplicates can arrive on any connection. + + For example, in billing, it is necessary to be able to weed out + duplicate accounting records, based on the accounting session-id, + event-timestamp and NAS identification information. Where + authentication requests are always idempotent, the resultant + duplicate responses from multiple servers will presumably be + identical, so that little harm will result. + + However, there are situations where the response to an authentication + request will depend on a previously established state, such as when + simultaneous usage restrictions are being enforced. In such cases, + authentication requests will not be idempotent. For example, while + an initial request might elicit an Accept response, a duplicate + request might elicit a Reject response from another server, if the + user were already presumed to be logged in, and only one simultaneous + session were permitted. In these situations, the AAA client might + receive both Accept and Reject responses to the same duplicate + request, and the outcome will depend on which response arrives first. + +2.6. Invalidation of Transport Parameter Estimates + + Congestion control principles [Congest],[RFC2914] require the ability + of a transport protocol to respond effectively to congestion, as + sensed via increasing delays, packet loss, or explicit congestion + notification. + + With network-driven applications, it is possible to respond to + congestion on a timescale comparable to the round-trip time (RTT). + + However, with AAA protocols, the time between sends may be longer + than the RTT, so that the network conditions can not be assumed to + + + +Aboba & Wood Standards Track [Page 8] + +RFC 3539 AAA Transport Profile June 2003 + + + persist between sends. For example, the congestion window may grow + during a period in which congestion is being experienced because few + packets are sent, limiting the opportunity for feedback. Similarly, + after congestion is detected, the congestion window may remain small, + even though the network conditions that existed at the time of + congestion no longer apply by the time when the next packets are + sent. In addition, due to the low sampling interval, estimates of + RTT and RTO made via the procedure described in [RFC2988] may become + invalid. + +2.7. Inability to Use Fast Re-transmit + + When congestion window validation [RFC2861] is implemented, the + result is that AAA protocols operate much of the time in slow-start + with an initial congestion window set to 1 or 2, depending on the + implementation [RFC3390]. This implies that AAA protocols gain + little benefit from the windowing features of reliable transport. + + Since the congestion window is so small, it is generally not possible + to receive enough duplicate ACKs (3) to trigger fast re-transmit. In + addition, since AAA traffic is two-way, ACKs including data will not + count as part of the duplicate ACKs necessary to trigger fast re- + transmit. As a result, dropped packets will require a retransmission + timeout (RTO). + +2.8. Congestion Avoidance + + The law of conservation of packets [Congest] suggests that a client + should not send another packet into the network until it can be + reasonably sure that a packet has exited the network on the same + path. In the case of a AAA client, the law suggests that it should + not retransmit to the same server or choose another server until it + can be reasonably sure that a packet has exited the network on the + same path. If the client advances the window as responses arrive, + then the client will "self clock", adjusting its transmission rate to + the available bandwidth. + + While a AAA client using a reliable transport such as TCP [RFC793] or + SCTP [RFC2960] will self-clock when communicating directly with a + AAA-server, end-to-end self-clocking is not assured when AAA agents + are present. + + As described in the Appendix, AAA agents include Relays, Proxies, + Re-directs, Store and Forward proxies, and Transport proxies. Of + these agents, only Transport proxies and Re-directs provide a direct + transport connection between the AAA client and server, allowing + end-to-end self-clocking to occur. + + + + +Aboba & Wood Standards Track [Page 9] + +RFC 3539 AAA Transport Profile June 2003 + + + With Relays, Proxies or Store and Forward proxies, two separate and + de-coupled transport connections are used. One connection operates + between the AAA client and agent, and another between the agent and + server. Since the two transport connections are de-coupled, + transport layer ACKs do not flow end-to-end, and self-clocking does + not occur. + + For example, consider what happens when the bottleneck exists between + a AAA Relay and a AAA server. Self-clocking will occur between the + AAA client and AAA Relay, causing the AAA client to adjust its + sending rate to the rate at which transport ACKs flow back from the + AAA Relay. However, since this rate is higher than the bottleneck + bandwidth, the overall system will not self-clock. + + Since there is no direct transport connection between the AAA client + and AAA server, the AAA client does not have the ability to estimate + end-to-end transport parameters and adjust its sending rate to the + bottleneck bandwidth between the Relay and server. As a result, the + incoming rate at the AAA Relay can be higher than the rate at which + packets can be sent to the AAA server. + + In this case, the end-to-end performance will be determined by + details of the agent implementation. In general, the end-to-end + transport performance in the presence of Relays, Proxies or Store and + Forward proxies will always be worse in terms of delay and packet + loss than if the AAA client and server were communicating directly. + + For example, if the agent operates with a large receive buffer, it is + possible that a large queue will develop on the receiving side, since + the AAA client is able to send packets to the AAA agent more rapidly + than the agent can send them to the AAA server. Eventually, the + buffer will overflow, causing wholesale packet loss as well as high + delay. + + Methods to induce fine-grained coupling between the two transport + connections are difficult to implement. One possible solution is for + the AAA agent to operate with a receive buffer that is no larger than + its send buffer. If this is done, "back pressure" (closing of the + receive window) will cause the agent to reduce the AAA client sending + rate when the agent send buffer fills. However, unless multiple + connections exist between the AAA client and AAA agent, closing of + the receive window will affect all traffic sent by the AAA client, + even traffic destined to AAA servers where no bottleneck exists. + Since multiple connections between a AAA client and agent result in + multiplication of the effective slow-start ramp rate, this is not + recommended. As a result, use of "back pressure" cannot enable + individual AAA client-server conversations to self-clock, and this + technique appears impractical for use in AAA. + + + +Aboba & Wood Standards Track [Page 10] + +RFC 3539 AAA Transport Profile June 2003 + + +2.9. Delayed Acknowledgments + + As described in Appendix B, ACKs may comprise as much as half of the + traffic generated in a AAA exchange. This occurs because AAA + conversations are typically application-driven, and therefore there + is frequently not enough traffic to enable ACK piggybacking. As a + result, AAA protocols running over TCP or SCTP transport may + experience a doubling of traffic as compared with implementations + utilizing UDP transport. + + It is typically not possible to address this issue via the sockets + API. ACK parameters (such as the value of the delayed ACK timer) are + typically fixed by TCP and SCTP implementations and are therefore not + tunable by the application. + +2.10. Premature Failover + + RADIUS failover implementations are typically based on the concept of + primary and secondary servers, in which all traffic flows to the + primary server unless it is unavailable. However, the failover + algorithm was not specified in [RFC2865] or [RFC2866]. As a result, + RADIUS failover implementations vary in quality, with some failing + over prematurely, violating the law of "conservation of packets". + + Where a Relay, Proxy or Store and Forward proxy is present, the AAA + client has no direct connection to a AAA server, and is unable to + estimate the end-to-end transport parameters. As a result, a AAA + client awaiting an application-layer response from the server has no + transport-based mechanism for determining an appropriate failover + timer. + + For example, if the path between the AAA agent and server includes a + high delay link, or if the AAA server is very heavily loaded, it is + possible that the NAS will failover to another agent while packets + are still in flight. This violates the principle of "conservation of + packets", since the AAA client will inject additional packets into + the network before having evidence that a previously sent packet has + left the network. Such behavior can result in a worse situation on + an already congested link, resulting in congestive collapse + [Congest]. + +2.11. Head of Line Blocking + + Head of line blocking occurs during periods of packet loss where the + time between sends is shorter than the re-transmission timeout value + (RTO). In such situations, packets back up in the send queue until + + + + + +Aboba & Wood Standards Track [Page 11] + +RFC 3539 AAA Transport Profile June 2003 + + + the lost packet can be successfully re-transmitted. This can be an + issue for SCTP when using ordered delivery over a single stream, and + for TCP. + + Head of line blocking is typically an issue only on larger NASes. + For example, a 48-port NAS with an average inter-packet spacing of 25 + seconds is unlikely to have an RTO greater than this, unless severe + packet loss has been experienced. However, a 2048-port NAS with an + average inter-packet spacing of 293 ms may experience head-of-line + blocking since the inter-packet spacing is less than the minimum RTO + value of 1 second [RFC2988]. + +2.12. Connection Load Balancing + + In order to lessen queuing delays and address head of line blocking, + a AAA implementation may wish to load balance between connections to + multiple destinations. While it is possible to employ dynamic load + balancing techniques, this level of sophistication may not be + required. In many situations, adequate reliability and load + balancing can be achieved via static load balancing, where traffic is + distributed between destinations based on static "weights". + +3. AAA Transport Profile + + In order to address AAA transport issues, it is recommended that AAA + protocols make use of standards track as well as experimental + techniques. More details are provided in the sections that follow. + +3.1. Transport Mappings + + AAA Servers MUST support TCP and SCTP. AAA clients SHOULD support + SCTP, but MUST support TCP if SCTP is not available. As support for + SCTP improves, it is possible that SCTP support will be required on + clients at some point in the future. AAA agents inherit all the + obligations of Servers with respect to transport support. + +3.2. Use of Nagle Algorithm + + While AAA protocols typically operate in the application-driven + regime, there are circumstances in which they are network driven. + For example, where an NAS reboots, or where connectivity is restored + between an NAS and a AAA agent, it is possible that multiple packets + will be available for sending. + + As a result, there are circumstances where the transport-layer + batching provided by the Nagle Algorithm (12) is useful, and as a + result, AAA implementations running over TCP MUST enable the Nagle + algorithm, [RFC896]. The Nagle algorithm is not used with SCTP. + + + +Aboba & Wood Standards Track [Page 12] + +RFC 3539 AAA Transport Profile June 2003 + + +3.3. Multiple Connections + + AAA protocols SHOULD use only a single persistent connection between + a AAA client and a AAA agent or server. They SHOULD provide for + pipelining of requests, so that more than one request can be in + progress at a time. In order to minimize use of inactive connections + in roaming situations, a AAA client or agent MAY bring down a + connection to a AAA agent or server if the connection has been + unutilized (discounting the watchdog) for a certain period of time, + which MUST NOT be less than BRINGDOWN_INTERVAL (5 minutes). + + While a AAA client/agent SHOULD only use a single persistent + connection to a given AAA agent or server, it MAY have connections to + multiple AAA agents or servers. A AAA client/agent connected to + multiple agents/servers can treat them as primary/secondary or + balance load between them. + +3.4. Application Layer Watchdog + + In order to enable AAA implementations to more quickly detect + transport and application-layer failures, AAA protocols MUST support + an application layer watchdog message. + + The application layer watchdog message enables failover from a peer + that has failed, either because it is unreachable or because its + applications functions have failed. This is distinct from the + purpose of the SCTP heartbeat, which is to enable failover between + interfaces. The SCTP heartbeat may enable a failover to another path + to reach the same server, but does not address the situation where + the server system or the application service has failed. Therefore + both mechanisms MAY be used together. + + The watchdog is used in order to enable a AAA client or agent to + determine when to resend on another connection. It operates on all + open connections and is used to suspend and eventually close + connections that are experiencing difficulties. The watchdog is also + used to re-open and validate connections that have returned to + health. The watchdog may be utilized either within primary/secondary + or load balancing configurations. However, it is not intended as a + cluster heartbeat mechanism. + + The application layer watchdog is designed to detect failures of the + immediate peer, and not to be affected by failures of downstream + proxies or servers. This prevents instability in downstream AAA + components from propagating upstream. While the receipt of any AAA + Response from a peer is taken as evidence that the peer is up, lack + of a Response is insufficient to conclude that the peer is down. + Since the lack of Response may be the result of problems with a + + + +Aboba & Wood Standards Track [Page 13] + +RFC 3539 AAA Transport Profile June 2003 + + + downstream proxy or server, only after failure to respond to the + watchdog message can it be determined that the peer is down. + + Since the watchdog algorithm takes any AAA Response into account in + determining peer liveness, decreases in the watchdog timer interval + do not significantly increase the level of watchdog traffic on + heavily loaded networks. This is because watchdog messages do not + need to be sent where other AAA Response traffic serves as a constant + reminder of peer liveness. Watchdog traffic only increases when AAA + traffic is light, and therefore a AAA Response "signal" is not + present. Nevertheless, decreasing the timer interval TWINIT does + increase the probability of false failover significantly, and so this + decision should be made with care. + +3.4.1. Algorithm Overview + + The watchdog behavior is controlled by an algorithm defined in this + section. This algorithm is appropriate for use either within + primary/secondary or load balancing configurations. Implementations + SHOULD implement this algorithm, which operates as follows: + + [1] Watchdog behavior is controlled by a single timer (Tw). The + initial value of Tw, prior to jittering is Twinit. The default + value of Twinit is 30 seconds. This value was selected because + it minimizes the probability that failover will be initiated due + to a routing flap, as noted in [Paxson]. + + While Twinit MAY be set as low as 6 seconds (not including + jitter), it MUST NOT be set lower than this. Note that setting + such a low value for Twinit is likely to result in an increased + probability of duplicates, as well as an increase in spurious + failover and failback attempts. + + In order to avoid synchronization behaviors that can occur with + fixed timers among distributed systems, each time the watchdog + interval is calculated with a jitter by using the Twinit value + and randomly adding a value drawn between -2 and 2 seconds. + Alternative calculations to create jitter MAY be used. These + MUST be pseudo-random, generated by a PRNG seeded as per + [RFC1750]. + + [2] When any AAA message is received, Tw is reset. This need not be + a response to a watchdog request. Receiving a watchdog response + from a peer constitutes activity, and Tw should be reset. If the + watchdog timer expires and no watchdog response is pending, then + a watchdog message is sent. On sending a watchdog request, Tw is + reset. + + + + +Aboba & Wood Standards Track [Page 14] + +RFC 3539 AAA Transport Profile June 2003 + + + Watchdog packets are not retransmitted by the AAA protocol, since + AAA protocols run over reliable transports that will handle all + retransmissions internally. As a result, a watchdog request is + only sent when there is no watchdog response pending. + + [3] If the watchdog timer expires and a watchdog response is pending, + then failover is initiated. In order for a AAA client or agent + to perform failover procedures, it is necessary to maintain a + pending message queue for a given peer. When an answer message + is received, the corresponding request is removed from the queue. + The Hop-by-Hop Identifier field MAY be used to match the answer + with the queued request. + + When failover is initiated, all messages in the queue are sent to + an alternate agent, if available. Multiple identical requests or + answers may be received as a result of a failover. The + combination of an end-to-end identifier and the origin host MUST + be used to identify duplicate messages. + + Note that where traffic is heavy, the application layer watchdog + can take as long as 2Tw to determine that a peer has gone down. + For peers receiving a high volume of AAA Requests, AAA Responses + will continually reset the timer, so that after a failure it will + take Tw for the lack of traffic to be noticed, and for the + watchdog message to be sent. Another Tw will elapse before + failover is initiated. + + On a lightly loaded network without much AAA Response traffic, + the watchdog timer will typically expire without being reset, so + that a watchdog response will be outstanding and failover will be + initiated after only a single timer interval has expired. + + [4] The client MUST NOT close the primary connection until the + primary's watchdog timer has expired at least twice without a + response (note that the watchdog is not sent a second time, + however). Once this has occurred, the client SHOULD cause a + transport reset or close to be done on the connection. + + Once the primary connection has failed, subsequent requests are + sent to the alternate server until the watchdog timer on the + primary connection is reset. + + Suspension of the primary connection prevents flapping between + primary and alternate connections, and ensures that failover + behavior remains consistent. The application may not receive a + response to the watchdog request message due to a connectivity + problem, in which case a transport layer ACK will not have been + received, or the lack of response may be due to an application + + + +Aboba & Wood Standards Track [Page 15] + +RFC 3539 AAA Transport Profile June 2003 + + + problem. Without transport layer visibility, the application is + unable to tell the difference, and must behave conservatively. + + In situations where no transport layer ACK is received on the + primary connection after multiple re-transmissions, the RTO will + be exponentially backed off as described in [RFC2988]. Due to + Karn's algorithm as implemented in SCTP and TCP, the RTO + estimator will not be reset until another ACK is received in + response to a non-re-transmitted request. Thus, in cases where + the problem occurs at the transport layer, after the client fails + over to the alternate server, the RTO of the primary will remain + at a high value unless an ACK is received on the primary + connection. + + In the case where the problem occurs at the transport layer, + subsequent requests sent on the primary connection will not + receive the same service as was originally provided. For + example, instead of failover occurring after 3 retransmissions, + failover might occur without even a single retransmission if RTO + has been sufficiently backed off. Of course, if the lack of a + watchdog response was due to an application layer problem, then + RTO will not have been backed off. However, without transport + layer visibility, there is no way for the application to know + this. + + Suspending use of the primary connection until a response to a + watchdog message is received guarantees that the RTO timer will + have been reset before the primary connection is reused. If no + response is received after the second watchdog timer expiration, + then the primary connection is closed and the suspension becomes + permanent. + + [5] While the connection is in the closed state, the AAA client MUST + NOT attempt to send further watchdog messages on the connection. + However, after the connection is closed, the AAA client continues + to periodically attempt to reopen the connection. + + The AAA client SHOULD wait for the transport layer to report + connection failure before attempting again, but MAY choose to + bound this wait time by the watchdog interval, Tw. If the + connection is successfully opened, then the watchdog message is + sent. Once three watchdog messages have been sent and responded + to, the connection is returned to service, and transactions are + once again sent over it. Connection validation via receipt of + multiple watchdogs is not required when a connection is initially + brought up -- in this case, the connection can immediately be put + into service. + + + + +Aboba & Wood Standards Track [Page 16] + +RFC 3539 AAA Transport Profile June 2003 + + + [6] When using SCTP as a transport, it is not necessary to disable + SCTP's transport-layer heartbeats. However, if AAA + implementations have access to SCTP's heartbeat parameters, they + MAY chose to ensure that SCTP's heartbeat interval is longer than + the AAA watchdog interval, Tw. This will ensure that alternate + paths are still probed by SCTP, while the primary path has a + minimum of heartbeat redundancy. + +3.4.2. Primary/Secondary Failover Support + + The watchdog timer MAY be integrated with primary/secondary style + failover so as to provide improved reliability and basic load + balancing. In order to balance load among multiple AAA servers, each + AAA server is designated the primary for a portion of the clients, + and designated as secondaries of varying priority for the remainder. + In this way, load can be balanced among the AAA servers. + + Within primary/secondary configurations, the watchdog timer operates + as follows: + + [1] Assume that each client or agent is initially configured with a + single primary agent or server, and one or more secondary + connections. + + [2] The watchdog mechanism is used to suspend and eventually close + primary connections that are experiencing difficulties. It is + also used to re-open and validate connections that have returned + to health. + + [3] Once a secondary is promoted to primary status, either on a + temporary or permanent basis, the next server on the list of + secondaries is promoted to fill the open secondary slot. + + [4] The client or agent periodically attempts to re-open closed + connections, so that it is possible that a previously closed + connection can be returned to service and become eligible for use + again. Implementations will typically retain a limit on the + number of connections open at a time, so that once a previously + closed connection is brought online again, the lowest priority + secondary connection will be closed. In order to prevent + periodic closing and re-opening of secondary connections, it is + recommended that functioning connections remain open for a + minimum of 5 minutes. + + [5] In order to enable diagnosis of failover behavior, it is + recommended that a table of failover events be kept within the + MIB. These failover events SHOULD include appropriate + transaction identifiers so that client and server data can be + + + +Aboba & Wood Standards Track [Page 17] + +RFC 3539 AAA Transport Profile June 2003 + + + compared, providing insight into the cause of the problem + (transport or application layer). + +3.4.3. Connection Load Balancing + + Primary/secondary failover is capable of providing improved + resilience and basic load balancing. However, it does not address + TCP head of line blocking, since only a single connection is in use + at a time. + + A AAA client or agent maintaining connections to multiple agents or + servers MAY load balance between them. Establishing connections to + multiple agents or servers reduces, but does not eliminate, head of + line blocking issues experienced on TCP connections. This issue does + not exist with SCTP connections utilizing multiple streams. + + In connection load balancing configurations, the application watchdog + operates as follows: + + [1] Assume that each client or agent is initially configured with + connections to multiple AAA agents or servers, with one + connection between a given client/agent and an agent/server. + + [2] In static load balancing, transactions are apportioned among the + connections based on the total number of connections and a + "weight" assigned to each connection. Pearson's hash [RFC3074] + applied to the NAI [RFC2486] can be used to determine which + connection will handle a given transaction. Hashing on the NAI + provides highly granular load balancing, while ensuring that all + traffic for a given conversation will be sent to the same agent + or server. In dynamic load balancing, the value of the "weight" + can vary based on conditions such as AAA server load. Such + techniques, while sophisticated, are beyond the scope of this + document. + + [3] Transactions are distributed to connections based on the total + number of available connections and their weights. A change in + the number of available connections forces recomputation of the + hash table. In order not to cause conversations in progress to + be switched to new destinations, on recomputation, a transitional + period is required in which both old and new hash tables are + needed in order to permit aging out of conversations in progress. + Note that this requires a way to easily determine whether a + Request represents a new conversation or the continuation of an + existing conversation. As a result, removing and adding of + connections is an expensive operation, and it is recommended that + the hash table only be recomputed once a connection is closed or + returned to service. + + + +Aboba & Wood Standards Track [Page 18] + +RFC 3539 AAA Transport Profile June 2003 + + + Suspended connections, although they are not used, do not force + hash table reconfiguration until they are closed. Similarly, + re-opened connections not accumulating sufficient watchdog + responses do not force a reconfiguration until they are returned + to service. + + While a connection is suspended, transactions that were to have + been assigned to it are instead assigned to the next available + server. While this results in a momentary imbalance, it is felt + that this is a relatively small price to pay in order to reduce + hash table thrashing. + + [4] In order to enable diagnosis of load balancing behavior, it is + recommended that in addition to a table of failover events, a + table of statistics be kept on each client, indexed by a AAA + server. That way, the effectiveness of the load balancing + algorithm can be evaluated. + +3.5. Duplicate Detection + + Multiple facilities are required to enable duplicate detection. + These include session identifiers as well as hop-by-hop and end-to- + end message identifiers. Hop-by-hop identifiers whose value may + change at each hop are not sufficient, since a AAA server may receive + the same message from multiple agents. For example, a AAA client can + send a request to Agent1, then failover and resend the request to + Agent2; both agents forward the request to the home AAA server, with + different hop-by-hop identifiers. A Session Identifier is + insufficient as it does not distinguish different messages for the + the same session. + + Proper treatment of the end-to-end message identifier ensures that + AAA operations are idempotent. For example, without an end-to-end + identifier, a AAA server keeping track of simultaneous logins might + send an Accept in response to an initial Request, and then a Reject + in response to a duplicate Request (where the user was allowed only + one simultaneous login). Depending on which Response arrived first, + the user might be allowed access or not. + + However, if the server were to store the end-to-end message + identifier along with the simultaneous login information, then the + duplicate Request (which utilizes the same end-to-end message + identifier) could be identified and the correct response could be + returned. + + + + + + + +Aboba & Wood Standards Track [Page 19] + +RFC 3539 AAA Transport Profile June 2003 + + +3.6. Invalidation of Transport Parameter Estimates + + In order to address invalidation of transport parameter estimates, + AAA protocol implementations MAY utilize Congestion Window Validation + [RFC2861] and RTO validation when using TCP. This specification also + recommends a procedure for RTO validation. + + [RFC2581] and [RFC2861] both recommend that a connection go into + slow-start after a period where no traffic has been sent within the + RTO interval. [RFC2861] recommends only increasing the congestion + window if it was full when the ACK arrived. The congestion window is + reduced by half once every RTO interval if no traffic is received. + + When Congestion Window Validation is used, the congestion window will + not build during application-driven periods, and instead will be + decayed. As a result, AAA applications operating within the + application-driven regime will typically run with a congestion window + equal to the initial window much of the time, operating in "perpetual + slowstart". + + During periods in which AAA behavior is application-driven this will + have no effect. Since the time between packets will be larger than + RTT, AAA will operate with an effective congestion window equal to + the initial window. However, during network-driven periods, the + effect will be to space out sending of AAA packets. Thus instead of + being able to send a large burst of packets into the network, a + client will need to wait several RTTs as the congestion window builds + during slow-start. + + For example, a client operating over TCP with an initial window of 2, + with 35 AAA requests to send would take approximately 6 RTTs to send + them, as the congestion window builds during slow start: 2, 3, 3, 6, + 9, 12. After the backlog is cleared, the implementation will once + again be application-driven and the congestion window size will + decay. If the client were using SCTP, the number of RTTs needed to + transmit all requests would usually be less, and would depend on the + size of the requests, since SCTP tracks the progress for the opening + of the congestion window by bytes, not segments. + + Note that [RFC2861] and [RFC2988] do not address the issue of RTO + validation. This is also a problem, particularly when the Congestion + Manager [RFC3124] is implemented. During periods of high packet + loss, the RTO may be repeatedly increased via exponential back-off, + and may attain a high value. Due to lack of timely feedback on RTT + and RTO during application-driven periods, the high RTO estimate may + persist long after the conditions that generated it have dissipated. + + + + + +Aboba & Wood Standards Track [Page 20] + +RFC 3539 AAA Transport Profile June 2003 + + + RTO validation MAY be used to address this issue for TCP, via the + following procedure: + + After the congestion window is decayed according to [RFC2861], + reset the estimated RTO to 3 seconds. After the next packet comes + in, re-calculate RTTavg, RTTdev, and RTO according to the method + described in [RFC2581]. + + To address this issue for SCTP, AAA implementations SHOULD use SCTP + heartbeats. [RFC2960] states that heartbeats should be enabled by + default, with an interval of 30 seconds. If this interval proves to + be too long to resolve this issue, AAA implementations MAY reduce the + heartbeat interval. + +3.7. Inability to Use Fast Re-Transmit + + When Congestion Window Validation [RFC2861] is used, AAA + implementations will operate with a congestion window equal to the + initial window much of the time. As a result, the window size will + often not be large enough to enable use of fast re-transmit for TCP. + In addition, since AAA traffic is two-way, ACKs carrying data will + not count towards triggering fast re-transmit. SCTP is less likely + to encounter this issue, so the measures described below apply to + TCP. + + To address this issue, AAA implementations SHOULD support selective + acknowledgement as described in [RFC2018] and [RFC2883]. AAA + implementations SHOULD also implement Limited Transmit for TCP, as + described in [RFC3042]. Rather than reducing the number of duplicate + ACKs required for triggering fast recovery, which would increase the + number of inappropriate re-transmissions, Limited Transmit enables + the window size be increased, thus enabling the sending of additional + packets which in turn may trigger fast re-transmit without a change + to the algorithm. + + However, if congestion window validation [RFC2861] is implemented, + this proposal will only have an effect in situations where the time + between packets is less than the estimated retransmission timeout + (RTO). If the time between packets is greater than RTO, additional + packets will typically not be available for sending so as to take + advantage of the increased window size. As a result, AAA protocols + will typically operate with the lowest possible congestion window + size, resulting in a re-transmission timeout for every lost packet. + + + + + + + + +Aboba & Wood Standards Track [Page 21] + +RFC 3539 AAA Transport Profile June 2003 + + +3.8. Head of Line Blocking + + TCP inherently does not provide a solution to the head-of-line + blocking problem, although its effects can be lessened by + implementation of Limited Transmit [RFC3042], and connection load + balancing. + +3.8.1. Using SCTP Streams to Prevent Head of Line Blocking + + Each AAA node SHOULD distribute its messages evenly across the range + of SCTP streams that it and its peer have agreed upon. (A lost + message in one stream will not cause any other streams to block.) A + trivial and effective implementation of this simply increments a + counter for the stream ID to send on. When the counter reaches the + maximum number of streams for the association, it resets to 0. + + AAA peers MUST be able to accept messages on any stream. Note that + streams are used *solely* to prevent head-of-the-line blocking. All + identifying information is carried within the Diameter payload. + Messages distributed across multiple streams may not be received in + the order they are sent. + + SCTP peers can allocate up to 65535 streams for an association. The + cost for idle streams may or may not be zero, depending on the + implementation, and the cost for non-idle streams is always greater + than 0. So administrators may wish to limit the number of possible + streams on their diameter nodes according to the resources (i.e. + memory, CPU power, etc.) of a particular node. + + On a Diameter client, the number of streams may be determined by the + maximum number of peak users on the NAS. If a stream is available + per user, then this should be sufficient to prevent head-of-line + blocking. On a Diameter proxy, the number of streams may be + determined by the maximum number of peak sessions in progress from + that proxy to each downstream AAA server. + + Stream IDs do not need to be preserved by relay agents. This + simplifies implementation, as agents can easily handle forwarding + between two associations with different numbers of streams. For + example, consider the following case, where a relay server DRL + forwards messages between a NAS and a home server, HMS. The NAS and + DRL have agreed upon 1000 streams for their association, and DRL and + HMS have agreed upon 2000 streams for their association. The + following figure shows the message flow from NAS to HMS via DRL, and + the stream ID assignments for each message: + + + + + + +Aboba & Wood Standards Track [Page 22] + +RFC 3539 AAA Transport Profile June 2003 + + + +------+ +------+ +------+ + | | | | | | + | NAS | ---------> | DRL | ---------> | HMS | + | | | | | | + +------+ 1000 streams +------+ 2000 streams +------+ + + msg 1: str id 0 msg 1: str id 0 + msg 2: str id 1 msg 2: str id 1 + ... + msg 1000: str id 999 msg 1000: str id 999 + msg 1001: str id 0 msg 1001: str id 1000 + + DRL can forward messages 1 through 1000 to HMS using the same stream + ID that NAS used to send to DRL. However, since the NAS / DRL + association has only 1000 streams, NAS wraps around to stream ID 0 + when sending message 1001. The DRL / HMS association, on the other + hand, has 2000 streams, so DRL can reassign message 1001 to stream ID + 1000 when forwarding it on to HMS. + + This distribution scheme acts like a hash table. It is possible, yet + unlikely, that two messages will end up in the same stream, and even + less likely that there will be message loss resulting in blocking + when this happens. If it does turn out to be a problem, local + administrators can increase the number of streams on their nodes to + improve performance. + +3.9. Congestion Avoidance + + In order to improve upon default timer estimates, AAA implementations + MAY implement the Congestion Manager (CM) [RFC3124]. CM is an end- + system module that: + + (i) Enables an ensemble of multiple concurrent streams from a + sender destined to the same receiver and sharing the same + congestion properties to perform proper congestion avoidance + and control, and + + (ii) Allows applications to easily adapt to network congestion. + + The CM helps integrate congestion management across all applications + and transport protocols. The CM maintains congestion parameters + (available aggregate and per-stream bandwidth, per-receiver round- + trip times, etc.) and exports an API that enables applications to + learn about network characteristics, pass information to the CM, + share congestion information with each other, and schedule data + transmissions. + + + + + +Aboba & Wood Standards Track [Page 23] + +RFC 3539 AAA Transport Profile June 2003 + + + The CM enables the AAA application to access transport parameters + (RTTavg, RTTdev) via callbacks. RTO estimates are currently not + available via the callback interface, though they probably should be. + Where available, transport parameters SHOULD be used to improve upon + default timer values. + +3.10. Premature Failover + + Premature failover is prevented by the watchdog functionality + described above. If the next hop does not return a reply, the AAA + client will send a watchdog message to it to verify liveness. If a + watchdog reply is received, then the AAA client will know that the + next hop server is functioning at the application layer. As a + result, it is only necessary to provide terminal error messages, such + as the following: + + "Busy": agent/Server too busy to handle additional requests, NAS + should failover all requests to another agent/server. + + "Can't Locate": agent can't locate the AAA server for the + indicated realm; NAS should failover that request to another + proxy. + + "Can't Forward": agent has tried both primary and secondary AAA + servers with no response; NAS should failover the request to + another agent. + + Note that these messages differ in their scope. The "Busy" message + tells the NAS that the agent/server is too busy for ANY request. The + "Can't Locate" and "Can't Forward" messages indicate that the + ultimate destination cannot be reached or isn't responding, implying + per-request failover. + +4. Security Considerations + + Since AAA clients, agents and servers serve as network access + gatekeepers, they are tempting targets for attackers. General + security considerations concerning TCP congestion control are + discussed in [RFC2581]. However, there are some additional + considerations that apply to this specification. + + By enabling failover between AAA agents, this specification improves + the resilience of AAA applications. However, it may also open + avenues for denial of service attacks. + + The failover algorithm is driven by lack of response to AAA requests + and watchdog packets. On a lightly loaded network where AAA + responses would not be received prior to expiration of the watchdog + + + +Aboba & Wood Standards Track [Page 24] + +RFC 3539 AAA Transport Profile June 2003 + + + timer, an attacker can swamp the network, causing watchdog packets to + be dropped. This will cause the AAA client to switch to another AAA + agent, where the attack can be repeated. By causing the AAA client + to cycle between AAA agents, service can be denied to users desiring + network access. + + Where TLS [RFC2246] is being used to provide AAA security, there will + be a vulnerability to spoofed reset packets, as well as other + transport layer denial of service attacks (e.g. SYN flooding). Since + SCTP offers improved denial of service resilience compared with TCP, + where AAA applications run over SCTP, this can be mitigated to some + extent. + + Where IPsec [RFC2401] is used to provide security, it is important + that IPsec policy require IPsec on incoming packets. In order to + enable a AAA client to determine what security mechanisms are in use + on an agent or server without prior knowledge, it may be tempting to + initiate a connection in the clear, and then to have the AAA agent + respond with IKE [RFC2409]. While this approach minimizes required + client configuration, it increases the vulnerability to denial of + service attack, since a connection request can now not only tie up + transport resources, but also resources within the IKE + implementation. + +5. IANA Considerations + + This document does not create any new number spaces for IANA + administration. + +References + +6.1. Normative References + + [RFC793] Postel, J., "Transmission Control Protocol", STD 7, RFC + 793, September 1981. + + [RFC896] Nagle, J., "Congestion Control in IP/TCP internetworks", + RFC 896, January 1984. + + [RFC1750] Eastlake, D., Crocker, S. and J. Schiller, "Randomness + Recommendations for Security", RFC 1750, December 1994. + + [RFC2018] Mathis, M., Mahdavi, J., Floyd, S. and A. Romanow, "TCP + Selective Acknowledgment Options", RFC 2018, October 1996. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + + + +Aboba & Wood Standards Track [Page 25] + +RFC 3539 AAA Transport Profile June 2003 + + + [RFC2486] Aboba, B. and M. Beadles, "The Network Access Identifier", + RFC 2486, January 1999. + + [RFC2581] Allman, M., Paxson, V. and W. Stevens, "TCP Congestion + Control", RFC 2581, April 1999. + + [RFC2883] Floyd, S., Mahdavi, J., Mathis, M., Podolsky, M. and A. + Romanow, "An Extension to the Selective Acknowledgment + (SACK) Option for TCP", RFC 2883, July 2000. + + [RFC2960] Stewart, R., Xie, Q., Morneault, K., Sharp, C., + Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M., Zhang, + L. and V. Paxson, "Stream Control Transmission Protocol", + RFC 2960, October 2000. + + [RFC2988] Paxson, V. and M. Allman, "Computing TCP's Retransmission + Timer", RFC 2988, November 2000. + + [RFC3042] Allman, M., Balakrishnan H. and S. Floyd, "Enhancing TCP's + Loss Recovery Using Limited Transmit", RFC 3042, January + 2001. + + [RFC3074] Volz, B., Gonczi, S., Lemon, T. and R. Stevens, "DHC Load + Balancing Algorithm", RFC 3074, February 2001. + + [RFC3124] Balakrishnan, H. and S. Seshan, "The Congestion Manager", + RFC 3124, June 2001. + +6.2. Informative References + + [RFC2246] Dierks, T. and C. Allen, "The TLS Protocol Version 1.0", + RFC 2246, January 1999. + + [RFC2401] Atkinson, R. and S. Kent, "Security Architecture for the + Internet Protocol", RFC 2401, November 1998. + + [RFC2409] Harkins, D. and D. Carrel, "The Internet Key Exchange + (IKE)", RFC 2409, November 1998. + + [RFC2607] Aboba, B. and J. Vollbrecht, "Proxy Chaining and Policy + Implementation in Roaming", RFC 2607, June 1999. + + [RFC2861] Handley, M., Padhye, J. and S. Floyd, "TCP Congestion + Window Validation", RFC 2861, June 2000. + + [RFC2865] Rigney, C., Willens, S., Rubens, A. and W. Simpson, "Remote + Authentication Dial In User Service (RADIUS)", RFC 2865, + June 2000. + + + +Aboba & Wood Standards Track [Page 26] + +RFC 3539 AAA Transport Profile June 2003 + + + [RFC2866] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000. + + [RFC2914] Floyd, S., "Congestion Control Principles", BCP 41, RFC + 2914, September 2000. + + [RFC2975] Aboba, B., Arkko, J. and D. Harrington, "Introduction to + Accounting Management", RFC 2975, June 2000. + + [RFC3390] Allman, M., Floyd, S. and C. Partridge, "Increasing TCP's + Initial Window", RFC 3390, October 2002. + + [Congest] Jacobson, V., "Congestion Avoidance and Control", Computer + Communication Review, vol. 18, no. 4, pp. 314-329, Aug. + 1988. ftp://ftp.ee.lbl.gov/papers/congavoid.ps.Z + + [Paxson] Paxson, V., "Measurement and Analysis of End-to-End + Internet Dynamics", Ph.D. Thesis, Computer Science + Division, University of California, Berkeley, April 1997. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Aboba & Wood Standards Track [Page 27] + +RFC 3539 AAA Transport Profile June 2003 + + +Appendix A - Detailed Watchdog Algorithm + + In this Appendix, the memory control structure that contains all + information regarding a specific peer is referred to as a Peer + Control Block, or PCB. The PCB contains the following fields: + + Status: + OKAY: The connection is up + SUSPECT: Failover has been initiated on the connection. + DOWN: Connection has been closed. + REOPEN: Attempting to reopen a closed connection + INITIAL: The initial state of the pcb when it is first created. + The pcb has never been opened. + + Variables: + Pending: Set to TRUE if there is an outstanding unanswered + watchdog request + Tw: Watchdog timer value + NumDWA: Number of DWAs received during REOPEN + + Tw is the watchdog timer, measured in seconds. Every second, Tw is + decremented. When it reaches 0, the OnTimerElapsed event (see below) + is invoked. Pseudo-code for the algorithm is included on the + following pages. + + SetWatchdog() + { + /* + SetWatchdog() is called whenever it is necessary + to reset the watchdog timer Tw. The value of the + watchdog timer is calculated based on the default + initial value TWINIT and a jitter ranging from + -2 to 2 seconds. The default for TWINIT is 30 seconds, + and MUST NOT be set lower than 6 seconds. + */ + Tw=TWINIT -2.0 + 4.0 * random() ; + SetTimer(Tw) ; + return ; + } + + /* + OnReceive() is called whenever a message + is received from the peer. This message MAY + be a request or an answer, and can include + DWR and DWA messages. Pending is assumed to + be a global variable. + */ + OnReceive(pcb, msgType) + + + +Aboba & Wood Standards Track [Page 28] + +RFC 3539 AAA Transport Profile June 2003 + + + { + if (msgType == DWA) { + Pending = FALSE; + } + switch (pcb->Status){ + case OKAY: + SetWatchdog(); + break; + case SUSPECT: + pcb->Status = OKAY; + Failback(pcb); + SetWatchdog(); + break; + case REOPEN: + if (msgType == DWA) { + NumDWA++; + if (NumDWA == 3) { + pcb->status = OKAY; + Failback(); + } + } else { + Throwaway(received packet); + } + break; + case INITIAL: + case DOWN: + Throwaway(received packet); + break; + default: + Error("Shouldn't be here!"); + break; + } + } + + /* + OnTimerElapsed() is called whenever Tw reaches zero (0). + */ + OnTimerElapsed(pcb) + { + switch (pcb->status){ + case OKAY: + if (!Pending) { + SendWatchdog(pcb); + SetWatchdog(); + Pending = TRUE; + break; + } + pcb->status = SUSPECT; + + + +Aboba & Wood Standards Track [Page 29] + +RFC 3539 AAA Transport Profile June 2003 + + + FailOver(pcb); + SetWatchdog(); + break ; + case SUSPECT: + pcb->status = DOWN; + CloseConnection(pcb); + SetWatchdog(); + break; + case INITIAL: + case DOWN: + AttemptOpen(pcb); + SetWatchdog(); + break; + case REOPEN: + if (!Pending) { + SendWatchdog(pbc); + SetWatchdog(); + Pending = TRUE; + break; + } + if (NumDWA < 0) { + pcb->status = DOWN; + CloseConnection(pcb); + } else { + NumDWA = -1; + } + SetWatchdog(); + break; + default: + error("Shouldn't be here!); + break; + } + } + + /* + OnConnectionUp() is called whenever a connection comes up + */ + OnConnectionUp(pcb) + { + switch (pcb->status){ + case INITIAL: + pcb->status = OKAY; + SetWatchdog(); + break; + case DOWN: + pcb->status = REOPEN; + NumDWA = 0; + SendWatchdog(pcb); + + + +Aboba & Wood Standards Track [Page 30] + +RFC 3539 AAA Transport Profile June 2003 + + + SetWatchdog(); + Pending = TRUE; + break; + default: + error("Shouldn't be here!); + break; + } + } + + /* + OnConnectionDown() is called whenever a connection goes down + */ + OnConnectionDown(pcb) + { + pcb->status = DOWN; + CloseConnection(); + switch (pcb->status){ + case OKAY: + Failover(pcb); + SetWatchdog(); + break; + case SUSPECT: + case REOPEN: + SetWatchdog(); + break; + default: + error("Shouldn't be here!); + break; + } + } + + /* Here is the state machine equivalent to the above code: + + STATE Event Actions New State + ===== ------ ------- ---------- + OKAY Receive DWA Pending = FALSE + SetWatchdog() OKAY + OKAY Receive non-DWA SetWatchdog() OKAY + SUSPECT Receive DWA Pending = FALSE + Failback() + SetWatchdog() OKAY + SUSPECT Receive non-DWA Failback() + SetWatchdog() OKAY + REOPEN Receive DWA & Pending = FALSE + NumDWA == 2 NumDWA++ + Failback() OKAY + REOPEN Receive DWA & Pending = FALSE + NumDWA < 2 NumDWA++ REOPEN + + + +Aboba & Wood Standards Track [Page 31] + +RFC 3539 AAA Transport Profile June 2003 + + + STATE Event Actions New State + ===== ------ ------- ---------- + REOPEN Receive non-DWA Throwaway() REOPEN + INITIAL Receive DWA Pending = FALSE + Throwaway() INITIAL + INITIAL Receive non-DWA Throwaway() INITIAL + DOWN Receive DWA Pending = FALSE + Throwaway() DOWN + DOWN Receive non-DWA Throwaway() DOWN + OKAY Timer expires & SendWatchdog() + !Pending SetWatchdog() + Pending = TRUE OKAY + OKAY Timer expires & Failover() + Pending SetWatchdog() SUSPECT + SUSPECT Timer expires CloseConnection() + SetWatchdog() DOWN + INITIAL Timer expires AttemptOpen() + SetWatchdog() INITIAL + DOWN Timer expires AttemptOpen() + SetWatchdog() DOWN + REOPEN Timer expires & SendWatchdog() + !Pending SetWatchdog() + Pending = TRUE REOPEN + REOPEN Timer expires & CloseConnection() + Pending & SetWatchdog() + NumDWA < 0 DOWN + REOPEN Timer expires & NumDWA = -1 + Pending & SetWatchdog() + NumDWA >= 0 REOPEN + INITIAL Connection up SetWatchdog() OKAY + DOWN Connection up NumDWA = 0 + SendWatchdog() + SetWatchdog() + Pending = TRUE REOPEN + OKAY Connection down CloseConnection() + Failover() + SetWatchdog() DOWN + SUSPECT Connection down CloseConnection() + SetWatchdog() DOWN + REOPEN Connection down CloseConnection() + SetWatchdog() DOWN + */ + + + + + + + + + +Aboba & Wood Standards Track [Page 32] + +RFC 3539 AAA Transport Profile June 2003 + + +Appendix B - AAA Agents + + As described in [RFC2865] and [RFC2607], AAA agents have become + popular in order to support services such as roaming and shared use + networks. Such agents are used both for + authentication/authorization, as well as accounting [RFC2975]. + + AAA agents include: + + Relays + Proxies + Re-directs + Store and Forward proxies + Transport layer proxies + + The transport layer behavior of each of these agents is described + below. + +B.1 Relays and Proxies + + While the application-layer behavior of relays and proxies are + different, at the transport layer the behavior is similar. In both + cases, two connections are established: one from the AAA client (NAS) + to the relay/proxy, and another from the relay/proxy to the AAA + server. The relay/proxy does not respond to a client request until + it receives a response from the server. Since the two connections + are de-coupled, the end-to-end conversation between the client and + server may not self clock. + + Since AAA transport is typically application-driven, there is + frequently not enough traffic to enable ACK piggybacking. As a + result, the Nagle algorithm is rarely triggered, and delayed ACKs may + comprise nearly half the traffic. Thus AAA protocols running over + reliable transport will see packet traffic nearly double that + experienced with UDP transport. Since ACK parameters (such as the + value of the delayed ACK timer) are typically fixed by the TCP + implementation and are not tunable by the application, there is + little that can be done about this. + + + + + + + + + + + + + +Aboba & Wood Standards Track [Page 33] + +RFC 3539 AAA Transport Profile June 2003 + + + A typical trace of a conversation between a NAS, proxy and server is + shown below: + + Time NAS Relay/Proxy Server + ------ --- ----------- ------ + + 0 Request + -------> + OTTnp + Tpr Request + -------> + + OTTnp + TdA Delayed ACK + <------- + + OTTnp + OTTps + Reply/ACK + Tpr + Tsr <------- + + OTTnp + OTTps + + Tpr + Tsr + Reply + OTTsp + TpR <------- + + OTTnp + OTTps + + Tpr + Tsr + Delayed ACK + OTTsp + TdA -------> + + OTTnp + OTTps + + OTTsp + OTTpn + + Tpr + Tsr + Delayed ACK + TpR + TdA -------> + + Key + --- + OTT = One-way Trip Time + OTTnp = One-way trip time (NAS to Relay/Proxy) + OTTpn = One-way trip time (Relay/Proxy to NAS) + OTTps = One-way trip time (Relay/Proxy to Server) + OTTsp = One-way trip time (Server to Relay/Proxy) + TdA = Delayed ACK timer + Tpr = Relay/Proxy request processing time + TpR = Relay/Proxy reply processing time + Tsr = Server request processing time + + At time 0, the NAS sends a request to the relay/proxy. Ignoring the + serialization time, the request arrives at the relay/proxy at time + OTTnp, and the relay/proxy takes an additional Tpr in order to + forward the request toward the home server. At time TdA after + + + + + +Aboba & Wood Standards Track [Page 34] + +RFC 3539 AAA Transport Profile June 2003 + + + receiving the request, the relay/proxy sends a delayed ACK. The + delayed ACK is sent, rather than being piggybacked on the reply, as + long as TdA < OTTps + OTTsp + Tpr + Tsr + TpR. + + Typically Tpr < TdA, so that the delayed ACK is sent after the + relay/proxy forwards the request toward the server, but before the + relay/proxy receives the reply from the server. However, depending + on the TCP implementation on the relay/proxy and when the request is + received, it is also possible for the delayed ACK to be sent prior to + forwarding the request. + + At time OTTnp + OTTps + Tpr, the server receives the request, and Tsr + later, it generates the reply. Where Tsr < TdA, the reply will + contain a piggybacked ACK. However, depending on the server + responsiveness and TCP implementation, the ACK and reply may be sent + separately. This can occur, for example, where a slow database or + storage system must be accessed prior to sending the reply. + + At time OTTnp + OTTps + OTTsp + Tpr + Tsr the reply/ACK reaches the + relay/proxy, which then takes TpR additional time to forward the + reply to the NAS. At TdA after receiving the reply, the relay/proxy + generates a delayed ACK. Typically TpR < TdA so that the delayed ACK + is sent to the server after the relay/proxy forwards the reply to the + NAS. However, depending on the circumstances and the relay/proxy TCP + implementation, the delayed ACK may be sent first. + + As with a delayed ACK sent in response to a request, which may be + piggybacked if the reply can be received quickly enough, piggybacking + of the ACK sent in response to a reply from the server is only + possible if additional request traffic is available. However, due to + the high inter-packet spacings in typical AAA scenarios, this is + unlikely unless the AAA protocol supports a reply ACK. + + At time OTTnp + OTTps + OTTsp + OTTpn + Tpr + Tsr + TpR the NAS + receives the reply. TdA later, a delayed ACK is generated. + +B.2 Re-directs + + Re-directs operate by referring a NAS to the AAA server, enabling the + NAS to talk to the AAA server directly. Since a direct transport + connection is established, the end-to-end connection will self-clock. + + With re-directs, delayed ACKs are less frequent than with + application-layer proxies since the Re-direct and Server will + typically piggyback replies with ACKs. + + + + + + +Aboba & Wood Standards Track [Page 35] + +RFC 3539 AAA Transport Profile June 2003 + + + The sequence of events is as follows: + + Time NAS Re-direct Server + ------ --- --------- ------ + + 0 Request + -------> + OTTnp + Tpr Redirect/ACK + <------- + + OTTnp + Tpr + Request + OTTpn + Tnr -------> + + OTTnp + OTTpn + + Tpr + Tsr + Reply/ACK + OTTns <------- + + OTTnp + OTTpn + + OTTns + OTTsn + + Tpr + Tsr + Delayed ACK + TdA -------> + + Key + --- + OTT = One-way Trip Time + OTTnp = One-way trip time (NAS to Re-direct) + OTTpn = One-way trip time (Re-direct to NAS) + OTTns = One-way trip time (NAS to Server) + OTTsn = One-way trip time (Server to NAS) + TdA = Delayed ACK timer + Tpr = Re-direct processing time + Tnr = NAS re-direct processing time + Tsr = Server request processing time + +B.3 Store and Forward Proxies + + With a store and forward proxy, the proxy may send a reply to the NAS + prior to forwarding the request to the server. While store and + forward proxies are most frequently deployed for accounting + [RFC2975], they also can be used to implement + authentication/authorization policy, as described in [RFC2607]. + + As noted in [RFC2975], store and forward proxies can have a negative + effect on accounting reliability. By sending a reply to the NAS + without receiving one from the accounting server, store and forward + proxies fool the NAS into thinking that the accounting request had + been accepted by the accounting server when this is not the case. As + a result, the NAS can delete the accounting packet from non-volatile + + + +Aboba & Wood Standards Track [Page 36] + +RFC 3539 AAA Transport Profile June 2003 + + + storage before it has been accepted by the accounting server. That + leaves the proxy responsible for delivering accounting packets. If + the proxy involves moving parts (e.g. a disk drive) while the NAS + does not, overall system reliability can be reduced. As a result, + store and forward proxies SHOULD NOT be used. + + The sequence of events is as follows: + + Time NAS Proxy Server + ------ --- ----- ------ + + 0 Request + -------> + OTTnp + TpR Reply/ACK + <------- + + OTTnp + Tpr Request + -------> + + OTTnp + OTTph + Reply/ACK + Tpr + Tsr <------- + + OTTnp + OTTph + + Tpr + Tsr + Reply + OTThp + TpR <------- + + OTTnp + OTTph + + Tpr + Tsr + Delayed ACK + OTThp + TdA -------> + + OTTnp + OTTph + + OTThp + OTTpn + + Tpr + Tsr + Delayed ACK + TpR + TdA -------> + + Key + --- + OTT = One-way Trip Time + OTTnp = One-way trip time (NAS to Proxy) + OTTpn = One-way trip time (Proxy to NAS) + OTTph = One-way trip time (Proxy to Home server) + OTThp = One-way trip time (Home Server to Proxy) + TdA = Delayed ACK timer + Tpr = Proxy request processing time + TpR = Proxy reply processing time + Tsr = Server request processing time + + + + + +Aboba & Wood Standards Track [Page 37] + +RFC 3539 AAA Transport Profile June 2003 + + +B.4 Transport Layer Proxies + + In addition to acting as proxies at the application layer, transport + layer proxies forward transport ACKs between the AAA client and + server. This splices together the client-proxy and proxy-server + connections into a single connection that behaves as though it + operates end-to-end, exhibiting self-clocking. However, since + transport proxies operate at the transport layer, they cannot be + implemented purely as applications and they are rarely deployed. + + With a transport proxy, the sequence of events is as follows: + + Time NAS Proxy Home Server + ------ --- ----- ----------- + + 0 Request + -------> + OTTnp + Tpr Request + -------> + + OTTnp + OTTph + Reply/ACK + Tpr + Tsr <------- + + OTTnp + OTTph + + Tpr + Tsr + Reply/ACK + OTThp + TpR <------- + + OTTnp + OTTph + + OTThp + OTTpn + + Tpr + Tsr + Delayed ACK + TpR + TdA -------> + + + OTTnp + OTTph + + OTThp + OTTpn + + Tpr + Tsr + Delayed ACK + TpR + TpD -------> + + Key + --- + OTT = One-way Trip Time + OTTnp = One-way trip time (NAS to Proxy) + OTTpn = One-way trip time (Proxy to NAS) + OTTph = One-way trip time (Proxy to Home server) + OTThp = One-way trip time (Home Server to Proxy) + TdA = Delayed ACK timer + Tpr = Proxy request processing time + TpR = Proxy reply processing time + + + +Aboba & Wood Standards Track [Page 38] + +RFC 3539 AAA Transport Profile June 2003 + + + Tsr = Server request processing time + TpD = Proxy delayed ack processing time + +Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementors or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + +Acknowledgments + + Thanks to Allison Mankin of AT&T, Barney Wolff of Databus, Steve Rich + of Cisco, Randy Bush of AT&T, Bo Landarv of IP Unplugged, Jari Arkko + of Ericsson, and Pat Calhoun of Blackstorm Networks for fruitful + discussions relating to AAA transport. + + + + + + + + + + + + + + + + + + + + +Aboba & Wood Standards Track [Page 39] + +RFC 3539 AAA Transport Profile June 2003 + + +Authors' Addresses + + Bernard Aboba + Microsoft Corporation + One Microsoft Way + Redmond, WA 98052 + + Phone: +1 425 706 6605 + Fax: +1 425 936 7329 + EMail: [email protected] + + + Jonathan Wood + Sun Microsystems, Inc. + 901 San Antonio Road + Palo Alto, CA 94303 + + EMail: [email protected] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Aboba & Wood Standards Track [Page 40] + +RFC 3539 AAA Transport Profile June 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Aboba & Wood Standards Track [Page 41] + diff --git a/lib/diameter/doc/standard/rfc3588.txt b/lib/diameter/doc/standard/rfc3588.txt new file mode 100644 index 0000000000..fe4ff08c81 --- /dev/null +++ b/lib/diameter/doc/standard/rfc3588.txt @@ -0,0 +1,8235 @@ + + + + + + +Network Working Group P. Calhoun +Request for Comments: 3588 Airespace, Inc. +Category: Standards Track J. Loughney + Nokia + E. Guttman + Sun Microsystems, Inc. + G. Zorn + Cisco Systems, Inc. + J. Arkko + Ericsson + September 2003 + + + Diameter Base Protocol + +Status of this Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2003). All Rights Reserved. + +Abstract + + The Diameter base protocol is intended to provide an Authentication, + Authorization and Accounting (AAA) framework for applications such as + network access or IP mobility. Diameter is also intended to work in + both local Authentication, Authorization & Accounting and roaming + situations. This document specifies the message format, transport, + error reporting, accounting and security services to be used by all + Diameter applications. The Diameter base application needs to be + supported by all Diameter implementations. + +Conventions Used In This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in BCP 14, RFC 2119 + [KEYWORD]. + + + + + + + +Calhoun, et al. Standards Track [Page 1] + +RFC 3588 Diameter Based Protocol September 2003 + + +Table of Contents + + 1. Introduction................................................. 6 + 1.1. Diameter Protocol..................................... 9 + 1.1.1. Description of the Document Set.............. 10 + 1.2. Approach to Extensibility............................. 11 + 1.2.1. Defining New AVP Values...................... 11 + 1.2.2. Creating New AVPs............................ 11 + 1.2.3. Creating New Authentication Applications..... 11 + 1.2.4. Creating New Accounting Applications......... 12 + 1.2.5. Application Authentication Procedures........ 14 + 1.3. Terminology........................................... 14 + 2. Protocol Overview............................................ 18 + 2.1. Transport............................................. 20 + 2.1.1. SCTP Guidelines.............................. 21 + 2.2. Securing Diameter Messages............................ 21 + 2.3. Diameter Application Compliance....................... 21 + 2.4. Application Identifiers............................... 22 + 2.5. Connections vs. Sessions.............................. 22 + 2.6. Peer Table............................................ 23 + 2.7. Realm-Based Routing Table............................. 24 + 2.8. Role of Diameter Agents............................... 25 + 2.8.1. Relay Agents................................. 26 + 2.8.2. Proxy Agents................................. 27 + 2.8.3. Redirect Agents.............................. 28 + 2.8.4. Translation Agents........................... 29 + 2.9. End-to-End Security Framework......................... 30 + 2.10. Diameter Path Authorization........................... 30 + 3. Diameter Header.............................................. 32 + 3.1. Command Codes......................................... 35 + 3.2. Command Code ABNF specification....................... 36 + 3.3. Diameter Command Naming Conventions................... 38 + 4. Diameter AVPs................................................ 38 + 4.1. AVP Header............................................ 39 + 4.1.1. Optional Header Elements..................... 41 + 4.2. Basic AVP Data Formats................................ 41 + 4.3. Derived AVP Data Formats.............................. 42 + 4.4. Grouped AVP Values.................................... 49 + 4.4.1. Example AVP with a Grouped Data Type......... 50 + 4.5. Diameter Base Protocol AVPs........................... 53 + 5. Diameter Peers............................................... 56 + 5.1. Peer Connections...................................... 56 + 5.2. Diameter Peer Discovery............................... 56 + 5.3. Capabilities Exchange................................. 59 + 5.3.1. Capabilities-Exchange-Request................ 60 + 5.3.2. Capabilities-Exchange-Answer................. 60 + 5.3.3. Vendor-Id AVP................................ 61 + 5.3.4. Firmware-Revision AVP........................ 61 + + + +Calhoun, et al. Standards Track [Page 2] + +RFC 3588 Diameter Based Protocol September 2003 + + + 5.3.5. Host-IP-Address AVP.......................... 62 + 5.3.6. Supported-Vendor-Id AVP...................... 62 + 5.3.7. Product-Name AVP............................. 62 + 5.4. Disconnecting Peer Connections........................ 62 + 5.4.1. Disconnect-Peer-Request...................... 63 + 5.4.2. Disconnect-Peer-Answer....................... 63 + 5.4.3. Disconnect-Cause AVP......................... 63 + 5.5. Transport Failure Detection........................... 64 + 5.5.1. Device-Watchdog-Request...................... 64 + 5.5.2. Device-Watchdog-Answer....................... 64 + 5.5.3. Transport Failure Algorithm.................. 65 + 5.5.4. Failover and Failback Procedures............. 65 + 5.6. Peer State Machine.................................... 66 + 5.6.1. Incoming connections......................... 68 + 5.6.2. Events....................................... 69 + 5.6.3. Actions...................................... 70 + 5.6.4. The Election Process......................... 71 + 6. Diameter Message Processing.................................. 71 + 6.1. Diameter Request Routing Overview..................... 71 + 6.1.1. Originating a Request........................ 73 + 6.1.2. Sending a Request............................ 73 + 6.1.3. Receiving Requests........................... 73 + 6.1.4. Processing Local Requests.................... 73 + 6.1.5. Request Forwarding........................... 74 + 6.1.6. Request Routing.............................. 74 + 6.1.7. Redirecting Requests......................... 74 + 6.1.8. Relaying and Proxying Requests............... 75 + 6.2. Diameter Answer Processing............................ 76 + 6.2.1. Processing Received Answers.................. 77 + 6.2.2. Relaying and Proxying Answers................ 77 + 6.3. Origin-Host AVP....................................... 77 + 6.4. Origin-Realm AVP...................................... 78 + 6.5. Destination-Host AVP.................................. 78 + 6.6. Destination-Realm AVP................................. 78 + 6.7. Routing AVPs.......................................... 78 + 6.7.1. Route-Record AVP............................. 79 + 6.7.2. Proxy-Info AVP............................... 79 + 6.7.3. Proxy-Host AVP............................... 79 + 6.7.4. Proxy-State AVP.............................. 79 + 6.8. Auth-Application-Id AVP............................... 79 + 6.9. Acct-Application-Id AVP............................... 79 + 6.10. Inband-Security-Id AVP................................ 79 + 6.11. Vendor-Specific-Application-Id AVP.................... 80 + 6.12. Redirect-Host AVP..................................... 80 + 6.13. Redirect-Host-Usage AVP............................... 80 + 6.14. Redirect-Max-Cache-Time AVP........................... 81 + 6.15. E2E-Sequence AVP...................................... 82 + + + + +Calhoun, et al. Standards Track [Page 3] + +RFC 3588 Diameter Based Protocol September 2003 + + + 7. Error Handling............................................... 82 + 7.1. Result-Code AVP....................................... 84 + 7.1.1. Informational................................ 84 + 7.1.2. Success...................................... 84 + 7.1.3. Protocol Errors.............................. 85 + 7.1.4. Transient Failures........................... 86 + 7.1.5. Permanent Failures........................... 86 + 7.2. Error Bit............................................. 88 + 7.3. Error-Message AVP..................................... 89 + 7.4. Error-Reporting-Host AVP.............................. 89 + 7.5. Failed-AVP AVP........................................ 89 + 7.6. Experimental-Result AVP............................... 90 + 7.7. Experimental-Result-Code AVP.......................... 90 + 8. Diameter User Sessions....................................... 90 + 8.1. Authorization Session State Machine................... 92 + 8.2. Accounting Session State Machine...................... 96 + 8.3. Server-Initiated Re-Auth.............................. 101 + 8.3.1. Re-Auth-Request.............................. 102 + 8.3.2. Re-Auth-Answer............................... 102 + 8.4. Session Termination................................... 103 + 8.4.1. Session-Termination-Request.................. 104 + 8.4.2. Session-Termination-Answer................... 105 + 8.5. Aborting a Session.................................... 105 + 8.5.1. Abort-Session-Request........................ 106 + 8.5.2. Abort-Session-Answer......................... 106 + 8.6. Inferring Session Termination from Origin-State-Id.... 107 + 8.7. Auth-Request-Type AVP................................. 108 + 8.8. Session-Id AVP........................................ 108 + 8.9. Authorization-Lifetime AVP............................ 109 + 8.10. Auth-Grace-Period AVP................................. 110 + 8.11. Auth-Session-State AVP................................ 110 + 8.12. Re-Auth-Request-Type AVP.............................. 110 + 8.13. Session-Timeout AVP................................... 111 + 8.14. User-Name AVP......................................... 111 + 8.15. Termination-Cause AVP................................. 111 + 8.16. Origin-State-Id AVP................................... 112 + 8.17. Session-Binding AVP................................... 113 + 8.18. Session-Server-Failover AVP........................... 113 + 8.19. Multi-Round-Time-Out AVP.............................. 114 + 8.20. Class AVP............................................. 114 + 8.21. Event-Timestamp AVP................................... 115 + 9. Accounting................................................... 115 + 9.1. Server Directed Model................................. 115 + 9.2. Protocol Messages..................................... 116 + 9.3. Application Document Requirements..................... 116 + 9.4. Fault Resilience...................................... 116 + 9.5. Accounting Records.................................... 117 + 9.6. Correlation of Accounting Records..................... 118 + + + +Calhoun, et al. Standards Track [Page 4] + +RFC 3588 Diameter Based Protocol September 2003 + + + 9.7. Accounting Command-Codes.............................. 119 + 9.7.1. Accounting-Request........................... 119 + 9.7.2. Accounting-Answer............................ 120 + 9.8. Accounting AVPs....................................... 121 + 9.8.1. Accounting-Record-Type AVP................... 121 + 9.8.2. Acct-Interim-Interval AVP.................... 122 + 9.8.3. Accounting-Record-Number AVP................. 123 + 9.8.4. Acct-Session-Id AVP.......................... 123 + 9.8.5. Acct-Multi-Session-Id AVP.................... 123 + 9.8.6. Accounting-Sub-Session-Id AVP................ 123 + 9.8.7. Accounting-Realtime-Required AVP............. 123 + 10. AVP Occurrence Table......................................... 124 + 10.1. Base Protocol Command AVP Table....................... 124 + 10.2. Accounting AVP Table.................................. 126 + 11. IANA Considerations.......................................... 127 + 11.1. AVP Header............................................ 127 + 11.1.1. AVP Code..................................... 127 + 11.1.2. AVP Flags.................................... 128 + 11.2. Diameter Header....................................... 128 + 11.2.1. Command Codes................................ 128 + 11.2.2. Command Flags................................ 129 + 11.3. Application Identifiers............................... 129 + 11.4. AVP Values............................................ 129 + 11.4.1. Result-Code AVP Values....................... 129 + 11.4.2. Accounting-Record-Type AVP Values............ 130 + 11.4.3. Termination-Cause AVP Values................. 130 + 11.4.4. Redirect-Host-Usage AVP Values............... 130 + 11.4.5. Session-Server-Failover AVP Values........... 130 + 11.4.6. Session-Binding AVP Values................... 130 + 11.4.7. Disconnect-Cause AVP Values.................. 130 + 11.4.8. Auth-Request-Type AVP Values................. 130 + 11.4.9. Auth-Session-State AVP Values................ 130 + 11.4.10. Re-Auth-Request-Type AVP Values.............. 131 + 11.4.11. Accounting-Realtime-Required AVP Values...... 131 + 11.5. Diameter TCP/SCTP Port Numbers........................ 131 + 11.6. NAPTR Service Fields.................................. 131 + 12. Diameter Protocol Related Configurable Parameters............ 131 + 13. Security Considerations...................................... 132 + 13.1. IPsec Usage........................................... 133 + 13.2. TLS Usage............................................. 134 + 13.3. Peer-to-Peer Considerations........................... 134 + 14. References................................................... 136 + 14.1. Normative References.................................. 136 + 14.2. Informative References................................ 138 + 15. Acknowledgements............................................. 140 + Appendix A. Diameter Service Template........................... 141 + Appendix B. NAPTR Example....................................... 142 + Appendix C. Duplicate Detection................................. 143 + + + +Calhoun, et al. Standards Track [Page 5] + +RFC 3588 Diameter Based Protocol September 2003 + + + Appendix D. Intellectual Property Statement..................... 145 + Authors' Addresses............................................... 146 + Full Copyright Statement......................................... 147 + +1. Introduction + + Authentication, Authorization and Accounting (AAA) protocols such as + TACACS [TACACS] and RADIUS [RADIUS] were initially deployed to + provide dial-up PPP [PPP] and terminal server access. Over time, + with the growth of the Internet and the introduction of new access + technologies, including wireless, DSL, Mobile IP and Ethernet, + routers and network access servers (NAS) have increased in complexity + and density, putting new demands on AAA protocols. + + Network access requirements for AAA protocols are summarized in + [AAAREQ]. These include: + + Failover + [RADIUS] does not define failover mechanisms, and as a result, + failover behavior differs between implementations. In order to + provide well defined failover behavior, Diameter supports + application-layer acknowledgements, and defines failover + algorithms and the associated state machine. This is described in + Section 5.5 and [AAATRANS]. + + Transmission-level security + [RADIUS] defines an application-layer authentication and integrity + scheme that is required only for use with Response packets. While + [RADEXT] defines an additional authentication and integrity + mechanism, use is only required during Extensible Authentication + Protocol (EAP) sessions. While attribute-hiding is supported, + [RADIUS] does not provide support for per-packet confidentiality. + In accounting, [RADACCT] assumes that replay protection is + provided by the backend billing server, rather than within the + protocol itself. + + While [RFC3162] defines the use of IPsec with RADIUS, support for + IPsec is not required. Since within [IKE] authentication occurs + only within Phase 1 prior to the establishment of IPsec SAs in + Phase 2, it is typically not possible to define separate trust or + authorization schemes for each application. This limits the + usefulness of IPsec in inter-domain AAA applications (such as + roaming) where it may be desirable to define a distinct + certificate hierarchy for use in a AAA deployment. In order to + provide universal support for transmission-level security, and + enable both intra- and inter-domain AAA deployments, IPsec support + is mandatory in Diameter, and TLS support is optional. Security + is discussed in Section 13. + + + +Calhoun, et al. Standards Track [Page 6] + +RFC 3588 Diameter Based Protocol September 2003 + + + Reliable transport + RADIUS runs over UDP, and does not define retransmission behavior; + as a result, reliability varies between implementations. As + described in [ACCMGMT], this is a major issue in accounting, where + packet loss may translate directly into revenue loss. In order to + provide well defined transport behavior, Diameter runs over + reliable transport mechanisms (TCP, SCTP) as defined in + [AAATRANS]. + + Agent support + [RADIUS] does not provide for explicit support for agents, + including Proxies, Redirects and Relays. Since the expected + behavior is not defined, it varies between implementations. + Diameter defines agent behavior explicitly; this is described in + Section 2.8. + + Server-initiated messages + While RADIUS server-initiated messages are defined in [DYNAUTH], + support is optional. This makes it difficult to implement + features such as unsolicited disconnect or + reauthentication/reauthorization on demand across a heterogeneous + deployment. Support for server-initiated messages is mandatory in + Diameter, and is described in Section 8. + + Auditability + RADIUS does not define data-object security mechanisms, and as a + result, untrusted proxies may modify attributes or even packet + headers without being detected. Combined with lack of support for + capabilities negotiation, this makes it very difficult to + determine what occurred in the event of a dispute. While + implementation of data object security is not mandatory within + Diameter, these capabilities are supported, and are described in + [AAACMS]. + + Transition support + While Diameter does not share a common protocol data unit (PDU) + with RADIUS, considerable effort has been expended in enabling + backward compatibility with RADIUS, so that the two protocols may + be deployed in the same network. Initially, it is expected that + Diameter will be deployed within new network devices, as well as + within gateways enabling communication between legacy RADIUS + devices and Diameter agents. This capability, described in + [NASREQ], enables Diameter support to be added to legacy networks, + by addition of a gateway or server speaking both RADIUS and + Diameter. + + + + + + +Calhoun, et al. Standards Track [Page 7] + +RFC 3588 Diameter Based Protocol September 2003 + + + In addition to addressing the above requirements, Diameter also + provides support for the following: + + Capability negotiation + RADIUS does not support error messages, capability negotiation, or + a mandatory/non-mandatory flag for attributes. Since RADIUS + clients and servers are not aware of each other's capabilities, + they may not be able to successfully negotiate a mutually + acceptable service, or in some cases, even be aware of what + service has been implemented. Diameter includes support for error + handling (Section 7), capability negotiation (Section 5.3), and + mandatory/non-mandatory attribute-value pairs (AVPs) (Section + 4.1). + + Peer discovery and configuration + RADIUS implementations typically require that the name or address + of servers or clients be manually configured, along with the + corresponding shared secrets. This results in a large + administrative burden, and creates the temptation to reuse the + RADIUS shared secret, which can result in major security + vulnerabilities if the Request Authenticator is not globally and + temporally unique as required in [RADIUS]. Through DNS, Diameter + enables dynamic discovery of peers. Derivation of dynamic session + keys is enabled via transmission-level security. + + Roaming support + The ROAMOPS WG provided a survey of roaming implementations + [ROAMREV], detailed roaming requirements [ROAMCRIT], defined the + Network Access Identifier (NAI) [NAI], and documented existing + implementations (and imitations) of RADIUS-based roaming + [PROXYCHAIN]. In order to improve scalability, [PROXYCHAIN] + introduced the concept of proxy chaining via an intermediate + server, facilitating roaming between providers. However, since + RADIUS does not provide explicit support for proxies, and lacks + auditability and transmission-level security features, RADIUS- + based roaming is vulnerable to attack from external parties as + well as susceptible to fraud perpetrated by the roaming partners + themselves. As a result, it is not suitable for wide-scale + deployment on the Internet [PROXYCHAIN]. By providing explicit + support for inter-domain roaming and message routing (Sections 2.7 + and 6), auditability [AAACMS], and transmission-layer security + (Section 13) features, Diameter addresses these limitations and + provides for secure and scalable roaming. + + In the decade since AAA protocols were first introduced, the + capabilities of Network Access Server (NAS) devices have increased + substantially. As a result, while Diameter is a considerably more + sophisticated protocol than RADIUS, it remains feasible to implement + + + +Calhoun, et al. Standards Track [Page 8] + +RFC 3588 Diameter Based Protocol September 2003 + + + within embedded devices, given improvements in processor speeds and + the widespread availability of embedded IPsec and TLS + implementations. + +1.1. Diameter Protocol + + The Diameter base protocol provides the following facilities: + + - Delivery of AVPs (attribute value pairs) + - Capabilities negotiation + - Error notification + - Extensibility, through addition of new commands and AVPs (required + in [AAAREQ]). + - Basic services necessary for applications, such as handling of + user sessions or accounting + + All data delivered by the protocol is in the form of an AVP. Some of + these AVP values are used by the Diameter protocol itself, while + others deliver data associated with particular applications that + employ Diameter. AVPs may be added arbitrarily to Diameter messages, + so long as the required AVPs are included and AVPs that are + explicitly excluded are not included. AVPs are used by the base + Diameter protocol to support the following required features: + + - Transporting of user authentication information, for the purposes + of enabling the Diameter server to authenticate the user. + + - Transporting of service specific authorization information, + between client and servers, allowing the peers to decide whether a + user's access request should be granted. + + - Exchanging resource usage information, which MAY be used for + accounting purposes, capacity planning, etc. + + - Relaying, proxying and redirecting of Diameter messages through a + server hierarchy. + + The Diameter base protocol provides the minimum requirements needed + for a AAA protocol, as required by [AAAREQ]. The base protocol may + be used by itself for accounting purposes only, or it may be used + with a Diameter application, such as Mobile IPv4 [DIAMMIP], or + network access [NASREQ]. It is also possible for the base protocol + to be extended for use in new applications, via the addition of new + commands or AVPs. At this time the focus of Diameter is network + access and accounting applications. A truly generic AAA protocol + used by many applications might provide functionality not provided by + Diameter. Therefore, it is imperative that the designers of new + applications understand their requirements before using Diameter. + + + +Calhoun, et al. Standards Track [Page 9] + +RFC 3588 Diameter Based Protocol September 2003 + + + See Section 2.4 for more information on Diameter applications. + + Any node can initiate a request. In that sense, Diameter is a peer- + to-peer protocol. In this document, a Diameter Client is a device at + the edge of the network that performs access control, such as a + Network Access Server (NAS) or a Foreign Agent (FA). A Diameter + client generates Diameter messages to request authentication, + authorization, and accounting services for the user. A Diameter + agent is a node that does not authenticate and/or authorize messages + locally; agents include proxies, redirects and relay agents. A + Diameter server performs authentication and/or authorization of the + user. A Diameter node MAY act as an agent for certain requests while + acting as a server for others. + + The Diameter protocol also supports server-initiated messages, such + as a request to abort service to a particular user. + +1.1.1. Description of the Document Set + + Currently, the Diameter specification consists of a base + specification (this document), Transport Profile [AAATRANS] and + applications: Mobile IPv4 [DIAMMIP], and NASREQ [NASREQ]. + + The Transport Profile document [AAATRANS] discusses transport layer + issues that arise with AAA protocols and recommendations on how to + overcome these issues. This document also defines the Diameter + failover algorithm and state machine. + + The Mobile IPv4 [DIAMMIP] application defines a Diameter application + that allows a Diameter server to perform AAA functions for Mobile + IPv4 services to a mobile node. + + The NASREQ [NASREQ] application defines a Diameter Application that + allows a Diameter server to be used in a PPP/SLIP Dial-Up and + Terminal Server Access environment. Consideration was given for + servers that need to perform protocol conversion between Diameter and + RADIUS. + + In summary, this document defines the base protocol specification for + AAA, which includes support for accounting. The Mobile IPv4 and the + NASREQ documents describe applications that use this base + specification for Authentication, Authorization and Accounting. + + + + + + + + + +Calhoun, et al. Standards Track [Page 10] + +RFC 3588 Diameter Based Protocol September 2003 + + +1.2. Approach to Extensibility + + The Diameter protocol is designed to be extensible, using several + mechanisms, including: + + - Defining new AVP values + - Creating new AVPs + - Creating new authentication/authorization applications + - Creating new accounting applications + - Application authentication procedures + + Reuse of existing AVP values, AVPs and Diameter applications are + strongly recommended. Reuse simplifies standardization and + implementation and avoids potential interoperability issues. It is + expected that command codes are reused; new command codes can only be + created by IETF Consensus (see Section 11.2.1). + +1.2.1. Defining New AVP Values + + New applications should attempt to reuse AVPs defined in existing + applications when possible, as opposed to creating new AVPs. For + AVPs of type Enumerated, an application may require a new value to + communicate some service-specific information. + + In order to allocate a new AVP value, a request MUST be sent to IANA + [IANA], along with an explanation of the new AVP value. IANA + considerations for Diameter are discussed in Section 11. + +1.2.2. Creating New AVPs + + When no existing AVP can be used, a new AVP should be created. The + new AVP being defined MUST use one of the data types listed in + Section 4.2. + + In the event that a logical grouping of AVPs is necessary, and + multiple "groups" are possible in a given command, it is recommended + that a Grouped AVP be used (see Section 4.4). + + In order to create a new AVP, a request MUST be sent to IANA, with a + specification for the AVP. The request MUST include the commands + that would make use of the AVP. + +1.2.3. Creating New Authentication Applications + + Every Diameter application specification MUST have an IANA assigned + Application Identifier (see Section 2.4) or a vendor specific + Application Identifier. + + + + +Calhoun, et al. Standards Track [Page 11] + +RFC 3588 Diameter Based Protocol September 2003 + + + Should a new Diameter usage scenario find itself unable to fit within + an existing application without requiring major changes to the + specification, it may be desirable to create a new Diameter + application. Major changes to an application include: + + - Adding new AVPs to the command, which have the "M" bit set. + + - Requiring a command that has a different number of round trips to + satisfy a request (e.g., application foo has a command that + requires one round trip, but new application bar has a command + that requires two round trips to complete). + + - Adding support for an authentication method requiring definition + of new AVPs for use with the application. Since a new EAP + authentication method can be supported within Diameter without + requiring new AVPs, addition of EAP methods does not require the + creation of a new authentication application. + + Creation of a new application should be viewed as a last resort. An + implementation MAY add arbitrary non-mandatory AVPs to any command + defined in an application, including vendor-specific AVPs without + needing to define a new application. Please refer to Section 11.1.1 + for details. + + In order to justify allocation of a new application identifier, + Diameter applications MUST define one Command Code, or add new + mandatory AVPs to the ABNF. + + The expected AVPs MUST be defined in an ABNF [ABNF] grammar (see + Section 3.2). If the Diameter application has accounting + requirements, it MUST also specify the AVPs that are to be present in + the Diameter Accounting messages (see Section 9.3). However, just + because a new authentication application id is required, does not + imply that a new accounting application id is required. + + When possible, a new Diameter application SHOULD reuse existing + Diameter AVPs, in order to avoid defining multiple AVPs that carry + similar information. + +1.2.4. Creating New Accounting Applications + + There are services that only require Diameter accounting. Such + services need to define the AVPs carried in the Accounting-Request + (ACR)/ Accounting-Answer (ACA) messages, but do not need to define + new command codes. An implementation MAY add arbitrary non-mandatory + AVPs (AVPs with the "M" bit not set) to any command defined in an + + + + + +Calhoun, et al. Standards Track [Page 12] + +RFC 3588 Diameter Based Protocol September 2003 + + + application, including vendor-specific AVPs, without needing to + define a new accounting application. Please refer to Section 11.1.1 + for details. + + Application Identifiers are still required for Diameter capability + exchange. Every Diameter accounting application specification MUST + have an IANA assigned Application Identifier (see Section 2.4) or a + vendor specific Application Identifier. + + Every Diameter implementation MUST support accounting. Basic + accounting support is sufficient to handle any application that uses + the ACR/ACA commands defined in this document, as long as no new + mandatory AVPs are added. A mandatory AVP is defined as one which + has the "M" bit set when sent within an accounting command, + regardless of whether it is required or optional within the ABNF for + the accounting application. + + The creation of a new accounting application should be viewed as a + last resort and MUST NOT be used unless a new command or additional + mechanisms (e.g., application defined state machine) is defined + within the application, or new mandatory AVPs are added to the ABNF. + + Within an accounting command, setting the "M" bit implies that a + backend server (e.g., billing server) or the accounting server itself + MUST understand the AVP in order to compute a correct bill. If the + AVP is not relevant to the billing process, when the AVP is included + within an accounting command, it MUST NOT have the "M" bit set, even + if the "M" bit is set when the same AVP is used within other Diameter + commands (i.e., authentication/authorization commands). + + A DIAMETER base accounting implementation MUST be configurable to + advertise supported accounting applications in order to prevent the + accounting server from accepting accounting requests for unbillable + services. The combination of the home domain and the accounting + application Id can be used in order to route the request to the + appropriate accounting server. + + When possible, a new Diameter accounting application SHOULD attempt + to reuse existing AVPs, in order to avoid defining multiple AVPs that + carry similar information. + + If the base accounting is used without any mandatory AVPs, new + commands or additional mechanisms (e.g., application defined state + machine), then the base protocol defined standard accounting + application Id (Section 2.4) MUST be used in ACR/ACA commands. + + + + + + +Calhoun, et al. Standards Track [Page 13] + +RFC 3588 Diameter Based Protocol September 2003 + + +1.2.5. Application Authentication Procedures + + When possible, applications SHOULD be designed such that new + authentication methods MAY be added without requiring changes to the + application. This MAY require that new AVP values be assigned to + represent the new authentication transform, or any other scheme that + produces similar results. When possible, authentication frameworks, + such as Extensible Authentication Protocol [EAP], SHOULD be used. + +1.3. Terminology + + AAA + Authentication, Authorization and Accounting. + + Accounting + The act of collecting information on resource usage for the + purpose of capacity planning, auditing, billing or cost + allocation. + + Accounting Record + An accounting record represents a summary of the resource + consumption of a user over the entire session. Accounting servers + creating the accounting record may do so by processing interim + accounting events or accounting events from several devices + serving the same user. + + Authentication + The act of verifying the identity of an entity (subject). + + Authorization + The act of determining whether a requesting entity (subject) will + be allowed access to a resource (object). + + AVP + The Diameter protocol consists of a header followed by one or more + Attribute-Value-Pairs (AVPs). An AVP includes a header and is + used to encapsulate protocol-specific data (e.g., routing + information) as well as authentication, authorization or + accounting information. + + Broker + A broker is a business term commonly used in AAA infrastructures. + A broker is either a relay, proxy or redirect agent, and MAY be + operated by roaming consortiums. Depending on the business model, + a broker may either choose to deploy relay agents or proxy + agents. + + + + + +Calhoun, et al. Standards Track [Page 14] + +RFC 3588 Diameter Based Protocol September 2003 + + + Diameter Agent + A Diameter Agent is a Diameter node that provides either relay, + proxy, redirect or translation services. + + Diameter Client + A Diameter Client is a device at the edge of the network that + performs access control. An example of a Diameter client is a + Network Access Server (NAS) or a Foreign Agent (FA). + + Diameter Node + A Diameter node is a host process that implements the Diameter + protocol, and acts either as a Client, Agent or Server. + + Diameter Peer + A Diameter Peer is a Diameter Node to which a given Diameter Node + has a direct transport connection. + + Diameter Security Exchange + A Diameter Security Exchange is a process through which two + Diameter nodes establish end-to-end security. + + Diameter Server + A Diameter Server is one that handles authentication, + authorization and accounting requests for a particular realm. By + its very nature, a Diameter Server MUST support Diameter + applications in addition to the base protocol. + + Downstream + Downstream is used to identify the direction of a particular + Diameter message from the home server towards the access device. + + End-to-End Security + TLS and IPsec provide hop-by-hop security, or security across a + transport connection. When relays or proxy are involved, this + hop-by-hop security does not protect the entire Diameter user + session. End-to-end security is security between two Diameter + nodes, possibly communicating through Diameter Agents. This + security protects the entire Diameter communications path from the + originating Diameter node to the terminating Diameter node. + + Home Realm + A Home Realm is the administrative domain with which the user + maintains an account relationship. + + Home Server + See Diameter Server. + + + + + +Calhoun, et al. Standards Track [Page 15] + +RFC 3588 Diameter Based Protocol September 2003 + + + Interim accounting + An interim accounting message provides a snapshot of usage during + a user's session. It is typically implemented in order to provide + for partial accounting of a user's session in the case of a device + reboot or other network problem prevents the reception of a + session summary message or session record. + + Local Realm + A local realm is the administrative domain providing services to a + user. An administrative domain MAY act as a local realm for + certain users, while being a home realm for others. + + Multi-session + A multi-session represents a logical linking of several sessions. + Multi-sessions are tracked by using the Acct-Multi-Session-Id. An + example of a multi-session would be a Multi-link PPP bundle. Each + leg of the bundle would be a session while the entire bundle would + be a multi-session. + + Network Access Identifier + The Network Access Identifier, or NAI [NAI], is used in the + Diameter protocol to extract a user's identity and realm. The + identity is used to identify the user during authentication and/or + authorization, while the realm is used for message routing + purposes. + + Proxy Agent or Proxy + In addition to forwarding requests and responses, proxies make + policy decisions relating to resource usage and provisioning. + This is typically accomplished by tracking the state of NAS + devices. While proxies typically do not respond to client + Requests prior to receiving a Response from the server, they may + originate Reject messages in cases where policies are violated. + As a result, proxies need to understand the semantics of the + messages passing through them, and may not support all Diameter + applications. + + Realm + The string in the NAI that immediately follows the '@' character. + NAI realm names are required to be unique, and are piggybacked on + the administration of the DNS namespace. Diameter makes use of + the realm, also loosely referred to as domain, to determine + whether messages can be satisfied locally, or whether they must be + routed or redirected. In RADIUS, realm names are not necessarily + piggybacked on the DNS namespace but may be independent of it. + + + + + + +Calhoun, et al. Standards Track [Page 16] + +RFC 3588 Diameter Based Protocol September 2003 + + + Real-time Accounting + Real-time accounting involves the processing of information on + resource usage within a defined time window. Time constraints are + typically imposed in order to limit financial risk. + + Relay Agent or Relay + Relays forward requests and responses based on routing-related + AVPs and realm routing table entries. Since relays do not make + policy decisions, they do not examine or alter non-routing AVPs. + As a result, relays never originate messages, do not need to + understand the semantics of messages or non-routing AVPs, and are + capable of handling any Diameter application or message type. + Since relays make decisions based on information in routing AVPs + and realm forwarding tables they do not keep state on NAS resource + usage or sessions in progress. + + Redirect Agent + Rather than forwarding requests and responses between clients and + servers, redirect agents refer clients to servers and allow them + to communicate directly. Since redirect agents do not sit in the + forwarding path, they do not alter any AVPs transiting between + client and server. Redirect agents do not originate messages and + are capable of handling any message type, although they may be + configured only to redirect messages of certain types, while + acting as relay or proxy agents for other types. As with proxy + agents, redirect agents do not keep state with respect to sessions + or NAS resources. + + Roaming Relationships + Roaming relationships include relationships between companies and + ISPs, relationships among peer ISPs within a roaming consortium, + and relationships between an ISP and a roaming consortium. + + Security Association + A security association is an association between two endpoints in + a Diameter session which allows the endpoints to communicate with + integrity and confidentially, even in the presence of relays + and/or proxies. + + Session + A session is a related progression of events devoted to a + particular activity. Each application SHOULD provide guidelines + as to when a session begins and ends. All Diameter packets with + the same Session-Identifier are considered to be part of the same + session. + + + + + + +Calhoun, et al. Standards Track [Page 17] + +RFC 3588 Diameter Based Protocol September 2003 + + + Session state + A stateful agent is one that maintains session state information, + by keeping track of all authorized active sessions. Each + authorized session is bound to a particular service, and its state + is considered active either until it is notified otherwise, or by + expiration. + + Sub-session + A sub-session represents a distinct service (e.g., QoS or data + characteristics) provided to a given session. These services may + happen concurrently (e.g., simultaneous voice and data transfer + during the same session) or serially. These changes in sessions + are tracked with the Accounting-Sub-Session-Id. + + Transaction state + The Diameter protocol requires that agents maintain transaction + state, which is used for failover purposes. Transaction state + implies that upon forwarding a request, the Hop-by-Hop identifier + is saved; the field is replaced with a locally unique identifier, + which is restored to its original value when the corresponding + answer is received. The request's state is released upon receipt + of the answer. A stateless agent is one that only maintains + transaction state. + + Translation Agent + A translation agent is a stateful Diameter node that performs + protocol translation between Diameter and another AAA protocol, + such as RADIUS. + + Transport Connection + A transport connection is a TCP or SCTP connection existing + directly between two Diameter peers, otherwise known as a Peer- + to-Peer Connection. + + Upstream + Upstream is used to identify the direction of a particular + Diameter message from the access device towards the home server. + + User + The entity requesting or using some resource, in support of which + a Diameter client has generated a request. + +2. Protocol Overview + + The base Diameter protocol may be used by itself for accounting + applications, but for use in authentication and authorization it is + always extended for a particular application. Two Diameter + applications are defined by companion documents: NASREQ [NASREQ], + + + +Calhoun, et al. Standards Track [Page 18] + +RFC 3588 Diameter Based Protocol September 2003 + + + Mobile IPv4 [DIAMMIP]. These applications are introduced in this + document but specified elsewhere. Additional Diameter applications + MAY be defined in the future (see Section 11.3). + + Diameter Clients MUST support the base protocol, which includes + accounting. In addition, they MUST fully support each Diameter + application that is needed to implement the client's service, e.g., + NASREQ and/or Mobile IPv4. A Diameter Client that does not support + both NASREQ and Mobile IPv4, MUST be referred to as "Diameter X + Client" where X is the application which it supports, and not a + "Diameter Client". + + Diameter Servers MUST support the base protocol, which includes + accounting. In addition, they MUST fully support each Diameter + application that is needed to implement the intended service, e.g., + NASREQ and/or Mobile IPv4. A Diameter Server that does not support + both NASREQ and Mobile IPv4, MUST be referred to as "Diameter X + Server" where X is the application which it supports, and not a + "Diameter Server". + + Diameter Relays and redirect agents are, by definition, protocol + transparent, and MUST transparently support the Diameter base + protocol, which includes accounting, and all Diameter applications. + + Diameter proxies MUST support the base protocol, which includes + accounting. In addition, they MUST fully support each Diameter + application that is needed to implement proxied services, e.g., + NASREQ and/or Mobile IPv4. A Diameter proxy which does not support + also both NASREQ and Mobile IPv4, MUST be referred to as "Diameter X + Proxy" where X is the application which it supports, and not a + "Diameter Proxy". + + The base Diameter protocol concerns itself with capabilities + negotiation, how messages are sent and how peers may eventually be + abandoned. The base protocol also defines certain rules that apply + to all exchanges of messages between Diameter nodes. + + Communication between Diameter peers begins with one peer sending a + message to another Diameter peer. The set of AVPs included in the + message is determined by a particular Diameter application. One AVP + that is included to reference a user's session is the Session-Id. + + The initial request for authentication and/or authorization of a user + would include the Session-Id. The Session-Id is then used in all + subsequent messages to identify the user's session (see Section 8 for + more information). The communicating party may accept the request, + or reject it by returning an answer message with the Result-Code AVP + + + + +Calhoun, et al. Standards Track [Page 19] + +RFC 3588 Diameter Based Protocol September 2003 + + + set to indicate an error occurred. The specific behavior of the + Diameter server or client receiving a request depends on the Diameter + application employed. + + Session state (associated with a Session-Id) MUST be freed upon + receipt of the Session-Termination-Request, Session-Termination- + Answer, expiration of authorized service time in the Session-Timeout + AVP, and according to rules established in a particular Diameter + application. + +2.1. Transport + + Transport profile is defined in [AAATRANS]. + + The base Diameter protocol is run on port 3868 of both TCP [TCP] and + SCTP [SCTP] transport protocols. + + Diameter clients MUST support either TCP or SCTP, while agents and + servers MUST support both. Future versions of this specification MAY + mandate that clients support SCTP. + + A Diameter node MAY initiate connections from a source port other + than the one that it declares it accepts incoming connections on, and + MUST be prepared to receive connections on port 3868. A given + Diameter instance of the peer state machine MUST NOT use more than + one transport connection to communicate with a given peer, unless + multiple instances exist on the peer in which case a separate + connection per process is allowed. + + When no transport connection exists with a peer, an attempt to + connect SHOULD be periodically made. This behavior is handled via + the Tc timer, whose recommended value is 30 seconds. There are + certain exceptions to this rule, such as when a peer has terminated + the transport connection stating that it does not wish to + communicate. + + When connecting to a peer and either zero or more transports are + specified, SCTP SHOULD be tried first, followed by TCP. See Section + 5.2 for more information on peer discovery. + + Diameter implementations SHOULD be able to interpret ICMP protocol + port unreachable messages as explicit indications that the server is + not reachable, subject to security policy on trusting such messages. + Diameter implementations SHOULD also be able to interpret a reset + from the transport and timed-out connection attempts. + + + + + + +Calhoun, et al. Standards Track [Page 20] + +RFC 3588 Diameter Based Protocol September 2003 + + + If Diameter receives data up from TCP that cannot be parsed or + identified as a Diameter error made by the peer, the stream is + compromised and cannot be recovered. The transport connection MUST + be closed using a RESET call (send a TCP RST bit) or an SCTP ABORT + message (graceful closure is compromised). + +2.1.1. SCTP Guidelines + + The following are guidelines for Diameter implementations that + support SCTP: + + 1. For interoperability: All Diameter nodes MUST be prepared to + receive Diameter messages on any SCTP stream in the association. + + 2. To prevent blocking: All Diameter nodes SHOULD utilize all SCTP + streams available to the association to prevent head-of-the-line + blocking. + +2.2. Securing Diameter Messages + + Diameter clients, such as Network Access Servers (NASes) and Mobility + Agents MUST support IP Security [SECARCH], and MAY support TLS [TLS]. + Diameter servers MUST support TLS and IPsec. The Diameter protocol + MUST NOT be used without any security mechanism (TLS or IPsec). + + It is suggested that IPsec can be used primarily at the edges and in + intra-domain traffic, such as using pre-shared keys between a NAS a + local AAA proxy. This also eases the requirements on the NAS to + support certificates. It is also suggested that inter-domain traffic + would primarily use TLS. See Sections 13.1 and 13.2 for more details + on IPsec and TLS usage. + +2.3. Diameter Application Compliance + + Application Identifiers are advertised during the capabilities + exchange phase (see Section 5.3). For a given application, + advertising support of an application implies that the sender + supports all command codes, and the AVPs specified in the associated + ABNFs, described in the specification. + + An implementation MAY add arbitrary non-mandatory AVPs to any command + defined in an application, including vendor-specific AVPs. Please + refer to Section 11.1.1 for details. + + + + + + + + +Calhoun, et al. Standards Track [Page 21] + +RFC 3588 Diameter Based Protocol September 2003 + + +2.4. Application Identifiers + + Each Diameter application MUST have an IANA assigned Application + Identifier (see Section 11.3). The base protocol does not require an + Application Identifier since its support is mandatory. During the + capabilities exchange, Diameter nodes inform their peers of locally + supported applications. Furthermore, all Diameter messages contain + an Application Identifier, which is used in the message forwarding + process. + + The following Application Identifier values are defined: + + Diameter Common Messages 0 + NASREQ 1 [NASREQ] + Mobile-IP 2 [DIAMMIP] + Diameter Base Accounting 3 + Relay 0xffffffff + + Relay and redirect agents MUST advertise the Relay Application + Identifier, while all other Diameter nodes MUST advertise locally + supported applications. The receiver of a Capabilities Exchange + message advertising Relay service MUST assume that the sender + supports all current and future applications. + + Diameter relay and proxy agents are responsible for finding an + upstream server that supports the application of a particular + message. If none can be found, an error message is returned with the + Result-Code AVP set to DIAMETER_UNABLE_TO_DELIVER. + +2.5. Connections vs. Sessions + + This section attempts to provide the reader with an understanding of + the difference between connection and session, which are terms used + extensively throughout this document. + + A connection is a transport level connection between two peers, used + to send and receive Diameter messages. A session is a logical + concept at the application layer, and is shared between an access + device and a server, and is identified via the Session-Id AVP + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 22] + +RFC 3588 Diameter Based Protocol September 2003 + + + +--------+ +-------+ +--------+ + | Client | | Relay | | Server | + +--------+ +-------+ +--------+ + <----------> <----------> + peer connection A peer connection B + + <-----------------------------> + User session x + + Figure 1: Diameter connections and sessions + + In the example provided in Figure 1, peer connection A is established + between the Client and its local Relay. Peer connection B is + established between the Relay and the Server. User session X spans + from the Client via the Relay to the Server. Each "user" of a + service causes an auth request to be sent, with a unique session + identifier. Once accepted by the server, both the client and the + server are aware of the session. It is important to note that there + is no relationship between a connection and a session, and that + Diameter messages for multiple sessions are all multiplexed through a + single connection. + +2.6. Peer Table + + The Diameter Peer Table is used in message forwarding, and referenced + by the Realm Routing Table. A Peer Table entry contains the + following fields: + + Host identity + Following the conventions described for the DiameterIdentity + derived AVP data format in Section 4.4. This field contains the + contents of the Origin-Host (Section 6.3) AVP found in the CER or + CEA message. + + StatusT + This is the state of the peer entry, and MUST match one of the + values listed in Section 5.6. + + Static or Dynamic + Specifies whether a peer entry was statically configured, or + dynamically discovered. + + Expiration time + Specifies the time at which dynamically discovered peer table + entries are to be either refreshed, or expired. + + + + + + +Calhoun, et al. Standards Track [Page 23] + +RFC 3588 Diameter Based Protocol September 2003 + + + TLS Enabled + Specifies whether TLS is to be used when communicating with the + peer. + + Additional security information, when needed (e.g., keys, + certificates) + +2.7. Realm-Based Routing Table + + All Realm-Based routing lookups are performed against what is + commonly known as the Realm Routing Table (see Section 12). A Realm + Routing Table Entry contains the following fields: + + Realm Name + This is the field that is typically used as a primary key in the + routing table lookups. Note that some implementations perform + their lookups based on longest-match-from-the-right on the realm + rather than requiring an exact match. + + Application Identifier + An application is identified by a vendor id and an application id. + For all IETF standards track Diameter applications, the vendor id + is zero. A route entry can have a different destination based on + the application identification AVP of the message. This field + MUST be used as a secondary key field in routing table lookups. + + Local Action + The Local Action field is used to identify how a message should be + treated. The following actions are supported: + + 1. LOCAL - Diameter messages that resolve to a route entry with + the Local Action set to Local can be satisfied locally, and do + not need to be routed to another server. + + 2. RELAY - All Diameter messages that fall within this category + MUST be routed to a next hop server, without modifying any + non-routing AVPs. See Section 6.1.8 for relaying guidelines + + 3. PROXY - All Diameter messages that fall within this category + MUST be routed to a next hop server. The local server MAY + apply its local policies to the message by including new AVPs + to the message prior to routing. See Section 6.1.8 for + proxying guidelines. + + 4. REDIRECT - Diameter messages that fall within this category + MUST have the identity of the home Diameter server(s) appended, + and returned to the sender of the message. See Section 6.1.7 + for redirect guidelines. + + + +Calhoun, et al. Standards Track [Page 24] + +RFC 3588 Diameter Based Protocol September 2003 + + + Server Identifier + One or more servers the message is to be routed to. These servers + MUST also be present in the Peer table. When the Local Action is + set to RELAY or PROXY, this field contains the identity of the + server(s) the message must be routed to. When the Local Action + field is set to REDIRECT, this field contains the identity of one + or more servers the message should be redirected to. + + Static or Dynamic + Specifies whether a route entry was statically configured, or + dynamically discovered. + + Expiration time + Specifies the time which a dynamically discovered route table + entry expires. + + It is important to note that Diameter agents MUST support at least + one of the LOCAL, RELAY, PROXY or REDIRECT modes of operation. + Agents do not need to support all modes of operation in order to + conform with the protocol specification, but MUST follow the protocol + compliance guidelines in Section 2. Relay agents MUST NOT reorder + AVPs, and proxies MUST NOT reorder AVPs. + + The routing table MAY include a default entry that MUST be used for + any requests not matching any of the other entries. The routing + table MAY consist of only such an entry. + + When a request is routed, the target server MUST have advertised the + Application Identifier (see Section 2.4) for the given message, or + have advertised itself as a relay or proxy agent. Otherwise, an + error is returned with the Result-Code AVP set to + DIAMETER_UNABLE_TO_DELIVER. + +2.8. Role of Diameter Agents + + In addition to client and servers, the Diameter protocol introduces + relay, proxy, redirect, and translation agents, each of which is + defined in Section 1.3. These Diameter agents are useful for several + reasons: + + - They can distribute administration of systems to a configurable + grouping, including the maintenance of security associations. + + - They can be used for concentration of requests from an number of + co-located or distributed NAS equipment sets to a set of like user + groups. + + - They can do value-added processing to the requests or responses. + + + +Calhoun, et al. Standards Track [Page 25] + +RFC 3588 Diameter Based Protocol September 2003 + + + - They can be used for load balancing. + + - A complex network will have multiple authentication sources, they + can sort requests and forward towards the correct target. + + The Diameter protocol requires that agents maintain transaction + state, which is used for failover purposes. Transaction state + implies that upon forwarding a request, its Hop-by-Hop identifier is + saved; the field is replaced with a locally unique identifier, which + is restored to its original value when the corresponding answer is + received. The request's state is released upon receipt of the + answer. A stateless agent is one that only maintains transaction + state. + + The Proxy-Info AVP allows stateless agents to add local state to a + Diameter request, with the guarantee that the same state will be + present in the answer. However, the protocol's failover procedures + require that agents maintain a copy of pending requests. + + A stateful agent is one that maintains session state information; by + keeping track of all authorized active sessions. Each authorized + session is bound to a particular service, and its state is considered + active either until it is notified otherwise, or by expiration. Each + authorized session has an expiration, which is communicated by + Diameter servers via the Session-Timeout AVP. + + Maintaining session state MAY be useful in certain applications, such + as: + + - Protocol translation (e.g., RADIUS <-> Diameter) + + - Limiting resources authorized to a particular user + + - Per user or transaction auditing + + A Diameter agent MAY act in a stateful manner for some requests and + be stateless for others. A Diameter implementation MAY act as one + type of agent for some requests, and as another type of agent for + others. + +2.8.1. Relay Agents + + Relay Agents are Diameter agents that accept requests and route + messages to other Diameter nodes based on information found in the + messages (e.g., Destination-Realm). This routing decision is + performed using a list of supported realms, and known peers. This is + known as the Realm Routing Table, as is defined further in Section + 2.7. + + + +Calhoun, et al. Standards Track [Page 26] + +RFC 3588 Diameter Based Protocol September 2003 + + + Relays MAY be used to aggregate requests from multiple Network Access + Servers (NASes) within a common geographical area (POP). The use of + Relays is advantageous since it eliminates the need for NASes to be + configured with the necessary security information they would + otherwise require to communicate with Diameter servers in other + realms. Likewise, this reduces the configuration load on Diameter + servers that would otherwise be necessary when NASes are added, + changed or deleted. + + Relays modify Diameter messages by inserting and removing routing + information, but do not modify any other portion of a message. + Relays SHOULD NOT maintain session state but MUST maintain + transaction state. + + +------+ ---------> +------+ ---------> +------+ + | | 1. Request | | 2. Request | | + | NAS | | DRL | | HMS | + | | 4. Answer | | 3. Answer | | + +------+ <--------- +------+ <--------- +------+ + example.net example.net example.com + + Figure 2: Relaying of Diameter messages + + The example provided in Figure 2 depicts a request issued from NAS, + which is an access device, for the user [email protected]. Prior to + issuing the request, NAS performs a Diameter route lookup, using + "example.com" as the key, and determines that the message is to be + relayed to DRL, which is a Diameter Relay. DRL performs the same + route lookup as NAS, and relays the message to HMS, which is + example.com's Home Diameter Server. HMS identifies that the request + can be locally supported (via the realm), processes the + authentication and/or authorization request, and replies with an + answer, which is routed back to NAS using saved transaction state. + + Since Relays do not perform any application level processing, they + provide relaying services for all Diameter applications, and + therefore MUST advertise the Relay Application Identifier. + +2.8.2. Proxy Agents + + Similarly to relays, proxy agents route Diameter messages using the + Diameter Routing Table. However, they differ since they modify + messages to implement policy enforcement. This requires that proxies + maintain the state of their downstream peers (e.g., access devices) + to enforce resource usage, provide admission control, and + provisioning. + + + + + +Calhoun, et al. Standards Track [Page 27] + +RFC 3588 Diameter Based Protocol September 2003 + + + It is important to note that although proxies MAY provide a value-add + function for NASes, they do not allow access devices to use end-to- + end security, since modifying messages breaks authentication. + + Proxies MAY be used in call control centers or access ISPs that + provide outsourced connections, they can monitor the number and types + of ports in use, and make allocation and admission decisions + according to their configuration. + + Proxies that wish to limit resources MUST maintain session state. + All proxies MUST maintain transaction state. + + Since enforcing policies requires an understanding of the service + being provided, Proxies MUST only advertise the Diameter applications + they support. + +2.8.3. Redirect Agents + + Redirect agents are useful in scenarios where the Diameter routing + configuration needs to be centralized. An example is a redirect + agent that provides services to all members of a consortium, but does + not wish to be burdened with relaying all messages between realms. + This scenario is advantageous since it does not require that the + consortium provide routing updates to its members when changes are + made to a member's infrastructure. + + Since redirect agents do not relay messages, and only return an + answer with the information necessary for Diameter agents to + communicate directly, they do not modify messages. Since redirect + agents do not receive answer messages, they cannot maintain session + state. Further, since redirect agents never relay requests, they are + not required to maintain transaction state. + + The example provided in Figure 3 depicts a request issued from the + access device, NAS, for the user [email protected]. The message is + forwarded by the NAS to its relay, DRL, which does not have a routing + entry in its Diameter Routing Table for example.com. DRL has a + default route configured to DRD, which is a redirect agent that + returns a redirect notification to DRL, as well as HMS' contact + information. Upon receipt of the redirect notification, DRL + establishes a transport connection with HMS, if one doesn't already + exist, and forwards the request to it. + + + + + + + + + +Calhoun, et al. Standards Track [Page 28] + +RFC 3588 Diameter Based Protocol September 2003 + + + +------+ + | | + | DRD | + | | + +------+ + ^ | + 2. Request | | 3. Redirection + | | Notification + | v + +------+ ---------> +------+ ---------> +------+ + | | 1. Request | | 4. Request | | + | NAS | | DRL | | HMS | + | | 6. Answer | | 5. Answer | | + +------+ <--------- +------+ <--------- +------+ + example.net example.net example.com + + Figure 3: Redirecting a Diameter Message + + Since redirect agents do not perform any application level + processing, they provide relaying services for all Diameter + applications, and therefore MUST advertise the Relay Application + Identifier. + +2.8.4. Translation Agents + + A translation agent is a device that provides translation between two + protocols (e.g., RADIUS<->Diameter, TACACS+<->Diameter). Translation + agents are likely to be used as aggregation servers to communicate + with a Diameter infrastructure, while allowing for the embedded + systems to be migrated at a slower pace. + + Given that the Diameter protocol introduces the concept of long-lived + authorized sessions, translation agents MUST be session stateful and + MUST maintain transaction state. + + Translation of messages can only occur if the agent recognizes the + application of a particular request, and therefore translation agents + MUST only advertise their locally supported applications. + + +------+ ---------> +------+ ---------> +------+ + | | RADIUS Request | | Diameter Request | | + | NAS | | TLA | | HMS | + | | RADIUS Answer | | Diameter Answer | | + +------+ <--------- +------+ <--------- +------+ + example.net example.net example.com + + Figure 4: Translation of RADIUS to Diameter + + + + +Calhoun, et al. Standards Track [Page 29] + +RFC 3588 Diameter Based Protocol September 2003 + + +2.9. End-to-End Security Framework + + End-to-end security services include confidentiality and message + origin authentication. These services are provided by supporting AVP + integrity and confidentiality between two peers, communicating + through agents. + + End-to-end security is provided via the End-to-End security + extension, described in [AAACMS]. The circumstances requiring the + use of end-to-end security are determined by policy on each of the + peers. Security policies, which are not the subject of + standardization, may be applied by next hop Diameter peer or by + destination realm. For example, where TLS or IPsec transmission- + level security is sufficient, there may be no need for end-to-end + security. + + End-to-end security policies include: + + - Never use end-to-end security. + + - Use end-to-end security on messages containing sensitive AVPs. + Which AVPs are sensitive is determined by service provider policy. + AVPs containing keys and passwords should be considered sensitive. + Accounting AVPs may be considered sensitive. Any AVP for which + the P bit may be set or which may be encrypted may be considered + sensitive. + + - Always use end-to-end security. + + It is strongly RECOMMENDED that all Diameter implementations support + end-to-end security. + +2.10. Diameter Path Authorization + + As noted in Section 2.2, Diameter requires transmission level + security to be used on each connection (TLS or IPsec). Therefore, + each connection is authenticated, replay and integrity protected and + confidential on a per-packet basis. + + In addition to authenticating each connection, each connection as + well as the entire session MUST also be authorized. Before + initiating a connection, a Diameter Peer MUST check that its peers + are authorized to act in their roles. For example, a Diameter peer + may be authentic, but that does not mean that it is authorized to act + as a Diameter Server advertising a set of Diameter applications. + + + + + + +Calhoun, et al. Standards Track [Page 30] + +RFC 3588 Diameter Based Protocol September 2003 + + + Prior to bringing up a connection, authorization checks are performed + at each connection along the path. Diameter capabilities negotiation + (CER/CEA) also MUST be carried out, in order to determine what + Diameter applications are supported by each peer. Diameter sessions + MUST be routed only through authorized nodes that have advertised + support for the Diameter application required by the session. + + As noted in Section 6.1.8, a relay or proxy agent MUST append a + Route-Record AVP to all requests forwarded. The AVP contains the + identity of the peer the request was received from. + + The home Diameter server, prior to authorizing a session, MUST check + the Route-Record AVPs to make sure that the route traversed by the + request is acceptable. For example, administrators within the home + realm may not wish to honor requests that have been routed through an + untrusted realm. By authorizing a request, the home Diameter server + is implicitly indicating its willingness to engage in the business + transaction as specified by the contractual relationship between the + server and the previous hop. A DIAMETER_AUTHORIZATION_REJECTED error + message (see Section 7.1.5) is sent if the route traversed by the + request is unacceptable. + + A home realm may also wish to check that each accounting request + message corresponds to a Diameter response authorizing the session. + Accounting requests without corresponding authorization responses + SHOULD be subjected to further scrutiny, as should accounting + requests indicating a difference between the requested and provided + service. + + Similarly, the local Diameter agent, on receiving a Diameter response + authorizing a session, MUST check the Route-Record AVPs to make sure + that the route traversed by the response is acceptable. At each + step, forwarding of an authorization response is considered evidence + of a willingness to take on financial risk relative to the session. + A local realm may wish to limit this exposure, for example, by + establishing credit limits for intermediate realms and refusing to + accept responses which would violate those limits. By issuing an + accounting request corresponding to the authorization response, the + local realm implicitly indicates its agreement to provide the service + indicated in the authorization response. If the service cannot be + provided by the local realm, then a DIAMETER_UNABLE_TO_COMPLY error + message MUST be sent within the accounting request; a Diameter client + receiving an authorization response for a service that it cannot + perform MUST NOT substitute an alternate service, and then send + accounting requests for the alternate service instead. + + + + + + +Calhoun, et al. Standards Track [Page 31] + +RFC 3588 Diameter Based Protocol September 2003 + + +3. Diameter Header + + A summary of the Diameter header format is shown below. The fields + are transmitted in network byte order. + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Version | Message Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | command flags | Command-Code | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Application-ID | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Hop-by-Hop Identifier | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | End-to-End Identifier | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AVPs ... + +-+-+-+-+-+-+-+-+-+-+-+-+- + + Version + This Version field MUST be set to 1 to indicate Diameter Version + 1. + + Message Length + The Message Length field is three octets and indicates the length + of the Diameter message including the header fields. + + Command Flags + The Command Flags field is eight bits. The following bits are + assigned: + + 0 1 2 3 4 5 6 7 + +-+-+-+-+-+-+-+-+ + |R P E T r r r r| + +-+-+-+-+-+-+-+-+ + + R(equest) - If set, the message is a request. If cleared, the + message is an answer. + P(roxiable) - If set, the message MAY be proxied, relayed or + redirected. If cleared, the message MUST be + locally processed. + E(rror) - If set, the message contains a protocol error, + and the message will not conform to the ABNF + described for this command. Messages with the 'E' + + + + + +Calhoun, et al. Standards Track [Page 32] + +RFC 3588 Diameter Based Protocol September 2003 + + + bit set are commonly referred to as error + messages. This bit MUST NOT be set in request + messages. See Section 7.2. + T(Potentially re-transmitted message) + - This flag is set after a link failover procedure, + to aid the removal of duplicate requests. It is + set when resending requests not yet acknowledged, + as an indication of a possible duplicate due to a + link failure. This bit MUST be cleared when + sending a request for the first time, otherwise + the sender MUST set this flag. Diameter agents + only need to be concerned about the number of + requests they send based on a single received + request; retransmissions by other entities need + not be tracked. Diameter agents that receive a + request with the T flag set, MUST keep the T flag + set in the forwarded request. This flag MUST NOT + be set if an error answer message (e.g., a + protocol error) has been received for the earlier + message. It can be set only in cases where no + answer has been received from the server for a + request and the request is sent again. This flag + MUST NOT be set in answer messages. + + r(eserved) - these flag bits are reserved for future use, and + MUST be set to zero, and ignored by the receiver. + + Command-Code + The Command-Code field is three octets, and is used in order to + communicate the command associated with the message. The 24-bit + address space is managed by IANA (see Section 11.2.1). + + Command-Code values 16,777,214 and 16,777,215 (hexadecimal values + FFFFFE -FFFFFF) are reserved for experimental use (See Section + 11.3). + + Application-ID + Application-ID is four octets and is used to identify to which + application the message is applicable for. The application can be + an authentication application, an accounting application or a + vendor specific application. See Section 11.3 for the possible + values that the application-id may use. + + The application-id in the header MUST be the same as what is + contained in any relevant AVPs contained in the message. + + + + + + +Calhoun, et al. Standards Track [Page 33] + +RFC 3588 Diameter Based Protocol September 2003 + + + Hop-by-Hop Identifier + The Hop-by-Hop Identifier is an unsigned 32-bit integer field (in + network byte order) and aids in matching requests and replies. + The sender MUST ensure that the Hop-by-Hop identifier in a request + is unique on a given connection at any given time, and MAY attempt + to ensure that the number is unique across reboots. The sender of + an Answer message MUST ensure that the Hop-by-Hop Identifier field + contains the same value that was found in the corresponding + request. The Hop-by-Hop identifier is normally a monotonically + increasing number, whose start value was randomly generated. An + answer message that is received with an unknown Hop-by-Hop + Identifier MUST be discarded. + + End-to-End Identifier + The End-to-End Identifier is an unsigned 32-bit integer field (in + network byte order) and is used to detect duplicate messages. + Upon reboot implementations MAY set the high order 12 bits to + contain the low order 12 bits of current time, and the low order + 20 bits to a random value. Senders of request messages MUST + insert a unique identifier on each message. The identifier MUST + remain locally unique for a period of at least 4 minutes, even + across reboots. The originator of an Answer message MUST ensure + that the End-to-End Identifier field contains the same value that + was found in the corresponding request. The End-to-End Identifier + MUST NOT be modified by Diameter agents of any kind. The + combination of the Origin-Host (see Section 6.3) and this field is + used to detect duplicates. Duplicate requests SHOULD cause the + same answer to be transmitted (modulo the hop-by-hop Identifier + field and any routing AVPs that may be present), and MUST NOT + affect any state that was set when the original request was + processed. Duplicate answer messages that are to be locally + consumed (see Section 6.2) SHOULD be silently discarded. + + AVPs + AVPs are a method of encapsulating information relevant to the + Diameter message. See Section 4 for more information on AVPs. + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 34] + +RFC 3588 Diameter Based Protocol September 2003 + + +3.1. Command Codes + + Each command Request/Answer pair is assigned a command code, and the + sub-type (i.e., request or answer) is identified via the 'R' bit in + the Command Flags field of the Diameter header. + + Every Diameter message MUST contain a command code in its header's + Command-Code field, which is used to determine the action that is to + be taken for a particular message. The following Command Codes are + defined in the Diameter base protocol: + + Command-Name Abbrev. Code Reference + -------------------------------------------------------- + Abort-Session-Request ASR 274 8.5.1 + Abort-Session-Answer ASA 274 8.5.2 + Accounting-Request ACR 271 9.7.1 + Accounting-Answer ACA 271 9.7.2 + Capabilities-Exchange- CER 257 5.3.1 + Request + Capabilities-Exchange- CEA 257 5.3.2 + Answer + Device-Watchdog-Request DWR 280 5.5.1 + Device-Watchdog-Answer DWA 280 5.5.2 + Disconnect-Peer-Request DPR 282 5.4.1 + Disconnect-Peer-Answer DPA 282 5.4.2 + Re-Auth-Request RAR 258 8.3.1 + Re-Auth-Answer RAA 258 8.3.2 + Session-Termination- STR 275 8.4.1 + Request + Session-Termination- STA 275 8.4.2 + Answer + + + + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 35] + +RFC 3588 Diameter Based Protocol September 2003 + + +3.2. Command Code ABNF specification + + Every Command Code defined MUST include a corresponding ABNF + specification, which is used to define the AVPs that MUST or MAY be + present. The following format is used in the definition: + + command-def = command-name "::=" diameter-message + + command-name = diameter-name + + diameter-name = ALPHA *(ALPHA / DIGIT / "-") + + diameter-message = header [ *fixed] [ *required] [ *optional] + [ *fixed] + + header = "<" Diameter-Header:" command-id + [r-bit] [p-bit] [e-bit] [application-id]">" + + application-id = 1*DIGIT + + command-id = 1*DIGIT + ; The Command Code assigned to the command + + r-bit = ", REQ" + ; If present, the 'R' bit in the Command + ; Flags is set, indicating that the message + ; is a request, as opposed to an answer. + + p-bit = ", PXY" + ; If present, the 'P' bit in the Command + ; Flags is set, indicating that the message + ; is proxiable. + + e-bit = ", ERR" + ; If present, the 'E' bit in the Command + ; Flags is set, indicating that the answer + ; message contains a Result-Code AVP in + ; the "protocol error" class. + + fixed = [qual] "<" avp-spec ">" + ; Defines the fixed position of an AVP + + required = [qual] "{" avp-spec "}" + ; The AVP MUST be present and can appear + ; anywhere in the message. + + + + + + +Calhoun, et al. Standards Track [Page 36] + +RFC 3588 Diameter Based Protocol September 2003 + + + optional = [qual] "[" avp-name "]" + ; The avp-name in the 'optional' rule cannot + ; evaluate to any AVP Name which is included + ; in a fixed or required rule. The AVP can + ; appear anywhere in the message. + + qual = [min] "*" [max] + ; See ABNF conventions, RFC 2234 Section 6.6. + ; The absence of any qualifiers depends on whether + ; it precedes a fixed, required, or optional + ; rule. If a fixed or required rule has no + ; qualifier, then exactly one such AVP MUST + ; be present. If an optional rule has no + ; qualifier, then 0 or 1 such AVP may be + ; present. + ; + ; NOTE: "[" and "]" have a different meaning + ; than in ABNF (see the optional rule, above). + ; These braces cannot be used to express + ; optional fixed rules (such as an optional + ; ICV at the end). To do this, the convention + ; is '0*1fixed'. + + min = 1*DIGIT + ; The minimum number of times the element may + ; be present. The default value is zero. + + max = 1*DIGIT + ; The maximum number of times the element may + ; be present. The default value is infinity. A + ; value of zero implies the AVP MUST NOT be + ; present. + + avp-spec = diameter-name + ; The avp-spec has to be an AVP Name, defined + ; in the base or extended Diameter + ; specifications. + + avp-name = avp-spec / "AVP" + ; The string "AVP" stands for *any* arbitrary + ; AVP Name, which does not conflict with the + ; required or fixed position AVPs defined in + ; the command code definition. + + + + + + + + +Calhoun, et al. Standards Track [Page 37] + +RFC 3588 Diameter Based Protocol September 2003 + + + The following is a definition of a fictitious command code: + + Example-Request ::= < "Diameter-Header: 9999999, REQ, PXY > + { User-Name } + * { Origin-Host } + * [ AVP + +3.3. Diameter Command Naming Conventions + + Diameter command names typically includes one or more English words + followed by the verb Request or Answer. Each English word is + delimited by a hyphen. A three-letter acronym for both the request + and answer is also normally provided. + + An example is a message set used to terminate a session. The command + name is Session-Terminate-Request and Session-Terminate-Answer, while + the acronyms are STR and STA, respectively. + + Both the request and the answer for a given command share the same + command code. The request is identified by the R(equest) bit in the + Diameter header set to one (1), to ask that a particular action be + performed, such as authorizing a user or terminating a session. Once + the receiver has completed the request it issues the corresponding + answer, which includes a result code that communicates one of the + following: + + - The request was successful + + - The request failed + + - An additional request must be sent to provide information the peer + requires prior to returning a successful or failed answer. + + - The receiver could not process the request, but provides + information about a Diameter peer that is able to satisfy the + request, known as redirect. + + Additional information, encoded within AVPs, MAY also be included in + answer messages. + +4. Diameter AVPs + + Diameter AVPs carry specific authentication, accounting, + authorization, routing and security information as well as + configuration details for the request and reply. + + Some AVPs MAY be listed more than once. The effect of such an AVP is + specific, and is specified in each case by the AVP description. + + + +Calhoun, et al. Standards Track [Page 38] + +RFC 3588 Diameter Based Protocol September 2003 + + + Each AVP of type OctetString MUST be padded to align on a 32-bit + boundary, while other AVP types align naturally. A number of zero- + valued bytes are added to the end of the AVP Data field till a word + boundary is reached. The length of the padding is not reflected in + the AVP Length field. + +4.1. AVP Header + + The fields in the AVP header MUST be sent in network byte order. The + format of the header is: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | AVP Code | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + |V M P r r r r r| AVP Length | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Vendor-ID (opt) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Data ... + +-+-+-+-+-+-+-+-+ + + AVP Code + The AVP Code, combined with the Vendor-Id field, identifies the + attribute uniquely. AVP numbers 1 through 255 are reserved for + backward compatibility with RADIUS, without setting the Vendor-Id + field. AVP numbers 256 and above are used for Diameter, which are + allocated by IANA (see Section 11.1). + + AVP Flags + The AVP Flags field informs the receiver how each attribute must + be handled. The 'r' (reserved) bits are unused and SHOULD be set + to 0. Note that subsequent Diameter applications MAY define + additional bits within the AVP Header, and an unrecognized bit + SHOULD be considered an error. The 'P' bit indicates the need for + encryption for end-to-end security. + + The 'M' Bit, known as the Mandatory bit, indicates whether support + of the AVP is required. If an AVP with the 'M' bit set is + received by a Diameter client, server, proxy, or translation agent + and either the AVP or its value is unrecognized, the message MUST + be rejected. Diameter Relay and redirect agents MUST NOT reject + messages with unrecognized AVPs. + + + + + + + +Calhoun, et al. Standards Track [Page 39] + +RFC 3588 Diameter Based Protocol September 2003 + + + The 'M' bit MUST be set according to the rules defined for the AVP + containing it. In order to preserve interoperability, a Diameter + implementation MUST be able to exclude from a Diameter message any + Mandatory AVP which is neither defined in the base Diameter + protocol nor in any of the Diameter Application specifications + governing the message in which it appears. It MAY do this in one + of the following ways: + + 1) If a message is rejected because it contains a Mandatory AVP + which is neither defined in the base Diameter standard nor in + any of the Diameter Application specifications governing the + message in which it appears, the implementation may resend the + message without the AVP, possibly inserting additional standard + AVPs instead. + + 2) A configuration option may be provided on a system wide, per + peer, or per realm basis that would allow/prevent particular + Mandatory AVPs to be sent. Thus an administrator could change + the configuration to avoid interoperability problems. + + Diameter implementations are required to support all Mandatory + AVPs which are allowed by the message's formal syntax and defined + either in the base Diameter standard or in one of the Diameter + Application specifications governing the message. + + AVPs with the 'M' bit cleared are informational only and a + receiver that receives a message with such an AVP that is not + supported, or whose value is not supported, MAY simply ignore the + AVP. + + The 'V' bit, known as the Vendor-Specific bit, indicates whether + the optional Vendor-ID field is present in the AVP header. When + set the AVP Code belongs to the specific vendor code address + space. + + Unless otherwise noted, AVPs will have the following default AVP + Flags field settings: + + The 'M' bit MUST be set. The 'V' bit MUST NOT be set. + + AVP Length + The AVP Length field is three octets, and indicates the number of + octets in this AVP including the AVP Code, AVP Length, AVP Flags, + Vendor-ID field (if present) and the AVP data. If a message is + received with an invalid attribute length, the message SHOULD be + rejected. + + + + + +Calhoun, et al. Standards Track [Page 40] + +RFC 3588 Diameter Based Protocol September 2003 + + +4.1.1. Optional Header Elements + + The AVP Header contains one optional field. This field is only + present if the respective bit-flag is enabled. + + Vendor-ID + The Vendor-ID field is present if the 'V' bit is set in the AVP + Flags field. The optional four-octet Vendor-ID field contains the + IANA assigned "SMI Network Management Private Enterprise Codes" + [ASSIGNNO] value, encoded in network byte order. Any vendor + wishing to implement a vendor-specific Diameter AVP MUST use their + own Vendor-ID along with their privately managed AVP address + space, guaranteeing that they will not collide with any other + vendor's vendor-specific AVP(s), nor with future IETF + applications. + + A vendor ID value of zero (0) corresponds to the IETF adopted AVP + values, as managed by the IANA. Since the absence of the vendor + ID field implies that the AVP in question is not vendor specific, + implementations MUST NOT use the zero (0) vendor ID. + +4.2. Basic AVP Data Formats + + The Data field is zero or more octets and contains information + specific to the Attribute. The format and length of the Data field + is determined by the AVP Code and AVP Length fields. The format of + the Data field MUST be one of the following base data types or a data + type derived from the base data types. In the event that a new Basic + AVP Data Format is needed, a new version of this RFC must be created. + + OctetString + The data contains arbitrary data of variable length. Unless + otherwise noted, the AVP Length field MUST be set to at least 8 + (12 if the 'V' bit is enabled). AVP Values of this type that are + not a multiple of four-octets in length is followed by the + necessary padding so that the next AVP (if any) will start on a + 32-bit boundary. + + Integer32 + 32 bit signed value, in network byte order. The AVP Length field + MUST be set to 12 (16 if the 'V' bit is enabled). + + Integer64 + 64 bit signed value, in network byte order. The AVP Length field + MUST be set to 16 (20 if the 'V' bit is enabled). + + + + + + +Calhoun, et al. Standards Track [Page 41] + +RFC 3588 Diameter Based Protocol September 2003 + + + Unsigned32 + 32 bit unsigned value, in network byte order. The AVP Length + field MUST be set to 12 (16 if the 'V' bit is enabled). + + Unsigned64 + 64 bit unsigned value, in network byte order. The AVP Length + field MUST be set to 16 (20 if the 'V' bit is enabled). + + Float32 + This represents floating point values of single precision as + described by [FLOATPOINT]. The 32-bit value is transmitted in + network byte order. The AVP Length field MUST be set to 12 (16 if + the 'V' bit is enabled). + + Float64 + This represents floating point values of double precision as + described by [FLOATPOINT]. The 64-bit value is transmitted in + network byte order. The AVP Length field MUST be set to 16 (20 if + the 'V' bit is enabled). + + Grouped + The Data field is specified as a sequence of AVPs. Each of these + AVPs follows - in the order in which they are specified - + including their headers and padding. The AVP Length field is set + to 8 (12 if the 'V' bit is enabled) plus the total length of all + included AVPs, including their headers and padding. Thus the AVP + length field of an AVP of type Grouped is always a multiple of 4. + +4.3. Derived AVP Data Formats + + In addition to using the Basic AVP Data Formats, applications may + define data formats derived from the Basic AVP Data Formats. An + application that defines new AVP Derived Data Formats MUST include + them in a section entitled "AVP Derived Data Formats", using the same + format as the definitions below. Each new definition must be either + defined or listed with a reference to the RFC that defines the + format. + + The below AVP Derived Data Formats are commonly used by applications. + + Address + The Address format is derived from the OctetString AVP Base + Format. It is a discriminated union, representing, for example a + 32-bit (IPv4) [IPV4] or 128-bit (IPv6) [IPV6] address, most + significant octet first. The first two octets of the Address + + + + + + +Calhoun, et al. Standards Track [Page 42] + +RFC 3588 Diameter Based Protocol September 2003 + + + AVP represents the AddressType, which contains an Address Family + defined in [IANAADFAM]. The AddressType is used to discriminate + the content and format of the remaining octets. + + Time + The Time format is derived from the OctetString AVP Base Format. + The string MUST contain four octets, in the same format as the + first four bytes are in the NTP timestamp format. The NTP + Timestamp format is defined in chapter 3 of [SNTP]. + + This represents the number of seconds since 0h on 1 January 1900 + with respect to the Coordinated Universal Time (UTC). + + On 6h 28m 16s UTC, 7 February 2036 the time value will overflow. + SNTP [SNTP] describes a procedure to extend the time to 2104. + This procedure MUST be supported by all DIAMETER nodes. + + UTF8String + The UTF8String format is derived from the OctetString AVP Base + Format. This is a human readable string represented using the + ISO/IEC IS 10646-1 character set, encoded as an OctetString using + the UTF-8 [UFT8] transformation format described in RFC 2279. + + Since additional code points are added by amendments to the 10646 + standard from time to time, implementations MUST be prepared to + encounter any code point from 0x00000001 to 0x7fffffff. Byte + sequences that do not correspond to the valid encoding of a code + point into UTF-8 charset or are outside this range are prohibited. + + The use of control codes SHOULD be avoided. When it is necessary + to represent a new line, the control code sequence CR LF SHOULD be + used. + + The use of leading or trailing white space SHOULD be avoided. + + For code points not directly supported by user interface hardware + or software, an alternative means of entry and display, such as + hexadecimal, MAY be provided. + + For information encoded in 7-bit US-ASCII, the UTF-8 charset is + identical to the US-ASCII charset. + + UTF-8 may require multiple bytes to represent a single character / + code point; thus the length of an UTF8String in octets may be + different from the number of characters encoded. + + Note that the AVP Length field of an UTF8String is measured in + octets, not characters. + + + +Calhoun, et al. Standards Track [Page 43] + +RFC 3588 Diameter Based Protocol September 2003 + + + DiameterIdentity + The DiameterIdentity format is derived from the OctetString AVP + Base Format. + + DiameterIdentity = FQDN + + DiameterIdentity value is used to uniquely identify a Diameter + node for purposes of duplicate connection and routing loop + detection. + + The contents of the string MUST be the FQDN of the Diameter node. + If multiple Diameter nodes run on the same host, each Diameter + node MUST be assigned a unique DiameterIdentity. If a Diameter + node can be identified by several FQDNs, a single FQDN should be + picked at startup, and used as the only DiameterIdentity for that + node, whatever the connection it is sent on. + + DiameterURI + + The DiameterURI MUST follow the Uniform Resource Identifiers (URI) + syntax [URI] rules specified below: + + "aaa://" FQDN [ port ] [ transport ] [ protocol ] + + ; No transport security + + "aaas://" FQDN [ port ] [ transport ] [ protocol ] + + ; Transport security used + + FQDN = Fully Qualified Host Name + + port = ":" 1*DIGIT + + ; One of the ports used to listen for + ; incoming connections. + ; If absent, + ; the default Diameter port (3868) is + ; assumed. + + transport = ";transport=" transport-protocol + + ; One of the transports used to listen + ; for incoming connections. If absent, + ; the default SCTP [SCTP] protocol is + ; assumed. UDP MUST NOT be used when + ; the aaa-protocol field is set to + ; diameter. + + + +Calhoun, et al. Standards Track [Page 44] + +RFC 3588 Diameter Based Protocol September 2003 + + + transport-protocol = ( "tcp" / "sctp" / "udp" ) + + protocol = ";protocol=" aaa-protocol + + ; If absent, the default AAA protocol + ; is diameter. + + aaa-protocol = ( "diameter" / "radius" / "tacacs+" ) + + The following are examples of valid Diameter host identities: + + aaa://host.example.com;transport=tcp + aaa://host.example.com:6666;transport=tcp + aaa://host.example.com;protocol=diameter + aaa://host.example.com:6666;protocol=diameter + aaa://host.example.com:6666;transport=tcp;protocol=diameter + aaa://host.example.com:1813;transport=udp;protocol=radius + + Enumerated + Enumerated is derived from the Integer32 AVP Base Format. The + definition contains a list of valid values and their + interpretation and is described in the Diameter application + introducing the AVP. + + IPFilterRule + The IPFilterRule format is derived from the OctetString AVP Base + Format. It uses the ASCII charset. Packets may be filtered based + on the following information that is associated with it: + + Direction (in or out) + Source and destination IP address (possibly masked) + Protocol + Source and destination port (lists or ranges) + TCP flags + IP fragment flag + IP options + ICMP types + + Rules for the appropriate direction are evaluated in order, with + the first matched rule terminating the evaluation. Each packet is + evaluated once. If no rule matches, the packet is dropped if the + last rule evaluated was a permit, and passed if the last rule was + a deny. + + + + + + + + +Calhoun, et al. Standards Track [Page 45] + +RFC 3588 Diameter Based Protocol September 2003 + + + IPFilterRule filters MUST follow the format: + + action dir proto from src to dst [options] + + action permit - Allow packets that match the rule. + deny - Drop packets that match the rule. + + dir "in" is from the terminal, "out" is to the + terminal. + + proto An IP protocol specified by number. The "ip" + keyword means any protocol will match. + + src and dst <address/mask> [ports] + + The <address/mask> may be specified as: + ipno An IPv4 or IPv6 number in dotted- + quad or canonical IPv6 form. Only + this exact IP number will match the + rule. + ipno/bits An IP number as above with a mask + width of the form 1.2.3.4/24. In + this case, all IP numbers from + 1.2.3.0 to 1.2.3.255 will match. + The bit width MUST be valid for the + IP version and the IP number MUST + NOT have bits set beyond the mask. + For a match to occur, the same IP + version must be present in the + packet that was used in describing + the IP address. To test for a + particular IP version, the bits part + can be set to zero. The keyword + "any" is 0.0.0.0/0 or the IPv6 + equivalent. The keyword "assigned" + is the address or set of addresses + assigned to the terminal. For IPv4, + a typical first rule is often "deny + in ip! assigned" + + The sense of the match can be inverted by + preceding an address with the not modifier (!), + causing all other addresses to be matched + instead. This does not affect the selection of + port numbers. + + + + + + +Calhoun, et al. Standards Track [Page 46] + +RFC 3588 Diameter Based Protocol September 2003 + + + With the TCP, UDP and SCTP protocols, optional + ports may be specified as: + + {port/port-port}[,ports[,...]] + + The '-' notation specifies a range of ports + (including boundaries). + + Fragmented packets that have a non-zero offset + (i.e., not the first fragment) will never match + a rule that has one or more port + specifications. See the frag option for + details on matching fragmented packets. + + options: + frag Match if the packet is a fragment and this is not + the first fragment of the datagram. frag may not + be used in conjunction with either tcpflags or + TCP/UDP port specifications. + + ipoptions spec + Match if the IP header contains the comma + separated list of options specified in spec. The + supported IP options are: + + ssrr (strict source route), lsrr (loose source + route), rr (record packet route) and ts + (timestamp). The absence of a particular option + may be denoted with a '!'. + + tcpoptions spec + Match if the TCP header contains the comma + separated list of options specified in spec. The + supported TCP options are: + + mss (maximum segment size), window (tcp window + advertisement), sack (selective ack), ts (rfc1323 + timestamp) and cc (rfc1644 t/tcp connection + count). The absence of a particular option may + be denoted with a '!'. + + established + TCP packets only. Match packets that have the RST + or ACK bits set. + + setup TCP packets only. Match packets that have the SYN + bit set but no ACK bit. + + + + +Calhoun, et al. Standards Track [Page 47] + +RFC 3588 Diameter Based Protocol September 2003 + + + tcpflags spec + TCP packets only. Match if the TCP header + contains the comma separated list of flags + specified in spec. The supported TCP flags are: + + fin, syn, rst, psh, ack and urg. The absence of a + particular flag may be denoted with a '!'. A rule + that contains a tcpflags specification can never + match a fragmented packet that has a non-zero + offset. See the frag option for details on + matching fragmented packets. + + icmptypes types + ICMP packets only. Match if the ICMP type is in + the list types. The list may be specified as any + combination of ranges or individual types + separated by commas. Both the numeric values and + the symbolic values listed below can be used. The + supported ICMP types are: + + echo reply (0), destination unreachable (3), + source quench (4), redirect (5), echo request + (8), router advertisement (9), router + solicitation (10), time-to-live exceeded (11), IP + header bad (12), timestamp request (13), + timestamp reply (14), information request (15), + information reply (16), address mask request (17) + and address mask reply (18). + + There is one kind of packet that the access device MUST always + discard, that is an IP fragment with a fragment offset of one. This + is a valid packet, but it only has one use, to try to circumvent + firewalls. + + An access device that is unable to interpret or apply a deny rule + MUST terminate the session. An access device that is unable to + interpret or apply a permit rule MAY apply a more restrictive + rule. An access device MAY apply deny rules of its own before the + supplied rules, for example to protect the access device owner's + infrastructure. + + The rule syntax is a modified subset of ipfw(8) from FreeBSD, and the + ipfw.c code may provide a useful base for implementations. + + + + + + + + +Calhoun, et al. Standards Track [Page 48] + +RFC 3588 Diameter Based Protocol September 2003 + + + 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 that is associated with + it: + + 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, with + the first matched rule terminating the evaluation. Each packet is + evaluated once. If no rule matches, the packet is treated as best + effort. An access device that is unable to interpret or apply a + QoS rule SHOULD NOT terminate the session. + + QoSFilterRule filters MUST follow the 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. + +4.4. Grouped AVP Values + + The Diameter protocol allows AVP values of type 'Grouped.' This + implies that the Data field is actually a sequence of AVPs. It is + possible to include an AVP with a Grouped type within a Grouped type, + that is, to nest them. AVPs within an AVP of type Grouped have the + same padding requirements as non-Grouped AVPs, as defined in Section + 4. + + + + + + + +Calhoun, et al. Standards Track [Page 49] + +RFC 3588 Diameter Based Protocol September 2003 + + + The AVP Code numbering space of all AVPs included in a Grouped AVP is + the same as for non-grouped AVPs. Further, if any of the AVPs + encapsulated within a Grouped AVP has the 'M' (mandatory) bit set, + the Grouped AVP itself MUST also include the 'M' bit set. + + Every Grouped AVP defined MUST include a corresponding grammar, using + ABNF [ABNF] (with modifications), as defined below. + + grouped-avp-def = name "::=" avp + + name-fmt = ALPHA *(ALPHA / DIGIT / "-") + + name = name-fmt + ; The name has to be the name of an AVP, + ; defined in the base or extended Diameter + ; specifications. + + avp = header [ *fixed] [ *required] [ *optional] + [ *fixed] + + header = "<" "AVP-Header:" avpcode [vendor] ">" + + avpcode = 1*DIGIT + ; The AVP Code assigned to the Grouped AVP + + vendor = 1*DIGIT + ; The Vendor-ID assigned to the Grouped AVP. + ; If absent, the default value of zero is + ; used. + +4.4.1. Example AVP with a Grouped Data type + + The Example-AVP (AVP Code 999999) is of type Grouped and is used to + clarify how Grouped AVP values work. The Grouped Data field has the + following ABNF grammar: + + Example-AVP ::= < AVP Header: 999999 > + { Origin-Host } + 1*{ Session-Id } + *[ AVP ] + + An Example-AVP with Grouped Data follows. + + The Origin-Host AVP is required (Section 6.3). In this case: + + Origin-Host = "example.com". + + + + + +Calhoun, et al. Standards Track [Page 50] + +RFC 3588 Diameter Based Protocol September 2003 + + + One or more Session-Ids must follow. Here there are two: + + Session-Id = + "grump.example.com:33041;23432;893;0AF3B81" + + Session-Id = + "grump.example.com:33054;23561;2358;0AF3B82" + + optional AVPs included are + + Recovery-Policy = <binary> + 2163bc1d0ad82371f6bc09484133c3f09ad74a0dd5346d54195a7cf0b35 + 2cabc881839a4fdcfbc1769e2677a4c1fb499284c5f70b48f58503a45c5 + c2d6943f82d5930f2b7c1da640f476f0e9c9572a50db8ea6e51e1c2c7bd + f8bb43dc995144b8dbe297ac739493946803e1cee3e15d9b765008a1b2a + cf4ac777c80041d72c01e691cf751dbf86e85f509f3988e5875dc905119 + 26841f00f0e29a6d1ddc1a842289d440268681e052b30fb638045f7779c + 1d873c784f054f688f5001559ecff64865ef975f3e60d2fd7966b8c7f92 + + Futuristic-Acct-Record = <binary> + fe19da5802acd98b07a5b86cb4d5d03f0314ab9ef1ad0b67111ff3b90a0 + 57fe29620bf3585fd2dd9fcc38ce62f6cc208c6163c008f4258d1bc88b8 + 17694a74ccad3ec69269461b14b2e7a4c111fb239e33714da207983f58c + 41d018d56fe938f3cbf089aac12a912a2f0d1923a9390e5f789cb2e5067 + d3427475e49968f841 + + The data for the optional AVPs is represented in hex since the format + of these AVPs is neither known at the time of definition of the + Example-AVP group, nor (likely) at the time when the example instance + of this AVP is interpreted - except by Diameter implementations which + support the same set of AVPs. The encoding example illustrates how + padding is used and how length fields are calculated. Also note that + AVPs may be present in the Grouped AVP value which the receiver + cannot interpret (here, the Recover-Policy and Futuristic-Acct-Record + AVPs). + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 51] + +RFC 3588 Diameter Based Protocol September 2003 + + + This AVP would be encoded as follows: + + 0 1 2 3 4 5 6 7 + +-------+-------+-------+-------+-------+-------+-------+-------+ + 0 | Example AVP Header (AVP Code = 999999), Length = 468 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 8 | Origin-Host AVP Header (AVP Code = 264), Length = 19 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 16 | 'e' | 'x' | 'a' | 'm' | 'p' | 'l' | 'e' | '.' | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 24 | 'c' | 'o' | 'm' |Padding| Session-Id AVP Header | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 32 | (AVP Code = 263), Length = 50 | 'g' | 'r' | 'u' | 'm' | + +-------+-------+-------+-------+-------+-------+-------+-------+ + . . . + +-------+-------+-------+-------+-------+-------+-------+-------+ + 64 | 'A' | 'F' | '3' | 'B' | '8' | '1' |Padding|Padding| + +-------+-------+-------+-------+-------+-------+-------+-------+ + 72 | Session-Id AVP Header (AVP Code = 263), Length = 51 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 80 | 'g' | 'r' | 'u' | 'm' | 'p' | '.' | 'e' | 'x' | + +-------+-------+-------+-------+-------+-------+-------+-------+ + . . . + +-------+-------+-------+-------+-------+-------+-------+-------+ + 104 | '0' | 'A' | 'F' | '3' | 'B' | '8' | '2' |Padding| + +-------+-------+-------+-------+-------+-------+-------+-------+ + 112 | Recovery-Policy Header (AVP Code = 8341), Length = 223 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + 120 | 0x21 | 0x63 | 0xbc | 0x1d | 0x0a | 0xd8 | 0x23 | 0x71 | + +-------+-------+-------+-------+-------+-------+-------+-------+ + . . . + +-------+-------+-------+-------+-------+-------+-------+-------+ + 320 | 0x2f | 0xd7 | 0x96 | 0x6b | 0x8c | 0x7f | 0x92 |Padding| + +-------+-------+-------+-------+-------+-------+-------+-------+ + 328 | Futuristic-Acct-Record Header (AVP Code = 15930), Length = 137| + +-------+-------+-------+-------+-------+-------+-------+-------+ + 336 | 0xfe | 0x19 | 0xda | 0x58 | 0x02 | 0xac | 0xd9 | 0x8b | + +-------+-------+-------+-------+-------+-------+-------+-------+ + . . . + +-------+-------+-------+-------+-------+-------+-------+-------+ + 464 | 0x41 |Padding|Padding|Padding| + +-------+-------+-------+-------+ + + + + + + + + + +Calhoun, et al. Standards Track [Page 52] + +RFC 3588 Diameter Based Protocol September 2003 + + +4.5. Diameter Base Protocol AVPs + + The following table describes the Diameter AVPs defined in the base + protocol, their AVP Code values, types, possible flag values and + whether the AVP MAY be encrypted. For the originator of a Diameter + message, "Encr" (Encryption) means that if a message containing that + AVP is to be sent via a Diameter agent (proxy, redirect or relay) + then the message MUST NOT be sent unless there is end-to-end security + between the originator and the recipient and integrity / + confidentiality protection is offered for this AVP OR the originator + has locally trusted configuration that indicates that end-to-end + security is not needed. Similarly, for the originator of a Diameter + message, a "P" in the "MAY" column means that if a message containing + that AVP is to be sent via a Diameter agent (proxy, redirect or + relay) then the message MUST NOT be sent unless there is end-to-end + security between the originator and the recipient or the originator + has locally trusted configuration that indicates that end-to-end + security is not needed. + + Due to space constraints, the short form DiamIdent is used to + represent DiameterIdentity. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 53] + +RFC 3588 Diameter Based Protocol September 2003 + + + +---------------------+ + | AVP Flag rules | + |----+-----+----+-----|----+ + AVP Section | | |SHLD| MUST| | + Attribute Name Code Defined Data Type |MUST| MAY | NOT| NOT|Encr| + -----------------------------------------|----+-----+----+-----|----| + Acct- 85 9.8.2 Unsigned32 | M | P | | V | Y | + Interim-Interval | | | | | | + Accounting- 483 9.8.7 Enumerated | M | P | | V | Y | + Realtime-Required | | | | | | + Acct- 50 9.8.5 UTF8String | M | P | | V | Y | + Multi-Session-Id | | | | | | + Accounting- 485 9.8.3 Unsigned32 | M | P | | V | Y | + Record-Number | | | | | | + Accounting- 480 9.8.1 Enumerated | M | P | | V | Y | + Record-Type | | | | | | + Accounting- 44 9.8.4 OctetString| M | P | | V | Y | + Session-Id | | | | | | + Accounting- 287 9.8.6 Unsigned64 | M | P | | V | Y | + Sub-Session-Id | | | | | | + Acct- 259 6.9 Unsigned32 | M | P | | V | N | + Application-Id | | | | | | + Auth- 258 6.8 Unsigned32 | M | P | | V | N | + Application-Id | | | | | | + Auth-Request- 274 8.7 Enumerated | M | P | | V | N | + Type | | | | | | + Authorization- 291 8.9 Unsigned32 | M | P | | V | N | + Lifetime | | | | | | + Auth-Grace- 276 8.10 Unsigned32 | M | P | | V | N | + Period | | | | | | + Auth-Session- 277 8.11 Enumerated | M | P | | V | N | + State | | | | | | + Re-Auth-Request- 285 8.12 Enumerated | M | P | | V | N | + Type | | | | | | + Class 25 8.20 OctetString| M | P | | V | Y | + Destination-Host 293 6.5 DiamIdent | M | P | | V | N | + Destination- 283 6.6 DiamIdent | M | P | | V | N | + Realm | | | | | | + Disconnect-Cause 273 5.4.3 Enumerated | M | P | | V | N | + E2E-Sequence AVP 300 6.15 Grouped | M | P | | V | Y | + Error-Message 281 7.3 UTF8String | | P | | V,M | N | + Error-Reporting- 294 7.4 DiamIdent | | P | | V,M | N | + Host | | | | | | + Event-Timestamp 55 8.21 Time | M | P | | V | N | + Experimental- 297 7.6 Grouped | M | P | | V | N | + Result | | | | | | + -----------------------------------------|----+-----+----+-----|----| + + + + +Calhoun, et al. Standards Track [Page 54] + +RFC 3588 Diameter Based Protocol September 2003 + + + +---------------------+ + | AVP Flag rules | + |----+-----+----+-----|----+ + AVP Section | | |SHLD| MUST|MAY | + Attribute Name Code Defined Data Type |MUST| MAY | NOT| NOT|Encr| + -----------------------------------------|----+-----+----+-----|----| + Experimental- 298 7.7 Unsigned32 | M | P | | V | N | + Result-Code | | | | | | + Failed-AVP 279 7.5 Grouped | M | P | | V | N | + Firmware- 267 5.3.4 Unsigned32 | | | |P,V,M| N | + Revision | | | | | | + Host-IP-Address 257 5.3.5 Address | M | P | | V | N | + Inband-Security | M | P | | V | N | + -Id 299 6.10 Unsigned32 | | | | | | + Multi-Round- 272 8.19 Unsigned32 | M | P | | V | Y | + Time-Out | | | | | | + Origin-Host 264 6.3 DiamIdent | M | P | | V | N | + Origin-Realm 296 6.4 DiamIdent | M | P | | V | N | + Origin-State-Id 278 8.16 Unsigned32 | M | P | | V | N | + Product-Name 269 5.3.7 UTF8String | | | |P,V,M| N | + Proxy-Host 280 6.7.3 DiamIdent | M | | | P,V | N | + Proxy-Info 284 6.7.2 Grouped | M | | | P,V | N | + Proxy-State 33 6.7.4 OctetString| M | | | P,V | N | + Redirect-Host 292 6.12 DiamURI | M | P | | V | N | + Redirect-Host- 261 6.13 Enumerated | M | P | | V | N | + Usage | | | | | | + Redirect-Max- 262 6.14 Unsigned32 | M | P | | V | N | + Cache-Time | | | | | | + Result-Code 268 7.1 Unsigned32 | M | P | | V | N | + Route-Record 282 6.7.1 DiamIdent | M | | | P,V | N | + Session-Id 263 8.8 UTF8String | M | P | | V | Y | + Session-Timeout 27 8.13 Unsigned32 | M | P | | V | N | + Session-Binding 270 8.17 Unsigned32 | M | P | | V | Y | + Session-Server- 271 8.18 Enumerated | M | P | | V | Y | + Failover | | | | | | + Supported- 265 5.3.6 Unsigned32 | M | P | | V | N | + Vendor-Id | | | | | | + Termination- 295 8.15 Enumerated | M | P | | V | N | + Cause | | | | | | + User-Name 1 8.14 UTF8String | M | P | | V | Y | + Vendor-Id 266 5.3.3 Unsigned32 | M | P | | V | N | + Vendor-Specific- 260 6.11 Grouped | M | P | | V | N | + Application-Id | | | | | | + -----------------------------------------|----+-----+----+-----|----| + + + + + + + +Calhoun, et al. Standards Track [Page 55] + +RFC 3588 Diameter Based Protocol September 2003 + + +5. Diameter Peers + + This section describes how Diameter nodes establish connections and + communicate with peers. + +5.1. Peer Connections + + Although a Diameter node may have many possible peers that it is able + to communicate with, it may not be economical to have an established + connection to all of them. At a minimum, a Diameter node SHOULD have + an established connection with two peers per realm, known as the + primary and secondary peers. Of course, a node MAY have additional + connections, if it is deemed necessary. Typically, all messages for + a realm are sent to the primary peer, but in the event that failover + procedures are invoked, any pending requests are sent to the + secondary peer. However, implementations are free to load balance + requests between a set of peers. + + Note that a given peer MAY act as a primary for a given realm, while + acting as a secondary for another realm. + + When a peer is deemed suspect, which could occur for various reasons, + including not receiving a DWA within an allotted timeframe, no new + requests should be forwarded to the peer, but failover procedures are + invoked. When an active peer is moved to this mode, additional + connections SHOULD be established to ensure that the necessary number + of active connections exists. + + There are two ways that a peer is removed from the suspect peer list: + + 1. The peer is no longer reachable, causing the transport connection + to be shutdown. The peer is moved to the closed state. + + 2. Three watchdog messages are exchanged with accepted round trip + times, and the connection to the peer is considered stabilized. + + In the event the peer being removed is either the primary or + secondary, an alternate peer SHOULD replace the deleted peer, and + assume the role of either primary or secondary. + +5.2. Diameter Peer Discovery + + Allowing for dynamic Diameter agent discovery will make it possible + for simpler and more robust deployment of Diameter services. In + order to promote interoperable implementations of Diameter peer + discovery, the following mechanisms are described. These are based + + + + + +Calhoun, et al. Standards Track [Page 56] + +RFC 3588 Diameter Based Protocol September 2003 + + + on existing IETF standards. The first option (manual configuration) + MUST be supported by all DIAMETER nodes, while the latter two options + (SRVLOC and DNS) MAY be supported. + + There are two cases where Diameter peer discovery may be performed. + The first is when a Diameter client needs to discover a first-hop + Diameter agent. The second case is when a Diameter agent needs to + discover another agent - for further handling of a Diameter + operation. In both cases, the following 'search order' is + recommended: + + 1. The Diameter implementation consults its list of static (manually) + configured Diameter agent locations. These will be used if they + exist and respond. + + 2. The Diameter implementation uses SLPv2 [SLP] to discover Diameter + services. The Diameter service template [TEMPLATE] is included in + Appendix A. + + It is recommended that SLPv2 security be deployed (this requires + distributing keys to SLPv2 agents). This is discussed further in + Appendix A. SLPv2 security SHOULD be used (requiring distribution + of keys to SLPv2 agents) in order to ensure that discovered peers + are authorized for their roles. SLPv2 is discussed further in + Appendix A. + + 3. The Diameter implementation performs a NAPTR query for a server in + a particular realm. The Diameter implementation has to know in + advance which realm to look for a Diameter agent in. This could + be deduced, for example, from the 'realm' in a NAI that a Diameter + implementation needed to perform a Diameter operation on. + + 3.1 The services relevant for the task of transport protocol + selection are those with NAPTR service fields with values + "AAA+D2x", where x is a letter that corresponds to a transport + protocol supported by the domain. This specification defines + D2T for TCP and D2S for SCTP. We also establish an IANA + registry for NAPTR service name to transport protocol + mappings. + + These NAPTR records provide a mapping from a domain, to the + SRV record for contacting a server with the specific transport + protocol in the NAPTR services field. The resource record + will contain an empty regular expression and a replacement + value, which is the SRV record for that particular transport + protocol. If the server supports multiple transport + protocols, there will be multiple NAPTR records, each with a + different service value. As per RFC 2915 [NAPTR], the client + + + +Calhoun, et al. Standards Track [Page 57] + +RFC 3588 Diameter Based Protocol September 2003 + + + discards any records whose services fields are not applicable. + For the purposes of this specification, several rules are + defined. + + 3.2 A client MUST discard any service fields that identify a + resolution service whose value is not "D2X", for values of X + that indicate transport protocols supported by the client. + The NAPTR processing as described in RFC 2915 will result in + discovery of the most preferred transport protocol of the + server that is supported by the client, as well as an SRV + record for the server. + + The domain suffixes in the NAPTR replacement field SHOULD + match the domain of the original query. + + 4. If no NAPTR records are found, the requester queries for those + address records for the destination address, + '_diameter._sctp'.realm or '_diameter._tcp'.realm. Address + records include A RR's, AAAA RR's or other similar records, chosen + according to the requestor's network protocol capabilities. If + the DNS server returns no address records, the requestor gives up. + + If the server is using a site certificate, the domain name in the + query and the domain name in the replacement field MUST both be + valid based on the site certificate handed out by the server in + the TLS or IKE exchange. Similarly, the domain name in the SRV + query and the domain name in the target in the SRV record MUST + both be valid based on the same site certificate. Otherwise, an + attacker could modify the DNS records to contain replacement + values in a different domain, and the client could not validate + that this was the desired behavior, or the result of an attack + + Also, the Diameter Peer MUST check to make sure that the + discovered peers are authorized to act in its role. + Authentication via IKE or TLS, or validation of DNS RRs via DNSSEC + is not sufficient to conclude this. For example, a web server may + have obtained a valid TLS certificate, and secured RRs may be + included in the DNS, but this does not imply that it is authorized + to act as a Diameter Server. + + Authorization can be achieved for example, by configuration of a + Diameter Server CA. Alternatively this can be achieved by + definition of OIDs within TLS or IKE certificates so as to signify + Diameter Server authorization. + + A dynamically discovered peer causes an entry in the Peer Table (see + Section 2.6) to be created. Note that entries created via DNS MUST + expire (or be refreshed) within the DNS TTL. If a peer is discovered + + + +Calhoun, et al. Standards Track [Page 58] + +RFC 3588 Diameter Based Protocol September 2003 + + + outside of the local realm, a routing table entry (see Section 2.7) + for the peer's realm is created. The routing table entry's + expiration MUST match the peer's expiration value. + +5.3. Capabilities Exchange + + When two Diameter peers establish a transport connection, they MUST + exchange the Capabilities Exchange messages, as specified in the peer + state machine (see Section 5.6). This message allows the discovery + of a peer's identity and its capabilities (protocol version number, + supported Diameter applications, security mechanisms, etc.) + + The receiver only issues commands to its peers that have advertised + support for the Diameter application that defines the command. A + Diameter node MUST cache the supported applications in order to + ensure that unrecognized commands and/or AVPs are not unnecessarily + sent to a peer. + + A receiver of a Capabilities-Exchange-Req (CER) message that does not + have any applications in common with the sender MUST return a + Capabilities-Exchange-Answer (CEA) with the Result-Code AVP set to + DIAMETER_NO_COMMON_APPLICATION, and SHOULD disconnect the transport + layer connection. Note that receiving a CER or CEA from a peer + advertising itself as a Relay (see Section 2.4) MUST be interpreted + as having common applications with the peer. + + Similarly, a receiver of a Capabilities-Exchange-Req (CER) message + that does not have any security mechanisms in common with the sender + MUST return a Capabilities-Exchange-Answer (CEA) with the Result-Code + AVP set to DIAMETER_NO_COMMON_SECURITY, and SHOULD disconnect the + transport layer connection. + + CERs received from unknown peers MAY be silently discarded, or a CEA + MAY be issued with the Result-Code AVP set to DIAMETER_UNKNOWN_PEER. + In both cases, the transport connection is closed. If the local + policy permits receiving CERs from unknown hosts, a successful CEA + MAY be returned. If a CER from an unknown peer is answered with a + successful CEA, the lifetime of the peer entry is equal to the + lifetime of the transport connection. In case of a transport + failure, all the pending transactions destined to the unknown peer + can be discarded. + + The CER and CEA messages MUST NOT be proxied, redirected or relayed. + + Since the CER/CEA messages cannot be proxied, it is still possible + that an upstream agent receives a message for which it has no + available peers to handle the application that corresponds to the + Command-Code. In such instances, the 'E' bit is set in the answer + + + +Calhoun, et al. Standards Track [Page 59] + +RFC 3588 Diameter Based Protocol September 2003 + + + message (see Section 7.) with the Result-Code AVP set to + DIAMETER_UNABLE_TO_DELIVER to inform the downstream to take action + (e.g., re-routing request to an alternate peer). + + With the exception of the Capabilities-Exchange-Request message, a + message of type Request that includes the Auth-Application-Id or + Acct-Application-Id AVPs, or a message with an application-specific + command code, MAY only be forwarded to a host that has explicitly + advertised support for the application (or has advertised the Relay + Application Identifier). + +5.3.1. Capabilities-Exchange-Request + + The Capabilities-Exchange-Request (CER), indicated by the Command- + Code set to 257 and the Command Flags' 'R' bit set, is sent to + exchange local capabilities. Upon detection of a transport failure, + this message MUST NOT be sent to an alternate peer. + + When Diameter is run over SCTP [SCTP], which allows for connections + to span multiple interfaces and multiple IP addresses, the + Capabilities-Exchange-Request message MUST contain one Host-IP- + Address AVP for each potential IP address that MAY be locally used + when transmitting Diameter messages. + + Message Format + + <CER> ::= < Diameter Header: 257, REQ > + { Origin-Host } + { Origin-Realm } + 1* { Host-IP-Address } + { Vendor-Id } + { Product-Name } + [ Origin-State-Id ] + * [ Supported-Vendor-Id ] + * [ Auth-Application-Id ] + * [ Inband-Security-Id ] + * [ Acct-Application-Id ] + * [ Vendor-Specific-Application-Id ] + [ Firmware-Revision ] + * [ AVP ] + +5.3.2. Capabilities-Exchange-Answer + + The Capabilities-Exchange-Answer (CEA), indicated by the Command-Code + set to 257 and the Command Flags' 'R' bit cleared, is sent in + response to a CER message. + + + + + +Calhoun, et al. Standards Track [Page 60] + +RFC 3588 Diameter Based Protocol September 2003 + + + When Diameter is run over SCTP [SCTP], which allows connections to + span multiple interfaces, hence, multiple IP addresses, the + Capabilities-Exchange-Answer message MUST contain one Host-IP-Address + AVP for each potential IP address that MAY be locally used when + transmitting Diameter messages. + + Message Format + + <CEA> ::= < Diameter Header: 257 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + 1* { Host-IP-Address } + { Vendor-Id } + { Product-Name } + [ Origin-State-Id ] + [ Error-Message ] + * [ Failed-AVP ] + * [ Supported-Vendor-Id ] + * [ Auth-Application-Id ] + * [ Inband-Security-Id ] + * [ Acct-Application-Id ] + * [ Vendor-Specific-Application-Id ] + [ Firmware-Revision ] + * [ AVP ] + +5.3.3. Vendor-Id AVP + + The Vendor-Id AVP (AVP Code 266) is of type Unsigned32 and contains + the IANA "SMI Network Management Private Enterprise Codes" [ASSIGNNO] + value assigned to the vendor of the Diameter application. In + combination with the Supported-Vendor-Id AVP (Section 5.3.6), this + MAY be used in order to know which vendor specific attributes may be + sent to the peer. It is also envisioned that the combination of the + Vendor-Id, Product-Name (Section 5.3.7) and the Firmware-Revision + (Section 5.3.4) AVPs MAY provide very useful debugging information. + + A Vendor-Id value of zero in the CER or CEA messages is reserved and + indicates that this field is ignored. + +5.3.4. Firmware-Revision AVP + + The Firmware-Revision AVP (AVP Code 267) is of type Unsigned32 and is + used to inform a Diameter peer of the firmware revision of the + issuing device. + + + + + + +Calhoun, et al. Standards Track [Page 61] + +RFC 3588 Diameter Based Protocol September 2003 + + + For devices that do not have a firmware revision (general purpose + computers running Diameter software modules, for instance), the + revision of the Diameter software module may be reported instead. + +5.3.5. Host-IP-Address AVP + + The Host-IP-Address AVP (AVP Code 257) is of type Address and is used + to inform a Diameter peer of the sender's IP address. All source + addresses that a Diameter node expects to use with SCTP [SCTP] MUST + be advertised in the CER and CEA messages by including a Host-IP- + Address AVP for each address. This AVP MUST ONLY be used in the CER + and CEA messages. + +5.3.6. Supported-Vendor-Id AVP + + The Supported-Vendor-Id AVP (AVP Code 265) is of type Unsigned32 and + contains the IANA "SMI Network Management Private Enterprise Codes" + [ASSIGNNO] value assigned to a vendor other than the device vendor. + This is used in the CER and CEA messages in order to inform the peer + that the sender supports (a subset of) the vendor-specific AVPs + defined by the vendor identified in this AVP. + +5.3.7. Product-Name AVP + + The Product-Name AVP (AVP Code 269) is of type UTF8String, and + contains the vendor assigned name for the product. The Product-Name + AVP SHOULD remain constant across firmware revisions for the same + product. + +5.4. Disconnecting Peer connections + + When a Diameter node disconnects one of its transport connections, + its peer cannot know the reason for the disconnect, and will most + likely assume that a connectivity problem occurred, or that the peer + has rebooted. In these cases, the peer may periodically attempt to + reconnect, as stated in Section 2.1. In the event that the + disconnect was a result of either a shortage of internal resources, + or simply that the node in question has no intentions of forwarding + any Diameter messages to the peer in the foreseeable future, a + periodic connection request would not be welcomed. The + Disconnection-Reason AVP contains the reason the Diameter node issued + the Disconnect-Peer-Request message. + + The Disconnect-Peer-Request message is used by a Diameter node to + inform its peer of its intent to disconnect the transport layer, and + that the peer shouldn't reconnect unless it has a valid reason to do + so (e.g., message to be forwarded). Upon receipt of the message, the + + + + +Calhoun, et al. Standards Track [Page 62] + +RFC 3588 Diameter Based Protocol September 2003 + + + Disconnect-Peer-Answer is returned, which SHOULD contain an error if + messages have recently been forwarded, and are likely in flight, + which would otherwise cause a race condition. + + The receiver of the Disconnect-Peer-Answer initiates the transport + disconnect. + +5.4.1. Disconnect-Peer-Request + + The Disconnect-Peer-Request (DPR), indicated by the Command-Code set + to 282 and the Command Flags' 'R' bit set, is sent to a peer to + inform its intentions to shutdown the transport connection. Upon + detection of a transport failure, this message MUST NOT be sent to an + alternate peer. + + Message Format + + <DPR> ::= < Diameter Header: 282, REQ > + { Origin-Host } + { Origin-Realm } + { Disconnect-Cause } + +5.4.2. Disconnect-Peer-Answer + + The Disconnect-Peer-Answer (DPA), indicated by the Command-Code set + to 282 and the Command Flags' 'R' bit cleared, is sent as a response + to the Disconnect-Peer-Request message. Upon receipt of this + message, the transport connection is shutdown. + + Message Format + + <DPA> ::= < Diameter Header: 282 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Error-Message ] + * [ Failed-AVP ] + +5.4.3. Disconnect-Cause AVP + + The Disconnect-Cause AVP (AVP Code 273) is of type Enumerated. A + Diameter node MUST include this AVP in the Disconnect-Peer-Request + message to inform the peer of the reason for its intention to + shutdown the transport connection. The following values are + supported: + + + + + + +Calhoun, et al. Standards Track [Page 63] + +RFC 3588 Diameter Based Protocol September 2003 + + + REBOOTING 0 + A scheduled reboot is imminent. + + BUSY 1 + The peer's internal resources are constrained, and it has + determined that the transport connection needs to be closed. + + DO_NOT_WANT_TO_TALK_TO_YOU 2 + The peer has determined that it does not see a need for the + transport connection to exist, since it does not expect any + messages to be exchanged in the near future. + +5.5. Transport Failure Detection + + Given the nature of the Diameter protocol, it is recommended that + transport failures be detected as soon as possible. Detecting such + failures will minimize the occurrence of messages sent to unavailable + agents, resulting in unnecessary delays, and will provide better + failover performance. The Device-Watchdog-Request and Device- + Watchdog-Answer messages, defined in this section, are used to pro- + actively detect transport failures. + +5.5.1. Device-Watchdog-Request + + The Device-Watchdog-Request (DWR), indicated by the Command-Code set + to 280 and the Command Flags' 'R' bit set, is sent to a peer when no + traffic has been exchanged between two peers (see Section 5.5.3). + Upon detection of a transport failure, this message MUST NOT be sent + to an alternate peer. + + Message Format + + <DWR> ::= < Diameter Header: 280, REQ > + { Origin-Host } + { Origin-Realm } + [ Origin-State-Id ] + +5.5.2. Device-Watchdog-Answer + + The Device-Watchdog-Answer (DWA), indicated by the Command-Code set + to 280 and the Command Flags' 'R' bit cleared, is sent as a response + to the Device-Watchdog-Request message. + + + + + + + + + +Calhoun, et al. Standards Track [Page 64] + +RFC 3588 Diameter Based Protocol September 2003 + + + Message Format + + <DWA> ::= < Diameter Header: 280 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Error-Message ] + * [ Failed-AVP ] + [ Original-State-Id ] + +5.5.3. Transport Failure Algorithm + + The transport failure algorithm is defined in [AAATRANS]. All + Diameter implementations MUST support the algorithm defined in the + specification in order to be compliant to the Diameter base protocol. + +5.5.4. Failover and Failback Procedures + + In the event that a transport failure is detected with a peer, it is + necessary for all pending request messages to be forwarded to an + alternate agent, if possible. This is commonly referred to as + failover. + + In order for a Diameter node to perform failover procedures, it is + necessary for the node to maintain a pending message queue for a + given peer. When an answer message is received, the corresponding + request is removed from the queue. The Hop-by-Hop Identifier field + is used to match the answer with the queued request. + + When a transport failure is detected, if possible all messages in the + queue are sent to an alternate agent with the T flag set. On booting + a Diameter client or agent, the T flag is also set on any records + still remaining to be transmitted in non-volatile storage. An + example of a case where it is not possible to forward the message to + an alternate server is when the message has a fixed destination, and + the unavailable peer is the message's final destination (see + Destination-Host AVP). Such an error requires that the agent return + an answer message with the 'E' bit set and the Result-Code AVP set to + DIAMETER_UNABLE_TO_DELIVER. + + It is important to note that multiple identical requests or answers + MAY be received as a result of a failover. The End-to-End Identifier + field in the Diameter header along with the Origin-Host AVP MUST be + used to identify duplicate messages. + + + + + + + +Calhoun, et al. Standards Track [Page 65] + +RFC 3588 Diameter Based Protocol September 2003 + + + As described in Section 2.1, a connection request should be + periodically attempted with the failed peer in order to re-establish + the transport connection. Once a connection has been successfully + established, messages can once again be forwarded to the peer. This + is commonly referred to as failback. + +5.6. Peer State Machine + + This section contains a finite state machine that MUST be observed by + all Diameter implementations. Each Diameter node MUST follow the + state machine described below when communicating with each peer. + Multiple actions are separated by commas, and may continue on + succeeding lines, as space requires. Similarly, state and next state + may also span multiple lines, as space requires. + + This state machine is closely coupled with the state machine + described in [AAATRANS], which is used to open, close, failover, + probe, and reopen transport connections. Note in particular that + [AAATRANS] requires the use of watchdog messages to probe + connections. For Diameter, DWR and DWA messages are to be used. + + I- is used to represent the initiator (connecting) connection, while + the R- is used to represent the responder (listening) connection. + The lack of a prefix indicates that the event or action is the same + regardless of the connection on which the event occurred. + + The stable states that a state machine may be in are Closed, I-Open + and R-Open; all other states are intermediate. Note that I-Open and + R-Open are equivalent except for whether the initiator or responder + transport connection is used for communication. + + A CER message is always sent on the initiating connection immediately + after the connection request is successfully completed. In the case + of an election, one of the two connections will shut down. The + responder connection will survive if the Origin-Host of the local + Diameter entity is higher than that of the peer; the initiator + connection will survive if the peer's Origin-Host is higher. All + subsequent messages are sent on the surviving connection. Note that + the results of an election on one peer are guaranteed to be the + inverse of the results on the other. + + For TLS usage, a TLS handshake will begin when both ends are in the + open state. If the TLS handshake is successful, all further messages + will be sent via TLS. If the handshake fails, both ends move to the + closed state. + + The state machine constrains only the behavior of a Diameter + implementation as seen by Diameter peers through events on the wire. + + + +Calhoun, et al. Standards Track [Page 66] + +RFC 3588 Diameter Based Protocol September 2003 + + + Any implementation that produces equivalent results is considered + compliant. + + state event action next state + ----------------------------------------------------------------- + Closed Start I-Snd-Conn-Req Wait-Conn-Ack + R-Conn-CER R-Accept, R-Open + Process-CER, + R-Snd-CEA + + Wait-Conn-Ack I-Rcv-Conn-Ack I-Snd-CER Wait-I-CEA + I-Rcv-Conn-Nack Cleanup Closed + R-Conn-CER R-Accept, Wait-Conn-Ack/ + Process-CER Elect + Timeout Error Closed + + Wait-I-CEA I-Rcv-CEA Process-CEA I-Open + R-Conn-CER R-Accept, Wait-Returns + Process-CER, + Elect + I-Peer-Disc I-Disc Closed + I-Rcv-Non-CEA Error Closed + Timeout Error Closed + + Wait-Conn-Ack/ I-Rcv-Conn-Ack I-Snd-CER,Elect Wait-Returns + Elect I-Rcv-Conn-Nack R-Snd-CEA R-Open + R-Peer-Disc R-Disc Wait-Conn-Ack + R-Conn-CER R-Reject Wait-Conn-Ack/ + Elect + Timeout Error Closed + + Wait-Returns Win-Election I-Disc,R-Snd-CEA R-Open + I-Peer-Disc I-Disc, R-Open + R-Snd-CEA + I-Rcv-CEA R-Disc I-Open + R-Peer-Disc R-Disc Wait-I-CEA + R-Conn-CER R-Reject Wait-Returns + Timeout Error Closed + + R-Open Send-Message R-Snd-Message R-Open + R-Rcv-Message Process R-Open + R-Rcv-DWR Process-DWR, R-Open + R-Snd-DWA + R-Rcv-DWA Process-DWA R-Open + R-Conn-CER R-Reject R-Open + Stop R-Snd-DPR Closing + R-Rcv-DPR R-Snd-DPA, Closed + R-Disc + + + +Calhoun, et al. Standards Track [Page 67] + +RFC 3588 Diameter Based Protocol September 2003 + + + R-Peer-Disc R-Disc Closed + R-Rcv-CER R-Snd-CEA R-Open + R-Rcv-CEA Process-CEA R-Open + + I-Open Send-Message I-Snd-Message I-Open + I-Rcv-Message Process I-Open + I-Rcv-DWR Process-DWR, I-Open + I-Snd-DWA + I-Rcv-DWA Process-DWA I-Open + R-Conn-CER R-Reject I-Open + Stop I-Snd-DPR Closing + I-Rcv-DPR I-Snd-DPA, Closed + I-Disc + I-Peer-Disc I-Disc Closed + I-Rcv-CER I-Snd-CEA I-Open + I-Rcv-CEA Process-CEA I-Open + + Closing I-Rcv-DPA I-Disc Closed + R-Rcv-DPA R-Disc Closed + Timeout Error Closed + I-Peer-Disc I-Disc Closed + R-Peer-Disc R-Disc Closed + +5.6.1. Incoming connections + + When a connection request is received from a Diameter peer, it is + not, in the general case, possible to know the identity of that peer + until a CER is received from it. This is because host and port + determine the identity of a Diameter peer; and the source port of an + incoming connection is arbitrary. Upon receipt of CER, the identity + of the connecting peer can be uniquely determined from Origin-Host. + + For this reason, a Diameter peer must employ logic separate from the + state machine to receive connection requests, accept them, and await + CER. Once CER arrives on a new connection, the Origin-Host that + identifies the peer is used to locate the state machine associated + with that peer, and the new connection and CER are passed to the + state machine as an R-Conn-CER event. + + The logic that handles incoming connections SHOULD close and discard + the connection if any message other than CER arrives, or if an + implementation-defined timeout occurs prior to receipt of CER. + + Because handling of incoming connections up to and including receipt + of CER requires logic, separate from that of any individual state + machine associated with a particular peer, it is described separately + in this section rather than in the state machine above. + + + + +Calhoun, et al. Standards Track [Page 68] + +RFC 3588 Diameter Based Protocol September 2003 + + +5.6.2. Events + + Transitions and actions in the automaton are caused by events. In + this section, we will ignore the -I and -R prefix, since the actual + event would be identical, but would occur on one of two possible + connections. + + Start The Diameter application has signaled that a + connection should be initiated with the peer. + + R-Conn-CER An acknowledgement is received stating that the + transport connection has been established, and the + associated CER has arrived. + + Rcv-Conn-Ack A positive acknowledgement is received confirming that + the transport connection is established. + + Rcv-Conn-Nack A negative acknowledgement was received stating that + the transport connection was not established. + + Timeout An application-defined timer has expired while waiting + for some event. + + Rcv-CER A CER message from the peer was received. + + Rcv-CEA A CEA message from the peer was received. + + Rcv-Non-CEA A message other than CEA from the peer was received. + + Peer-Disc A disconnection indication from the peer was received. + + Rcv-DPR A DPR message from the peer was received. + + Rcv-DPA A DPA message from the peer was received. + + Win-Election An election was held, and the local node was the + winner. + + Send-Message A message is to be sent. + + Rcv-Message A message other than CER, CEA, DPR, DPA, DWR or DWA + was received. + + Stop The Diameter application has signaled that a + connection should be terminated (e.g., on system + shutdown). + + + + + +Calhoun, et al. Standards Track [Page 69] + +RFC 3588 Diameter Based Protocol September 2003 + + +5.6.3. Actions + + Actions in the automaton are caused by events and typically indicate + the transmission of packets and/or an action to be taken on the + connection. In this section we will ignore the I- and R-prefix, + since the actual action would be identical, but would occur on one of + two possible connections. + + Snd-Conn-Req A transport connection is initiated with the peer. + + Accept The incoming connection associated with the R-Conn-CER + is accepted as the responder connection. + + Reject The incoming connection associated with the R-Conn-CER + is disconnected. + + Process-CER The CER associated with the R-Conn-CER is processed. + + Snd-CER A CER message is sent to the peer. + + Snd-CEA A CEA message is sent to the peer. + + Cleanup If necessary, the connection is shutdown, and any + local resources are freed. + + Error The transport layer connection is disconnected, either + politely or abortively, in response to an error + condition. Local resources are freed. + + Process-CEA A received CEA is processed. + + Snd-DPR A DPR message is sent to the peer. + + Snd-DPA A DPA message is sent to the peer. + + Disc The transport layer connection is disconnected, and + local resources are freed. + + Elect An election occurs (see Section 5.6.4 for more + information). + + Snd-Message A message is sent. + + Snd-DWR A DWR message is sent. + + Snd-DWA A DWA message is sent. + + Process-DWR The DWR message is serviced. + + + +Calhoun, et al. Standards Track [Page 70] + +RFC 3588 Diameter Based Protocol September 2003 + + + Process-DWA The DWA message is serviced. + + Process A message is serviced. + +5.6.4. The Election Process + + The election is performed on the responder. The responder compares + the Origin-Host received in the CER sent by its peer with its own + Origin-Host. If the local Diameter entity's Origin-Host is higher + than the peer's, a Win-Election event is issued locally. + + The comparison proceeds by considering the shorter OctetString to be + padded with zeros so that it length is the same as the length of the + longer, then performing an octet-by-octet unsigned comparison with + the first octet being most significant. Any remaining octets are + assumed to have value 0x80. + +6. Diameter message processing + + This section describes how Diameter requests and answers are created + and processed. + +6.1. Diameter Request Routing Overview + + A request is sent towards its final destination using a combination + of the Destination-Realm and Destination-Host AVPs, in one of these + three combinations: + + - a request that is not able to be proxied (such as CER) MUST NOT + contain either Destination-Realm or Destination-Host AVPs. + + - a request that needs to be sent to a home server serving a + specific realm, but not to a specific server (such as the first + request of a series of round-trips), MUST contain a Destination- + Realm AVP, but MUST NOT contain a Destination-Host AVP. + + - otherwise, a request that needs to be sent to a specific home + server among those serving a given realm, MUST contain both the + Destination-Realm and Destination-Host AVPs. + + The Destination-Host AVP is used as described above when the + destination of the request is fixed, which includes: + + - Authentication requests that span multiple round trips + + - A Diameter message that uses a security mechanism that makes use + of a pre-established session key shared between the source and the + final destination of the message. + + + +Calhoun, et al. Standards Track [Page 71] + +RFC 3588 Diameter Based Protocol September 2003 + + + - Server initiated messages that MUST be received by a specific + Diameter client (e.g., access device), such as the Abort-Session- + Request message, which is used to request that a particular user's + session be terminated. + + Note that an agent can forward a request to a host described in the + Destination-Host AVP only if the host in question is included in its + peer table (see Section 2.7). Otherwise, the request is routed based + on the Destination-Realm only (see Sections 6.1.6). + + The Destination-Realm AVP MUST be present if the message is + proxiable. Request messages that may be forwarded by Diameter agents + (proxies, redirects or relays) MUST also contain an Acct- + Application-Id AVP, an Auth-Application-Id AVP or a Vendor-Specific- + Application-Id AVP. A message that MUST NOT be forwarded by Diameter + agents (proxies, redirects or relays) MUST not include the + Destination-Realm in its ABNF. The value of the Destination-Realm + AVP MAY be extracted from the User-Name AVP, or other application- + specific methods. + + When a message is received, the message is processed in the following + order: + + 1. If the message is destined for the local host, the procedures + listed in Section 6.1.4 are followed. + + 2. If the message is intended for a Diameter peer with whom the local + host is able to directly communicate, the procedures listed in + Section 6.1.5 are followed. This is known as Request Forwarding. + + 3. The procedures listed in Section 6.1.6 are followed, which is + known as Request Routing. + + 4. If none of the above is successful, an answer is returned with the + Result-Code set to DIAMETER_UNABLE_TO_DELIVER, with the E-bit set. + + For routing of Diameter messages to work within an administrative + domain, all Diameter nodes within the realm MUST be peers. + + Note the processing rules contained in this section are intended to + be used as general guidelines to Diameter developers. Certain + implementations MAY use different methods than the ones described + here, and still comply with the protocol specification. See Section + 7 for more detail on error handling. + + + + + + + +Calhoun, et al. Standards Track [Page 72] + +RFC 3588 Diameter Based Protocol September 2003 + + +6.1.1. Originating a Request + + When creating a request, in addition to any other procedures + described in the application definition for that specific request, + the following procedures MUST be followed: + + - the Command-Code is set to the appropriate value + + - the 'R' bit is set + + - the End-to-End Identifier is set to a locally unique value + + - the Origin-Host and Origin-Realm AVPs MUST be set to the + appropriate values, used to identify the source of the message + + - the Destination-Host and Destination-Realm AVPs MUST be set to the + appropriate values as described in Section 6.1. + + - an Acct-Application-Id AVP, an Auth-Application-Id or a Vendor- + Specific-Application-Id AVP must be included if the request is + proxiable. + +6.1.2. Sending a Request + + When sending a request, originated either locally, or as the result + of a forwarding or routing operation, the following procedures MUST + be followed: + + - the Hop-by-Hop Identifier should be set to a locally unique value + + - The message should be saved in the list of pending requests. + + Other actions to perform on the message based on the particular role + the agent is playing are described in the following sections. + +6.1.3. Receiving Requests + + A relay or proxy agent MUST check for forwarding loops when receiving + requests. A loop is detected if the server finds its own identity in + a Route-Record AVP. When such an event occurs, the agent MUST answer + with the Result-Code AVP set to DIAMETER_LOOP_DETECTED. + +6.1.4. Processing Local Requests + + A request is known to be for local consumption when one of the + following conditions occur: + + - The Destination-Host AVP contains the local host's identity, + + + +Calhoun, et al. Standards Track [Page 73] + +RFC 3588 Diameter Based Protocol September 2003 + + + - The Destination-Host AVP is not present, the Destination-Realm AVP + contains a realm the server is configured to process locally, and + the Diameter application is locally supported, or + + - Both the Destination-Host and the Destination-Realm are not + present. + + When a request is locally processed, the rules in Section 6.2 should + be used to generate the corresponding answer. + +6.1.5. Request Forwarding + + Request forwarding is done using the Diameter Peer Table. The + Diameter peer table contains all of the peers that the local node is + able to directly communicate with. + + When a request is received, and the host encoded in the Destination- + Host AVP is one that is present in the peer table, the message SHOULD + be forwarded to the peer. + +6.1.6. Request Routing + + Diameter request message routing is done via realms and applications. + A Diameter message that may be forwarded by Diameter agents (proxies, + redirects or relays) MUST include the target realm in the + Destination-Realm AVP and one of the application identification AVPs + Auth-Application-Id, Acct-Application-Id or Vendor-Specific- + Application-Id. The realm MAY be retrieved from the User-Name AVP, + which is in the form of a Network Access Identifier (NAI). The realm + portion of the NAI is inserted in the Destination-Realm AVP. + + Diameter agents MAY have a list of locally supported realms and + applications, and MAY have a list of externally supported realms and + applications. When a request is received that includes a realm + and/or application that is not locally supported, the message is + routed to the peer configured in the Realm Routing Table (see Section + 2.7). + +6.1.7. Redirecting requests + + When a redirect agent receives a request whose routing entry is set + to REDIRECT, it MUST reply with an answer message with the 'E' bit + set, while maintaining the Hop-by-Hop Identifier in the header, and + include the Result-Code AVP to DIAMETER_REDIRECT_INDICATION. Each of + the servers associated with the routing entry are added in separate + Redirect-Host AVP. + + + + + +Calhoun, et al. Standards Track [Page 74] + +RFC 3588 Diameter Based Protocol September 2003 + + + +------------------+ + | Diameter | + | Redirect Agent | + +------------------+ + ^ | 2. command + 'E' bit + 1. Request | | Result-Code = + [email protected] | | DIAMETER_REDIRECT_INDICATION + + | | Redirect-Host AVP(s) + | v + +-------------+ 3. Request +-------------+ + | example.com |------------->| example.net | + | Relay | | Diameter | + | Agent |<-------------| Server | + +-------------+ 4. Answer +-------------+ + + Figure 5: Diameter Redirect Agent + + The receiver of the answer message with the 'E' bit set, and the + Result-Code AVP set to DIAMETER_REDIRECT_INDICATION uses the hop-by- + hop field in the Diameter header to identify the request in the + pending message queue (see Section 5.3) that is to be redirected. If + no transport connection exists with the new agent, one is created, + and the request is sent directly to it. + + Multiple Redirect-Host AVPs are allowed. The receiver of the answer + message with the 'E' bit set selects exactly one of these hosts as + the destination of the redirected message. + +6.1.8. Relaying and Proxying Requests + + A relay or proxy agent MUST append a Route-Record AVP to all requests + forwarded. The AVP contains the identity of the peer the request was + received from. + + The Hop-by-Hop identifier in the request is saved, and replaced with + a locally unique value. The source of the request is also saved, + which includes the IP address, port and protocol. + + A relay or proxy agent MAY include the Proxy-Info AVP in requests if + it requires access to any local state information when the + corresponding response is received. Proxy-Info AVP has certain + security implications and SHOULD contain an embedded HMAC with a + node-local key. Alternatively, it MAY simply use local storage to + store state information. + + The message is then forwarded to the next hop, as identified in the + Realm Routing Table. + + + + +Calhoun, et al. Standards Track [Page 75] + +RFC 3588 Diameter Based Protocol September 2003 + + + Figure 6 provides an example of message routing using the procedures + listed in these sections. + + (Origin-Host=nas.mno.net) (Origin-Host=nas.mno.net) + (Origin-Realm=mno.net) (Origin-Realm=mno.net) + (Destination-Realm=example.com) (Destination- + Realm=example.com) + (Route-Record=nas.example.net) + +------+ ------> +------+ ------> +------+ + | | (Request) | | (Request) | | + | NAS +-------------------+ DRL +-------------------+ HMS | + | | | | | | + +------+ <------ +------+ <------ +------+ + example.net (Answer) example.net (Answer) example.com + (Origin-Host=hms.example.com) (Origin-Host=hms.example.com) + (Origin-Realm=example.com) (Origin-Realm=example.com) + + Figure 6: Routing of Diameter messages + +6.2. Diameter Answer Processing + + When a request is locally processed, the following procedures MUST be + applied to create the associated answer, in addition to any + additional procedures that MAY be discussed in the Diameter + application defining the command: + + - The same Hop-by-Hop identifier in the request is used in the + answer. + + - The local host's identity is encoded in the Origin-Host AVP. + + - The Destination-Host and Destination-Realm AVPs MUST NOT be + present in the answer message. + + - The Result-Code AVP is added with its value indicating success or + failure. + + - If the Session-Id is present in the request, it MUST be included + in the answer. + + - Any Proxy-Info AVPs in the request MUST be added to the answer + message, in the same order they were present in the request. + + - The 'P' bit is set to the same value as the one in the request. + + - The same End-to-End identifier in the request is used in the + answer. + + + + +Calhoun, et al. Standards Track [Page 76] + +RFC 3588 Diameter Based Protocol September 2003 + + + Note that the error messages (see Section 7.3) are also subjected to + the above processing rules. + +6.2.1. Processing received Answers + + A Diameter client or proxy MUST match the Hop-by-Hop Identifier in an + answer received against the list of pending requests. The + corresponding message should be removed from the list of pending + requests. It SHOULD ignore answers received that do not match a + known Hop-by-Hop Identifier. + +6.2.2. Relaying and Proxying Answers + + If the answer is for a request which was proxied or relayed, the + agent MUST restore the original value of the Diameter header's Hop- + by-Hop Identifier field. + + If the last Proxy-Info AVP in the message is targeted to the local + Diameter server, the AVP MUST be removed before the answer is + forwarded. + + If a relay or proxy agent receives an answer with a Result-Code AVP + indicating a failure, it MUST NOT modify the contents of the AVP. + Any additional local errors detected SHOULD be logged, but not + reflected in the Result-Code AVP. If the agent receives an answer + message with a Result-Code AVP indicating success, and it wishes to + modify the AVP to indicate an error, it MUST modify the Result-Code + AVP to contain the appropriate error in the message destined towards + the access device as well as include the Error-Reporting-Host AVP and + it MUST issue an STR on behalf of the access device. + + The agent MUST then send the answer to the host that it received the + original request from. + +6.3. Origin-Host AVP + + The Origin-Host AVP (AVP Code 264) is of type DiameterIdentity, and + MUST be present in all Diameter messages. This AVP identifies the + endpoint that originated the Diameter message. Relay agents MUST NOT + modify this AVP. + + The value of the Origin-Host AVP is guaranteed to be unique within a + single host. + + Note that the Origin-Host AVP may resolve to more than one address as + the Diameter peer may support more than one address. + + + + + +Calhoun, et al. Standards Track [Page 77] + +RFC 3588 Diameter Based Protocol September 2003 + + + This AVP SHOULD be placed as close to the Diameter header as + possible. 6.10 + +6.4. Origin-Realm AVP + + The Origin-Realm AVP (AVP Code 296) is of type DiameterIdentity. + This AVP contains the Realm of the originator of any Diameter message + and MUST be present in all messages. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + +6.5. Destination-Host AVP + + The Destination-Host AVP (AVP Code 293) is of type DiameterIdentity. + This AVP MUST be present in all unsolicited agent initiated messages, + MAY be present in request messages, and MUST NOT be present in Answer + messages. + + The absence of the Destination-Host AVP will cause a message to be + sent to any Diameter server supporting the application within the + realm specified in Destination-Realm AVP. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + +6.6. Destination-Realm AVP + + The Destination-Realm AVP (AVP Code 283) is of type DiameterIdentity, + and contains the realm the message is to be routed to. The + Destination-Realm AVP MUST NOT be present in Answer messages. + Diameter Clients insert the realm portion of the User-Name AVP. + Diameter servers initiating a request message use the value of the + Origin-Realm AVP from a previous message received from the intended + target host (unless it is known a priori). When present, the + Destination-Realm AVP is used to perform message routing decisions. + + Request messages whose ABNF does not list the Destination-Realm AVP + as a mandatory AVP are inherently non-routable messages. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + +6.7. Routing AVPs + + The AVPs defined in this section are Diameter AVPs used for routing + purposes. These AVPs change as Diameter messages are processed by + agents, and therefore MUST NOT be protected by end-to-end security. + + + +Calhoun, et al. Standards Track [Page 78] + +RFC 3588 Diameter Based Protocol September 2003 + + +6.7.1. Route-Record AVP + + The Route-Record AVP (AVP Code 282) is of type DiameterIdentity. The + identity added in this AVP MUST be the same as the one received in + the Origin-Host of the Capabilities Exchange message. + +6.7.2. Proxy-Info AVP + + The Proxy-Info AVP (AVP Code 284) is of type Grouped. The Grouped + Data field has the following ABNF grammar: + + Proxy-Info ::= < AVP Header: 284 > + { Proxy-Host } + { Proxy-State } + * [ AVP ] + +6.7.3. Proxy-Host AVP + + The Proxy-Host AVP (AVP Code 280) is of type DiameterIdentity. This + AVP contains the identity of the host that added the Proxy-Info AVP. + +6.7.4. Proxy-State AVP + + The Proxy-State AVP (AVP Code 33) is of type OctetString, and + contains state local information, and MUST be treated as opaque data. + +6.8. Auth-Application-Id AVP + + The Auth-Application-Id AVP (AVP Code 258) is of type Unsigned32 and + is used in order to advertise support of the Authentication and + Authorization portion of an application (see Section 2.4). The + Auth-Application-Id MUST also be present in all Authentication and/or + Authorization messages that are defined in a separate Diameter + specification and have an Application ID assigned. + +6.9. Acct-Application-Id AVP + + The Acct-Application-Id AVP (AVP Code 259) is of type Unsigned32 and + is used in order to advertise support of the Accounting portion of an + application (see Section 2.4). The Acct-Application-Id MUST also be + present in all Accounting messages. Exactly one of the Auth- + Application-Id and Acct-Application-Id AVPs MAY be present. + +6.10. Inband-Security-Id AVP + + The Inband-Security-Id AVP (AVP Code 299) is of type Unsigned32 and + is used in order to advertise support of the Security portion of the + application. + + + +Calhoun, et al. Standards Track [Page 79] + +RFC 3588 Diameter Based Protocol September 2003 + + + Currently, the following values are supported, but there is ample + room to add new security Ids. + + NO_INBAND_SECURITY 0 + This peer does not support TLS. This is the default value, if the + AVP is omitted. + + TLS 1 + This node supports TLS security, as defined by [TLS]. + +6.11. Vendor-Specific-Application-Id AVP + + The Vendor-Specific-Application-Id AVP (AVP Code 260) is of type + Grouped and is used to advertise support of a vendor-specific + Diameter Application. Exactly one of the Auth-Application-Id and + Acct-Application-Id AVPs MAY be present. + + This AVP MUST also be present as the first AVP in all experimental + commands defined in the vendor-specific application. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + + AVP Format + + <Vendor-Specific-Application-Id> ::= < AVP Header: 260 > + 1* [ Vendor-Id ] + 0*1{ Auth-Application-Id } + 0*1{ Acct-Application-Id } + +6.12. Redirect-Host AVP + + One or more of instances of this AVP MUST be present if the answer + message's 'E' bit is set and the Result-Code AVP is set to + DIAMETER_REDIRECT_INDICATION. + + Upon receiving the above, the receiving Diameter node SHOULD forward + the request directly to one of the hosts identified in these AVPs. + The server contained in the selected Redirect-Host AVP SHOULD be used + for all messages pertaining to this session. + +6.13. Redirect-Host-Usage AVP + + The Redirect-Host-Usage AVP (AVP Code 261) is of type Enumerated. + This AVP MAY be present in answer messages whose 'E' bit is set and + the Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION. + + + + + +Calhoun, et al. Standards Track [Page 80] + +RFC 3588 Diameter Based Protocol September 2003 + + + When present, this AVP dictates how the routing entry resulting from + the Redirect-Host is to be used. The following values are supported: + + DONT_CACHE 0 + The host specified in the Redirect-Host AVP should not be cached. + This is the default value. + + ALL_SESSION 1 + All messages within the same session, as defined by the same value + of the Session-ID AVP MAY be sent to the host specified in the + Redirect-Host AVP. + + ALL_REALM 2 + All messages destined for the realm requested MAY be sent to the + host specified in the Redirect-Host AVP. + + REALM_AND_APPLICATION 3 + All messages for the application requested to the realm specified + MAY be sent to the host specified in the Redirect-Host AVP. + + ALL_APPLICATION 4 + All messages for the application requested MAY be sent to the host + specified in the Redirect-Host AVP. + + ALL_HOST 5 + All messages that would be sent to the host that generated the + Redirect-Host MAY be sent to the host specified in the Redirect- + Host AVP. + + ALL_USER 6 + All messages for the user requested MAY be sent to the host + specified in the Redirect-Host AVP. + +6.14. Redirect-Max-Cache-Time AVP + + The Redirect-Max-Cache-Time AVP (AVP Code 262) is of type Unsigned32. + This AVP MUST be present in answer messages whose 'E' bit is set, the + Result-Code AVP is set to DIAMETER_REDIRECT_INDICATION and the + Redirect-Host-Usage AVP set to a non-zero value. + + This AVP contains the maximum number of seconds the peer and route + table entries, created as a result of the Redirect-Host, will be + cached. Note that once a host created due to a redirect indication + is no longer reachable, any associated peer and routing table entries + MUST be deleted. + + + + + + +Calhoun, et al. Standards Track [Page 81] + +RFC 3588 Diameter Based Protocol September 2003 + + +6.15. E2E-Sequence AVP + + The E2E-Sequence AVP (AVP Code 300) provides anti-replay protection + for end to end messages and is of type grouped. It contains a random + value (an OctetString with a nonce) and counter (an Integer). For + each end-to-end peer with which a node communicates (or remembers + communicating) a different nonce value MUST be used and the counter + is initiated at zero and increases by one each time this AVP is + emitted to that peer. This AVP MUST be included in all messages + which use end-to-end protection (e.g., CMS signing or encryption). + +7. Error Handling + + There are two different types of errors in Diameter; protocol and + application errors. A protocol error is one that occurs at the base + protocol level, and MAY require per hop attention (e.g., message + routing error). Application errors, on the other hand, generally + occur due to a problem with a function specified in a Diameter + application (e.g., user authentication, Missing AVP). + + Result-Code AVP values that are used to report protocol errors MUST + only be present in answer messages whose 'E' bit is set. When a + request message is received that causes a protocol error, an answer + message is returned with the 'E' bit set, and the Result-Code AVP is + set to the appropriate protocol error value. As the answer is sent + back towards the originator of the request, each proxy or relay agent + MAY take action on the message. + + 1. Request +---------+ Link Broken + +-------------------------->|Diameter |----///----+ + | +---------------------| | v + +------+--+ | 2. answer + 'E' set | Relay 2 | +--------+ + |Diameter |<-+ (Unable to Forward) +---------+ |Diameter| + | | | Home | + | Relay 1 |--+ +---------+ | Server | + +---------+ | 3. Request |Diameter | +--------+ + +-------------------->| | ^ + | Relay 3 |-----------+ + +---------+ + + Figure 7: Example of Protocol Error causing answer message + + Figure 7 provides an example of a message forwarded upstream by a + Diameter relay. When the message is received by Relay 2, and it + detects that it cannot forward the request to the home server, an + answer message is returned with the 'E' bit set and the Result-Code + AVP set to DIAMETER_UNABLE_TO_DELIVER. Given that this error falls + + + + +Calhoun, et al. Standards Track [Page 82] + +RFC 3588 Diameter Based Protocol September 2003 + + + within the protocol error category, Relay 1 would take special + action, and given the error, attempt to route the message through its + alternate Relay 3. + + +---------+ 1. Request +---------+ 2. Request +---------+ + | Access |------------>|Diameter |------------>|Diameter | + | | | | | Home | + | Device |<------------| Relay |<------------| Server | + +---------+ 4. Answer +---------+ 3. Answer +---------+ + (Missing AVP) (Missing AVP) + + Figure 8: Example of Application Error Answer message + + Figure 8 provides an example of a Diameter message that caused an + application error. When application errors occur, the Diameter + entity reporting the error clears the 'R' bit in the Command Flags, + and adds the Result-Code AVP with the proper value. Application + errors do not require any proxy or relay agent involvement, and + therefore the message would be forwarded back to the originator of + the request. + + There are certain Result-Code AVP application errors that require + additional AVPs to be present in the answer. In these cases, the + Diameter node that sets the Result-Code AVP to indicate the error + MUST add the AVPs. Examples are: + + - An unrecognized AVP is received with the 'M' bit (Mandatory bit) + set, causes an answer to be sent with the Result-Code AVP set to + DIAMETER_AVP_UNSUPPORTED, and the Failed-AVP AVP containing the + offending AVP. + + - An AVP that is received with an unrecognized value causes an + answer to be returned with the Result-Code AVP set to + DIAMETER_INVALID_AVP_VALUE, with the Failed-AVP AVP containing the + AVP causing the error. + + - A command is received with an AVP that is omitted, yet is + mandatory according to the command's ABNF. The receiver issues an + answer with the Result-Code set to DIAMETER_MISSING_AVP, and + creates an AVP with the AVP Code and other fields set as expected + in the missing AVP. The created AVP is then added to the Failed- + AVP AVP. + + The Result-Code AVP describes the error that the Diameter node + encountered in its processing. In case there are multiple errors, + the Diameter node MUST report only the first error it encountered + + + + + +Calhoun, et al. Standards Track [Page 83] + +RFC 3588 Diameter Based Protocol September 2003 + + + (detected possibly in some implementation dependent order). The + specific errors that can be described by this AVP are described in + the following section. + +7.1. Result-Code AVP + + The Result-Code AVP (AVP Code 268) is of type Unsigned32 and + indicates whether a particular request was completed successfully or + whether an error occurred. All Diameter answer messages defined in + IETF applications MUST include one Result-Code AVP. A non-successful + Result-Code AVP (one containing a non 2xxx value other than + DIAMETER_REDIRECT_INDICATION) MUST include the Error-Reporting-Host + AVP if the host setting the Result-Code AVP is different from the + identity encoded in the Origin-Host AVP. + + The Result-Code data field contains an IANA-managed 32-bit address + space representing errors (see Section 11.4). Diameter provides the + following classes of errors, all identified by the thousands digit in + the decimal notation: + + - 1xxx (Informational) + - 2xxx (Success) + - 3xxx (Protocol Errors) + - 4xxx (Transient Failures) + - 5xxx (Permanent Failure) + + A non-recognized class (one whose first digit is not defined in this + section) MUST be handled as a permanent failure. + +7.1.1. Informational + + Errors that fall within this category are used to inform the + requester that a request could not be satisfied, and additional + action is required on its part before access is granted. + + DIAMETER_MULTI_ROUND_AUTH 1001 + This informational error is returned by a Diameter server to + inform the access device that the authentication mechanism being + used requires multiple round trips, and a subsequent request needs + to be issued in order for access to be granted. + +7.1.2. Success + + Errors that fall within the Success category are used to inform a + peer that a request has been successfully completed. + + DIAMETER_SUCCESS 2001 + The Request was successfully completed. + + + +Calhoun, et al. Standards Track [Page 84] + +RFC 3588 Diameter Based Protocol September 2003 + + + DIAMETER_LIMITED_SUCCESS 2002 + When returned, the request was successfully completed, but + additional processing is required by the application in order to + provide service to the user. + +7.1.3. Protocol Errors + + Errors that fall within the Protocol Error category SHOULD be treated + on a per-hop basis, and Diameter proxies MAY attempt to correct the + error, if it is possible. Note that these and only these errors MUST + only be used in answer messages whose 'E' bit is set. + + DIAMETER_COMMAND_UNSUPPORTED 3001 + The Request contained a Command-Code that the receiver did not + recognize or support. This MUST be used when a Diameter node + receives an experimental command that it does not understand. + + DIAMETER_UNABLE_TO_DELIVER 3002 + This error is given when Diameter can not deliver the message to + the destination, either because no host within the realm + supporting the required application was available to process the + request, or because Destination-Host AVP was given without the + associated Destination-Realm AVP. + + DIAMETER_REALM_NOT_SERVED 3003 + The intended realm of the request is not recognized. + + DIAMETER_TOO_BUSY 3004 + When returned, a Diameter node SHOULD attempt to send the message + to an alternate peer. This error MUST only be used when a + specific server is requested, and it cannot provide the requested + service. + + DIAMETER_LOOP_DETECTED 3005 + An agent detected a loop while trying to get the message to the + intended recipient. The message MAY be sent to an alternate peer, + if one is available, but the peer reporting the error has + identified a configuration problem. + + DIAMETER_REDIRECT_INDICATION 3006 + A redirect agent has determined that the request could not be + satisfied locally and the initiator of the request should direct + the request directly to the server, whose contact information has + been added to the response. When set, the Redirect-Host AVP MUST + be present. + + DIAMETER_APPLICATION_UNSUPPORTED 3007 + A request was sent for an application that is not supported. + + + +Calhoun, et al. Standards Track [Page 85] + +RFC 3588 Diameter Based Protocol September 2003 + + + DIAMETER_INVALID_HDR_BITS 3008 + A request was received whose bits in the Diameter header were + either set to an invalid combination, or to a value that is + inconsistent with the command code's definition. + + DIAMETER_INVALID_AVP_BITS 3009 + A request was received that included an AVP whose flag bits are + set to an unrecognized value, or that is inconsistent with the + AVP's definition. + + DIAMETER_UNKNOWN_PEER 3010 + A CER was received from an unknown peer. + +7.1.4. Transient Failures + + Errors that fall within the transient failures category are used + to inform a peer that the request could not be satisfied at the + time it was received, but MAY be able to satisfy the request in + the future. + + DIAMETER_AUTHENTICATION_REJECTED 4001 + The authentication process for the user failed, most likely due to + an invalid password used by the user. Further attempts MUST only + be tried after prompting the user for a new password. + + DIAMETER_OUT_OF_SPACE 4002 + A Diameter node received the accounting request but was unable to + commit it to stable storage due to a temporary lack of space. + + ELECTION_LOST 4003 + The peer has determined that it has lost the election process and + has therefore disconnected the transport connection. + +7.1.5. Permanent Failures + + Errors that fall within the permanent failures category are used + to inform the peer that the request failed, and should not be + attempted again. + + DIAMETER_AVP_UNSUPPORTED 5001 + The peer received a message that contained an AVP that is not + recognized or supported and was marked with the Mandatory bit. A + Diameter message with this error MUST contain one or more Failed- + AVP AVP containing the AVPs that caused the failure. + + DIAMETER_UNKNOWN_SESSION_ID 5002 + The request contained an unknown Session-Id. + + + + +Calhoun, et al. Standards Track [Page 86] + +RFC 3588 Diameter Based Protocol September 2003 + + + DIAMETER_AUTHORIZATION_REJECTED 5003 + A request was received for which the user could not be authorized. + This error could occur if the service requested is not permitted + to the user. + + DIAMETER_INVALID_AVP_VALUE 5004 + The request contained an AVP with an invalid value in its data + portion. A Diameter message indicating this error MUST include + the offending AVPs within a Failed-AVP AVP. + + DIAMETER_MISSING_AVP 5005 + The request did not contain an AVP that is required by the Command + Code definition. If this value is sent in the Result-Code AVP, a + Failed-AVP AVP SHOULD be included in the message. The Failed-AVP + AVP MUST contain an example of the missing AVP complete with the + Vendor-Id if applicable. The value field of the missing AVP + should be of correct minimum length and contain zeroes. + + DIAMETER_RESOURCES_EXCEEDED 5006 + A request was received that cannot be authorized because the user + has already expended allowed resources. An example of this error + condition is a user that is restricted to one dial-up PPP port, + attempts to establish a second PPP connection. + + DIAMETER_CONTRADICTING_AVPS 5007 + The Home Diameter server has detected AVPs in the request that + contradicted each other, and is not willing to provide service to + the user. One or more Failed-AVP AVPs MUST be present, containing + the AVPs that contradicted each other. + + DIAMETER_AVP_NOT_ALLOWED 5008 + A message was received with an AVP that MUST NOT be present. The + Failed-AVP AVP MUST be included and contain a copy of the + offending AVP. + + DIAMETER_AVP_OCCURS_TOO_MANY_TIMES 5009 + A message was received that included an AVP that appeared more + often than permitted in the message definition. The Failed-AVP + AVP MUST be included and contain a copy of the first instance of + the offending AVP that exceeded the maximum number of occurrences + + DIAMETER_NO_COMMON_APPLICATION 5010 + This error is returned when a CER message is received, and there + are no common applications supported between the peers. + + DIAMETER_UNSUPPORTED_VERSION 5011 + This error is returned when a request was received, whose version + number is unsupported. + + + +Calhoun, et al. Standards Track [Page 87] + +RFC 3588 Diameter Based Protocol September 2003 + + + DIAMETER_UNABLE_TO_COMPLY 5012 + This error is returned when a request is rejected for unspecified + reasons. + + DIAMETER_INVALID_BIT_IN_HEADER 5013 + This error is returned when an unrecognized bit in the Diameter + header is set to one (1). + + DIAMETER_INVALID_AVP_LENGTH 5014 + The request contained an AVP with an invalid length. A Diameter + message indicating this error MUST include the offending AVPs + within a Failed-AVP AVP. + + DIAMETER_INVALID_MESSAGE_LENGTH 5015 + This error is returned when a request is received with an invalid + message length. + + DIAMETER_INVALID_AVP_BIT_COMBO 5016 + The request contained an AVP with which is not allowed to have the + given value in the AVP Flags field. A Diameter message indicating + this error MUST include the offending AVPs within a Failed-AVP + AVP. + + DIAMETER_NO_COMMON_SECURITY 5017 + This error is returned when a CER message is received, and there + are no common security mechanisms supported between the peers. A + Capabilities-Exchange-Answer (CEA) MUST be returned with the + Result-Code AVP set to DIAMETER_NO_COMMON_SECURITY. + +7.2. Error Bit + + The 'E' (Error Bit) in the Diameter header is set when the request + caused a protocol-related error (see Section 7.1.3). A message with + the 'E' bit MUST NOT be sent as a response to an answer message. + Note that a message with the 'E' bit set is still subjected to the + processing rules defined in Section 6.2. When set, the answer + message will not conform to the ABNF specification for the command, + and will instead conform to the following ABNF: + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 88] + +RFC 3588 Diameter Based Protocol September 2003 + + + Message Format + + <answer-message> ::= < Diameter Header: code, ERR [PXY] > + 0*1< Session-Id > + { Origin-Host } + { Origin-Realm } + { Result-Code } + [ Origin-State-Id ] + [ Error-Reporting-Host ] + [ Proxy-Info ] + * [ AVP ] + + Note that the code used in the header is the same than the one found + in the request message, but with the 'R' bit cleared and the 'E' bit + set. The 'P' bit in the header is set to the same value as the one + found in the request message. + +7.3. Error-Message AVP + + The Error-Message AVP (AVP Code 281) is of type UTF8String. It MAY + accompany a Result-Code AVP as a human readable error message. The + Error-Message AVP is not intended to be useful in real-time, and + SHOULD NOT be expected to be parsed by network entities. + +7.4. Error-Reporting-Host AVP + + The Error-Reporting-Host AVP (AVP Code 294) is of type + DiameterIdentity. This AVP contains the identity of the Diameter + host that sent the Result-Code AVP to a value other than 2001 + (Success), only if the host setting the Result-Code is different from + the one encoded in the Origin-Host AVP. This AVP is intended to be + used for troubleshooting purposes, and MUST be set when the Result- + Code AVP indicates a failure. + +7.5. Failed-AVP AVP + + The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides + debugging information in cases where a request is rejected or not + fully processed due to erroneous information in a specific AVP. The + value of the Result-Code AVP will provide information on the reason + for the Failed-AVP AVP. + + The possible reasons for this AVP are the presence of an improperly + constructed AVP, an unsupported or unrecognized AVP, an invalid AVP + value, the omission of a required AVP, the presence of an explicitly + excluded AVP (see tables in Section 10), or the presence of two or + more occurrences of an AVP which is restricted to 0, 1, or 0-1 + occurrences. + + + +Calhoun, et al. Standards Track [Page 89] + +RFC 3588 Diameter Based Protocol September 2003 + + + A Diameter message MAY contain one Failed-AVP AVP, containing the + entire AVP that could not be processed successfully. If the failure + reason is omission of a required AVP, an AVP with the missing AVP + code, the missing vendor id, and a zero filled payload of the minimum + required length for the omitted AVP will be added. + + AVP Format + + <Failed-AVP> ::= < AVP Header: 279 > + 1* {AVP} + +7.6. Experimental-Result AVP + + The Experimental-Result AVP (AVP Code 297) is of type Grouped, and + indicates whether a particular vendor-specific request was completed + successfully or whether an error occurred. Its Data field has the + following ABNF grammar: + + AVP Format + + Experimental-Result ::= < AVP Header: 297 > + { Vendor-Id } + { Experimental-Result-Code } + + The Vendor-Id AVP (see Section 5.3.3) in this grouped AVP identifies + the vendor responsible for the assignment of the result code which + follows. All Diameter answer messages defined in vendor-specific + applications MUST include either one Result-Code AVP or one + Experimental-Result AVP. + +7.7. Experimental-Result-Code AVP + + The Experimental-Result-Code AVP (AVP Code 298) is of type Unsigned32 + and contains a vendor-assigned value representing the result of + processing the request. + + It is recommended that vendor-specific result codes follow the same + conventions given for the Result-Code AVP regarding the different + types of result codes and the handling of errors (for non 2xxx + values). + +8. Diameter User Sessions + + Diameter can provide two different types of services to applications. + The first involves authentication and authorization, and can + optionally make use of accounting. The second only makes use of + accounting. + + + + +Calhoun, et al. Standards Track [Page 90] + +RFC 3588 Diameter Based Protocol September 2003 + + + When a service makes use of the authentication and/or authorization + portion of an application, and a user requests access to the network, + the Diameter client issues an auth request to its local server. The + auth request is defined in a service specific Diameter application + (e.g., NASREQ). The request contains a Session-Id AVP, which is used + in subsequent messages (e.g., subsequent authorization, accounting, + etc) relating to the user's session. The Session-Id AVP is a means + for the client and servers to correlate a Diameter message with a + user session. + + When a Diameter server authorizes a user to use network resources for + a finite amount of time, and it is willing to extend the + authorization via a future request, it MUST add the Authorization- + Lifetime AVP to the answer message. The Authorization-Lifetime AVP + defines the maximum number of seconds a user MAY make use of the + resources before another authorization request is expected by the + server. The Auth-Grace-Period AVP contains the number of seconds + following the expiration of the Authorization-Lifetime, after which + the server will release all state information related to the user's + session. Note that if payment for services is expected by the + serving realm from the user's home realm, the Authorization-Lifetime + AVP, combined with the Auth-Grace-Period AVP, implies the maximum + length of the session the home realm is willing to be fiscally + responsible for. Services provided past the expiration of the + Authorization-Lifetime and Auth-Grace-Period AVPs are the + responsibility of the access device. Of course, the actual cost of + services rendered is clearly outside the scope of the protocol. + + An access device that does not expect to send a re-authorization or a + session termination request to the server MAY include the Auth- + Session-State AVP with the value set to NO_STATE_MAINTAINED as a hint + to the server. If the server accepts the hint, it agrees that since + no session termination message will be received once service to the + user is terminated, it cannot maintain state for the session. If the + answer message from the server contains a different value in the + Auth-Session-State AVP (or the default value if the AVP is absent), + the access device MUST follow the server's directives. Note that the + value NO_STATE_MAINTAINED MUST NOT be set in subsequent re- + authorization requests and answers. + + The base protocol does not include any authorization request + messages, since these are largely application-specific and are + defined in a Diameter application document. However, the base + protocol does define a set of messages that is used to terminate user + sessions. These are used to allow servers that maintain state + information to free resources. + + + + + +Calhoun, et al. Standards Track [Page 91] + +RFC 3588 Diameter Based Protocol September 2003 + + + When a service only makes use of the Accounting portion of the + Diameter protocol, even in combination with an application, the + Session-Id is still used to identify user sessions. However, the + session termination messages are not used, since a session is + signaled as being terminated by issuing an accounting stop message. + +8.1. Authorization Session State Machine + + This section contains a set of finite state machines, representing + the life cycle of Diameter sessions, and which MUST be observed by + all Diameter implementations that make use of the authentication + and/or authorization portion of a Diameter application. The term + Service-Specific below refers to a message defined in a Diameter + application (e.g., Mobile IPv4, NASREQ). + + There are four different authorization session state machines + supported in the Diameter base protocol. The first two describe a + session in which the server is maintaining session state, indicated + by the value of the Auth-Session-State AVP (or its absence). One + describes the session from a client perspective, the other from a + server perspective. The second two state machines are used when the + server does not maintain session state. Here again, one describes + the session from a client perspective, the other from a server + perspective. + + When a session is moved to the Idle state, any resources that were + allocated for the particular session must be released. Any event not + listed in the state machines MUST be considered as an error + condition, and an answer, if applicable, MUST be returned to the + originator of the message. + + In the state table, the event 'Failure to send X' means that the + Diameter agent is unable to send command X to the desired + destination. This could be due to the peer being down, or due to the + peer sending back a transient failure or temporary protocol error + notification DIAMETER_TOO_BUSY or DIAMETER_LOOP_DETECTED in the + Result-Code AVP of the corresponding Answer command. The event 'X + successfully sent' is the complement of 'Failure to send X'. + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 92] + +RFC 3588 Diameter Based Protocol September 2003 + + + The following state machine is observed by a client when state is + maintained on the server: + + CLIENT, STATEFUL + State Event Action New State + ------------------------------------------------------------- + Idle Client or Device Requests Send Pending + access service + specific + auth req + + Idle ASR Received Send ASA Idle + for unknown session with + Result-Code + = UNKNOWN_ + SESSION_ID + + Pending Successful Service-specific Grant Open + authorization answer Access + received with default + Auth-Session-State value + + Pending Successful Service-specific Sent STR Discon + authorization answer received + but service not provided + + Pending Error processing successful Sent STR Discon + Service-specific authorization + answer + + Pending Failed Service-specific Cleanup Idle + authorization answer received + + Open User or client device Send Open + requests access to service service + specific + auth req + + Open Successful Service-specific Provide Open + authorization answer received Service + + Open Failed Service-specific Discon. Idle + authorization answer user/device + received. + + Open Session-Timeout Expires on Send STR Discon + Access Device + + + + +Calhoun, et al. Standards Track [Page 93] + +RFC 3588 Diameter Based Protocol September 2003 + + + Open ASR Received, Send ASA Discon + client will comply with with + request to end the session Result-Code + = SUCCESS, + Send STR. + + Open ASR Received, Send ASA Open + client will not comply with with + request to end the session Result-Code + != SUCCESS + + Open Authorization-Lifetime + Send STR Discon + Auth-Grace-Period expires on + access device + + Discon ASR Received Send ASA Discon + + Discon STA Received Discon. Idle + user/device + + The following state machine is observed by a server when it is + maintaining state for the session: + + SERVER, STATEFUL + State Event Action New State + ------------------------------------------------------------- + Idle Service-specific authorization Send Open + request received, and successful + user is authorized serv. + specific answer + + Idle Service-specific authorization Send Idle + request received, and failed serv. + user is not authorized specific answer + + Open Service-specific authorization Send Open + request received, and user successful + is authorized serv. specific + answer + + Open Service-specific authorization Send Idle + request received, and user failed serv. + is not authorized specific + answer, + Cleanup + + Open Home server wants to Send ASR Discon + terminate the service + + + +Calhoun, et al. Standards Track [Page 94] + +RFC 3588 Diameter Based Protocol September 2003 + + + Open Authorization-Lifetime (and Cleanup Idle + Auth-Grace-Period) expires + on home server. + + Open Session-Timeout expires on Cleanup Idle + home server + + Discon Failure to send ASR Wait, Discon + resend ASR + + Discon ASR successfully sent and Cleanup Idle + ASA Received with Result-Code + + Not ASA Received None No Change. + Discon + + Any STR Received Send STA, Idle + Cleanup. + + The following state machine is observed by a client when state is not + maintained on the server: + + CLIENT, STATELESS + State Event Action New State + ------------------------------------------------------------- + Idle Client or Device Requests Send Pending + access service + specific + auth req + + Pending Successful Service-specific Grant Open + authorization answer Access + received with Auth-Session- + State set to + NO_STATE_MAINTAINED + + Pending Failed Service-specific Cleanup Idle + authorization answer + received + + Open Session-Timeout Expires on Discon. Idle + Access Device user/device + + Open Service to user is terminated Discon. Idle + user/device + + + + + + +Calhoun, et al. Standards Track [Page 95] + +RFC 3588 Diameter Based Protocol September 2003 + + + The following state machine is observed by a server when it is not + maintaining state for the session: + + SERVER, STATELESS + State Event Action New State + ------------------------------------------------------------- + Idle Service-specific authorization Send serv. Idle + request received, and specific + successfully processed answer + +8.2. Accounting Session State Machine + + The following state machines MUST be supported for applications that + have an accounting portion or that require only accounting services. + The first state machine is to be observed by clients. + + See Section 9.7 for Accounting Command Codes and Section 9.8 for + Accounting AVPs. + + The server side in the accounting state machine depends in some cases + on the particular application. The Diameter base protocol defines a + default state machine that MUST be followed by all applications that + have not specified other state machines. This is the second state + machine in this section described below. + + The default server side state machine requires the reception of + accounting records in any order and at any time, and does not place + any standards requirement on the processing of these records. + Implementations of Diameter MAY perform checking, ordering, + correlation, fraud detection, and other tasks based on these records. + Both base Diameter AVPs as well as application specific AVPs MAY be + inspected as a part of these tasks. The tasks can happen either + immediately after record reception or in a post-processing phase. + However, as these tasks are typically application or even policy + dependent, they are not standardized by the Diameter specifications. + Applications MAY define requirements on when to accept accounting + records based on the used value of Accounting-Realtime-Required AVP, + credit limits checks, and so on. + + However, the Diameter base protocol defines one optional server side + state machine that MAY be followed by applications that require + keeping track of the session state at the accounting server. Note + that such tracking is incompatible with the ability to sustain long + duration connectivity problems. Therefore, the use of this state + machine is recommended only in applications where the value of the + Accounting-Realtime-Required AVP is DELIVER_AND_GRANT, and hence + accounting connectivity problems are required to cause the serviced + user to be disconnected. Otherwise, records produced by the client + + + +Calhoun, et al. Standards Track [Page 96] + +RFC 3588 Diameter Based Protocol September 2003 + + + may be lost by the server which no longer accepts them after the + connectivity is re-established. This state machine is the third + state machine in this section. The state machine is supervised by a + supervision session timer Ts, which the value should be reasonably + higher than the Acct_Interim_Interval value. Ts MAY be set to two + times the value of the Acct_Interim_Interval so as to avoid the + accounting session in the Diameter server to change to Idle state in + case of short transient network failure. + + Any event not listed in the state machines MUST be considered as an + error condition, and a corresponding answer, if applicable, MUST be + returned to the originator of the message. + + In the state table, the event 'Failure to send' means that the + Diameter client is unable to communicate with the desired + destination. This could be due to the peer being down, or due to the + peer sending back a transient failure or temporary protocol error + notification DIAMETER_OUT_OF_SPACE, DIAMETER_TOO_BUSY, or + DIAMETER_LOOP_DETECTED in the Result-Code AVP of the Accounting + Answer command. + + The event 'Failed answer' means that the Diameter client received a + non-transient failure notification in the Accounting Answer command. + + Note that the action 'Disconnect user/dev' MUST have an effect also + to the authorization session state table, e.g., cause the STR message + to be sent, if the given application has both + authentication/authorization and accounting portions. + + The states PendingS, PendingI, PendingL, PendingE and PendingB stand + for pending states to wait for an answer to an accounting request + related to a Start, Interim, Stop, Event or buffered record, + respectively. + + CLIENT, ACCOUNTING + State Event Action New State + ------------------------------------------------------------- + Idle Client or device requests Send PendingS + access accounting + start req. + + Idle Client or device requests Send PendingE + a one-time service accounting + event req + + Idle Records in storage Send PendingB + record + + + + +Calhoun, et al. Standards Track [Page 97] + +RFC 3588 Diameter Based Protocol September 2003 + + + PendingS Successful accounting Open + start answer received + + PendingS Failure to send and buffer Store Open + space available and realtime Start + not equal to DELIVER_AND_GRANT Record + + PendingS Failure to send and no buffer Open + space available and realtime + equal to GRANT_AND_LOSE + + PendingS Failure to send and no buffer Disconnect Idle + space available and realtime user/dev + not equal to + GRANT_AND_LOSE + + PendingS Failed accounting start answer Open + received and realtime equal + to GRANT_AND_LOSE + + PendingS Failed accounting start answer Disconnect Idle + received and realtime not user/dev + equal to GRANT_AND_LOSE + + PendingS User service terminated Store PendingS + stop + record + + Open Interim interval elapses Send PendingI + accounting + interim + record + Open User service terminated Send PendingL + accounting + stop req. + + PendingI Successful accounting interim Open + answer received + + PendingI Failure to send and (buffer Store Open + space available or old record interim + can be overwritten) and record + realtime not equal to + DELIVER_AND_GRANT + + PendingI Failure to send and no buffer Open + space available and realtime + equal to GRANT_AND_LOSE + + + +Calhoun, et al. Standards Track [Page 98] + +RFC 3588 Diameter Based Protocol September 2003 + + + PendingI Failure to send and no buffer Disconnect Idle + space available and realtime user/dev + not equal to GRANT_AND_LOSE + + PendingI Failed accounting interim Open + answer received and realtime + equal to GRANT_AND_LOSE + + PendingI Failed accounting interim Disconnect Idle + answer received and realtime user/dev + not equal to GRANT_AND_LOSE + + PendingI User service terminated Store PendingI + stop + record + PendingE Successful accounting Idle + event answer received + + PendingE Failure to send and buffer Store Idle + space available event + record + + PendingE Failure to send and no buffer Idle + space available + + PendingE Failed accounting event answer Idle + received + + PendingB Successful accounting answer Delete Idle + received record + + PendingB Failure to send Idle + + PendingB Failed accounting answer Delete Idle + received record + + PendingL Successful accounting Idle + stop answer received + + PendingL Failure to send and buffer Store Idle + space available stop + record + + PendingL Failure to send and no buffer Idle + space available + + PendingL Failed accounting stop answer Idle + received + + + +Calhoun, et al. Standards Track [Page 99] + +RFC 3588 Diameter Based Protocol September 2003 + + + SERVER, STATELESS ACCOUNTING + State Event Action New State + ------------------------------------------------------------- + + Idle Accounting start request Send Idle + received, and successfully accounting + processed. start + answer + + Idle Accounting event request Send Idle + received, and successfully accounting + processed. event + answer + + Idle Interim record received, Send Idle + and successfully processed. accounting + interim + answer + + Idle Accounting stop request Send Idle + received, and successfully accounting + processed stop answer + + Idle Accounting request received, Send Idle + no space left to store accounting + records answer, + Result-Code + = OUT_OF_ + SPACE + + SERVER, STATEFUL ACCOUNTING + State Event Action New State + ------------------------------------------------------------- + + Idle Accounting start request Send Open + received, and successfully accounting + processed. start + answer, + Start Ts + + Idle Accounting event request Send Idle + received, and successfully accounting + processed. event + answer + + + + + + + +Calhoun, et al. Standards Track [Page 100] + +RFC 3588 Diameter Based Protocol September 2003 + + + Idle Accounting request received, Send Idle + no space left to store accounting + records answer, + Result-Code + = OUT_OF_ + SPACE + + Open Interim record received, Send Open + and successfully processed. accounting + interim + answer, + Restart Ts + + Open Accounting stop request Send Idle + received, and successfully accounting + processed stop answer, + Stop Ts + + Open Accounting request received, Send Idle + no space left to store accounting + records answer, + Result-Code + = OUT_OF_ + SPACE, + Stop Ts + + Open Session supervision timer Ts Stop Ts Idle + expired + +8.3. Server-Initiated Re-Auth + + A Diameter server may initiate a re-authentication and/or re- + authorization service for a particular session by issuing a Re-Auth- + Request (RAR). + + For example, for pre-paid services, the Diameter server that + originally authorized a session may need some confirmation that the + user is still using the services. + + An access device that receives a RAR message with Session-Id equal to + a currently active session MUST initiate a re-auth towards the user, + if the service supports this particular feature. Each Diameter + application MUST state whether service-initiated re-auth is + supported, since some applications do not allow access devices to + prompt the user for re-auth. + + + + + + +Calhoun, et al. Standards Track [Page 101] + +RFC 3588 Diameter Based Protocol September 2003 + + +8.3.1. Re-Auth-Request + + The Re-Auth-Request (RAR), indicated by the Command-Code set to 258 + and the message flags' 'R' bit set, may be sent by any server to the + access device that is providing session service, to request that the + user be re-authenticated and/or re-authorized. + + Message Format + + <RAR> ::= < 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-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.3.2. Re-Auth-Answer + + The Re-Auth-Answer (RAA), indicated by the Command-Code set to 258 + and the message flags' 'R' bit clear, is sent in response to the RAR. + The Result-Code AVP MUST be present, and indicates the disposition of + the request. + + A successful RAA message MUST be followed by an application-specific + authentication and/or authorization message. + + + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 102] + +RFC 3588 Diameter Based Protocol September 2003 + + + Message Format + + <RAA> ::= < Diameter Header: 258, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Host-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + +8.4. Session Termination + + It is necessary for a Diameter server that authorized a session, for + which it is maintaining state, to be notified when that session is no + longer active, both for tracking purposes as well as to allow + stateful agents to release any resources that they may have provided + for the user's session. For sessions whose state is not being + maintained, this section is not used. + + When a user session that required Diameter authorization terminates, + the access device that provided the service MUST issue a Session- + Termination-Request (STR) message to the Diameter server that + authorized the service, to notify it that the session is no longer + active. An STR MUST be issued when a user session terminates for any + reason, including user logoff, expiration of Session-Timeout, + administrative action, termination upon receipt of an Abort-Session- + Request (see below), orderly shutdown of the access device, etc. + + The access device also MUST issue an STR for a session that was + authorized but never actually started. This could occur, for + example, due to a sudden resource shortage in the access device, or + because the access device is unwilling to provide the type of service + requested in the authorization, or because the access device does not + support a mandatory AVP returned in the authorization, etc. + + It is also possible that a session that was authorized is never + actually started due to action of a proxy. For example, a proxy may + modify an authorization answer, converting the result from success to + failure, prior to forwarding the message to the access device. If + the answer did not contain an Auth-Session-State AVP with the value + + + +Calhoun, et al. Standards Track [Page 103] + +RFC 3588 Diameter Based Protocol September 2003 + + + NO_STATE_MAINTAINED, a proxy that causes an authorized session not to + be started MUST issue an STR to the Diameter server that authorized + the session, since the access device has no way of knowing that the + session had been authorized. + + A Diameter server that receives an STR message MUST clean up + resources (e.g., session state) associated with the Session-Id + specified in the STR, and return a Session-Termination-Answer. + + A Diameter server also MUST clean up resources when the Session- + Timeout expires, or when the Authorization-Lifetime and the Auth- + Grace-Period AVPs expires without receipt of a re-authorization + request, regardless of whether an STR for that session is received. + The access device is not expected to provide service beyond the + expiration of these timers; thus, expiration of either of these + timers implies that the access device may have unexpectedly shut + down. + +8.4.1. Session-Termination-Request + + The Session-Termination-Request (STR), indicated by the Command-Code + set to 275 and the Command Flags' 'R' bit set, is sent by the access + device to inform the Diameter Server that an authenticated and/or + authorized session is being terminated. + + Message Format + + <STR> ::= < Diameter Header: 275, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Termination-Cause } + [ User-Name ] + [ Destination-Host ] + * [ Class ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + + + + + + + + + +Calhoun, et al. Standards Track [Page 104] + +RFC 3588 Diameter Based Protocol September 2003 + + +8.4.2. Session-Termination-Answer + + The Session-Termination-Answer (STA), indicated by the Command-Code + set to 275 and the message flags' 'R' bit clear, is sent by the + Diameter Server to acknowledge the notification that the session has + been terminated. The Result-Code AVP MUST be present, and MAY + contain an indication that an error occurred while servicing the STR. + + Upon sending or receipt of the STA, the Diameter Server MUST release + all resources for the session indicated by the Session-Id AVP. Any + intermediate server in the Proxy-Chain MAY also release any + resources, if necessary. + + Message Format + + <STA> ::= < Diameter Header: 275, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + * [ Class ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Origin-State-Id ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + ^ + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + +8.5. Aborting a Session + + A Diameter server may request that the access device stop providing + service for a particular session by issuing an Abort-Session-Request + (ASR). + + For example, the Diameter server that originally authorized the + session may be required to cause that session to be stopped for + credit or other reasons that were not anticipated when the session + was first authorized. On the other hand, an operator may maintain a + management server for the purpose of issuing ASRs to administratively + remove users from the network. + + An access device that receives an ASR with Session-ID equal to a + currently active session MAY stop the session. Whether the access + + + +Calhoun, et al. Standards Track [Page 105] + +RFC 3588 Diameter Based Protocol September 2003 + + + device stops the session or not is implementation- and/or + configuration-dependent. For example, an access device may honor + ASRs from certain agents only. In any case, the access device MUST + respond with an Abort-Session-Answer, including a Result-Code AVP to + indicate what action it took. + + Note that if the access device does stop the session upon receipt of + an ASR, it issues an STR to the authorizing server (which may or may + not be the agent issuing the ASR) just as it would if the session + were terminated for any other reason. + +8.5.1. Abort-Session-Request + + The Abort-Session-Request (ASR), indicated by the Command-Code set to + 274 and the message flags' 'R' bit set, may be sent by any server to + the access device that is providing session service, to request that + the session identified by the Session-Id be stopped. + + Message Format + + <ASR> ::= < Diameter Header: 274, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + [ User-Name ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.5.2. Abort-Session-Answer + + The Abort-Session-Answer (ASA), indicated by the Command-Code set to + 274 and the message flags' 'R' bit clear, is sent in response to the + ASR. The Result-Code AVP MUST be present, and indicates the + disposition of the request. + + If the session identified by Session-Id in the ASR was successfully + terminated, Result-Code is set to DIAMETER_SUCCESS. If the session + is not currently active, Result-Code is set to + DIAMETER_UNKNOWN_SESSION_ID. If the access device does not stop the + session for any other reason, Result-Code is set to + DIAMETER_UNABLE_TO_COMPLY. + + + + + +Calhoun, et al. Standards Track [Page 106] + +RFC 3588 Diameter Based Protocol September 2003 + + + Message Format + + <ASA> ::= < Diameter Header: 274, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + +8.6. Inferring Session Termination from Origin-State-Id + + Origin-State-Id is used to allow rapid detection of terminated + sessions for which no STR would have been issued, due to + unanticipated shutdown of an access device. + + By including Origin-State-Id in CER/CEA messages, an access device + allows a next-hop server to determine immediately upon connection + whether the device has lost its sessions since the last connection. + + By including Origin-State-Id in request messages, an access device + also allows a server with which it communicates via proxy to make + such a determination. However, a server that is not directly + connected with the access device will not discover that the access + device has been restarted unless and until it receives a new request + from the access device. Thus, use of this mechanism across proxies + is opportunistic rather than reliable, but useful nonetheless. + + When a Diameter server receives an Origin-State-Id that is greater + than the Origin-State-Id previously received from the same issuer, it + may assume that the issuer has lost state since the previous message + and that all sessions that were active under the lower Origin-State- + Id have been terminated. The Diameter server MAY clean up all + session state associated with such lost sessions, and MAY also issues + STRs for all such lost sessions that were authorized on upstream + servers, to allow session state to be cleaned up globally. + + + + + + + +Calhoun, et al. Standards Track [Page 107] + +RFC 3588 Diameter Based Protocol September 2003 + + +8.7. Auth-Request-Type AVP + + The Auth-Request-Type AVP (AVP Code 274) is of type Enumerated and is + included in application-specific auth requests to inform the peers + whether a user is to be authenticated only, authorized only or both. + Note any value other than both MAY cause RADIUS interoperability + issues. The following values are defined: + + AUTHENTICATE_ONLY 1 + The request being sent is for authentication only, and MUST + contain the relevant application specific authentication AVPs that + are needed by the Diameter server to authenticate the user. + + AUTHORIZE_ONLY 2 + The request being sent is for authorization only, and MUST contain + the application specific authorization AVPs that are necessary to + identify the service being requested/offered. + + AUTHORIZE_AUTHENTICATE 3 + The request contains a request for both authentication and + authorization. The request MUST include both the relevant + application specific authentication information, and authorization + information necessary to identify the service being + requested/offered. + +8.8. Session-Id AVP + + The Session-Id AVP (AVP Code 263) is of type UTF8String and is used + to identify a specific session (see Section 8). All messages + pertaining to a specific session MUST include only one Session-Id AVP + and the same value MUST be used throughout the life of a session. + When present, the Session-Id SHOULD appear immediately following the + Diameter Header (see Section 3). + + The Session-Id MUST be globally and eternally unique, as it is meant + to uniquely identify a user session without reference to any other + information, and may be needed to correlate historical authentication + information with accounting information. The Session-Id includes a + mandatory portion and an implementation-defined portion; a + recommended format for the implementation-defined portion is outlined + below. + + The Session-Id MUST begin with the sender's identity encoded in the + DiameterIdentity type (see Section 4.4). The remainder of the + Session-Id is delimited by a ";" character, and MAY be any sequence + that the client can guarantee to be eternally unique; however, the + following format is recommended, (square brackets [] indicate an + optional element): + + + +Calhoun, et al. Standards Track [Page 108] + +RFC 3588 Diameter Based Protocol September 2003 + + + <DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>] + + <high 32 bits> and <low 32 bits> are decimal representations of the + high and low 32 bits of a monotonically increasing 64-bit value. The + 64-bit value is rendered in two part to simplify formatting by 32-bit + processors. At startup, the high 32 bits of the 64-bit value MAY be + initialized to the time, and the low 32 bits MAY be initialized to + zero. This will for practical purposes eliminate the possibility of + overlapping Session-Ids after a reboot, assuming the reboot process + takes longer than a second. Alternatively, an implementation MAY + keep track of the increasing value in non-volatile memory. + + <optional value> is implementation specific but may include a modem's + device Id, a layer 2 address, timestamp, etc. + + Example, in which there is no optional value: + accesspoint7.acme.com;1876543210;523 + + Example, in which there is an optional value: + accesspoint7.acme.com;1876543210;523;[email protected] + + The Session-Id is created by the Diameter application initiating the + session, which in most cases is done by the client. Note that a + Session-Id MAY be used for both the authorization and accounting + commands of a given application. + +8.9. Authorization-Lifetime AVP + + The Authorization-Lifetime AVP (AVP Code 291) is of type Unsigned32 + and contains the maximum number of seconds of service to be provided + to the user before the user is to be re-authenticated and/or re- + authorized. Great care should be taken when the Authorization- + Lifetime value is determined, since a low, non-zero, value could + create significant Diameter traffic, which could congest both the + network and the agents. + + A value of zero (0) means that immediate re-auth is necessary by the + access device. This is typically used in cases where multiple + authentication methods are used, and a successful auth response with + this AVP set to zero is used to signal that the next authentication + method is to be immediately initiated. The absence of this AVP, or a + value of all ones (meaning all bits in the 32 bit field are set to + one) means no re-auth is expected. + + If both this AVP and the Session-Timeout AVP are present in a + message, the value of the latter MUST NOT be smaller than the + Authorization-Lifetime AVP. + + + + +Calhoun, et al. Standards Track [Page 109] + +RFC 3588 Diameter Based Protocol September 2003 + + + An Authorization-Lifetime AVP MAY be present in re-authorization + messages, and contains the number of seconds the user is authorized + to receive service from the time the re-auth answer message is + received by the access device. + + This AVP MAY be provided by the client as a hint of the maximum + lifetime that it is willing to accept. However, the server MAY + return a value that is equal to, or smaller, than the one provided by + the client. + +8.10. Auth-Grace-Period AVP + + The Auth-Grace-Period AVP (AVP Code 276) is of type Unsigned32 and + contains the number of seconds the Diameter server will wait + following the expiration of the Authorization-Lifetime AVP before + cleaning up resources for the session. + +8.11. Auth-Session-State AVP + + The Auth-Session-State AVP (AVP Code 277) is of type Enumerated and + specifies whether state is maintained for a particular session. The + client MAY include this AVP in requests as a hint to the server, but + the value in the server's answer message is binding. The following + values are supported: + + STATE_MAINTAINED 0 + This value is used to specify that session state is being + maintained, and the access device MUST issue a session termination + message when service to the user is terminated. This is the + default value. + + NO_STATE_MAINTAINED 1 + This value is used to specify that no session termination messages + will be sent by the access device upon expiration of the + Authorization-Lifetime. + +8.12. Re-Auth-Request-Type AVP + + The Re-Auth-Request-Type AVP (AVP Code 285) is of type Enumerated and + is included in application-specific auth answers to inform the client + of the action expected upon expiration of the Authorization-Lifetime. + If the answer message contains an Authorization-Lifetime AVP with a + positive value, the Re-Auth-Request-Type AVP MUST be present in an + answer message. The following values are defined: + + + + + + + +Calhoun, et al. Standards Track [Page 110] + +RFC 3588 Diameter Based Protocol September 2003 + + + AUTHORIZE_ONLY 0 + An authorization only re-auth is expected upon expiration of the + Authorization-Lifetime. This is the default value if the AVP is + not present in answer messages that include the Authorization- + Lifetime. + + AUTHORIZE_AUTHENTICATE 1 + An authentication and authorization re-auth is expected upon + expiration of the Authorization-Lifetime. + +8.13. Session-Timeout AVP + + The Session-Timeout AVP (AVP Code 27) [RADIUS] is of type Unsigned32 + and contains the maximum number of seconds of service to be provided + to the user before termination of the session. When both the + Session-Timeout and the Authorization-Lifetime AVPs are present in an + answer message, the former MUST be equal to or greater than the value + of the latter. + + A session that terminates on an access device due to the expiration + of the Session-Timeout MUST cause an STR to be issued, unless both + the access device and the home server had previously agreed that no + session termination messages would be sent (see Section 8.9). + + A Session-Timeout AVP MAY be present in a re-authorization answer + message, and contains the remaining number of seconds from the + beginning of the re-auth. + + A value of zero, or the absence of this AVP, means that this session + has an unlimited number of seconds before termination. + + This AVP MAY be provided by the client as a hint of the maximum + timeout that it is willing to accept. However, the server MAY return + a value that is equal to, or smaller, than the one provided by the + client. + +8.14. User-Name AVP + + The User-Name AVP (AVP Code 1) [RADIUS] is of type UTF8String, which + contains the User-Name, in a format consistent with the NAI + specification [NAI]. + +8.15. Termination-Cause AVP + + The Termination-Cause AVP (AVP Code 295) is of type Enumerated, and + is used to indicate the reason why a session was terminated on the + access device. The following values are defined: + + + + +Calhoun, et al. Standards Track [Page 111] + +RFC 3588 Diameter Based Protocol September 2003 + + + DIAMETER_LOGOUT 1 + The user initiated a disconnect + + DIAMETER_SERVICE_NOT_PROVIDED 2 + This value is used when the user disconnected prior to the receipt + of the authorization answer message. + + DIAMETER_BAD_ANSWER 3 + This value indicates that the authorization answer received by the + access device was not processed successfully. + + DIAMETER_ADMINISTRATIVE 4 + The user was not granted access, or was disconnected, due to + administrative reasons, such as the receipt of a Abort-Session- + Request message. + + DIAMETER_LINK_BROKEN 5 + The communication to the user was abruptly disconnected. + + DIAMETER_AUTH_EXPIRED 6 + The user's access was terminated since its authorized session time + has expired. + + DIAMETER_USER_MOVED 7 + The user is receiving services from another access device. + + DIAMETER_SESSION_TIMEOUT 8 + The user's session has timed out, and service has been terminated. + +8.16. Origin-State-Id AVP + + The Origin-State-Id AVP (AVP Code 278), of type Unsigned32, is a + monotonically increasing value that is advanced whenever a Diameter + entity restarts with loss of previous state, for example upon reboot. + Origin-State-Id MAY be included in any Diameter message, including + CER. + + A Diameter entity issuing this AVP MUST create a higher value for + this AVP each time its state is reset. A Diameter entity MAY set + Origin-State-Id to the time of startup, or it MAY use an incrementing + counter retained in non-volatile memory across restarts. + + The Origin-State-Id, if present, MUST reflect the state of the entity + indicated by Origin-Host. If a proxy modifies Origin-Host, it MUST + either remove Origin-State-Id or modify it appropriately as well. + + + + + + +Calhoun, et al. Standards Track [Page 112] + +RFC 3588 Diameter Based Protocol September 2003 + + + Typically, Origin-State-Id is used by an access device that always + starts up with no active sessions; that is, any session active prior + to restart will have been lost. By including Origin-State-Id in a + message, it allows other Diameter entities to infer that sessions + associated with a lower Origin-State-Id are no longer active. If an + access device does not intend for such inferences to be made, it MUST + either not include Origin-State-Id in any message, or set its value + to 0. + +8.17. Session-Binding AVP + + The Session-Binding AVP (AVP Code 270) is of type Unsigned32, and MAY + be present in application-specific authorization answer messages. If + present, this AVP MAY inform the Diameter client that all future + application-specific re-auth messages for this session MUST be sent + to the same authorization server. This AVP MAY also specify that a + Session-Termination-Request message for this session MUST be sent to + the same authorizing server. + + This field is a bit mask, and the following bits have been defined: + + RE_AUTH 1 + When set, future re-auth messages for this session MUST NOT + include the Destination-Host AVP. When cleared, the default + value, the Destination-Host AVP MUST be present in all re-auth + messages for this session. + + STR 2 + When set, the STR message for this session MUST NOT include the + Destination-Host AVP. When cleared, the default value, the + Destination-Host AVP MUST be present in the STR message for this + session. + + ACCOUNTING 4 + When set, all accounting messages for this session MUST NOT + include the Destination-Host AVP. When cleared, the default + value, the Destination-Host AVP, if known, MUST be present in all + accounting messages for this session. + +8.18. Session-Server-Failover AVP + + The Session-Server-Failover AVP (AVP Code 271) is of type Enumerated, + and MAY be present in application-specific authorization answer + messages that either do not include the Session-Binding AVP or + include the Session-Binding AVP with any of the bits set to a zero + value. If present, this AVP MAY inform the Diameter client that if a + + + + + +Calhoun, et al. Standards Track [Page 113] + +RFC 3588 Diameter Based Protocol September 2003 + + + re-auth or STR message fails due to a delivery problem, the Diameter + client SHOULD issue a subsequent message without the Destination-Host + AVP. When absent, the default value is REFUSE_SERVICE. + + The following values are supported: + + REFUSE_SERVICE 0 + If either the re-auth or the STR message delivery fails, terminate + service with the user, and do not attempt any subsequent attempts. + + TRY_AGAIN 1 + If either the re-auth or the STR message delivery fails, resend + the failed message without the Destination-Host AVP present. + + ALLOW_SERVICE 2 + If re-auth message delivery fails, assume that re-authorization + succeeded. If STR message delivery fails, terminate the session. + + TRY_AGAIN_ALLOW_SERVICE 3 + If either the re-auth or the STR message delivery fails, resend + the failed message without the Destination-Host AVP present. If + the second delivery fails for re-auth, assume re-authorization + succeeded. If the second delivery fails for STR, terminate the + session. + +8.19. Multi-Round-Time-Out AVP + + The Multi-Round-Time-Out AVP (AVP Code 272) is of type Unsigned32, + and SHOULD be present in application-specific authorization answer + messages whose Result-Code AVP is set to DIAMETER_MULTI_ROUND_AUTH. + This AVP contains the maximum number of seconds that the access + device MUST provide the user in responding to an authentication + request. + +8.20. Class AVP + + The Class AVP (AVP Code 25) is of type OctetString and is used to by + Diameter servers to return state information to the access device. + When one or more Class AVPs are present in application-specific + authorization answer messages, they MUST be present in subsequent + re-authorization, session termination and accounting messages. Class + AVPs found in a re-authorization answer message override the ones + found in any previous authorization answer message. Diameter server + implementations SHOULD NOT return Class AVPs that require more than + 4096 bytes of storage on the Diameter client. A Diameter client that + receives Class AVPs whose size exceeds local available storage MUST + terminate the session. + + + + +Calhoun, et al. Standards Track [Page 114] + +RFC 3588 Diameter Based Protocol September 2003 + + +8.21. Event-Timestamp AVP + + The Event-Timestamp (AVP Code 55) is of type Time, and MAY be + included in an Accounting-Request and Accounting-Answer messages to + record the time that the reported event occurred, in seconds since + January 1, 1900 00:00 UTC. + +9. Accounting + + This accounting protocol is based on a server directed model with + capabilities for real-time delivery of accounting information. + Several fault resilience methods [ACCMGMT] have been built in to the + protocol in order minimize loss of accounting data in various fault + situations and under different assumptions about the capabilities of + the used devices. + +9.1. Server Directed Model + + The server directed model means that the device generating the + accounting data gets information from either the authorization server + (if contacted) or the accounting server regarding the way accounting + data shall be forwarded. This information includes accounting record + timeliness requirements. + + As discussed in [ACCMGMT], real-time transfer of accounting records + is a requirement, such as the need to perform credit limit checks and + fraud detection. Note that batch accounting is not a requirement, + and is therefore not supported by Diameter. Should batched + accounting be required in the future, a new Diameter application will + need to be created, or it could be handled using another protocol. + Note, however, that even if at the Diameter layer accounting requests + are processed one by one, transport protocols used under Diameter + typically batch several requests in the same packet under heavy + traffic conditions. This may be sufficient for many applications. + + The authorization server (chain) directs the selection of proper + transfer strategy, based on its knowledge of the user and + relationships of roaming partnerships. The server (or agents) uses + the Acct-Interim-Interval and Accounting-Realtime-Required AVPs to + control the operation of the Diameter peer operating as a client. + The Acct-Interim-Interval AVP, when present, instructs the Diameter + node acting as a client to produce accounting records continuously + even during a session. Accounting-Realtime-Required AVP is used to + control the behavior of the client when the transfer of accounting + records from the Diameter client is delayed or unsuccessful. + + + + + + +Calhoun, et al. Standards Track [Page 115] + +RFC 3588 Diameter Based Protocol September 2003 + + + The Diameter accounting server MAY override the interim interval or + the realtime requirements by including the Acct-Interim-Interval or + Accounting-Realtime-Required AVP in the Accounting-Answer message. + When one of these AVPs is present, the latest value received SHOULD + be used in further accounting activities for the same session. + +9.2. Protocol Messages + + A Diameter node that receives a successful authentication and/or + authorization messages from the Home AAA server MUST collect + accounting information for the session. The Accounting-Request + message is used to transmit the accounting information to the Home + AAA server, which MUST reply with the Accounting-Answer message to + confirm reception. The Accounting-Answer message includes the + Result-Code AVP, which MAY indicate that an error was present in the + accounting message. A rejected Accounting-Request message MAY cause + the user's session to be terminated, depending on the value of the + Accounting-Realtime-Required AVP received earlier for the session in + question. + + Each Diameter Accounting protocol message MAY be compressed, in order + to reduce network bandwidth usage. If IPsec and IKE are used to + secure the Diameter session, then IP compression [IPComp] MAY be used + and IKE [IKE] MAY be used to negotiate the compression parameters. + If TLS is used to secure the Diameter session, then TLS compression + [TLS] MAY be used. + +9.3. Application document requirements + + Each Diameter application (e.g., NASREQ, MobileIP), MUST define their + Service-Specific AVPs that MUST be present in the Accounting-Request + message in a section entitled "Accounting AVPs". The application + MUST assume that the AVPs described in this document will be present + in all Accounting messages, so only their respective service-specific + AVPs need to be defined in this section. + +9.4. Fault Resilience + + Diameter Base protocol mechanisms are used to overcome small message + loss and network faults of temporary nature. + + Diameter peers acting as clients MUST implement the use of failover + to guard against server failures and certain network failures. + Diameter peers acting as agents or related off-line processing + systems MUST detect duplicate accounting records caused by the + sending of same record to several servers and duplication of messages + + + + + +Calhoun, et al. Standards Track [Page 116] + +RFC 3588 Diameter Based Protocol September 2003 + + + in transit. This detection MUST be based on the inspection of the + Session-Id and Accounting-Record-Number AVP pairs. Appendix C + discusses duplicate detection needs and implementation issues. + + Diameter clients MAY have non-volatile memory for the safe storage of + accounting records over reboots or extended network failures, network + partitions, and server failures. If such memory is available, the + client SHOULD store new accounting records there as soon as the + records are created and until a positive acknowledgement of their + reception from the Diameter Server has been received. Upon a reboot, + the client MUST starting sending the records in the non-volatile + memory to the accounting server with appropriate modifications in + termination cause, session length, and other relevant information in + the records. + + A further application of this protocol may include AVPs to control + how many accounting records may at most be stored in the Diameter + client without committing them to the non-volatile memory or + transferring them to the Diameter server. + + The client SHOULD NOT remove the accounting data from any of its + memory areas before the correct Accounting-Answer has been received. + The client MAY remove oldest, undelivered or yet unacknowledged + accounting data if it runs out of resources such as memory. It is an + implementation dependent matter for the client to accept new sessions + under this condition. + +9.5. Accounting Records + + In all accounting records, the Session-Id AVP MUST be present; the + User-Name AVP MUST be present if it is available to the Diameter + client. If strong authentication across agents is required, end-to- + end security may be used for authentication purposes. + + Different types of accounting records are sent depending on the + actual type of accounted service and the authorization server's + directions for interim accounting. If the accounted service is a + one-time event, meaning that the start and stop of the event are + simultaneous, then the Accounting-Record-Type AVP MUST be present and + set to the value EVENT_RECORD. + + If the accounted service is of a measurable length, then the AVP MUST + use the values START_RECORD, STOP_RECORD, and possibly, + INTERIM_RECORD. If the authorization server has not directed interim + accounting to be enabled for the session, two accounting records MUST + be generated for each service of type session. When the initial + + + + + +Calhoun, et al. Standards Track [Page 117] + +RFC 3588 Diameter Based Protocol September 2003 + + + Accounting-Request for a given session is sent, the Accounting- + Record-Type AVP MUST be set to the value START_RECORD. When the last + Accounting-Request is sent, the value MUST be STOP_RECORD. + + If the authorization server has directed interim accounting to be + enabled, the Diameter client MUST produce additional records between + the START_RECORD and STOP_RECORD, marked INTERIM_RECORD. The + production of these records is directed by Acct-Interim-Interval as + well as any re-authentication or re-authorization of the session. The + Diameter client MUST overwrite any previous interim accounting + records that are locally stored for delivery, if a new record is + being generated for the same session. This ensures that only one + pending interim record can exist on an access device for any given + session. + + A particular value of Accounting-Sub-Session-Id MUST appear only in + one sequence of accounting records from a DIAMETER client, except for + the purposes of retransmission. The one sequence that is sent MUST + be either one record with Accounting-Record-Type AVP set to the value + EVENT_RECORD, or several records starting with one having the value + START_RECORD, followed by zero or more INTERIM_RECORD and a single + STOP_RECORD. A particular Diameter application specification MUST + define the type of sequences that MUST be used. + +9.6. Correlation of Accounting Records + + The Diameter protocol's Session-Id AVP, which is globally unique (see + Section 8.8), is used during the authorization phase to identify a + particular session. Services that do not require any authorization + still use the Session-Id AVP to identify sessions. Accounting + messages MAY use a different Session-Id from that sent in + authorization messages. Specific applications MAY require different + a Session-ID for accounting messages. + + However, there are certain applications that require multiple + accounting sub-sessions. Such applications would send messages with + a constant Session-Id AVP, but a different Accounting-Sub-Session-Id + AVP. In these cases, correlation is performed using the Session-Id. + It is important to note that receiving a STOP_RECORD with no + Accounting-Sub-Session-Id AVP when sub-sessions were originally used + in the START_RECORD messages implies that all sub-sessions are + terminated. + + Furthermore, there are certain applications where a user receives + service from different access devices (e.g., Mobile IPv4), each with + their own unique Session-Id. In such cases, the Acct-Multi-Session- + Id AVP is used for correlation. During authorization, a server that + + + + +Calhoun, et al. Standards Track [Page 118] + +RFC 3588 Diameter Based Protocol September 2003 + + + determines that a request is for an existing session SHOULD include + the Acct-Multi-Session-Id AVP, which the access device MUST include + in all subsequent accounting messages. + + The Acct-Multi-Session-Id AVP MAY include the value of the original + Session-Id. It's contents are implementation specific, but MUST be + globally unique across other Acct-Multi-Session-Id, and MUST NOT + change during the life of a session. + + A Diameter application document MUST define the exact concept of a + session that is being accounted, and MAY define the concept of a + multi-session. For instance, the NASREQ DIAMETER application treats + a single PPP connection to a Network Access Server as one session, + and a set of Multilink PPP sessions as one multi-session. + +9.7. Accounting Command-Codes + + This section defines Command-Code values that MUST be supported by + all Diameter implementations that provide Accounting services. + +9.7.1. Accounting-Request + + The Accounting-Request (ACR) command, indicated by the Command-Code + field set to 271 and the Command Flags' 'R' bit set, is sent by a + Diameter node, acting as a client, in order to exchange accounting + information with a peer. + + One of Acct-Application-Id and Vendor-Specific-Application-Id AVPs + MUST be present. If the Vendor-Specific-Application-Id grouped AVP + is present, it must have an Acct-Application-Id inside. + + The AVP listed below SHOULD include service specific accounting AVPs, + as described in Section 9.3. + + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 119] + +RFC 3588 Diameter Based Protocol September 2003 + + + Message Format + + <ACR> ::= < 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 ] + [ Acct-Interim-Interval ] + [ Accounting-Realtime-Required ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +9.7.2. Accounting-Answer + + The Accounting-Answer (ACA) command, indicated by the Command-Code + field set to 271 and the Command Flags' 'R' bit cleared, is used to + acknowledge an Accounting-Request command. The Accounting-Answer + command contains the same Session-Id and includes the usage AVPs only + if CMS is in use when sending this command. Note that the inclusion + of the usage AVPs when CMS is not being used leads to unnecessarily + large answer messages, and can not be used as a server's proof of the + receipt of these AVPs in an end-to-end fashion. If the Accounting- + Request was protected by end-to-end security, then the corresponding + ACA message MUST be protected by end-to-end security. + + Only the target Diameter Server, known as the home Diameter Server, + SHOULD respond with the Accounting-Answer command. + + One of Acct-Application-Id and Vendor-Specific-Application-Id AVPs + MUST be present. If the Vendor-Specific-Application-Id grouped AVP + is present, it must have an Acct-Application-Id inside. + + The AVP listed below SHOULD include service specific accounting AVPs, + as described in Section 9.3. + + + + + + +Calhoun, et al. Standards Track [Page 120] + +RFC 3588 Diameter Based Protocol September 2003 + + + Message Format + + <ACA> ::= < 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 ] + [ Error-Reporting-Host ] + [ Acct-Interim-Interval ] + [ Accounting-Realtime-Required ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Proxy-Info ] + * [ AVP ] + +9.8. Accounting AVPs + + This section contains AVPs that describe accounting usage information + related to a specific session. + +9.8.1. Accounting-Record-Type AVP + + The Accounting-Record-Type AVP (AVP Code 480) is of type Enumerated + and contains the type of accounting record being sent. The following + values are currently defined for the Accounting-Record-Type AVP: + + EVENT_RECORD 1 + An Accounting Event Record is used to indicate that a one-time + event has occurred (meaning that the start and end of the event + are simultaneous). This record contains all information relevant + to the service, and is the only record of the service. + + START_RECORD 2 + An Accounting Start, Interim, and Stop Records are used to + indicate that a service of a measurable length has been given. An + Accounting Start Record is used to initiate an accounting session, + and contains accounting information that is relevant to the + initiation of the session. + + + + + +Calhoun, et al. Standards Track [Page 121] + +RFC 3588 Diameter Based Protocol September 2003 + + + INTERIM_RECORD 3 + An Interim Accounting Record contains cumulative accounting + information for an existing accounting session. Interim + Accounting Records SHOULD be sent every time a re-authentication + or re-authorization occurs. Further, additional interim record + triggers MAY be defined by application-specific Diameter + applications. The selection of whether to use INTERIM_RECORD + records is done by the Acct-Interim-Interval AVP. + + STOP_RECORD 4 + An Accounting Stop Record is sent to terminate an accounting + session and contains cumulative accounting information relevant to + the existing session. + +9.8.2. Acct-Interim-Interval + + The Acct-Interim-Interval AVP (AVP Code 85) is of type Unsigned32 and + is sent from the Diameter home authorization server to the Diameter + client. The client uses information in this AVP to decide how and + when to produce accounting records. With different values in this + AVP, service sessions can result in one, two, or two+N accounting + records, based on the needs of the home-organization. The following + accounting record production behavior is directed by the inclusion of + this AVP: + + 1. The omission of the Acct-Interim-Interval AVP or its inclusion + with Value field set to 0 means that EVENT_RECORD, START_RECORD, + and STOP_RECORD are produced, as appropriate for the service. + + 2. The inclusion of the AVP with Value field set to a non-zero value + means that INTERIM_RECORD records MUST be produced between the + START_RECORD and STOP_RECORD records. The Value field of this AVP + is the nominal interval between these records in seconds. The + Diameter node that originates the accounting information, known as + the client, MUST produce the first INTERIM_RECORD record roughly + at the time when this nominal interval has elapsed from the + START_RECORD, the next one again as the interval has elapsed once + more, and so on until the session ends and a STOP_RECORD record is + produced. + + The client MUST ensure that the interim record production times + are randomized so that large accounting message storms are not + created either among records or around a common service start + time. + + + + + + + +Calhoun, et al. Standards Track [Page 122] + +RFC 3588 Diameter Based Protocol September 2003 + + +9.8.3. Accounting-Record-Number AVP + + The Accounting-Record-Number AVP (AVP Code 485) is of type Unsigned32 + and identifies this record within one session. As Session-Id AVPs + are globally unique, the combination of Session-Id and Accounting- + Record-Number AVPs is also globally unique, and can be used in + matching accounting records with confirmations. An easy way to + produce unique numbers is to set the value to 0 for records of type + EVENT_RECORD and START_RECORD, and set the value to 1 for the first + INTERIM_RECORD, 2 for the second, and so on until the value for + STOP_RECORD is one more than for the last INTERIM_RECORD. + +9.8.4. Acct-Session-Id AVP + + The Acct-Session-Id AVP (AVP Code 44) is of type OctetString is only + used when RADIUS/Diameter translation occurs. This AVP contains the + contents of the RADIUS Acct-Session-Id attribute. + +9.8.5. Acct-Multi-Session-Id AVP + + The Acct-Multi-Session-Id AVP (AVP Code 50) is of type UTF8String, + following the format specified in Section 8.8. The Acct-Multi- + Session-Id AVP is used to link together multiple related accounting + sessions, where each session would have a unique Session-Id, but the + same Acct-Multi-Session-Id AVP. This AVP MAY be returned by the + Diameter server in an authorization answer, and MUST be used in all + accounting messages for the given session. + +9.8.6. Accounting-Sub-Session-Id AVP + + The Accounting-Sub-Session-Id AVP (AVP Code 287) is of type + Unsigned64 and contains the accounting sub-session identifier. The + combination of the Session-Id and this AVP MUST be unique per sub- + session, and the value of this AVP MUST be monotonically increased by + one for all new sub-sessions. The absence of this AVP implies no + sub-sessions are in use, with the exception of an Accounting-Request + whose Accounting-Record-Type is set to STOP_RECORD. A STOP_RECORD + message with no Accounting-Sub-Session-Id AVP present will signal the + termination of all sub-sessions for a given Session-Id. + +9.8.7. Accounting-Realtime-Required AVP + + The Accounting-Realtime-Required AVP (AVP Code 483) is of type + Enumerated and is sent from the Diameter home authorization server to + the Diameter client or in the Accounting-Answer from the accounting + server. The client uses information in this AVP to decide what to do + if the sending of accounting records to the accounting server has + been temporarily prevented due to, for instance, a network problem. + + + +Calhoun, et al. Standards Track [Page 123] + +RFC 3588 Diameter Based Protocol September 2003 + + + DELIVER_AND_GRANT 1 + The AVP with Value field set to DELIVER_AND_GRANT means that the + service MUST only be granted as long as there is a connection to + an accounting server. Note that the set of alternative accounting + servers are treated as one server in this sense. Having to move + the accounting record stream to a backup server is not a reason to + discontinue the service to the user. + + GRANT_AND_STORE 2 + The AVP with Value field set to GRANT_AND_STORE means that service + SHOULD be granted if there is a connection, or as long as records + can still be stored as described in Section 9.4. + + This is the default behavior if the AVP isn't included in the + reply from the authorization server. + + GRANT_AND_LOSE 3 + The AVP with Value field set to GRANT_AND_LOSE means that service + SHOULD be granted even if the records can not be delivered or + stored. + +10. AVP Occurrence Table + + The following tables presents the AVPs defined in this document, and + specifies in which Diameter messages they MAY, or MAY NOT be present. + Note that AVPs that can only be present within a Grouped AVP are not + represented in this table. + + The table uses the following symbols: + + 0 The AVP MUST NOT be present in the message. + 0+ Zero or more instances of the AVP MAY be present in the + message. + 0-1 Zero or one instance of the AVP MAY be present in the + message. It is considered an error if there are more than + one instance of the AVP. + 1 One instance of the AVP MUST be present in the message. + 1+ At least one instance of the AVP MUST be present in the + message. + +10.1. Base Protocol Command AVP Table + + The table in this section is limited to the non-accounting Command + Codes defined in this specification. + + + + + + + +Calhoun, et al. Standards Track [Page 124] + +RFC 3588 Diameter Based Protocol September 2003 + + + +-----------------------------------------------+ + | Command-Code | + +---+---+---+---+---+---+---+---+---+---+---+---+ + Attribute Name |CER|CEA|DPR|DPA|DWR|DWA|RAR|RAA|ASR|ASA|STR|STA| + --------------------+---+---+---+---+---+---+---+---+---+---+---+---+ + Acct-Interim- |0 |0 |0 |0 |0 |0 |0-1|0 |0 |0 |0 |0 | + Interval | | | | | | | | | | | | | + Accounting-Realtime-|0 |0 |0 |0 |0 |0 |0-1|0 |0 |0 |0 |0 | + Required | | | | | | | | | | | | | + Acct-Application-Id |0+ |0+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Auth-Application-Id |0+ |0+ |0 |0 |0 |0 |1 |0 |1 |0 |1 |0 | + Auth-Grace-Period |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Auth-Request-Type |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Auth-Session-State |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Authorization- |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Lifetime | | | | | | | | | | | | | + Class |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0+ |0+ | + Destination-Host |0 |0 |0 |0 |0 |0 |1 |0 |1 |0 |0-1|0 | + Destination-Realm |0 |0 |0 |0 |0 |0 |1 |0 |1 |0 |1 |0 | + Disconnect-Cause |0 |0 |1 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Error-Message |0 |0-1|0 |0-1|0 |0-1|0 |0-1|0 |0-1|0 |0-1| + Error-Reporting-Host|0 |0 |0 |0 |0 |0 |0 |0-1|0 |0-1|0 |0-1| + Failed-AVP |0 |0+ |0 |0+ |0 |0+ |0 |0+ |0 |0+ |0 |0+ | + Firmware-Revision |0-1|0-1|0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Host-IP-Address |1+ |1+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Inband-Security-Id |0+ |0+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Multi-Round-Time-Out|0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Origin-Host |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 | + Origin-Realm |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 |1 | + Origin-State-Id |0-1|0-1|0 |0 |0-1|0-1|0-1|0-1|0-1|0-1|0-1|0-1| + Product-Name |1 |1 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Proxy-Info |0 |0 |0 |0 |0 |0 |0+ |0+ |0+ |0+ |0+ |0+ | + Redirect-Host |0 |0 |0 |0 |0 |0 |0 |0+ |0 |0+ |0 |0+ | + Redirect-Host-Usage |0 |0 |0 |0 |0 |0 |0 |0-1|0 |0-1|0 |0-1| + Redirect-Max-Cache- |0 |0 |0 |0 |0 |0 |0 |0-1|0 |0-1|0 |0-1| + Time | | | | | | | | | | | | | + Result-Code |0 |1 |0 |1 |0 |1 |0 |1 |0 |0 |0 |1 | + Re-Auth-Request-Type|0 |0 |0 |0 |0 |0 |1 |0 |0 |0 |0 |0 | + Route-Record |0 |0 |0 |0 |0 |0 |0+ |0 |0+ |0 |0+ |0 | + Session-Binding |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Session-Id |0 |0 |0 |0 |0 |0 |1 |1 |1 |1 |1 |1 | + Session-Server- |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Failover | | | | | | | | | | | | | + Session-Timeout |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Supported-Vendor-Id |0+ |0+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Termination-Cause |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 |1 |0 | + User-Name |0 |0 |0 |0 |0 |0 |0-1|0-1|0-1|0-1|0-1|0-1| + Vendor-Id |1 |1 |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + + + +Calhoun, et al. Standards Track [Page 125] + +RFC 3588 Diameter Based Protocol September 2003 + + + Vendor-Specific- |0+ |0+ |0 |0 |0 |0 |0 |0 |0 |0 |0 |0 | + Application-Id | | | | | | | | | | | | | + --------------------+---+---+---+---+---+---+---+---+---+---+---+---+ + +10.2. Accounting AVP Table + + The table in this section is used to represent which AVPs defined in + this document are to be present in the Accounting messages. These + AVP occurrence requirements are guidelines, which may be expanded, + and/or overridden by application-specific requirements in the + Diameter applications documents. + + +-----------+ + | Command | + | Code | + +-----+-----+ + Attribute Name | ACR | ACA | + ------------------------------+-----+-----+ + Acct-Interim-Interval | 0-1 | 0-1 | + Acct-Multi-Session-Id | 0-1 | 0-1 | + Accounting-Record-Number | 1 | 1 | + Accounting-Record-Type | 1 | 1 | + Acct-Session-Id | 0-1 | 0-1 | + Accounting-Sub-Session-Id | 0-1 | 0-1 | + Accounting-Realtime-Required | 0-1 | 0-1 | + Acct-Application-Id | 0-1 | 0-1 | + Auth-Application-Id | 0 | 0 | + Class | 0+ | 0+ | + Destination-Host | 0-1 | 0 | + Destination-Realm | 1 | 0 | + Error-Reporting-Host | 0 | 0+ | + Event-Timestamp | 0-1 | 0-1 | + Origin-Host | 1 | 1 | + Origin-Realm | 1 | 1 | + Proxy-Info | 0+ | 0+ | + Route-Record | 0+ | 0+ | + Result-Code | 0 | 1 | + Session-Id | 1 | 1 | + Termination-Cause | 0-1 | 0-1 | + User-Name | 0-1 | 0-1 | + Vendor-Specific-Application-Id| 0-1 | 0-1 | + ------------------------------+-----+-----+ + + + + + + + + + +Calhoun, et al. Standards Track [Page 126] + +RFC 3588 Diameter Based Protocol September 2003 + + +11. IANA Considerations + + This section provides guidance to the Internet Assigned Numbers + Authority (IANA) regarding registration of values related to the + Diameter protocol, in accordance with BCP 26 [IANA]. The following + policies are used here with the meanings defined in BCP 26: "Private + Use", "First Come First Served", "Expert Review", "Specification + Required", "IETF Consensus", "Standards Action". + + This section explains the criteria to be used by the IANA for + assignment of numbers within namespaces defined within this document. + + Diameter is not intended as a general purpose protocol, and + allocations SHOULD NOT be made for purposes unrelated to + authentication, authorization or accounting. + + For registration requests where a Designated Expert should be + consulted, the responsible IESG area director should appoint the + Designated Expert. For Designated Expert with Specification + Required, the request is posted to the AAA WG mailing list (or, if it + has been disbanded, a successor designated by the Area Director) for + comment and review, and MUST include a pointer to a public + specification. Before a period of 30 days has passed, the Designated + Expert will either approve or deny the registration request and + publish a notice of the decision to the AAA WG mailing list or its + successor. A denial notice must be justified by an explanation and, + in the cases where it is possible, concrete suggestions on how the + request can be modified so as to become acceptable. + +11.1. AVP Header + + As defined in Section 4, the AVP header contains three fields that + requires IANA namespace management; the AVP Code, Vendor-ID and Flags + field. + +11.1.1. AVP Codes + + The AVP Code namespace is used to identify attributes. There are + multiple namespaces. Vendors can have their own AVP Codes namespace + which will be identified by their Vendor-ID (also known as + Enterprise-Number) and they control the assignments of their vendor- + specific AVP codes within their own namespace. The absence of a + Vendor-ID or a Vendor-ID value of zero (0) identifies the IETF IANA + controlled AVP Codes namespace. The AVP Codes and sometimes also + possible values in an AVP are controlled and maintained by IANA. + + + + + + +Calhoun, et al. Standards Track [Page 127] + +RFC 3588 Diameter Based Protocol September 2003 + + + AVP Code 0 is not used. AVP Codes 1-255 are managed separately as + RADIUS Attribute Types [RADTYPE]. This document defines the AVP + Codes 257-274, 276-285, 287, 291-300, 480, 483 and 485-486. See + Section 4.5 for the assignment of the namespace in this + specification. + + AVPs may be allocated following Designated Expert with Specification + Required [IANA]. Release of blocks of AVPs (more than 3 at a time + for a given purpose) should require IETF Consensus. + + Note that Diameter defines a mechanism for Vendor-Specific AVPs, + where the Vendor-Id field in the AVP header is set to a non-zero + value. Vendor-Specific AVPs codes are for Private Use and should be + encouraged instead of allocation of global attribute types, for + functions specific only to one vendor's implementation of Diameter, + where no interoperability is deemed useful. Where a Vendor-Specific + AVP is implemented by more than one vendor, allocation of global AVPs + should be encouraged instead. + +11.1.2. AVP Flags + + There are 8 bits in the AVP Flags field of the AVP header, defined in + Section 4. This document assigns bit 0 ('V'endor Specific), bit 1 + ('M'andatory) and bit 2 ('P'rotected). The remaining bits should + only be assigned via a Standards Action [IANA]. + +11.2. Diameter Header + + As defined in Section 3, the Diameter header contains two fields that + require IANA namespace management; Command Code and Command Flags. + +11.2.1. Command Codes + + The Command Code namespace is used to identify Diameter commands. + The values 0-255 are reserved for RADIUS backward compatibility, and + are defined as "RADIUS Packet Type Codes" in [RADTYPE]. Values 256- + 16,777,213 are for permanent, standard commands, allocated by IETF + Consensus [IANA]. This document defines the Command Codes 257, 258, + 271, 274-275, 280 and 282. See Section 3.1 for the assignment of the + namespace in this specification. + + The values 16,777,214 and 16,777,215 (hexadecimal values 0xfffffe - + 0xffffff) are reserved for experimental commands. As these codes are + only for experimental and testing purposes, no guarantee is made for + interoperability between Diameter peers using experimental commands, + as outlined in [IANA-EXP]. + + + + + +Calhoun, et al. Standards Track [Page 128] + +RFC 3588 Diameter Based Protocol September 2003 + + +11.2.2. Command Flags + + There are eight bits in the Command Flags field of the Diameter + header. This document assigns bit 0 ('R'equest), bit 1 ('P'roxy), + bit 2 ('E'rror) and bit 3 ('T'). Bits 4 through 7 MUST only be + assigned via a Standards Action [IANA]. + +11.3. Application Identifiers + + As defined in Section 2.4, the Application Identifier is used to + identify a specific Diameter Application. There are standards-track + application ids and vendor specific application ids. + + IANA [IANA] has assigned the range 0x00000001 to 0x00ffffff for + standards-track applications; and 0x01000000 - 0xfffffffe for vendor + specific applications, on a first-come, first-served basis. The + following values are allocated. + + Diameter Common Messages 0 + NASREQ 1 [NASREQ] + Mobile-IP 2 [DIAMMIP] + Diameter Base Accounting 3 + Relay 0xffffffff + + Assignment of standards-track application IDs are by Designated + Expert with Specification Required [IANA]. + + Both Application-Id and Acct-Application-Id AVPs use the same + Application Identifier space. + + Vendor-Specific Application Identifiers, are for Private Use. + Vendor-Specific Application Identifiers are assigned on a First Come, + First Served basis by IANA. + +11.4. AVP Values + + Certain AVPs in Diameter define a list of values with various + meanings. For attributes other than those specified in this section, + adding additional values to the list can be done on a First Come, + First Served basis by IANA. + +11.4.1. Result-Code AVP Values + + As defined in Section 7.1, the Result-Code AVP (AVP Code 268) defines + the values 1001, 2001-2002, 3001-3010, 4001-4002 and 5001-5017. + + All remaining values are available for assignment via IETF Consensus + [IANA]. + + + +Calhoun, et al. Standards Track [Page 129] + +RFC 3588 Diameter Based Protocol September 2003 + + +11.4.2. Accounting-Record-Type AVP Values + + As defined in Section 9.8.1, the Accounting-Record-Type AVP (AVP Code + 480) defines the values 1-4. All remaining values are available for + assignment via IETF Consensus [IANA]. + +11.4.3. Termination-Cause AVP Values + + As defined in Section 8.15, the Termination-Cause AVP (AVP Code 295) + defines the values 1-8. All remaining values are available for + assignment via IETF Consensus [IANA]. + +11.4.4. Redirect-Host-Usage AVP Values + + As defined in Section 6.13, the Redirect-Host-Usage AVP (AVP Code + 261) defines the values 0-5. All remaining values are available for + assignment via IETF Consensus [IANA]. + +11.4.5. Session-Server-Failover AVP Values + + As defined in Section 8.18, the Session-Server-Failover AVP (AVP Code + 271) defines the values 0-3. All remaining values are available for + assignment via IETF Consensus [IANA]. + +11.4.6. Session-Binding AVP Values + + As defined in Section 8.17, the Session-Binding AVP (AVP Code 270) + defines the bits 1-4. All remaining bits are available for + assignment via IETF Consensus [IANA]. + +11.4.7. Disconnect-Cause AVP Values + + As defined in Section 5.4.3, the Disconnect-Cause AVP (AVP Code 273) + defines the values 0-2. All remaining values are available for + assignment via IETF Consensus [IANA]. + +11.4.8. Auth-Request-Type AVP Values + + As defined in Section 8.7, the Auth-Request-Type AVP (AVP Code 274) + defines the values 1-3. All remaining values are available for + assignment via IETF Consensus [IANA]. + +11.4.9. Auth-Session-State AVP Values + + As defined in Section 8.11, the Auth-Session-State AVP (AVP Code 277) + defines the values 0-1. All remaining values are available for + assignment via IETF Consensus [IANA]. + + + + +Calhoun, et al. Standards Track [Page 130] + +RFC 3588 Diameter Based Protocol September 2003 + + +11.4.10. Re-Auth-Request-Type AVP Values + + As defined in Section 8.12, the Re-Auth-Request-Type AVP (AVP Code + 285) defines the values 0-1. All remaining values are available for + assignment via IETF Consensus [IANA]. + +11.4.11. Accounting-Realtime-Required AVP Values + + As defined in Section 9.8.7, the Accounting-Realtime-Required AVP + (AVP Code 483) defines the values 1-3. All remaining values are + available for assignment via IETF Consensus [IANA]. + +11.4.12. Inband-Security-Id AVP (code 299) + + As defined in Section 6.10, the Inband-Security-Id AVP (AVP Code 299) + defines the values 0-1. All remaining values are available for + assignment via IETF Consensus [IANA]. + +11.5. Diameter TCP/SCTP Port Numbers + + The IANA has assigned TCP and SCTP port number 3868 to Diameter. + +11.6. NAPTR Service Fields + + The registration in the RFC MUST include the following information: + + Service Field: The service field being registered. An example for a + new fictitious transport protocol called NCTP might be "AAA+D2N". + + Protocol: The specific transport protocol associated with that + service field. This MUST include the name and acronym for the + protocol, along with reference to a document that describes the + transport protocol. For example - "New Connectionless Transport + Protocol (NCTP), RFC 5766". + + Name and Contact Information: The name, address, email address and + telephone number for the person performing the registration. + + The following values have been placed into the registry: + + Services Field Protocol + AAA+D2T TCP + AAA+D2S SCTP + +12. Diameter protocol related configurable parameters + + This section contains the configurable parameters that are found + throughout this document: + + + +Calhoun, et al. Standards Track [Page 131] + +RFC 3588 Diameter Based Protocol September 2003 + + + Diameter Peer + A Diameter entity MAY communicate with peers that are statically + configured. A statically configured Diameter peer would require + that either the IP address or the fully qualified domain name + (FQDN) be supplied, which would then be used to resolve through + DNS. + + Realm Routing Table + A Diameter proxy server routes messages based on the realm portion + of a Network Access Identifier (NAI). The server MUST have a + table of Realm Names, and the address of the peer to which the + message must be forwarded to. The routing table MAY also include + a "default route", which is typically used for all messages that + cannot be locally processed. + + Tc timer + The Tc timer controls the frequency that transport connection + attempts are done to a peer with whom no active transport + connection exists. The recommended value is 30 seconds. + +13. Security Considerations + + The Diameter base protocol assumes that messages are secured by using + either IPSec or TLS. This security mechanism is acceptable in + environments where there is no untrusted third party agent. In other + situations, end-to-end security is needed. + + Diameter clients, such as Network Access Servers (NASes) and Mobility + Agents MUST support IP Security [SECARCH] and MAY support TLS [TLS]. + Diameter servers MUST support TLS and IPsec. Diameter + implementations MUST use transmission-level security of some kind + (IPsec or TLS) on each connection. + + If a Diameter connection is not protected by IPsec, then the CER/CEA + exchange MUST include an Inband-Security-ID AVP with a value of TLS. + For TLS usage, a TLS handshake will begin when both ends are in the + open state, after completion of the CER/CEA exchange. If the TLS + handshake is successful, all further messages will be sent via TLS. + If the handshake fails, both ends move to the closed state. + + It is suggested that IPsec be used primarily at the edges for intra- + domain exchanges. For NAS devices without certificate support, pre- + shared keys can be used between the NAS and a local AAA proxy. + + For protection of inter-domain exchanges, TLS is recommended. See + Sections 13.1 and 13.2 for more details on IPsec and TLS usage. + + + + + +Calhoun, et al. Standards Track [Page 132] + +RFC 3588 Diameter Based Protocol September 2003 + + +13.1. IPsec Usage + + All Diameter implementations MUST support IPsec ESP [IPsec] in + transport mode with non-null encryption and authentication algorithms + to provide per-packet authentication, integrity protection and + confidentiality, and MUST support the replay protection mechanisms of + IPsec. + + Diameter implementations MUST support IKE for peer authentication, + negotiation of security associations, and key management, using the + IPsec DOI [IPSECDOI]. Diameter implementations MUST support peer + authentication using a pre-shared key, and MAY support certificate- + based peer authentication using digital signatures. Peer + authentication using the public key encryption methods outlined in + IKE's Sections 5.2 and 5.3 [IKE] SHOULD NOT be used. + + Conformant implementations MUST support both IKE Main Mode and + Aggressive Mode. When pre-shared keys are used for authentication, + IKE Aggressive Mode SHOULD be used, and IKE Main Mode SHOULD NOT be + used. When digital signatures are used for authentication, either + IKE Main Mode or IKE Aggressive Mode MAY be used. + + When digital signatures are used to achieve authentication, an IKE + negotiator SHOULD use IKE Certificate Request Payload(s) to specify + the certificate authority (or authorities) that are trusted in + accordance with its local policy. IKE negotiators SHOULD use + pertinent certificate revocation checks before accepting a PKI + certificate for use in IKE's authentication procedures. + + The Phase 2 Quick Mode exchanges used to negotiate protection for + Diameter connections MUST explicitly carry the Identity Payload + fields (IDci and IDcr). The DOI provides for several types of + identification data. However, when used in conformant + implementations, each ID Payload MUST carry a single IP address and a + single non-zero port number, and MUST NOT use the IP Subnet or IP + Address Range formats. This allows the Phase 2 security association + to correspond to specific TCP and SCTP connections. + + Since IPsec acceleration hardware may only be able to handle a + limited number of active IKE Phase 2 SAs, Phase 2 delete messages may + be sent for idle SAs, as a means of keeping the number of active + Phase 2 SAs to a minimum. The receipt of an IKE Phase 2 delete + message SHOULD NOT be interpreted as a reason for tearing down a + Diameter connection. Rather, it is preferable to leave the + connection up, and if additional traffic is sent on it, to bring up + another IKE Phase 2 SA to protect it. This avoids the potential for + continually bringing connections up and down. + + + + +Calhoun, et al. Standards Track [Page 133] + +RFC 3588 Diameter Based Protocol September 2003 + + +13.2. TLS Usage + + A Diameter node that initiates a connection to another Diameter node + acts as a TLS client according to [TLS], and a Diameter node that + accepts a connection acts as a TLS server. Diameter nodes + implementing TLS for security MUST mutually authenticate as part of + TLS session establishment. In order to ensure mutual authentication, + the Diameter node acting as TLS server must request a certificate + from the Diameter node acting as TLS client, and the Diameter node + acting as TLS client MUST be prepared to supply a certificate on + request. + + Diameter nodes MUST be able to negotiate the following TLS cipher + suites: + + TLS_RSA_WITH_RC4_128_MD5 + TLS_RSA_WITH_RC4_128_SHA + TLS_RSA_WITH_3DES_EDE_CBC_SHA + + Diameter nodes SHOULD be able to negotiate the following TLS cipher + suite: + + TLS_RSA_WITH_AES_128_CBC_SHA + + Diameter nodes MAY negotiate other TLS cipher suites. + +13.3. Peer-to-Peer Considerations + + As with any peer-to-peer protocol, proper configuration of the trust + model within a Diameter peer is essential to security. When + certificates are used, it is necessary to configure the root + certificate authorities trusted by the Diameter peer. These root CAs + are likely to be unique to Diameter usage and distinct from the root + CAs that might be trusted for other purposes such as Web browsing. + In general, it is expected that those root CAs will be configured so + as to reflect the business relationships between the organization + hosting the Diameter peer and other organizations. As a result, a + Diameter peer will typically not be configured to allow connectivity + with any arbitrary peer. When certificate authentication Diameter + peers may not be known beforehand, and therefore peer discovery may + be required. + + Note that IPsec is considerably less flexible than TLS when it comes + to configuring root CAs. Since use of Port identifiers is prohibited + within IKE Phase 1, within IPsec it is not possible to uniquely + configure trusted root CAs for each application individually; the + same policy must be used for all applications. This implies, for + example, that a root CA trusted for use with Diameter must also be + + + +Calhoun, et al. Standards Track [Page 134] + +RFC 3588 Diameter Based Protocol September 2003 + + + trusted to protect SNMP. These restrictions can be awkward at best. + Since TLS supports application-level granularity in certificate + policy, TLS SHOULD be used to protect Diameter connections between + administrative domains. IPsec is most appropriate for intra-domain + usage when pre-shared keys are used as a security mechanism. + + When pre-shared key authentication is used with IPsec to protect + Diameter, unique pre-shared keys are configured with Diameter peers, + who are identified by their IP address (Main Mode), or possibly their + FQDN (Aggressive Mode). As a result, it is necessary for the set of + Diameter peers to be known beforehand. Therefore, peer discovery is + typically not necessary. + + The following is intended to provide some guidance on the issue. + + It is recommended that a Diameter peer implement the same security + mechanism (IPsec or TLS) across all its peer-to-peer connections. + Inconsistent use of security mechanisms can result in redundant + security mechanisms being used (e.g., TLS over IPsec) or worse, + potential security vulnerabilities. When IPsec is used with + Diameter, a typical security policy for outbound traffic is "Initiate + IPsec, from me to any, destination port Diameter"; for inbound + traffic, the policy would be "Require IPsec, from any to me, + destination port Diameter". + + This policy causes IPsec to be used whenever a Diameter peer + initiates a connection to another Diameter peer, and to be required + whenever an inbound Diameter connection occurs. This policy is + attractive, since it does not require policy to be set for each peer + or dynamically modified each time a new Diameter connection is + created; an IPsec SA is automatically created based on a simple + static policy. Since IPsec extensions are typically not available to + the sockets API on most platforms, and IPsec policy functionality is + implementation dependent, use of a simple static policy is the often + the simplest route to IPsec-enabling a Diameter implementation. + + One implication of the recommended policy is that if a node is using + both TLS and IPsec, there is not a convenient way in which to use + either TLS or IPsec, but not both, without reserving an additional + port for TLS usage. Since Diameter uses the same port for TLS and + non-TLS usage, where the recommended IPsec policy is put in place, a + TLS-protected connection will match the IPsec policy, and both IPsec + and TLS will be used to protect the Diameter connection. To avoid + this, it would be necessary to plumb peer-specific policies either + statically or dynamically. + + + + + + +Calhoun, et al. Standards Track [Page 135] + +RFC 3588 Diameter Based Protocol September 2003 + + + If IPsec is used to secure Diameter peer-to-peer connections, IPsec + policy SHOULD be set so as to require IPsec protection for inbound + connections, and to initiate IPsec protection for outbound + connections. This can be accomplished via use of inbound and + outbound filter policy. + +14. References + +14.1. Normative References + + [AAATRANS] Aboba, B. and J. Wood, "Authentication, Authorization + and Accounting (AAA) Transport Profile", RFC 3539, + June 2003. + + [ABNF] Crocker, D. and P. Overell, "Augmented BNF for Syntax + Specifications: ABNF", RFC 2234, November 1997. + + [ASSIGNNO] Reynolds, J., "Assigned Numbers: RFC 1700 is Replaced + by an On-line Database", RFC 3232, January 2002. + + [DIFFSERV] Nichols, K., Blake, S., Baker, F. and D. Black, + "Definition of the Differentiated Services Field (DS + Field) in the IPv4 and IPv6 Headers", RFC 2474, + December 1998. + + [DIFFSERVAF] Heinanen, J., Baker, F., Weiss, W. and J. Wroclawski, + "Assured Forwarding PHB Group", RFC 2597, June 1999. + + [DIFFSERVEF] Davie, B., Charny, A., Bennet, J., Benson, K., Le + Boudec, J., Courtney, W., Davari, S., Firoiu, V. and + D. Stiliadis, "An Expedited Forwarding PHB", RFC 3246, + March 2002. + + [DNSSRV] Gulbrandsen, A., Vixie, P. and L. Esibov, "A DNS RR + for specifying the location of services (DNS SRV)", + RFC 2782, February 2000. + + [EAP] Blunk, L. and J. Vollbrecht, "PPP Extensible + Authentication Protocol (EAP)", RFC 2284, March 1998. + + [FLOATPOINT] Institute of Electrical and Electronics Engineers, + "IEEE Standard for Binary Floating-Point Arithmetic", + ANSI/IEEE Standard 754-1985, August 1985. + + [IANA] Narten, T. and H. Alvestrand, "Guidelines for Writing + an IANA Considerations Section in RFCs", BCP 26, RFC + 2434, October 1998. + + + + +Calhoun, et al. Standards Track [Page 136] + +RFC 3588 Diameter Based Protocol September 2003 + + + [IANAADFAM] IANA; "Address Family Numbers", + http://www.iana.org/assignments/address-family-numbers + + [IANAWEB] IANA, "Number assignment", http://www.iana.org + + [IKE] Harkins, D. and D. Carrel, "The Internet Key Exchange + (IKE)", RFC 2409, November 1998. + + [IPComp] Shacham, A., Monsour, R., Pereira, R. and M. Thomas, + "IP Payload Compression Protocol (IPComp)", RFC 3173, + September 2001. + + [IPSECDOI] Piper, D., "The Internet IP Security Domain of + Interpretation for ISAKMP", RFC 2407, November 1998. + + [IPV4] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [IPV6] Hinden, R. and S. Deering, "IP Version 6 Addressing + Architecture", RFC 2373, July 1998. + + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [NAI] Aboba, B. and M. Beadles, "The Network Access + Identifier", RFC 2486, January 1999. + + [NAPTR] Mealling, M. and R. Daniel, "The naming authority + pointer (NAPTR) DNS resource record," RFC 2915, + September 2000. + + [RADTYPE] IANA, "RADIUS Types", + http://www.iana.org/assignments/radius-types + + [SCTP] Stewart, R., Xie, Q., Morneault, K., Sharp, C., + Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M., + Zhang, L. and V. Paxson, "Stream Control Transmission + Protocol", RFC 2960, October 2000. + + [SLP] Veizades, J., Guttman, E., Perkins, C. and M. Day, + "Service Location Protocol, Version 2", RFC 2165, June + 1999. + + [SNTP] Mills, D., "Simple Network Time Protocol (SNTP) + Version 4 for IPv4, IPv6 and OSI", RFC 2030, October + 1996. + + + + + +Calhoun, et al. Standards Track [Page 137] + +RFC 3588 Diameter Based Protocol September 2003 + + + [TCP] Postel, J. "Transmission Control Protocol", STD 7, RFC + 793, January 1981. + + [TEMPLATE] Guttman, E., Perkins, C. and J. Kempf, "Service + Templates and Service: Schemes", RFC 2609, June 1999. + + [TLS] Dierks, T. and C. Allen, "The TLS Protocol Version + 1.0", RFC 2246, January 1999. + + [TLSSCTP] Jungmaier, A., Rescorla, E. and M. Tuexen, "Transport + Layer Security over Stream Control Transmission + Protocol", RFC 3436, December 2002. + + [URI] Berners-Lee, T., Fielding, R. and L. Masinter, + "Uniform Resource Identifiers (URI): Generic Syntax", + RFC 2396, August 1998. + + [UTF8] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", RFC 2279, January 1998. + +14.2. Informative References + + [AAACMS] P. Calhoun, W. Bulley, S. Farrell, "Diameter CMS + Security Application", Work in Progress. + + [AAAREQ] Aboba, B., Calhoun, P., Glass, S., Hiller, T., McCann, + P., Shiino, H., Zorn, G., Dommety, G., Perkins, C., + Patil, B., Mitton, D., Manning, S., Beadles, M., + Walsh, P., Chen, X., Sivalingham, S., Hameed, A., + Munson, M., Jacobs, S., Lim, B., Hirschman, B., Hsu, + R., Xu, Y., Campbell, E., Baba, S. and E. Jaques, + "Criteria for Evaluating AAA Protocols for Network + Access", RFC 2989, November 2000. + + [ACCMGMT] Aboba, B., Arkko, J. and D. Harrington. "Introduction + to Accounting Management", RFC 2975, October 2000. + + [CDMA2000] Hiller, T., Walsh, P., Chen, X., Munson, M., Dommety, + G., Sivalingham, S., Lim, B., McCann, P., Shiino, H., + Hirschman, B., Manning, S., Hsu, R., Koo, H., Lipford, + M., Calhoun, P., Lo, C., Jaques, E., Campbell, E., Xu, + Y., Baba, S., Ayaki, T., Seki, T. and A. Hameed, + "CDMA2000 Wireless Data Requirements for AAA", RFC + 3141, June 2001. + + [DIAMMIP] P. Calhoun, C. Perkins, "Diameter Mobile IP + Application", Work in Progress. + + + + +Calhoun, et al. Standards Track [Page 138] + +RFC 3588 Diameter Based Protocol September 2003 + + + [DYNAUTH] Chiba, M., Dommety, G., Eklund, M., Mitton, D. and B. + Aboba, "Dynamic Authorization Extensions to Remote + Authentication Dial In User Service (RADIUS)", RFC + 3576, July 2003. + + [IANA-EXP] T. Narten, "Assigning Experimental and Testing Numbers + Considered Useful", Work in Progress. + + [MIPV4] Perkins, C., "IP Mobility Support for IPv4", RFC 3344, + August 2002. + + [MIPREQ] Glass, S., Hiller, T., Jacobs, S. and C. Perkins, + "Mobile IP Authentication, Authorization, and + Accounting Requirements", RFC 2977, October 2000. + + [NASNG] Mitton, D. and M. Beadles, "Network Access Server + Requirements Next Generation (NASREQNG) NAS Model", + RFC 2881, July 2000. + + [NASREQ] P. Calhoun, W. Bulley, A. Rubens, J. Haag, "Diameter + NASREQ Application", Work in Progress. + + [NASCRIT] Beadles, M. and D. Mitton, "Criteria for Evaluating + Network Access Server Protocols", RFC 3169, September + 2001. + + [PPP] Simpson, W., "The Point-to-Point Protocol (PPP)", STD + 51, RFC 1661, July 1994. + + [PROXYCHAIN] Aboba, B. and J. Vollbrecht, "Proxy Chaining and + Policy Implementation in Roaming", RFC 2607, June + 1999. + + [RADACCT] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000. + + [RADEXT] Rigney, C., Willats, W. and P. Calhoun, "RADIUS + Extensions", RFC 2869, June 2000. + + [RADIUS] Rigney, C., Willens, S., Rubens, A. and W. Simpson, + "Remote Authentication Dial In User Service (RADIUS)", + RFC 2865, June 2000. + + [ROAMREV] Aboba, B., Lu, J., Alsop, J., Ding, J. and W. Wang, + "Review of Roaming Implementations", RFC 2194, + September 1997. + + [ROAMCRIT] Aboba, B. and G. Zorn, "Criteria for Evaluating + Roaming Protocols", RFC 2477, January 1999. + + + +Calhoun, et al. Standards Track [Page 139] + +RFC 3588 Diameter Based Protocol September 2003 + + + [SECARCH] Kent, S. and R. Atkinson, "Security Architecture for + the Internet Protocol", RFC 2401, November 1998. + + [TACACS] Finseth, C., "An Access Control Protocol, Sometimes + Called TACACS", RFC 1492, July 1993. + +15. Acknowledgements + + The authors would like to thank Nenad Trifunovic, Tony Johansson and + Pankaj Patel for their participation in the pre-IETF Document Reading + Party. Allison Mankin, Jonathan Wood and Bernard Aboba provided + invaluable assistance in working out transport issues, and similarly + with Steven Bellovin in the security area. + + Paul Funk and David Mitton were instrumental in getting the Peer + State Machine correct, and our deep thanks go to them for their time. + + Text in this document was also provided by Paul Funk, Mark Eklund, + Mark Jones and Dave Spence. Jacques Caron provided many great + comments as a result of a thorough review of the spec. + + The authors would also like to acknowledge the following people for + their contribution in the development of the Diameter protocol: + + Allan C. Rubens, Haseeb Akhtar, William Bulley, Stephen Farrell, + David Frascone, Daniel C. Fox, Lol Grant, Ignacio Goyret, Nancy + Greene, Peter Heitman, Fredrik Johansson, Mark Jones, Martin Julien, + Bob Kopacz, Paul Krumviede, Fergal Ladley, Ryan Moats, Victor Muslin, + Kenneth Peirce, John Schnizlein, Sumit Vakil, John R. Vollbrecht and + Jeff Weisberg. + + Finally, Pat Calhoun would like to thank Sun Microsystems since most + of the effort put into this document was done while he was in their + employ. + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 140] + +RFC 3588 Diameter Based Protocol September 2003 + + +Appendix A. Diameter Service Template + + The following service template describes the attributes used by + Diameter servers to advertise themselves. This simplifies the + process of selecting an appropriate server to communicate with. A + Diameter client can request specific Diameter servers based on + characteristics of the Diameter service desired (for example, an AAA + server to use for accounting.) + + Name of submitter: "Erik Guttman" <[email protected]> Language of + service template: en + + Security Considerations: + Diameter clients and servers use various cryptographic mechanisms + to protect communication integrity, confidentiality as well as + perform end-point authentication. It would thus be difficult if + not impossible for an attacker to advertise itself using SLPv2 and + pose as a legitimate Diameter peer without proper preconfigured + secrets or cryptographic keys. Still, as Diameter services are + vital for network operation it is important to use SLPv2 + authentication to prevent an attacker from modifying or + eliminating service advertisements for legitimate Diameter + servers. + + Template text: + -------------------------template begins here----------------------- + template-type=service:diameter + + template-version=0.0 + + template-description= + The Diameter protocol is defined by RFC 3588. + + template-url-syntax= + url-path= ; The Diameter URL format is described in Section 2.9. + ; Example: 'aaa://aaa.example.com:1812;transport=tcp + supported-auth-applications= string L M + # This attribute lists the Diameter applications supported by the + # AAA implementation. The applications currently defined are: + # Application Name Defined by + # ---------------- ----------------------------------- + # NASREQ Diameter Network Access Server Application + # MobileIP Diameter Mobile IP Application + # + # Notes: + # . Diameter implementations support one or more applications. + # . Additional applications may be defined in the future. + # An updated service template will be created at that time. + + + +Calhoun, et al. Standards Track [Page 141] + +RFC 3588 Diameter Based Protocol September 2003 + + + # + NASREQ,MobileIP + + supported-acct-applications= string L M + # This attribute lists the Diameter applications supported by the + # AAA implementation. The applications currently defined are: + # Application Name Defined by + # ---------------- ----------------------------------- + # NASREQ Diameter Network Access Server Application + # MobileIP Diameter Mobile IP Application + # + # Notes: + # . Diameter implementations support one or more applications. + # . Additional applications may be defined in the future. + # An updated service template will be created at that time. + # + NASREQ,MobileIP + + supported-transports= string L M + SCTP + # This attribute lists the supported transports that the Diameter + # implementation accepts. Note that a compliant Diameter + # implementation MUST support SCTP, though it MAY support other + # transports, too. + SCTP,TCP + + -------------------------template ends here----------------------- + +Appendix B. NAPTR Example + + As an example, consider a client that wishes to resolve aaa:ex.com. + The client performs a NAPTR query for that domain, and the following + NAPTR records are returned: + + ;; order pref flags service regexp replacement + IN NAPTR 50 50 "s" "AAA+D2S" "" + _diameter._sctp.example.com IN NAPTR 100 50 "s" "AAA+D2T" + "" _aaa._tcp.example.com + + This indicates that the server supports SCTP, and TCP, in that order. + If the client supports over SCTP, SCTP will be used, targeted to a + host determined by an SRV lookup of _diameter._sctp.ex.com. That + lookup would return: + + ;; Priority Weight Port Target + IN SRV 0 1 5060 server1.example.com IN SRV 0 + 2 5060 server2.example.com + + + + +Calhoun, et al. Standards Track [Page 142] + +RFC 3588 Diameter Based Protocol September 2003 + + +Appendix C. Duplicate Detection + + As described in Section 9.4, accounting record duplicate detection is + based on session identifiers. Duplicates can appear for various + reasons: + + - Failover to an alternate server. Where close to real-time + performance is required, failover thresholds need to be kept low + and this may lead to an increased likelihood of duplicates. + Failover can occur at the client or within Diameter agents. + + - Failure of a client or agent after sending of a record from non- + volatile memory, but prior to receipt of an application layer ACK + and deletion of the record. record to be sent. This will result + in retransmission of the record soon after the client or agent has + rebooted. + + - Duplicates received from RADIUS gateways. Since the + retransmission behavior of RADIUS is not defined within [RFC2865], + the likelihood of duplication will vary according to the + implementation. + + - Implementation problems and misconfiguration. + + The T flag is used as an indication of an application layer + retransmission event, e.g., due to failover to an alternate server. + It is defined only for request messages sent by Diameter clients or + agents. For instance, after a reboot, a client may not know whether + it has already tried to send the accounting records in its non- + volatile memory before the reboot occurred. Diameter servers MAY use + the T flag as an aid when processing requests and detecting duplicate + messages. However, servers that do this MUST ensure that duplicates + are found even when the first transmitted request arrives at the + server after the retransmitted request. It can be used only in cases + where no answer has been received from the Server for a request and + the request is sent again, (e.g., due to a failover to an alternate + peer, due to a recovered primary peer or due to a client re-sending a + stored record from non-volatile memory such as after reboot of a + client or agent). + + In some cases the Diameter accounting server can delay the duplicate + detection and accounting record processing until a post-processing + phase takes place. At that time records are likely to be sorted + according to the included User-Name and duplicate elimination is easy + in this case. In other situations it may be necessary to perform + real-time duplicate detection, such as when credit limits are imposed + or real-time fraud detection is desired. + + + + +Calhoun, et al. Standards Track [Page 143] + +RFC 3588 Diameter Based Protocol September 2003 + + + In general, only generation of duplicates due to failover or re- + sending of records in non-volatile storage can be reliably detected + by Diameter clients or agents. In such cases the Diameter client or + agents can mark the message as possible duplicate by setting the T + flag. Since the Diameter server is responsible for duplicate + detection, it can choose to make use of the T flag or not, in order + to optimize duplicate detection. Since the T flag does not affect + interoperability, and may not be needed by some servers, generation + of the T flag is REQUIRED for Diameter clients and agents, but MAY be + implemented by Diameter servers. + + As an example, it can be usually be assumed that duplicates appear + within a time window of longest recorded network partition or device + fault, perhaps a day. So only records within this time window need + to be looked at in the backward direction. Secondly, hashing + techniques or other schemes, such as the use of the T flag in the + received messages, may be used to eliminate the need to do a full + search even in this set except for rare cases. + + The following is an example of how the T flag may be used by the + server to detect duplicate requests. + + A Diameter server MAY check the T flag of the received message to + determine if the record is a possible duplicate. If the T flag is + set in the request message, the server searches for a duplicate + within a configurable duplication time window backward and + forward. This limits database searching to those records where + the T flag is set. In a well run network, network partitions and + device faults will presumably be rare events, so this approach + represents a substantial optimization of the duplicate detection + process. During failover, it is possible for the original record + to be received after the T flag marked record, due to differences + in network delays experienced along the path by the original and + duplicate transmissions. The likelihood of this occurring + increases as the failover interval is decreased. In order to be + able to detect out of order duplicates, the Diameter server should + use backward and forward time windows when performing duplicate + checking for the T flag marked request. For example, in order to + allow time for the original record to exit the network and be + recorded by the accounting server, the Diameter server can delay + processing records with the T flag set until a time period + TIME_WAIT + RECORD_PROCESSING_TIME has elapsed after the closing + of the original transport connection. After this time period has + expired, then it may check the T flag marked records against the + database with relative assurance that the original records, if + sent, have been received and recorded. + + + + + +Calhoun, et al. Standards Track [Page 144] + +RFC 3588 Diameter Based Protocol September 2003 + + +Appendix D. Intellectual Property Statement + + The IETF takes no position regarding the validity or scope of any + intellectual property or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; neither does it represent that it + has made any effort to identify any such rights. Information on the + IETF's procedures with respect to rights in standards-track and + standards-related documentation can be found in BCP-11. Copies of + claims of rights made available for publication and any assurances of + licenses to be made available, or the result of an attempt made to + obtain a general license or permission for the use of such + proprietary rights by implementers or users of this specification can + be obtained from the IETF Secretariat. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights which may cover technology that may be required to practice + this standard. Please address the information to the IETF Executive + Director. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 145] + +RFC 3588 Diameter Based Protocol September 2003 + + +Authors' Addresses + + Pat R. Calhoun + Airespace, Inc. + 110 Nortech Parkway + San Jose, California, 95134 + USA + + Phone: +1 408-635-2023 + Fax: +1 408-635-2020 + EMail: [email protected] + + John Loughney + Nokia Research Center + Itamerenkatu 11-13 + 00180 Helsinki + Finland + + Phone: +358 50 483 6242 + EMail: [email protected] + + Jari Arkko + Ericsson + 02420 Jorvas + Finland + + Phone: +358 40 5079256 + EMail: [email protected] + + Erik Guttman + Sun Microsystems, Inc. + Eichhoelzelstr. 7 + 74915 Waibstadt + Germany + + Phone: +49 7263 911 701 + EMail: [email protected] + + Glen Zorn + Cisco Systems, Inc. + 500 108th Avenue N.E., Suite 500 + Bellevue, WA 98004 + USA + + Phone: +1 425 438 8218 + + + + + + +Calhoun, et al. Standards Track [Page 146] + +RFC 3588 Diameter Based Protocol September 2003 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2003). All Rights Reserved. + + This document and translations of it may be copied and furnished to + others, and derivative works that comment on or otherwise explain it + or assist in its implementation may be prepared, copied, published + and distributed, in whole or in part, without restriction of any + kind, provided that the above copyright notice and this paragraph are + included on all such copies and derivative works. However, this + document itself may not be modified in any way, such as by removing + the copyright notice or references to the Internet Society or other + Internet organizations, except as needed for the purpose of + developing Internet standards in which case the procedures for + copyrights defined in the Internet Standards process must be + followed, or as required to translate it into languages other than + English. + + The limited permissions granted above are perpetual and will not be + revoked by the Internet Society or its successors or assigns. + + This document and the information contained herein is provided on an + "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING + TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION + HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF + MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 147] + diff --git a/lib/diameter/doc/standard/rfc4005.txt b/lib/diameter/doc/standard/rfc4005.txt new file mode 100644 index 0000000000..561508b53b --- /dev/null +++ b/lib/diameter/doc/standard/rfc4005.txt @@ -0,0 +1,4763 @@ + + + + + + +Network Working Group P. Calhoun +Request for Comments: 4005 G. Zorn +Category: Standards Track Cisco Systems Inc. + D. Spence + Consultant + D. Mitton + Circular Networks + August 2005 + + + Diameter Network Access Server Application + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + This document describes the Diameter protocol application used for + Authentication, Authorization, and Accounting (AAA) services in the + Network Access Server (NAS) environment. When combined with the + Diameter Base protocol, Transport Profile, and Extensible + Authentication Protocol specifications, this application + specification satisfies typical network access services requirements. + + Initial deployments of the Diameter protocol are expected to include + legacy systems. Therefore, this application has been carefully + designed to ease the burden of protocol conversion between RADIUS and + Diameter. This is achieved by including the RADIUS attribute space + to eliminate the need to perform many attribute translations. + + The interactions between Diameter applications and RADIUS specified + in this document are to be applied to all Diameter applications. In + this sense, this document extends the Base Diameter protocol. + + + + + + + + + +Calhoun, et al. Standards Track [Page 1] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 1.1. Terminology . . . . . . . . . . . . . . . . . . . . . . 5 + 1.2. Requirements Language . . . . . . . . . . . . . . . . . 6 + 1.3. Advertising Application Support . . . . . . . . . . . . 6 + 2. NAS Calls, Ports, and Sessions . . . . . . . . . . . . . . . . 6 + 2.1. Diameter Session Establishment . . . . . . . . . . . . . 7 + 2.2. Diameter Session Reauthentication or Reauthorization . . 7 + 2.3. Diameter Session Termination . . . . . . . . . . . . . . 8 + 3. NAS Messages . . . . . . . . . . . . . . . . . . . . . . . . . 9 + 3.1. AA-Request (AAR) Command . . . . . . . . . . . . . . . . 9 + 3.2. AA-Answer (AAA) Command . . . . . . . . . . . . . . . . 11 + 3.3. Re-Auth-Request (RAR) Command . . . . . . . . . . . . . 13 + 3.4. Re-Auth-Answer (RAA) Command . . . . . . . . . . . . . . 14 + 3.5. Session-Termination-Request (STR) Command . . . . . . . 15 + 3.6. Session-Termination-Answer (STA) Command . . . . . . . . 15 + 3.7. Abort-Session-Request (ASR) Command . . . . . . . . . . 16 + 3.8. Abort-Session-Answer (ASA) Command . . . . . . . . . . . 17 + 3.9. Accounting-Request (ACR) Command . . . . . . . . . . . . 17 + 3.10. Accounting-Answer (ACA) Command. . . . . . . . . . . . . 19 + 4. NAS Session AVPs . . . . . . . . . . . . . . . . . . . . . . . 20 + 4.1. Call and Session Information . . . . . . . . . . . . . . 21 + 4.2. NAS-Port AVP . . . . . . . . . . . . . . . . . . . . . . 22 + 4.3. NAS-Port-Id AVP . . . . . . . . . . . . . . . . . . . . 22 + 4.4. NAS-Port-Type AVP . . . . . . . . . . . . . . . . . . . 22 + 4.5. Called-Station-Id AVP . . . . . . . . . . . . . . . . . 23 + 4.6. Calling-Station-Id AVP . . . . . . . . . . . . . . . . . 23 + 4.7. Connect-Info AVP . . . . . . . . . . . . . . . . . . . . 24 + 4.8. Originating-Line-Info AVP . . . . . . . . . . . . . . . 24 + 4.9. Reply-Message AVP . . . . . . . . . . . . . . . . . . . 25 + 5. NAS Authentication AVPs . . . . . . . . . . . . . . . . . . . 26 + 5.1. User-Password AVP . . . . . . . . . . . . . . . . . . . 26 + 5.2. Password-Retry AVP . . . . . . . . . . . . . . . . . . . 27 + 5.3. Prompt AVP . . . . . . . . . . . . . . . . . . . . . . . 27 + 5.4. CHAP-Auth AVP . . . . . . . . . . . . . . . . . . . . . 27 + 5.5. CHAP-Algorithm AVP . . . . . . . . . . . . . . . . . . . 28 + 5.6. CHAP-Ident AVP . . . . . . . . . . . . . . . . . . . . . 28 + 5.7. CHAP-Response AVP . . . . . . . . . . . . . . . . . . . 28 + 5.8. CHAP-Challenge AVP . . . . . . . . . . . . . . . . . . . 28 + 5.9. ARAP-Password AVP . . . . . . . . . . . . . . . . . . . 28 + 5.10. ARAP-Challenge-Response AVP. . . . . . . . . . . . . . . 28 + 5.11. ARAP-Security AVP. . . . . . . . . . . . . . . . . . . . 29 + 5.12. ARAP-Security-Data AVP . . . . . . . . . . . . . . . . . 29 + 6. NAS Authorization AVPs . . . . . . . . . . . . . . . . . . . . 29 + 6.1. Service-Type AVP . . . . . . . . . . . . . . . . . . . . 30 + 6.2. Callback-Number AVP . . . . . . . . . . . . . . . . . . 32 + 6.3. Callback-Id AVP . . . . . . . . . . . . . . . . . . . . 32 + + + +Calhoun, et al. Standards Track [Page 2] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 6.4. Idle-Timeout AVP . . . . . . . . . . . . . . . . . . . . 32 + 6.5. Port-Limit AVP . . . . . . . . . . . . . . . . . . . . . 32 + 6.6. NAS-Filter-Rule AVP . . . . . . . . . . . . . . . . . . 32 + 6.7. Filter-Id AVP . . . . . . . . . . . . . . . . . . . . . 33 + 6.8. Configuration-Token AVP . . . . . . . . . . . . . . . . 33 + 6.9. QoS-Filter-Rule AVP . . . . . . . . . . . . . . . . . . 33 + 6.10. Framed Access Authorization AVPs . . . . . . . . . . . . 35 + 6.10.1. Framed-Protocol AVP . . . . . . . . . . . . . . 35 + 6.10.2. Framed-Routing AVP. . . . . . . . . . . . . . . 35 + 6.10.3. Framed-MTU AVP. . . . . . . . . . . . . . . . . 35 + 6.10.4. Framed-Compression AVP. . . . . . . . . . . . . 36 + 6.11. IP Access Authorization AVPs.. . . . . . . . . . . . . . 36 + 6.11.1. Framed-IP-Address AVP . . . . . . . . . . . . . 36 + 6.11.2. Framed-IP-Netmask AVP . . . . . . . . . . . . . 36 + 6.11.3. Framed-Route AVP. . . . . . . . . . . . . . . . 37 + 6.11.4. Framed-Pool AVP . . . . . . . . . . . . . . . . 37 + 6.11.5. Framed-Interface-Id AVP . . . . . . . . . . . . 37 + 6.11.6. Framed-IPv6-Prefix AVP. . . . . . . . . . . . . 38 + 6.11.7. Framed-IPv6-Route AVP . . . . . . . . . . . . . 38 + 6.11.8. Framed-IPv6-Pool AVP. . . . . . . . . . . . . . 38 + 6.12. IPX Access . . . . . . . . . . . . . . . . . . . . . . . 38 + 6.12.1. Framed-IPX-Network AVP. . . . . . . . . . . . . 39 + 6.13. AppleTalk Network Access . . . . . . . . . . . . . . . . 39 + 6.13.1. Framed-AppleTalk-Link AVP . . . . . . . . . . . 39 + 6.13.2. Framed-AppleTalk-Network AVP . . . . . . . . . 39 + 6.13.3. Framed-AppleTalk-Zone AVP . . . . . . . . . . . 40 + 6.14. AppleTalk Remote Access. . . . . . . . . . . . . . . . . 40 + 6.14.1. ARAP-Features AVP . . . . . . . . . . . . . . . 40 + 6.14.2. ARAP-Zone-Access AVP. . . . . . . . . . . . . . 40 + 6.15. Non-Framed Access Authorization AVPs . . . . . . . . . . 40 + 6.15.1. Login-IP-Host AVP . . . . . . . . . . . . . . . 40 + 6.15.2. Login-IPv6-Host AVP . . . . . . . . . . . . . . 41 + 6.15.3. Login-Service AVP . . . . . . . . . . . . . . . 41 + 6.16. TCP Services . . . . . . . . . . . . . . . . . . . . . . 42 + 6.16.1. Login-TCP-Port AVP . . . . . . . . . . . . . . 42 + 6.17. LAT Services . . . . . . . . . . . . . . . . . . . . . . 42 + 6.17.1. Login-LAT-Service AVP . . . . . . . . . . . . . 42 + 6.17.2. Login-LAT-Node AVP. . . . . . . . . . . . . . . 43 + 6.17.3. Login-LAT-Group AVP . . . . . . . . . . . . . . 43 + 6.17.4. Login-LAT-Port AVP. . . . . . . . . . . . . . . 43 + 7. NAS Tunneling . . . . . . . . . . . . . . . . . . . . . . . . 44 + 7.1. Tunneling AVP . . . . . . . . . . . . . . . . . . . . . 44 + 7.2. Tunnel-Type AVP . . . . . . . . . . . . . . . . . . . . 45 + 7.3. Tunnel-Medium-Type AVP . . . . . . . . . . . . . . . . . 46 + 7.4. Tunnel-Client-Endpoint AVP . . . . . . . . . . . . . . . 46 + 7.5. Tunnel-Server-Endpoint AVP . . . . . . . . . . . . . . . 47 + 7.6. Tunnel-Password AVP . . . . . . . . . . . . . . . . . . 48 + 7.7. Tunnel-Private-Group-Id AVP . . . . . . . . . . . . . . 48 + + + +Calhoun, et al. Standards Track [Page 3] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 7.8. Tunnel-Assignment-Id AVP . . . . . . . . . . . . . . . . 48 + 7.9. Tunnel-Preference AVP . . . . . . . . . . . . . . . . . 49 + 7.10. Tunnel-Client-Auth-Id AVP. . . . . . . . . . . . . . . . 50 + 7.11. Tunnel-Server-Auth-Id AVP. . . . . . . . . . . . . . . . 50 + 8. NAS Accounting . . . . . . . . . . . . . . . . . . . . . . . . 50 + 8.1. Accounting-Input-Octets AVP . . . . . . . . . . . . . . 51 + 8.2. Accounting-Output-Octets AVP . . . . . . . . . . . . . . 52 + 8.3. Accounting-Input-Packets AVP . . . . . . . . . . . . . . 52 + 8.4. Accounting-Output-Packets AVP . . . . . . . . . . . . . 52 + 8.5. Acct-Session-Time AVP . . . . . . . . . . . . . . . . . 52 + 8.6. Acct-Authentic AVP . . . . . . . . . . . . . . . . . . . 52 + 8.7. Accounting-Auth-Method AVP . . . . . . . . . . . . . . . 53 + 8.8. Acct-Delay-Time . . . . . . . . . . . . . . . . . . . . 53 + 8.9. Acct-Link-Count . . . . . . . . . . . . . . . . . . . . 54 + 8.10. Acct-Tunnel-Connection AVP . . . . . . . . . . . . . . . 54 + 8.11. Acct-Tunnel-Packets-Lost AVP . . . . . . . . . . . . . . 55 + 9. RADIUS/Diameter Protocol Interactions . . . . . . . . . . . . 55 + 9.1. RADIUS Request Forwarded as Diameter Request . . . . . . 55 + 9.1.1. RADIUS Dynamic Authorization Considerations . . 59 + 9.2. Diameter Request Forwarded as RADIUS Request . . . . . . 60 + 9.2.1. RADIUS Dynamic Authorization Considerations . . 62 + 9.3. AVPs Used Only for Compatibility . . . . . . . . . . . . 63 + 9.3.1. NAS-Identifier AVP. . . . . . . . . . . . . . . 63 + 9.3.2. NAS-IP-Address AVP. . . . . . . . . . . . . . . 64 + 9.3.3. NAS-IPv6-Address AVP. . . . . . . . . . . . . . 65 + 9.3.4. State AVP . . . . . . . . . . . . . . . . . . . 65 + 9.3.5. Termination-Cause AVP Code Values . . . . . . . 66 + 9.3.6. Origin-AAA-Protocol . . . . . . . . . . . . . . 68 + 9.4. Prohibited RADIUS Attributes . . . . . . . . . . . . . . 69 + 9.5. Translatable Diameter AVPs . . . . . . . . . . . . . . . 69 + 9.6. RADIUS Vendor-Specific Attributes . . . . . . . . . . . 69 + 9.6.1. Forwarding a Diameter Vendor Specific AVP as a + RADIUS VSA . . . . . . . . . . . . . . . . . . . 70 + 9.6.2. Forwarding a RADIUS VSA as a Diameter Vendor + Specific AVP . . . . . . . . . . . . . . . . . . 70 + 10. AVP Occurrence Tables. . . . . . . . . . . . . . . . . . . . . 71 + 10.1. AA-Request/Answer AVP Table. . . . . . . . . . . . . . . 71 + 10.2. Accounting AVP Tables. . . . . . . . . . . . . . . . . . 73 + 10.2.1. Accounting Framed Access AVP Table. . . . . . . 74 + 10.2.2. Accounting Non-Framed Access AVP Table. . . . . 76 + 11. IANA Considerations. . . . . . . . . . . . . . . . . . . . . . 77 + 11.1. Command Codes. . . . . . . . . . . . . . . . . . . . . . 77 + 11.2. AVP Codes. . . . . . . . . . . . . . . . . . . . . . . . 78 + 11.3. Application Identifier . . . . . . . . . . . . . . . . . 78 + 11.4. CHAP-Algorithm AVP Values. . . . . . . . . . . . . . . . 78 + 11.5. Accounting-Auth-Method AVP Values. . . . . . . . . . . . 78 + 11.6. Origin-AAA-Protocol AVP Values . . . . . . . . . . . . . 78 + 12. Security Considerations. . . . . . . . . . . . . . . . . . . . 78 + + + +Calhoun, et al. Standards Track [Page 4] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 13. References . . . . . . . . . . . . . . . . . . . . . . . . . . 79 + 13.1. Normative References . . . . . . . . . . . . . . . . . . 79 + 13.2. Informative References . . . . . . . . . . . . . . . . . 80 + 14. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 83 + Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 84 + Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 85 + +1. Introduction + + This document describes the Diameter protocol application used for + AAA in the Network Access Server (NAS) environment. When combined + with the Diameter Base protocol [BASE], Transport Profile + [DiamTrans], and EAP [DiamEAP] specifications, this Diameter NAS + application specification satisfies NAS-related requirements defined + in RFC 2989 [AAACriteria] and RFC 3169 [NASCriteria]. + + Initial deployments of the Diameter protocol are expected to include + legacy systems. Therefore, this application has been carefully + designed to ease the burden of protocol conversion between RADIUS and + Diameter. This is achieved by including the RADIUS attribute space + to eliminate the need to perform many attribute translations. + + The interactions specified in this document between Diameter + applications and RADIUS are to be applied to all Diameter + applications. In this sense, this document extends the Base Diameter + protocol [BASE]. + + First, this document describes the operation of a Diameter NAS + application. Then it defines the Diameter message Command-Codes. + The following sections list the AVPs used in these messages, grouped + by common usage. These are session identification, authentication, + authorization, tunneling, and accounting. The authorization AVPs are + further broken down by service type. Interaction and backward + compatibility issues with RADIUS are discussed in later sections. + +1.1. Terminology + + The base Diameter [BASE] specification section 1.4 defines most of + the terminology used in this document. Additionally, the following + terms and acronyms are used in this application: + + NAS (Network Access Server) - A device that provides an access + service for a user to a network. The service may be a network + connection or a value-added service such as terminal emulation + [NASModel]. + + + + + + +Calhoun, et al. Standards Track [Page 5] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + PPP (Point-to-Point Protocol) - A multiprotocol serial datalink. PPP + is the primary IP datalink used for dial-in NAS connection service + [PPP]. + + CHAP (Challenge Handshake Authentication Protocol) - An + authentication process used in PPP [PPPCHAP]. + + PAP (Password Authentication Protocol) - A deprecated PPP + authentication process, but often used for backward compatibility + [PAP]. + + SLIP (Serial Line Interface Protocol) - A serial datalink that only + supports IP. A design prior to PPP. + + ARAP (Appletalk Remote Access Protocol) - A serial datalink for + accessing Appletalk networks [ARAP]. + + IPX (Internet Packet Exchange) - The network protocol used by NetWare + networks [IPX]. + + LAT (Local Area Transport) - A Digital Equipment Corp. LAN protocol + for terminal services [LAT]. + + VPN (Virtual Private Network) - In this document, this term is used + to describe access services that use tunneling methods. + +1.2. Requirements Language + + In this document, the key words "MAY", "MUST", "MUST NOT", + "OPTIONAL", "RECOMMENDED", "SHOULD", and "SHOULD NOT" are to be + interpreted as described in [Keywords]. + +1.3. Advertising Application Support + + Diameter applications conforming to this specification MUST advertise + support by including the value of one (1) in the Auth-Application-Id + of Capabilities-Exchange-Request (CER), AA-Request (AAR), and AA- + Answer (AAA) messages. All other messages are defined by [BASE] and + use the Base application id value. + +2. NAS Calls, Ports, and Sessions + + The arrival of a new call or service connection at a port of a + Network Access Server (NAS) starts a Diameter NAS message exchange. + Information about the call, the identity of the user, and the user's + authentication information are packaged into a Diameter AA-Request + (AAR) message and sent to a server. + + + + +Calhoun, et al. Standards Track [Page 6] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + The server processes the information and responds with a Diameter + AA-Answer (AAA) message that contains authorization information for + the NAS, or a failure code (Result-Code AVP). A value of + DIAMETER_MULTI_ROUND_AUTH indicates an additional authentication + exchange, and several AAR and AAA messages may be exchanged until the + transaction completes. + + Depending on the Auth-Request-Type AVP, the Diameter protocol allows + authorization-only requests that contain no authentication + information from the client. This capability goes beyond the Call + Check capabilities described in section 5.6 of [RADIUS] in that no + access decision is requested. As a result, service cannot be started + as a result of a response to an authorization-only request without + introducing a significant security vulnerability. + + Since no equivalent capability exists in RADIUS, authorization-only + requests from a NAS implementing Diameter may not be easily + translated to an equivalent RADIUS message by a Diameter/RADIUS + gateway. For example, when a Diameter authorization-only request + cannot be translated to a RADIUS Call Check, it would be necessary + for the Diameter/RADIUS gateway to add authentication information to + the RADIUS Access Request. On receiving the Access-Reply, the + Diameter/RADIUS gateway would need to discard the access decision + (Accept/Reject). It is not clear whether these translations can be + accomplished without adding significant security vulnerabilities. + +2.1. Diameter Session Establishment + + When the authentication or authorization exchange completes + successfully, the NAS application SHOULD start a session context. If + the Result-Code of DIAMETER_MULTI_ROUND_AUTH is returned, the + exchange continues until a success or error is returned. + + If accounting is active, the application MUST also send an Accounting + message [BASE]. An Accounting-Record-Type of START_RECORD is sent + for a new session. If a session fails to start, the EVENT_RECORD + message is sent with the reason for the failure described. + + Note that the return of an unsupportable Accounting-Realtime-Required + value [BASE] would result in a failure to establish the session. + +2.2. Diameter Session Reauthentication or Reauthorization + + The Diameter Base protocol allows users to be periodically + reauthenticated and/or reauthorized. In such instances, the + Session-Id AVP in the AAR message MUST be the same as the one present + in the original authentication/authorization message. + + + + +Calhoun, et al. Standards Track [Page 7] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + A Diameter server informs the NAS of the maximum time allowed before + reauthentication or reauthorization via the Authorization-Lifetime + AVP [BASE]. A NAS MAY reauthenticate and/or reauthorize before the + end, but A NAS MUST reauthenticate and/or reauthorize at the end of + the period provided by the Authorization-Lifetime AVP. The failure + of a reauthentication exchange will terminate the service. + + Furthermore, it is possible for Diameter servers to issue an + unsolicited reauthentication and/or reauthorization request (e.g., + Re-Auth-Request (RAR) message [BASE]) to the NAS. Upon receipt of + such a message, the NAS MUST respond to the request with a Re-Auth- + Answer (RAA) message [BASE]. + + If the RAR properly identifies an active session, the NAS will + initiate a new local reauthentication or authorization sequence as + indicated by the Re-Auth-Request-Type value. This will cause the NAS + to send a new AAR message using the existing Session-Id. The server + will respond with an AAA message to specify the new service + parameters. + + If accounting is active, every change of authentication or + authorization SHOULD generate an accounting message. If the NAS + service is a continuation of the prior user context, then an + Accounting-Record-Type of INTERIM_RECORD indicating the new session + attributes and cumulative status would be appropriate. If a new user + or a significant change in authorization is detected by the NAS, then + the service may send two messages of the types STOP_RECORD and + START_RECORD. Accounting may change the subsession identifiers + (Acct-Session-ID, or Acct-Sub-Session-Id) to indicate such sub- + sessions. A service may also use a different Session-Id value for + accounting (see [BASE] section 9.6). + + However, the Diameter Session-ID AVP value used for the initial + authorization exchange MUST be used to generate an STR message when + the session context is terminated. + +2.3. Diameter Session Termination + + When a NAS receives an indication that a user's session is being + disconnected by the client (e.g., LCP Terminate is received) or an + administrative command, the NAS MUST issue a Session-Termination- + Request (STR) [BASE] to its Diameter Server. This will ensure that + any resources maintained on the servers are freed appropriately. + + Furthermore, a NAS that receives an Abort-Session-Request (ASR) + [BASE] MUST issue an ASA if the session identified is active and + disconnect the PPP (or tunneling) session. + + + + +Calhoun, et al. Standards Track [Page 8] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + If accounting is active, an Accounting STOP_RECORD message [BASE] + MUST be sent upon termination of the session context. + + More information on Diameter Session Termination is included in + [BASE] sections 8.4 and 8.5. + +3. NAS Messages + + This section defines the Diameter message Command-Code [BASE] values + that MUST be supported by all Diameter implementations conforming to + this specification. The Command Codes are as follows: + + Command-Name Abbrev. Code Reference + ------------------------------------------------------- + AA-Request AAR 265 3.1 + AA-Answer AAA 265 3.2 + Re-Auth-Request RAR 258 3.3 + Re-Auth-Answer RAA 258 3.4 + Session-Termination-Request STR 275 3.5 + Session-Termination-Answer STA 275 3.6 + Abort-Session-Request ASR 274 3.7 + Abort-Session-Answer ASA 274 3.8 + Accounting-Request ACR 271 3.9 + Accounting-Answer ACA 271 3.10 + +3.1. 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. + + + + +Calhoun, et al. Standards Track [Page 9] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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 + <AA-Request> ::= < 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 ] + + + +Calhoun, et al. Standards Track [Page 10] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + * [ 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 ] + +3.2. 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 + + <AA-Answer> ::= < 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 ] + + + +Calhoun, et al. Standards Track [Page 11] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + [ 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 ] + + + +Calhoun, et al. Standards Track [Page 12] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + [ Login-TCP-Port ] + * [ NAS-Filter-Rule ] + * [ QoS-Filter-Rule ] + * [ Tunneling ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + +3.3. Re-Auth-Request (RAR) Command + + A Diameter server may initiate a re-authentication and/or re- + authorization service for a particular session by issuing a Re-Auth- + Request (RAR) message [BASE]. + + For example, for pre-paid services, the Diameter server that + originally authorized a session may need some confirmation that the + user is still using the services. + + If a NAS receives an RAR message with Session-Id equal to a currently + active session and a Re-Auth-Type that includes authentication, it + MUST initiate a re-authentication toward the user, if the service + supports this particular feature. + + Message Format + + <RA-Request> ::= < 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 ] + + + +Calhoun, et al. Standards Track [Page 13] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + [ 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 ] + +3.4. Re-Auth-Answer (RAA) Command + + The Re-Auth-Answer (RAA) message [BASE] is sent in response to the + RAR. The Result-Code AVP MUST be present and indicates the + disposition of the request. + + A successful RAA transaction MUST be followed by an AAR message. + + Message Format + + <RA-Answer> ::= < 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 ] + + + +Calhoun, et al. Standards Track [Page 14] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +3.5. Session-Termination-Request (STR) Command + + The Session-Termination-Request (STR) message [BASE] is sent by the + NAS to inform the Diameter Server that an authenticated and/or + authorized session is being terminated. + + Message Format + + <ST-Request> ::= < 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 ] + +3.6. Session-Termination-Answer (STA) Command + + The Session-Termination-Answer (STA) message [BASE] is sent by the + Diameter Server to acknowledge the notification that the session has + been terminated. The Result-Code AVP MUST be present and MAY contain + an indication that an error occurred while the STR was being + serviced. + + Upon sending or receiving the STA, the Diameter Server MUST release + all resources for the session indicated by the Session-Id AVP. Any + intermediate server in the Proxy-Chain MAY also release any + resources, if necessary. + + Message Format + + <ST-Answer> ::= < Diameter Header: 275, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + * [ Class ] + [ Error-Message ] + [ Error-Reporting-Host ] + + + +Calhoun, et al. Standards Track [Page 15] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + * [ Failed-AVP ] + [ Origin-AAA-Protocol ] + [ Origin-State-Id ] + * [ Redirect-Host ] + [ Redirect-Host-Usase ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + +3.7. Abort-Session-Request (ASR) Command + + The Abort-Session-Request (ASR) message [BASE] may be sent by any + server to the NAS providing session service, to request that the + session identified by the Session-Id be stopped. + + Message Format + + <AS-Request> ::= < 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 ] + + + +Calhoun, et al. Standards Track [Page 16] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +3.8. Abort-Session-Answer (ASA) Command + + The ASA message [BASE] is sent in response to the ASR. The Result- + Code AVP MUST be present and indicates the disposition of the + request. + + If the session identified by Session-Id in the ASR was successfully + terminated, Result-Code is set to DIAMETER_SUCCESS. If the session + is not currently active, Result-Code is set to + DIAMETER_UNKNOWN_SESSION_ID. If the access device does not stop the + session for any other reason, Result-Code is set to + DIAMETER_UNABLE_TO_COMPLY. + + Message Format + + <AS-Answer> ::= < 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 ] + +3.9. Accounting-Request (ACR) Command + + The ACR message [BASE] is sent by the NAS to report its session + information to a target server downstream. + + Either of Acct-Application-Id or Vendor-Specific-Application-Id AVPs + MUST be present. If the Vendor-Specific-Application-Id grouped AVP + is present, it must have an Acct-Application-Id inside. + + The AVPs listed in the Base MUST be assumed to be present, as + appropriate. NAS service-specific accounting AVPs SHOULD be present + as described in section 8 and the rest of this specification. + + + + + + +Calhoun, et al. Standards Track [Page 17] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + Message Format + + <AC-Request> ::= < 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 ] + + + +Calhoun, et al. Standards Track [Page 18] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + [ 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 ] + +3.10. Accounting-Answer (ACA) Command + + The ACA message [BASE] is used to acknowledge an Accounting-Request + command. The Accounting-Answer command contains the same Session-Id + as the Request. If the Accounting-Request was protected by end-to- + end security, then the corresponding ACA message MUST be protected as + well. + + Only the target Diameter Server or home Diameter Server SHOULD + respond with the Accounting-Answer command. + + Either Acct-Application-Id or Vendor-Specific-Application-Id AVPs + MUST be present, as it was in the request. + + + +Calhoun, et al. Standards Track [Page 19] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + The AVPs listed in the Base MUST be assumed to be present, as + appropriate. NAS service-specific accounting AVPs SHOULD be present + as described in section 8 and the rest of this specification. + + Message Format + + <AC-Answer> ::= < 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 ] + +4. NAS Session AVPs + + Diameter reserves the AVP Codes 0 - 255 for RADIUS functions that are + implemented in Diameter. + + AVPs new to Diameter have code values of 256 and greater. A Diameter + message that includes one of these AVPs may represent functions not + present in the RADIUS environment and may cause interoperability + + + +Calhoun, et al. Standards Track [Page 20] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + issues, should the request traverse an AAA system that only supports + the RADIUS protocol. + + Some RADIUS attributes are not allowed or supported directly in + Diameter. See section 9 for more information. + +4.1. Call and Session Information + + This section contains the AVPs specific to NAS Diameter applications + that are needed to identify the call and session context and status + information. On a request, this information allows the server to + qualify the session. + + These AVPs are used in addition to the Base AVPs of: + + Session-Id + Auth-Application-Id + Origin-Host + Origin-Realm + Auth-Request-Type + Termination-Cause + + The following table describes the session level AVPs; their AVP Code + values, types, and possible flag values; and whether the AVP MAY be + encrypted. + + +---------------------+ + | AVP Flag rules | + |----+-----+----+-----|----+ + AVP Section | | |SHLD| MUST| | + Attribute Name Code Defined Value Type |MUST| MAY | NOT| NOT|Encr| + -----------------------------------------|----+-----+----+-----|----| + NAS-Port 5 4.2 Unsigned32 | M | P | | V | Y | + NAS-Port-Id 87 4.3 UTF8String | M | P | | V | Y | + NAS-Port-Type 61 4.4 Enumerated | M | P | | V | Y | + Called-Station-Id 30 4.5 UTF8String | M | P | | V | Y | + Calling-Station- 31 4.6 UTF8String | M | P | | V | Y | + Id | | | | | | + Connect-Info 77 4.7 UTF8String | M | P | | V | Y | + Originating-Line- 94 4.8 OctetString| | M,P | | V | Y | + Info | | | | | | + Reply-Message 18 4.9 UTF8String | M | P | | V | Y | + -----------------------------------------|----+-----+----+-----|----| + + + + + + + + +Calhoun, et al. Standards Track [Page 21] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +4.2. NAS-Port AVP + + 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. + +4.3. NAS-Port-Id AVP + + 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. + +4.4. NAS-Port-Type AVP + + 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. + + 0 Async + 1 Sync + 2 ISDN Sync + 3 ISDN Async V.120 + 4 ISDN Async V.110 + 5 Virtual + 6 PIAFS + 7 HDLC Clear Channel + 8 X.25 + 9 X.75 + 10 G.3 Fax + 11 SDSL - Symmetric DSL + 12 ADSL-CAP - Asymmetric DSL, Carrierless Amplitude Phase + Modulation + 13 ADSL-DMT - Asymmetric DSL, Discrete Multi-Tone + 14 IDSL - ISDN Digital Subscriber Line + + + +Calhoun, et al. Standards Track [Page 22] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 15 Ethernet + 16 xDSL - Digital Subscriber Line of unknown type + 17 Cable + 18 Wireless - Other + 19 Wireless - IEEE 802.11 + 20 Token-Ring [RAD802.1X] + 21 FDDI [RAD802.1X] + 22 Wireless - CDMA2000 + 23 Wireless - UMTS + 24 Wireless - 1X-EV + 25 IAPP [IEEE 802.11f] + +4.5. Called-Station-Id AVP + + 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. + + The codification of this field's allowed usage range is outside the + scope of this specification. + +4.6. Calling-Station-Id AVP + + 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.) + + + +Calhoun, et al. Standards Track [Page 23] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + The codification of this field's allowed usage range is outside the + scope of this specification. + +4.7. Connect-Info AVP + + 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. + +4.8. Originating-Line-Info AVP + + 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 [ANITypes]. + + + + + +Calhoun, et al. Standards Track [Page 24] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + Value Description + ------------------------------------------------------------ + 00 Plain Old Telephone Service (POTS) + 01 Multiparty Line (more than 2) + 02 ANI Failure + 03 ANI Observed + 04 ONI Observed + 05 ANI Failure Observed + 06 Station Level Rating + 07 Special Operator Handling Required + 08 InterLATA Restricted + 10 Test Call + 20 Automatic Identified Outward Dialing (AIOD) + 23 Coin or Non-Coin + 24 Toll Free Service (Non-Pay Origination) + 25 Toll Free Service (Pay Origination) + 27 Toll Free Service (Coin Control Origination) + 29 Prison/Inmate Service + 30-32 Intercept + 30 Intercept (Blank) + 31 Intercept (Trouble) + 32 Intercept (Regular) + 34 Telco Operator Handled Call + 40-49 Unrestricted Use + 52 Outward Wide Area Telecommunications Service (OUTWATS) + 60 Telecommunications Relay Service (TRS)(Unrestricted) + 61 Cellular/Wireless PCS (Type 1) + 62 Cellular/Wireless PCS (Type 2) + 63 Cellular/Wireless PCS (Roaming) + 66 TRS (Hotel) + 67 TRS (Restricted) + 70 Pay Station, No Coin Control + 93 Access for Private Virtual Network Service + +4.9. Reply-Message AVP + + 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. + + + + +Calhoun, et al. Standards Track [Page 25] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +5. NAS Authentication AVPs + + This section defines the AVPs necessary to carry the authentication + information in the Diameter protocol. The functionality defined here + provides a RADIUS-like AAA service over a more reliable and secure + transport, as defined in the base protocol [BASE]. + + The following table describes the AVPs; their AVP Code values, types, + and possible flag values, and whether the AVP MAY be encrypted. + + +---------------------+ + | AVP Flag rules | + |----+-----+----+-----|----+ + AVP Section | | |SHLD| MUST| | + Attribute Name Code Defined Value Type |MUST| MAY | NOT| NOT|Encr| + -----------------------------------------|----+-----+----+-----|----| + User-Password 2 5.1 OctetString| M | P | | V | Y | + Password-Retry 75 5.2 Unsigned32 | M | P | | V | Y | + Prompt 76 5.3 Enumerated | M | P | | V | Y | + CHAP-Auth 402 5.4 Grouped | M | P | | V | Y | + CHAP-Algorithm 403 5.5 Enumerated | M | P | | V | Y | + CHAP-Ident 404 5.6 OctetString| M | P | | V | Y | + CHAP-Response 405 5.7 OctetString| M | P | | V | Y | + CHAP-Challenge 60 5.8 OctetString| M | P | | V | Y | + ARAP-Password 70 5.9 OctetString| M | P | | V | Y | + ARAP-Challenge- 84 5.10 OctetString| M | P | | V | Y | + Response | | | | | | + ARAP-Security 73 5.11 Unsigned32 | M | P | | V | Y | + ARAP-Security- 74 5.12 OctetString| M | P | | V | Y | + Data | | | | | | + -----------------------------------------|----+-----+----+-----|----| + +5.1. User-Password AVP + + 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 + + + + + +Calhoun, et al. Standards Track [Page 26] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +5.2. Password-Retry AVP + + 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. + +5.3. Prompt AVP + + 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 [RADIUSTypes]. The following list + is informational: + + 0 No Echo + 1 Echo + +5.4. CHAP-Auth AVP + + 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 ] + + + + + + + +Calhoun, et al. Standards Track [Page 27] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +5.5. CHAP-Algorithm AVP + + 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. + +5.6. CHAP-Ident AVP + + 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]. + +5.7. CHAP-Response AVP + + 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]. + +5.8. CHAP-Challenge AVP + + 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]. + +5.9. ARAP-Password AVP + + 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. + +5.10. ARAP-Challenge-Response AVP + + 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 + + + + + +Calhoun, et al. Standards Track [Page 28] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +5.11. ARAP-Security AVP + + 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. + +5.12. ARAP-Security-Data AVP + + The ARAP-Security 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. + +6. NAS Authorization AVPs + + This section contains the authorization AVPs supported in the NAS + Application. The Service-Type AVP SHOULD be present in all messages, + and, based on its value, additional AVPs defined in this section and + in section 7 MAY be present. + + Due to space constraints, the short-form IPFltrRule is used to + represent IPFilterRule, and QoSFltrRule is used for QoSFilterRule. + + +---------------------+ + | AVP Flag rules | + |----+-----+----+-----|----+ + AVP Section | | |SHLD| MUST| | + Attribute Name Code Defined Value Type |MUST| MAY | NOT| NOT|Encr| + -----------------------------------------|----+-----+----+-----|----| + Service-Type 6 6.1 Enumerated | M | P | | V | Y | + Callback-Number 19 6.2 UTF8String | M | P | | V | Y | + Callback-Id 20 6.3 UTF8String | M | P | | V | Y | + Idle-Timeout 28 6.4 Unsigned32 | M | P | | V | Y | + Port-Limit 62 6.5 Unsigned32 | M | P | | V | Y | + NAS-Filter-Rule 400 6.6 IPFltrRule | M | P | | V | Y | + Filter-Id 11 6.7 UTF8String | M | P | | V | Y | + Configuration- 78 6.8 OctetString| M | | | P,V | | + Token | | | | | | + QoS-Filter-Rule 407 6.9 QoSFltrRule| | | | | | + Framed-Protocol 7 6.10.1 Enumerated | M | P | | V | Y | + + + +Calhoun, et al. Standards Track [Page 29] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + Framed-Routing 10 6.10.2 Enumerated | M | P | | V | Y | + Framed-MTU 12 6.10.3 Unsigned32 | M | P | | V | Y | + Framed- 13 6.10.4 Enumerated | M | P | | V | Y | + Compression | | | | | | + Framed-IP-Address 8 6.11.1 OctetString| M | P | | V | Y | + Framed-IP-Netmask 9 6.11.2 OctetString| M | P | | V | Y | + Framed-Route 22 6.11.3 UTF8String | M | P | | V | Y | + Framed-Pool 88 6.11.4 OctetString| M | P | | V | Y | + Framed- 96 6.11.5 Unsigned64 | M | P | | V | Y | + Interface-Id | | | | | | + Framed-IPv6- 97 6.11.6 OctetString| M | P | | V | Y | + Prefix | | | | | | + Framed-IPv6- 99 6.11.7 UTF8String | M | P | | V | Y | + Route | | | | | | + Framed-IPv6-Pool 100 6.11.8 OctetString| M | P | | V | Y | + Framed-IPX- 23 6.12.1 UTF8String | M | P | | V | Y | + Network | | | | | | + Framed-Appletalk- 37 6.13.1 Unsigned32 | M | P | | V | Y | + Link | | | | | | + Framed-Appletalk- 38 6.13.2 Unsigned32 | M | P | | V | Y | + Network | | | | | | + Framed-Appletalk- 39 6.13.3 OctetString| M | P | | V | Y | + Zone | | | | | | + ARAP-Features 71 6.14.1 OctetString| M | P | | V | Y | + ARAP-Zone-Access 72 6.14.2 Enumerated | M | P | | V | Y | + Login-IP-Host 14 6.15.1 OctetString| M | P | | V | Y | + Login-IPv6-Host 98 6.15.2 OctetString| M | P | | V | Y | + Login-Service 15 6.15.3 Enumerated | M | P | | V | Y | + Login-TCP-Port 16 6.16.1 Unsigned32 | M | P | | V | Y | + Login-LAT-Service 34 6.17.1 OctetString| M | P | | V | Y | + Login-LAT-Node 35 6.17.2 OctetString| M | P | | V | Y | + Login-LAT-Group 36 6.17.3 OctetString| M | P | | V | Y | + Login-LAT-Port 63 6.17.4 OctetString| M | P | | V | Y | + -----------------------------------------|----+-----+----+-----|----| + +6.1. Service-Type AVP + + 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 + + + +Calhoun, et al. Standards Track [Page 30] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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]. The following list is informational: + + 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 + 13 Fax + 14 Modem Relay + 15 IAPP-Register [IEEE 802.11f] + 16 IAPP-AP-Check [IEEE 802.11f] + 17 Authorize Only [RADDynAuth] + + 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. + + + +Calhoun, et al. Standards Track [Page 31] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +6.2. Callback-Number AVP + + 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. + + The codification of this field's allowed usage range is outside the + scope of this specification. + +6.3. Callback-Id AVP + + 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. + +6.4. Idle-Timeout AVP + + 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. + +6.5. Port-Limit AVP + + 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. + +6.6. NAS-Filter-Rule AVP + + 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. + + + + + + + + +Calhoun, et al. Standards Track [Page 32] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +6.7. Filter-Id AVP + + 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. + +6.8. Configuration-Token AVP + + 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. + +6.9. QoS-Filter-Rule AVP + + 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. + + Note: Due to an editorial mistake in [BASE], only the AVP format is + discussed. The complete QoSFilterRule definition was not included. + It is reprinted here for clarification. + + 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 + + + +Calhoun, et al. Standards Track [Page 33] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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> + Color values as defined in [DIFFSERV]. Exact + matching of DSCP values is required (no masks or + ranges). + + metering <rate> <color_under> <color_over> + 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. + + + + +Calhoun, et al. Standards Track [Page 34] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + The rule syntax is a modified subset of ipfw(8) from FreeBSD, + and the ipfw.c code may provide a useful base for + implementations. + +6.10. Framed Access Authorization AVPs + + This section lists the authorization AVPs necessary to + support framed access, such as PPP and SLIP. AVPs defined in this + section MAY be present in a message if the Service-Type AVP was set + to "Framed" or "Callback Framed". + +6.10.1. Framed-Protocol AVP + + 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]. The following list is informational: + + 1 PPP + 2 SLIP + 3 AppleTalk Remote Access Protocol (ARAP) + 4 Gandalf proprietary SingleLink/MultiLink protocol + 5 Xylogics proprietary IPX/SLIP + 6 X.75 Synchronous + +6.10.2. Framed-Routing AVP + + 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]. The + following list is informational: + + 0 None + 1 Send routing packets + 2 Listen for routing packets + 3 Send and Listen + +6.10.3. Framed-MTU AVP + + 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. + + + + + + +Calhoun, et al. Standards Track [Page 35] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +6.10.4. Framed-Compression AVP + + 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]. The following list + is informational: + + 0 None + 1 VJ TCP/IP header compression + 2 IPX header compression + 3 Stac-LZS compression + +6.11. IP Access Authorization AVPs + + The AVPs defined in this section are used when the user requests, or + is being granted, access service to IP. + +6.11.1. Framed-IP-Address AVP + + 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). + +6.11.2. Framed-IP-Netmask AVP + + 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 + + + + + +Calhoun, et al. Standards Track [Page 36] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +6.11.3. Framed-Route AVP + + 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. + +6.11.4. Framed-Pool AVP + + 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. + +6.11.5. Framed-Interface-Id AVP + + 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. + + + +Calhoun, et al. Standards Track [Page 37] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +6.11.6. Framed-IPv6-Prefix AVP + + 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. + +6.11.7. Framed-IPv6-Route AVP + + 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". + +6.11.8. Framed-IPv6-Pool AVP + + 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. + +6.12. IPX Access + + The AVPs defined in this section are used when the user requests, or + is being granted, access to an IPX network service. + + + + + + + +Calhoun, et al. Standards Track [Page 38] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +6.12.1. Framed-IPX-Network AVP + + 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). + +6.13. AppleTalk Network Access + + The AVPs defined in this section are used when the user requests, or + is being granted, access to an AppleTalk network [AppleTalk]. + +6.13.1. Framed-AppleTalk-Link AVP + + 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. + +6.13.2. Framed-AppleTalk-Network AVP + + 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. + + + + + +Calhoun, et al. Standards Track [Page 39] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +6.13.3. Framed-AppleTalk-Zone AVP + + 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. + +6.14. AppleTalk Remote Access + + The AVPs defined in this section are used when the user requests, or + is being granted, access to the AppleTalk network via the AppleTalk + Remote Access Protocol [ARAP]. They are only present if the Framed- + Protocol AVP (see section 6.10.1) is set to ARAP. Section 2.2 of RFC + 2869 [RADIUSExt] describes the operational use of these attributes. + +6.14.1. ARAP-Features AVP + + 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. + +6.14.2. ARAP-Zone-Access AVP + + 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]. + +6.15. Non-Framed Access Authorization AVPs + + This section contains the authorization AVPs that are needed to + support terminal server functionality. AVPs defined in this section + MAY be present in a message if the Service-Type AVP was set to + "Login" or "Callback Login". + +6.15.1. Login-IP-Host AVP + + 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 + + + + +Calhoun, et al. Standards Track [Page 40] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +6.15.2. Login-IPv6-Host AVP + + 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. + +6.15.3. Login-Service AVP + + 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]. The following list + is informational: + + 0 Telnet + 1 Rlogin + 2 TCP Clear + 3 PortMaster (proprietary) + 4 LAT + 5 X25-PAD + 6 X25-T3POS + 8 TCP Clear Quiet (suppresses any NAS-generated connect + string) + + + + + + + + +Calhoun, et al. Standards Track [Page 41] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +6.16. TCP Services + + The AVPs described in this section MAY be present if the Login- + Service AVP is set to Telnet, Rlogin, TCP Clear, or TCP Clear Quiet. + +6.16.1. Login-TCP-Port AVP + + 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. + +6.17. LAT Services + + The AVPs described in this section MAY be present if the Login- + Service AVP is set to LAT [LAT]. + +6.17.1. Login-LAT-Service AVP + + 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. + + + + +Calhoun, et al. Standards Track [Page 42] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +6.17.2. Login-LAT-Node AVP + + 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. + +6.17.3. Login-LAT-Group AVP + + 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. + +6.17.4. Login-LAT-Port AVP + + 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. + + + + +Calhoun, et al. Standards Track [Page 43] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +7. NAS Tunneling + + Some NASes support compulsory tunnel services in which the incoming + connection data is conveyed by an encapsulation method to a gateway + elsewhere in the network. This is typically transparent to the + service user, and the tunnel characteristics may be described by the + remote AAA server, based on the user's authorization information. + Several tunnel characteristics may be returned, and the NAS + implementation may choose one [RADTunnels], [RADTunlAcct]. + + +---------------------+ + | AVP Flag rules | + |----+-----+----+-----|----+ + AVP Section | | |SHLD| MUST| | + Attribute Name Code Defined Value Type |MUST| MAY | NOT| NOT |Encr| + -----------------------------------------|----+-----+----+-----|----| + Tunneling 401 7.1 Grouped | M | P | | V | N | + Tunnel-Type 64 7.2 Enumerated | M | P | | V | Y | + Tunnel-Medium- 65 7.3 Enumerated | M | P | | V | Y | + Type | | | | | | + Tunnel-Client- 66 7.4 UTF8String | M | P | | V | Y | + Endpoint | | | | | | + Tunnel-Server- 67 7.5 UTF8String | M | P | | V | Y | + Endpoint | | | | | | + Tunnel-Password 69 7.6 OctetString| M | P | | V | Y | + Tunnel-Private- 81 7.7 OctetString| M | P | | V | Y | + Group-Id | | | | | | + Tunnel- 82 7.8 OctetString| M | P | | V | Y | + Assignment-Id | | | | | | + Tunnel-Preference 83 7.9 Unsigned32 | M | P | | V | Y | + Tunnel-Client- 90 7.10 UTF8String | M | P | | V | Y | + Auth-Id | | | | | | + Tunnel-Server- 91 7.11 UTF8String | M | P | | V | Y | + Auth-Id | | | | | | + -----------------------------------------|----+-----+----+-----|----| + +7.1. Tunneling AVP + + 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: + + + +Calhoun, et al. Standards Track [Page 44] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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 ] + +7.2. Tunnel-Type AVP + + 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]. The following list + is informational: + + 1 Point-to-Point Tunneling Protocol (PPTP) + 2 Layer Two Forwarding (L2F) + 3 Layer Two Tunneling Protocol (L2TP) + 4 Ascend Tunnel Management Protocol (ATMP) + 5 Virtual Tunneling Protocol (VTP) + 6 IP Authentication Header in the Tunnel-mode (AH) + 7 IP-in-IP Encapsulation (IP-IP) + 8 Minimal IP-in-IP Encapsulation (MIN-IP-IP) + 9 IP Encapsulating Security Payload in the Tunnel-mode (ESP) + 10 Generic Route Encapsulation (GRE) + 11 Bay Dial Virtual Services (DVS) + 12 IP-in-IP Tunneling + 13 Virtual LANs (VLAN) + + + + + +Calhoun, et al. Standards Track [Page 45] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +7.3. Tunnel-Medium-Type AVP + + 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]. The following list + is informational: + + 1 IPv4 (IP version 4) + 2 IPv6 (IP version 6) + 3 NSAP + 4 HDLC (8-bit multidrop) + 5 BBN 1822 + 6 802 (includes all 802 media plus Ethernet "canonical + format") + 7 E.163 (POTS) + 8 E.164 (SMDS, Frame Relay, ATM) + 9 F.69 (Telex) + 10 X.121 (X.25, Frame Relay) + 11 IPX + 12 Appletalk + 13 Decnet IV + 14 Banyan Vines + 15 E.164 with NSAP format subaddress + +7.4. Tunnel-Client-Endpoint AVP + + 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 + + + + + +Calhoun, et al. Standards Track [Page 46] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + "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. + +7.5. Tunnel-Server-Endpoint AVP + + 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. + + + + + + +Calhoun, et al. Standards Track [Page 47] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +7.6. Tunnel-Password AVP + + 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]. + +7.7. Tunnel-Private-Group-Id AVP + + 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. + +7.8. Tunnel-Assignment-Id AVP + + 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 + + + +Calhoun, et al. Standards Track [Page 48] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +7.9. Tunnel-Preference AVP + + 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 + + + +Calhoun, et al. Standards Track [Page 49] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +7.10. Tunnel-Client-Auth-Id AVP + + 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. + +7.11. Tunnel-Server-Auth-Id AVP + + 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. + +8. NAS Accounting + + Applications implementing this specification use Diameter Accounting, + as defined in [BASE], and the AVPs in the following section. + Service-specific AVP usage is defined in the tables in section 10. + + If accounting is active, Accounting Request (ACR) messages SHOULD be + sent after the completion of any Authentication or Authorization + + + +Calhoun, et al. Standards Track [Page 50] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + transaction and at the end of a Session. The Accounting-Record-Type + value indicates the type of event. All other AVPs identify the + session and provide additional information relevant to the event. + + The successful completion of the first Authentication or + Authorization transaction SHOULD cause a START_RECORD to be sent. If + additional Authentications or Authorizations occur in later + transactions, the first exchange should generate a START_RECORD, and + the later an INTERIM_RECORD. For a given session, there MUST only be + one set of matching START and STOP records, with any number of + INTERIM_RECORDS in between, or one EVENT_RECORD indicating the reason + a session wasn't started. + + The following table describes the AVPs; their AVP Code values, types, + and possible flag values; and whether the AVP MAY be encrypted. + + +---------------------+ + | AVP Flag rules | + |----+-----+----+-----|----+ + AVP Section | | |SHLD| MUST| | + Attribute Name Code Defined Value Type |MUST| MAY | NOT| NOT|Encr| + -----------------------------------------|----+-----+----+-----|----| + Accounting- 363 8.1 Unsigned64 | M | P | | V | Y | + Input-Octets | | | | | | + Accounting- 364 8.2 Unsigned64 | M | P | | V | Y | + Output-Octets | | | | | | + Accounting- 365 8.3 Unsigned64 | M | P | | V | Y | + Input-Packets | | | | | | + Accounting- 366 8.4 Unsigned64 | M | P | | V | Y | + Output-Packets | | | | | | + Acct-Session-Time 46 8.5 Unsigned32 | M | P | | V | Y | + Acct-Authentic 45 8.6 Enumerated | M | P | | V | Y | + Acounting-Auth- 406 8.7 Enumerated | M | P | | V | Y | + Method | | | | | | + Acct-Delay-Time 41 8.8 Unsigned32 | M | P | | V | Y | + Acct-Link-Count 51 8.9 Unsigned32 | M | P | | V | Y | + Acct-Tunnel- 68 8.10 OctetString| M | P | | V | Y | + Connection | | | | | | + Acct-Tunnel- 86 8.11 Unsigned32 | M | P | | V | Y | + Packets-Lost | | | | | | + -----------------------------------------|----+-----+----+-----|----| + +8.1. Accounting-Input-Octets AVP + + The Accounting-Input-Octets AVP (AVP Code 363) is of type Unsigned64 + and contains the number of octets received from the user. + + + + + +Calhoun, et al. Standards Track [Page 51] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +8.2. Accounting-Output-Octets AVP + + 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. + +8.3. Accounting-Input-Packets AVP + + 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. + +8.4. Accounting-Output-Packets AVP + + 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. + +8.5. Acct-Session-Time AVP + + 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. + +8.6. Acct-Authentic AVP + + 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]. The following list is informational: + + + + +Calhoun, et al. Standards Track [Page 52] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 1 RADIUS + 2 Local + 3 Remote + 4 Diameter + +8.7. Accounting-Auth-Method AVP + + 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 + +8.8. 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. + + + + + + + + + + +Calhoun, et al. Standards Track [Page 53] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +8.9. 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 + +8.10. Acct-Tunnel-Connection AVP + + 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. + + + + + +Calhoun, et al. Standards Track [Page 54] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +8.11. Acct-Tunnel-Packets-Lost AVP + + The Acct-Tunnel-Packets-Lost AVP (AVP Code 86) is of type Unsigned32 + and contains the number of packets lost on a given link. + +9. RADIUS/Diameter Protocol Interactions + + This section describes some basic guidelines that servers acting as + AAA Translation Agents may use. A complete description of all the + differences between RADIUS and Diameter is beyond the scope of this + section and document. Note that this document does not restrict + implementations from creating additional translation methods, as long + as the translation function doesn't violate the RADIUS or the + Diameter protocols. + + Although the Diameter protocol is in many ways a superset of RADIUS + functions, a number of RADIUS representations are not allowed, so + that new capabilities can be used without the old problems. + + There are primarily two different situations that must be handled: + one in which a RADIUS request is received that must be forwarded as a + Diameter request, and another in which the inverse is true. RADIUS + does not support a peer-to-peer architecture, and server-initiated + operations are generally not supported. See [RADDynAuth] for an + alternative. + + Some RADIUS attributes are encrypted. RADIUS security and encryption + techniques are applied on a hop-per-hop basis. A Diameter agent will + have to decrypt RADIUS attribute data entering the Diameter system, + and if that information is forwarded, the agent MUST secure it by + using Diameter specific techniques. + + Note that this section uses the two terms, "AVP" and "attribute", in + a concise and specific manner. The former is used to signify a + Diameter AVP, and the latter to signify a RADIUS attribute. + +9.1. RADIUS Request Forwarded as Diameter Request + + This section describes the actions that should be taken when a + Translation Agent receives a RADIUS message to be translated to a + Diameter message. + + Note that RADIUS servers are assumed to be stateless. It is also + quite possible for the RADIUS messages that comprise the session + (i.e., authentication and accounting messages) to be handled by + different Translation Agents in the proxy network. Therefore, a + RADIUS/Diameter Translation Agent SHOULD NOT be assumed to have an + accurate track on session-state information. + + + +Calhoun, et al. Standards Track [Page 55] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + When a Translation Agent receives a RADIUS message, the following + steps should be taken: + + - If a Message-Authenticator attribute is present, the value MUST + be checked but not included in the Diameter message. If it is + incorrect, the RADIUS message should be silently discarded. + The gateway system SHOULD generate and include a Message- + Authenticator in returned RADIUS responses. + + - The transport address of the sender MUST be checked against the + NAS identifying attributes. See the description of NAS- + Identifier and NAS-IP-Address below. + + - The Translation Agent must maintain transaction state + information relevant to the RADIUS request, such as the + Identifier field in the RADIUS header, any existing RADIUS + Proxy-State attribute, and the source IP address and port + number of the UDP packet. These may be maintained locally in a + state table or saved in a Proxy-Info AVP group. A Diameter + Session-Id AVP value must be created using a session state + mapping mechanism. + + - If the RADIUS request contained a State attribute and the + prefix of the data is "Diameter/", the data following the + prefix contains the Diameter Origin-Host/Origin-Realm/Session- + Id. If no such attributes are present and the RADIUS command + is an Access-Request, a new Session-Id is created. The + Session-Id is included in the Session-Id AVP. + + - The Diameter Origin-Host and Origin-Realm AVPs MUST be created + and added by using the information from an FQDN corresponding + to the NAS-IP-Address attribute (preferred if available), + and/or to the NAS-Identifier attribute. (Note that the RADIUS + NAS-Identifier is not required to be an FQDN.) + + - The response MUST have an Origin-AAA-Protocol AVP added, + indicating the protocol of origin of the message. + + - The Proxy-Info group SHOULD be added, with the local server's + identity specified in the Proxy-Host AVP. This should ensure + that the response is returned to this system. + + - The Destination-Realm AVP is created from the information found + in the RADIUS User-Name attribute. + + + + + + + +Calhoun, et al. Standards Track [Page 56] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + - If the RADIUS User-Password attribute is present, the password + must be unencrypted by using the link's RADIUS shared secret. + The unencrypted value must be forwarded in a User-Password AVP + using Diameter security. + + - If the RADIUS CHAP-Password attribute is present, the Ident and + Data portion of the attribute are used to create the CHAP-Auth + grouped AVP. + + - If the RADIUS message contains an address attribute, it MUST be + converted to the appropriate Diameter AVP and type. + + - If the RADIUS message contains Tunnel information [RADTunnels], + the attributes or tagged groups should each be converted to a + Diameter Tunneling Grouped AVP set. If the tunnel information + contains a Tunnel-Password attribute, the RADIUS encryption + must be resolved, and the password forwarded, by using Diameter + security methods. + + - If the RADIUS message received is an Accounting-Request, the + Acct-Status-Type attribute value must be converted to a + Accounting-Record-Type AVP value. If the Acct-Status-Type + attribute value is STOP, the local server MUST issue a + Session-Termination-Request message once the Diameter + Accounting-Answer message has been received. + + - If the Accounting message contains an Acct-Termination-Cause + attribute, it should be translated to the equivalent + Termination-Cause AVP value. (see below) + + - If the RADIUS message contains the Accounting-Input-Octets, + Accounting-Input-Packets, Accounting-Output-Octets, or + Accounting-Output-Packets, these attributes must be converted + to the Diameter equivalents. Further, if the Acct-Input- + Gigawords or Acct-Output-Gigawords attributes are present, + these must be used to properly compute the Diameter accounting + AVPs. + + The corresponding Diameter response is always guaranteed to be + received by the same Translation Agent that translated the original + request, due to the contents of the Proxy-Info AVP group in the + Diameter request. The following steps are applied to the response + message during the Diameter-to-RADIUS translation: + + - If the Diameter Command-Code is set to AA-Answer and the + Result-Code AVP is set to DIAMETER_MULTI_ROUND_AUTH, the + gateway must send a RADIUS Access-Challenge. This must have + the Origin-Host, Origin-Realm, and Diameter Session-Id AVPs + + + +Calhoun, et al. Standards Track [Page 57] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + encapsulated in the RADIUS State attribute, with the prefix + "Diameter/", concatenated in the above order separated with "/" + characters, in UTF-8 [UTF-8]. This is necessary to ensure that + the Translation Agent receiving the subsequent RADIUS Access- + Request will have access to the Session Identifier and be able + to set the Destination-Host to the correct value. If the + Multi-Round-Time-Out AVP is present, the value of the AVP MUST + be inserted in the RADIUS Session-Timeout AVP. + + - If the Command-Code is set to AA-Answer, the Diameter Session- + Id AVP is saved in a new RADIUS Class attribute whose format + consists of the string "Diameter/" followed by the Diameter + Session Identifier. This will ensure that the subsequent + Accounting messages, which could be received by any Translation + Agent, would have access to the original Diameter Session + Identifier. + - If a Proxy-State attribute was present in the RADIUS request, + the same attribute is added in the response. This information + may be found in the Proxy-Info AVP group, or in a local state + table. + + - If state information regarding the RADIUS request was saved in + a Proxy-Info AVP or local state table, the RADIUS Identifier + and UDP IP Address and port number are extracted and used in + issuing the RADIUS reply. + + When translating a Diameter AA-Answer (with successful result code) + to RADIUS Access-Accept that contains a Session-Timeout or + Authorization-Lifetime AVP, take the following steps: + + - If the Diameter message contains a Session-Timeout AVP but no + Authorization-Lifetime AVP, translate it to a Session-Timeout + attribute (not a Termination-Action). + + - If the Diameter message contains an Authorization-Lifetime AVP + but no Session-Timeout AVP, translate it to a Session-Timeout + attribute and a Termination-Action set to AA-REQUEST. (Remove + Authorization-Lifetime and Re-Auth-Request-Type.) + + - If the Diameter message has both, the Session-Timeout must be + greater than or equal to the Authorization-Lifetime (required + by [BASE]). Translate it to a Session-Timeout value (with + value from Authorization-Lifetime AVP, the smaller one) and + with the Termination-Action set to AA-REQUEST. (Remove the + Authorization-Lifetime and Re-Auth-Request-Type.) + + + + + + +Calhoun, et al. Standards Track [Page 58] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +9.1.1. RADIUS Dynamic Authorization Considerations + + A Diameter/RADIUS gateway may communicate with a server that + implements RADIUS Dynamic Authorization [RADDynAuth]. If the server + supports these functions, it MUST be listening on the assigned port + and would receive RADIUS CoA-Request and Disconnect-Request messages. + These can be mapped into the Diameter Re-Auth-Request (RAR) and + Abort-Session-Request (ASR) message exchanges, respectively [BASE]. + + If the [RADDynAuth] is not supported, the port would not be active + and the RADIUS server would receive an ICMP Port Unreachable + indication. Alternatively, if the messages are received but with an + inappropriate Service-Type, the gateway can respond with the + appropriate NAK message and an Error-Cause attribute with the value + of 405, "Unsupported Service". + + The RADIUS CoA-Request and Disconnect-Request messages will not + contain a Diameter Session-Id. Diameter requires that this value + match an active session context. The gateway MUST have a session Id + cache (or other means) to identify the sessions these functions + pertain to. If unable to identify the session, the gateway (or NAS) + should return an Error-Cause value 503, "Session Context Not Found". + + The RADIUS CoA-Request message only supports a change of + authorization attributes, and the received CoA-Request SHOULD include + a Service-Type of "Authorize-Only". This indicates an extended + exchange request by the rules given in [RADDynAuth] section 3.2, note + 6. This is the only type of exchange supported by Diameter [BASE]. + + For the CoA-Request, the translated RAR message will have a Re-Auth- + Type of AUTHORIZE_ONLY. The returned RAA will be translated into a + CoA-NAK with Error-Cause "Request Initiated". The gateway's Diameter + client SHOULD also start a reauthorization sequence by sending an AAR + message, which will be translated into an Access-Request message. + The RADIUS server will use the Access-Accept (or Access-Reject) + message to convey the new authorization attributes, which the gateway + will pass back in an AAA message. + + Any attributes included in the COA-Request or Access-Accept message + are to be considered mandatory in Diameter. If they cannot be + supported, they MUST result in an error message return to the RADIUS + server, with an Error-Cause of "Unsupported Attribute". The Diameter + NAS will attempt to apply all the attributes supplied in the AA + message to the session. + + A RADIUS Disconnect-Request message received by the gateway would be + translated to a Diameter Abort-Session-Request (ASR) message [BASE]. + The results will be returned by the Diameter client in an Abort- + + + +Calhoun, et al. Standards Track [Page 59] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + Session-Answer (ASA) message. A success indication would translate + to a RADIUS Disconnect-ACK, and a failure would generate a + Disconnect-NAK. + +9.2. Diameter Request Forwarded as RADIUS Request + + When a server receives a Diameter request to be forwarded to a RADIUS + entity, the following are examples of the steps that may be taken: + + - The Origin-Host AVP's value is inserted into the NAS-Identifier + attribute. + + - The following information MUST be present in the corresponding + Diameter response and therefore MUST be saved, either in a + local state table or encoded in a RADIUS Proxy-State attribute: + + 1. Origin-Host AVP + 2. Session-Id AVP + 3. Proxy-Info AVP + 4. Any other AVP that MUST be present in the response and + has no corresponding RADIUS attribute. + + - If the CHAP-Auth AVP is present, the grouped AVPs are used to + create the RADIUS CHAP-Password attribute data. + + - If the User-Password AVP is present, the data should be + encrypted and forwarded by using RADIUS rules. The same is + true for any other RADIUS-encrypted attribute values. + + - AVPs of the type Address must be translated to the + corresponding RADIUS attribute. + + - If the Accounting-Input-Octets, Accounting-Input-Packets, + Accounting-Output-Octets, or Accounting-Output-Packets AVPs are + present, they must be translated to the corresponding RADIUS + attributes. If the value of the Diameter AVPs do not fit + within a 32-bit RADIUS attribute, the RADIUS Acct-Input- + Gigawords and Acct-Output-Gigawords must be used. + + - If the RADIUS link supports the Message-Authenticator attribute + [RADIUSExt], it SHOULD be generated and added to the request. + + When the corresponding response is received by the Translation Agent, + which is guaranteed in the RADIUS protocol, the following steps may + be taken: + + + + + + +Calhoun, et al. Standards Track [Page 60] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + - If the RADIUS code is set to Access-Challenge, a Diameter AA- + Answer message is created with the Result-Code set to + DIAMETER_MULTI_ROUND_AUTH. If the Session-Timeout AVP is + present in the RADIUS message, its value is inserted into the + Multi-Round-Time-Out AVP. + + - If a Proxy-State attribute is present, extract the encoded + information; otherwise, retrieve the original Proxy-Info AVP + group information from the local state table. + + - The response's Origin-Host information is created from the FQDN + of the RADIUS message's source IP address. The same FQDN is + also stored to a Route-Record AVP. + + - The response's Destination-Host AVP is copied from the saved + request's Origin-Host information. + + - The Session-Id information can be recovered from local state, + or from the constructed State or Proxy-State attribute, as + above. + + - If a Proxy-Info AVP was present in the request, the same AVP + MUST be added to the response. + + - If the RADIUS State attributes are present, they must be + present in the Diameter response, minus those added by the + gateway. + + - Any other AVPs that were saved at request time, and that MUST + be present in the response, are added to the message. + + When translating a RADIUS Access-Accept to Diameter AA-Answer that + contains a Session-Timeout attribute, do the following: + + - If the RADIUS message contains a Session-Timeout attribute and + a Termination-Action attribute set to DEFAULT (or no + Termination-Action attribute at all), translate it to AA-Answer + with a Session-Timeout AVP and remove the Termination-Action + attribute. + + - If the RADIUS message contains a Session-Timeout attribute and + a Termination-Action attribute set to AA-REQUEST, translate it + to AA-Answer with Authorization-Lifetime AVP and with Re-Auth- + Request-Type set to AUTHORIZE_AUTHENTICATE and remove the + Session-Timeout attribute. + + + + + + +Calhoun, et al. Standards Track [Page 61] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +9.2.1. RADIUS Dynamic Authorization Considerations + + A RADIUS/Diameter gateway communicating with a RADIUS client that + implements RADIUS Dynamic Authorization [RADDynAuth] may translate + Diameter Re-Auth-Request (RAR) messages and Abort-Session-Request + (ASR) messages [BASE] into RADIUS CoA-Request and Disconnect-Request + messages respectively. + + If the RADIUS client does not support the capability, the gateway + will receive an ICMP Port Unreachable indication when it transmits + the RADIUS message. Even if the NAS supports [RADDynAuth], it may + not support the Service-Type in the request message. In this case it + will respond with a NAK message and (optionally) an Error-Cause + attribute with value 405, "Unsupported Service". If the gateway + encounters these error conditions, or if it does not support + [RADDynAuth], it sends a Diameter Answer message with an Result-Code + AVP of "DIAMETER_COMMAND_UNSUPPORTED" to the AAA server. + + When encoding the RADIUS messages, the gateway MUST include the + Diameter Session-ID in the RADIUS State attribute value, as mentioned + above. The RADIUS client should return it in the response. + + A Diameter Re-Auth-Request (RAR) message [BASE] received by the + gateway will be translated into a RADIUS CoA-Request and sent to the + RADIUS client. The RADIUS client should respond with a CoA-ACK or + CoA-NAK message, which the gateway should translate into a Re-Auth- + Answer (RAA) message. + + If the gateway receives a RADIUS CoA-NAK response containing a + Service-Type Attribute with value "Authorize Only" and an Error-Cause + Attribute with value "Request Initiated", this indicates an extended + exchange request per [RADDynAuth] section 3.2, note 6. + + The response is translated to a Diameter Re-Auth-Answer (RAA) with a + Result-Code AVP of "DIAMETER_LIMITED_SUCCESS" sent to the AAA server. + + Subsequently, the gateway should receive a RADIUS Access-Request from + the NAS, with a Service-Type of "Authorize Only". This is translated + into a Diameter AA-Request with an Auth-Request-Type AVP of + AUTHORIZE_ONLY and sent to the AAA server. The AAA server will then + reply with a Diameter AA-Answer, which is translated into a RADIUS + Access-Accept or Access-Reject, depending on the value of the + Result-Code AVP. + + A Diameter Abort-Session-Request (ASR) message [BASE] received by the + gateway will be translated into a RADIUS Disconnect-Request and sent + to the RADIUS client. The RADIUS client should respond with a + + + + +Calhoun, et al. Standards Track [Page 62] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + Disconnect-ACK or Disconnect-NAK message, which the gateway should + translate into an Abort-Session-Answer (ASA) message. + + If the gateway receives a RADIUS Disconnect-NAK response containing a + Service-Type Attribute with value "Authorize Only" and an Error-Cause + Attribute with value "Request Initiated", the Disconnect-NAK response + is translated into a Diameter Abort-Session-Answer (ASA) with a + Result-Code AVP of "DIAMETER_LIMITED_SUCCESS" sent to the AAA server. + + Subsequently, the gateway should receive a RADIUS Access-Request from + the NAS, with a Service-Type of "Authorize Only". This is translated + into a Diameter AA-Request with an Auth-Request-Type AVP of + AUTHORIZE_ONLY and sent to the AAA server. The AAA server will then + reply with a Diameter AA-Answer, which is translated into a RADIUS + Access-Accept or Access-Reject, depending on the value of the + Result-Code AVP. + +9.3. AVPs Used Only for Compatibility + + The AVPs defined in this section SHOULD only be used for backwards + compatibility when a Diameter/RADIUS translation function is invoked + and are not typically originated by Diameter systems during normal + operations. + + +---------------------+ + | AVP Flag rules | + |----+-----+----+-----|----+ + AVP Section | | |SHLD| MUST| | + Attribute Name Code Defined Value Type |MUST| MAY | NOT| NOT|Encr| + -----------------------------------------|----+-----+----+-----|----| + NAS-Identifier 32 9.3.1 UTF8String | M | P | | V | Y | + NAS-IP-Address 4 9.3.2 OctetString| M | P | | V | Y | + NAS-IPv6-Address 95 9.3.3 OctetString| M | P | | V | Y | + State 24 9.3.4 OctetString| M | P | | V | Y | + Termination- 295 9.3.5 Enumerated | M | P | | V | Y | + Cause | | | | | | + Origin-AAA- 408 9.3.6 Enumerated | M | P | | V | Y | + Protocol | | | | | | + -----------------------------------------|----+-----+----+-----|----| + +9.3.1. NAS-Identifier AVP + + 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. + + + + +Calhoun, et al. Standards Track [Page 63] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +9.3.2. NAS-IP-Address AVP + + 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- + + + +Calhoun, et al. Standards Track [Page 64] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + Record AVP. If no match is found, then an error is logged, but no + other action is taken. + +9.3.3. NAS-IPv6-Address AVP + + 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. + +9.3.4. State AVP + + 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. + + + + +Calhoun, et al. Standards Track [Page 65] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + 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. + +9.3.5. Termination-Cause AVP Code Values + + This section defines a mapping between Termination-Cause AVP code + values and RADIUS Acct-Terminate-Cause attribute code values from RFC + 2866 [RADIUSAcct] and [RADIUSTypes], thereby allowing a + RADIUS/Diameter Translation Agent to convert between the attribute + and AVP values. This section thus extends the definitions in the + "Termination-Cause AVP" section of the Base Diameter specification. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 66] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + The table in this section defines the mapping between Termination- + Cause AVP and RADIUS Acct-Terminate-Cause causes. + + +-----------------------+ + | Value | + +-----------+-----------+ + Cause Value Name | RADIUS | Diameter | + ------------------------------|-----------+-----------+ + User Request | 1 | 11 | + Lost Carrier | 2 | 12 | + Lost Service | 3 | 13 | + Idle Timeout | 4 | 14 | + Session Timeout | 5 | 15 | + Admin Reset | 6 | 16 | + Admin Reboot | 7 | 17 | + Port Error | 8 | 18 | + NAS Error | 9 | 19 | + NAS Request | 10 | 20 | + NAS Reboot | 11 | 21 | + Port Unneeded | 12 | 22 | + Port Preempted | 13 | 23 | + Port Suspended | 14 | 24 | + Service Unavailable | 15 | 25 | + Callback | 16 | 26 | + User Error | 17 | 27 | + Host Request | 18 | 28 | + Supplicant Restart | 19 | 29 | [RAD802.1X] + Reauthentication Failure | 20 | 30 | [RAD802.1X] + Port Reinit | 21 | 31 | [RAD802.1X] + Port Disabled | 22 | 32 | [RAD802.1X] + ------------------------------|-----------+-----------+ + + From RFC 2866, the termination causes are as follows: + + User Request User requested termination of service, for + example with LCP Terminate or by logging out. + + Lost Carrier DCD was dropped on the port. + + Lost Service Service can no longer be provided; for + example, user's connection to a host was + interrupted. + + Idle Timeout Idle timer expired. + + Session Timeout Maximum session length timer expired. + + Admin Reset Administrator reset the port or session. + + + +Calhoun, et al. Standards Track [Page 67] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + Admin Reboot Administrator is ending service on the NAS, + for example, prior to rebooting the NAS. + + Port Error NAS detected an error on the port that + required ending the session. + + NAS Error NAS detected an error (other than on the + port) that required ending the session. + + NAS Request NAS ended the session for a non-error reason not + otherwise listed here. + + NAS Reboot NAS ended the session to reboot + non-administratively ("crash"). + + Port Unneeded NAS ended the session because resource usage + fell below a low-water mark (for example, if + a bandwidth-on-demand algorithm decided that + the port was no longer needed). + + Port Preempted NAS ended the session to allocate the + port to a higher priority use. + + Port Suspended NAS ended the session to suspend a virtual + session. + + Service Unavailable NAS was unable to provide requested service. + + Callback NAS is terminating the current session + to perform callback for a new session. + + User Error Input from user is in error, causing + session termination. + + Host Request Login Host terminated session normally. + +9.3.6. 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 + + + + +Calhoun, et al. Standards Track [Page 68] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +9.4. Prohibited RADIUS Attributes + + The following RADIUS attributes MUST NOT appear in a Diameter + message. Instead, they are translated to other Diameter AVPs or + handled in some special manner. The rules for the treatment of the + attributes are discussed in sections 9.1, 9.2, and 9.6. + + Attribute Description Defined Nearest Diameter AVP + ----------------------------------------------------------------- + 3 CHAP-Password RFC 2865 CHAP-Auth Group + 26 Vendor-Specific RFC 2865 Vendor Specific AVP + 29 Termination-Action RFC 2865 Authorization-Lifetime + 40 Acct-Status-Type RFC 2866 Accounting-Record-Type + 42 Acct-Input-Octets RFC 2866 Accounting-Input-Octets + 43 Acct-Output-Octets RFC 2866 Accounting-Output-Octets + 47 Acct-Input-Packets RFC 2866 Accounting-Input-Packets + 48 Acct-Output-Packets RFC 2866 Accounting-Output-Packets + 49 Acct-Terminate-Cause RFC 2866 Termination-Cause + 52 Acct-Input-Gigawords RFC 2869 Accounting-Input-Octets + 53 Acct-Output-Gigawords RFC 2869 Accounting-Output-Octets + 80 Message-Authenticator RFC 2869 none - check and discard + +9.5. Translatable Diameter AVPs + + In general, Diameter AVPs that are not RADIUS compatible have code + values greater than 255. The table in the section above shows the + AVPs that can be converted into RADIUS attributes. + + Another problem may occur with Diameter AVP values that may be more + than 253 octets in length. Some RADIUS attributes (including but not + limited to (8)Reply-Message, (79)EAP-Message, and (77)Connect-Info) + allow concatenation of multiple instances to overcome this + limitation. If this is not possible, a Result-Code of + DIAMETER_INVALID_AVP_LENGTH should be returned. + +9.6. RADIUS Vendor Specific Attributes + + RADIUS supports the inclusion of Vendor Specific Attributes (VSAs) + through the use of attribute 26. The recommended format [RADIUS] of + the attribute data field includes a 4 octet vendor code followed by a + one octet vendor type field and a one octet length field. The last + two fields MAY be repeated. + + A system communicating between Diameter and RADIUS MAY have specific + knowledge of vendor formats, and MAY be able to translate between the + two formats. However, given the deployment of many RADIUS vendor + formats that do not follow the example format in RFC 2865 [RADIUS], + (e.g., those that use a longer vendor type code) the translations in + + + +Calhoun, et al. Standards Track [Page 69] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + the next two sections will not work in general for those VSAs. RFC + 2865 states that a robust implementation SHOULD support the field as + undistinguished octets. + + Systems that don't have vendor format knowledge MAY discard such + attributes without knowing a suitable translation. An alternative + format is under consideration [VSA], which proposes encodings that + would preserve the native information and not require vendor + knowledge in the gateway system. + + The following sections are an example for translating RADIUS VSAs + that use the example RADIUS format, and Diameter VSAs that have type + codes less than 255, and value field lengths less than 252. + +9.6.1. Forwarding a Diameter Vendor Specific AVP as a RADIUS VSA + + For Type codes less than 255, the value field length MUST be less + than 252 or the AVP will be discarded. The RADIUS VSA attribute + should consist of the following fields; + + RADIUS Type = 26, Vendor Specific Attribute + RADIUS Length = total length of attribute (header + data) + RADIUS Vendor code = Diameter Vendor code + RADIUS Vendor type code = low order byte of Diameter AVP code + RADIUS Vendor data length = length of Diameter data + + If the Diameter AVP code is greater than 255, then the RADIUS + speaking code may use a Vendor specific field coding, if it knows one + for that vendor. Otherwise, the AVP will be ignored. If it is + flagged as Mandatory, a "DIAMETER_AVP_UNSUPPORTED" Result-Code will + be returned, and the RADIUS message will not be sent. + +9.6.2. Forwarding a RADIUS VSA as a Diameter Vendor Specific AVP + + The Diameter AVP will consist of the following fields: + + Diameter Flags: V=1, M=0, P=0 + Diameter Vendor code = RADIUS VSA Vendor code + Diameter AVP code = RADIUS VSA Vendor type code + Diameter AVP length = length of AVP (header + data) + Diameter Data = RADIUS VSA vendor data + + Note that the VSAs are considered optional by RADIUS rules, and this + specification does not set the Mandatory flag. If an implementor + desires a VSA be made mandatory because it represents a required + service policy, the RADIUS gateway should have a process to set the + bit on the Diameter side. + + + + +Calhoun, et al. Standards Track [Page 70] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + If the RADIUS receiving code knows of vendor specific field + interpretations for the specific vendor, it may employ them to parse + an extended AVP code or data length. Otherwise the recommended + standard fields will be used. + + Nested Multiple vendor data fields MUST be expanded into multiple + Diameter AVPs. + +10. AVP Occurrence Tables + + The following tables present the AVPs used by NAS applications in NAS + messages and specify in which Diameter messages they MAY or MAY NOT + be present. [BASE] messages and AVPs are not described in this + document. Note that AVPs that can only be present within a Grouped + AVP are not represented in this table. + + The table uses the following symbols: + + 0 The AVP MUST NOT be present in the message. + 0+ Zero or more instances of the AVP MAY be present in the + message. + 0-1 Zero or one instance of the AVP MAY be present in the + message. + 1 One instance of the AVP MUST be present in the message. + +10.1. AA-Request/Answer AVP Table + + The table in this section is limited to the Command Codes defined in + this specification. + + +-----------+ + | Command | + |-----+-----+ + Attribute Name | AAR | AAA | + ------------------------------|-----+-----+ + Acct-Interim-Interval | 0 | 0-1 | + ARAP-Challenge-Response | 0 | 0-1 | + ARAP-Features | 0 | 0-1 | + ARAP-Password | 0-1 | 0 | + ARAP-Security | 0-1 | 0-1 | + ARAP-Security-Data | 0+ | 0+ | + ARAP-Zone-Access | 0 | 0-1 | + Auth-Application-Id | 1 | 1 | + Auth-Grace-Period | 0-1 | 0-1 | + Auth-Request-Type | 1 | 1 | + Auth-Session-State | 0-1 | 0-1 | + Authorization-Lifetime | 0-1 | 0-1 | + ------------------------------|-----+-----+ + + + +Calhoun, et al. Standards Track [Page 71] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + +-----------+ + | Command | + |-----+-----+ + Attribute Name | AAR | AAA | + ------------------------------|-----+-----+ + Callback-Id | 0 | 0-1 | + Callback-Number | 0-1 | 0-1 | + Called-Station-Id | 0-1 | 0 | + Calling-Station-Id | 0-1 | 0 | + CHAP-Auth | 0-1 | 0 | + CHAP-Challenge | 0-1 | 0 | + Class | 0 | 0+ | + Configuration-Token | 0 | 0+ | + Connect-Info | 0+ | 0 | + Destination-Host | 0-1 | 0 | + Destination-Realm | 1 | 0 | + Error-Message | 0 | 0-1 | + Error-Reporting-Host | 0 | 0-1 | + Failed-AVP | 0+ | 0+ | + Filter-Id | 0 | 0+ | + Framed-Appletalk-Link | 0 | 0-1 | + Framed-Appletalk-Network | 0 | 0+ | + Framed-Appletalk-Zone | 0 | 0-1 | + Framed-Compression | 0+ | 0+ | + Framed-Interface-Id | 0-1 | 0-1 | + Framed-IP-Address | 0-1 | 0-1 | + Framed-IP-Netmask | 0-1 | 0-1 | + Framed-IPv6-Prefix | 0+ | 0+ | + Framed-IPv6-Pool | 0 | 0-1 | + Framed-IPv6-Route | 0 | 0+ | + Framed-IPX-Network | 0 | 0-1 | + Framed-MTU | 0-1 | 0-1 | + Framed-Pool | 0 | 0-1 | + Framed-Protocol | 0-1 | 0-1 | + Framed-Route | 0 | 0+ | + Framed-Routing | 0 | 0-1 | + Idle-Timeout | 0 | 0-1 | + Login-IP-Host | 0+ | 0+ | + Login-IPv6-Host | 0+ | 0+ | + Login-LAT-Group | 0-1 | 0-1 | + Login-LAT-Node | 0-1 | 0-1 | + Login-LAT-Port | 0-1 | 0-1 | + Login-LAT-Service | 0-1 | 0-1 | + Login-Service | 0 | 0-1 | + Login-TCP-Port | 0 | 0-1 | + Multi-Round-Time-Out | 0 | 0-1 | + ------------------------------|-----+-----+ + + + + +Calhoun, et al. Standards Track [Page 72] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + +-----------+ + | Command | + |-----+-----+ + Attribute Name | AAR | AAA | + ------------------------------|-----+-----+ + NAS-Filter-Rule | 0 | 0+ | + NAS-Identifier | 0-1 | 0 | + NAS-IP-Address | 0-1 | 0 | + NAS-IPv6-Address | 0-1 | 0 | + NAS-Port | 0-1 | 0 | + NAS-Port-Id | 0-1 | 0 | + NAS-Port-Type | 0-1 | 0 | + Origin-AAA-Protocol | 0-1 | 0-1 | + Origin-Host | 1 | 1 | + Origin-Realm | 1 | 1 | + Origin-State-Id | 0-1 | 0-1 | + Originating-Line-Info | 0-1 | 0 | + Password-Retry | 0 | 0-1 | + Port-Limit | 0-1 | 0-1 | + Prompt | 0 | 0-1 | + Proxy-Info | 0+ | 0+ | + QoS-Filter-Rule | 0 | 0+ | + Re-Auth-Request-Type | 0 | 0-1 | + Redirect-Host | 0 | 0+ | + Redirect-Host-Usage | 0 | 0-1 | + Redirect-Max-Cache-Time | 0 | 0-1 | + Reply-Message | 0 | 0+ | + Result-Code | 0 | 1 | + Route-Record | 0+ | 0+ | + Service-Type | 0-1 | 0-1 | + Session-Id | 1 | 1 | + Session-Timeout | 0 | 0-1 | + State | 0-1 | 0-1 | + Tunneling | 0+ | 0+ | + User-Name | 0-1 | 0-1 | + User-Password | 0-1 | 0 | + ------------------------------|-----+-----+ + +10.2. Accounting AVP Tables + + The tables in this section are used to show which AVPs defined in + this document are to be present and used in NAS application + Accounting messages. These AVPs are defined in this document, as + well as in [BASE] and [RADIUSAcct]. + + + + + + + +Calhoun, et al. Standards Track [Page 73] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +10.2.1. Accounting Framed Access AVP Table + + The table in this section is used when the Service-Type specifies + Framed Access. + + +-----------+ + | Command | + |-----+-----+ + Attribute Name | ACR | ACA | + ---------------------------------------|-----+-----+ + Accounting-Auth-Method | 0-1 | 0 | + Accounting-Input-Octets | 1 | 0 | + Accounting-Input-Packets | 1 | 0 | + Accounting-Output-Octets | 1 | 0 | + Accounting-Output-Packets | 1 | 0 | + Accounting-Record-Number | 0-1 | 0-1 | + Accounting-Record-Type | 1 | 1 | + Accounting-Realtime-Required | 0-1 | 0-1 | + Accounting-Sub-Session-Id | 0-1 | 0-1 | + Acct-Application-Id | 0-1 | 0-1 | + Acct-Session-Id | 1 | 0-1 | + Acct-Multi-Session-Id | 0-1 | 0-1 | + Acct-Authentic | 1 | 0 | + Acct-Delay-Time | 0-1 | 0 | + Acct-Interim-Interval | 0-1 | 0-1 | + Acct-Link-Count | 0-1 | 0 | + Acct-Session-Time | 1 | 0 | + Acct-Tunnel-Connection | 0-1 | 0 | + Acct-Tunnel-Packets-Lost | 0-1 | 0 | + Authorization-Lifetime | 0-1 | 0 | + Callback-Id | 0-1 | 0 | + Callback-Number | 0-1 | 0 | + Called-Station-Id | 0-1 | 0 | + Calling-Station-Id | 0-1 | 0 | + Class | 0+ | 0+ | + Connection-Info | 0+ | 0 | + Destination-Host | 0-1 | 0 | + Destination-Realm | 1 | 0 | + Event-Timestamp | 0-1 | 0-1 | + Error-Message | 0 | 0-1 | + Error-Reporting-Host | 0 | 0-1 | + Failed-AVP | 0 | 0+ | + ---------------------------------------|-----+-----+ + + + + + + + + +Calhoun, et al. Standards Track [Page 74] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + +-----------+ + | Command | + |-----+-----+ + Attribute Name | ACR | ACA | + ---------------------------------------|-----+-----+ + Framed-AppleTalk-Link | 0-1 | 0 | + Framed-AppleTalk-Network | 0-1 | 0 | + Framed-AppleTalk-Zone | 0-1 | 0 | + Framed-Compression | 0-1 | 0 | + Framed-IP-Address | 0-1 | 0 | + Framed-IP-Netmask | 0-1 | 0 | + Framed-IPv6-Prefix | 0+ | 0 | + Framed-IPv6-Pool | 0-1 | 0 | + Framed-IPX-Network | 0-1 | 0 | + Framed-MTU | 0-1 | 0 | + Framed-Pool | 0-1 | 0 | + Framed-Protocol | 0-1 | 0 | + Framed-Route | 0-1 | 0 | + Framed-Routing | 0-1 | 0 | + NAS-Filter-Rule | 0+ | 0 | + NAS-Identifier | 0-1 | 0-1 | + NAS-IP-Address | 0-1 | 0-1 | + NAS-IPv6-Address | 0-1 | 0-1 | + NAS-Port | 0-1 | 0-1 | + NAS-Port-Id | 0-1 | 0-1 | + NAS-Port-Type | 0-1 | 0-1 | + Origin-AAA-Protocol | 0-1 | 0-1 | + Origin-Host | 1 | 1 | + Origin-Realm | 1 | 1 | + Origin-State-Id | 0-1 | 0-1 | + Originating-Line-Info | 0-1 | 0 | + Proxy-Info | 0+ | 0+ | + QoS-Filter-Rule | 0+ | 0 | + Route-Record | 0+ | 0+ | + Result-Code | 0 | 1 | + Service-Type | 0-1 | 0-1 | + Session-Id | 1 | 1 | + Termination-Cause | 0-1 | 0-1 | + Tunnel-Assignment-Id | 0-1 | 0 | + Tunnel-Client-Endpoint | 0-1 | 0 | + Tunnel-Medium-Type | 0-1 | 0 | + Tunnel-Private-Group-Id | 0-1 | 0 | + Tunnel-Server-Endpoint | 0-1 | 0 | + Tunnel-Type | 0-1 | 0 | + User-Name | 0-1 | 0-1 | + Vendor-Specific-Application-Id | 0-1 | 0-1 | + ---------------------------------------|-----+-----+ + + + + +Calhoun, et al. Standards Track [Page 75] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +10.2.2. Accounting Non-Framed Access AVP Table + + The table in this section is used when the Service-Type specifies + Non-Framed Access. + + +-----------+ + | Command | + |-----+-----+ + Attribute Name | ACR | ACA | + ---------------------------------------|-----+-----+ + Accounting-Auth-Method | 0-1 | 0 | + Accounting-Input-Octets | 1 | 0 | + Accounting-Output-Octets | 1 | 0 | + Accounting-Record-Type | 1 | 1 | + Accounting-Record-Number | 0-1 | 0-1 | + Accounting-Realtime-Required | 0-1 | 0-1 | + Accounting-Sub-Session-Id | 0-1 | 0-1 | + Acct-Application-Id | 0-1 | 0-1 | + Acct-Session-Id | 1 | 0-1 | + Acct-Multi-Session-Id | 0-1 | 0-1 | + Acct-Authentic | 1 | 0 | + Acct-Delay-Time | 0-1 | 0 | + Acct-Interim-Interval | 0-1 | 0-1 | + Acct-Link-Count | 0-1 | 0 | + Acct-Session-Time | 1 | 0 | + Authorization-Lifetime | 0-1 | 0 | + Callback-Id | 0-1 | 0 | + Callback-Number | 0-1 | 0 | + Called-Station-Id | 0-1 | 0 | + Calling-Station-Id | 0-1 | 0 | + Class | 0+ | 0+ | + Connection-Info | 0+ | 0 | + Destination-Host | 0-1 | 0 | + Destination-Realm | 1 | 0 | + Event-Timestamp | 0-1 | 0-1 | + Error-Message | 0 | 0-1 | + Error-Reporting-Host | 0 | 0-1 | + Failed-AVP | 0 | 0+ | + Login-IP-Host | 0+ | 0 | + Login-IPv6-Host | 0+ | 0 | + Login-LAT-Service | 0-1 | 0 | + Login-LAT-Node | 0-1 | 0 | + Login-LAT-Group | 0-1 | 0 | + Login-LAT-Port | 0-1 | 0 | + Login-Service | 0-1 | 0 | + Login-TCP-Port | 0-1 | 0 | + ---------------------------------------|-----+-----+ + + + + +Calhoun, et al. Standards Track [Page 76] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + +-----------+ + | Command | + |-----+-----+ + Attribute Name | ACR | ACA | + ---------------------------------------|-----+-----+ + NAS-Identifier | 0-1 | 0-1 | + NAS-IP-Address | 0-1 | 0-1 | + NAS-IPv6-Address | 0-1 | 0-1 | + NAS-Port | 0-1 | 0-1 | + NAS-Port-Id | 0-1 | 0-1 | + NAS-Port-Type | 0-1 | 0-1 | + Origin-AAA-Protocol | 0-1 | 0-1 | + Origin-Host | 1 | 1 | + Origin-Realm | 1 | 1 | + Origin-State-Id | 0-1 | 0-1 | + Originating-Line-Info | 0-1 | 0 | + Proxy-Info | 0+ | 0+ | + QoS-Filter-Rule | 0+ | 0 | + Route-Record | 0+ | 0+ | + Result-Code | 0 | 1 | + Session-Id | 1 | 1 | + Service-Type | 0-1 | 0-1 | + Termination-Cause | 0-1 | 0-1 | + User-Name | 0-1 | 0-1 | + Vendor-Specific-Application-Id | 0-1 | 0-1 | + ---------------------------------------|-----+-----+ + +11. IANA Considerations + + This section provides guidance to the Internet Assigned Numbers + Authority (IANA) regarding registration of values related to the + Diameter protocol, in accordance with BCP 26 [IANAConsid]. + + This document defines values in the namespaces that have been created + and defined in the Diameter Base [BASE]. The IANA Considerations + section of that document details the assignment criteria. Values + assigned in this document, or by future IANA action, must be + coordinated within this shared namespace. + +11.1. Command Codes + + This specification assigns the value 265 from the Command Code + namespace defined in [BASE]. See sections 3.1 and 3.2 for the + assignment of the namespace in this specification. + + + + + + + +Calhoun, et al. Standards Track [Page 77] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +11.2. AVP Codes + + This specification assigns the values 363 - 366 and 400 - 408 from + the AVP Code namespace defined in [BASE]. See sections 4 and 5 for + the assignment of the namespace in this specification. Note that the + values 363 - 366 are jointly, but consistently, assigned in + [DiamMIP]. This document also creates one new namespace to be + managed by IANA, as described in section 11.5. + + This specification also specifies the use of AVPs in the 0 - 255 + range, which are defined in [RADIUSTypes]. These values are assigned + by the policy in RFC 2865 section 6 [RADIUS] and are amended by RFC + 3575 [RADIUSIANA]. + +11.3. Application Identifier + + This specification uses the value one (1) in the Application + Identifier namespace as assigned in [BASE]. See section 1.2 above + for more information. + +11.4. CHAP-Algorithm AVP Values + + As defined in section 5.5, the CHAP-Algorithm AVP (AVP Code 403) uses + the values of the "PPP AUTHENTICATION ALGORITHMS" namespace defined + in [PPPCHAP]. + +11.5. Accounting-Auth-Method AVP Values + + As defined in section 8.6, the Accounting-Auth-Method AVP (AVP Code + 406) defines the values 1 - 5. All remaining values are available + for assignment via IETF Consensus [IANA]. + +11.6. Origin-AAA-Protocol AVP Values + + As defined in section 9.3.6, the Origin-AAA-Protocol AVP (AVP Code + 408) defines the value 1. All remaining values are available for + assignment with a "Specification Required" policy [IANAConsid]. + +12. Security Considerations + + This document describes the extension of Diameter for the NAS + application. The security considerations of the Diameter protocol + itself have been discussed in [BASE]. Use of this application of + Diameter MUST take into consideration the security issues and + requirements of the Base protocol. + + + + + + +Calhoun, et al. Standards Track [Page 78] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + This document does not contain a security protocol but does discuss + how PPP authentication protocols can be carried within the Diameter + protocol. The PPP authentication protocols described are PAP and + CHAP. + + The use of PAP SHOULD be discouraged, as it exposes users' passwords + to possibly non-trusted entities. However, PAP is also frequently + used for use with One-Time Passwords, which do not expose a security + risk. + + This document also describes how CHAP can be carried within the + Diameter protocol, which is required for RADIUS backward + compatibility. The CHAP protocol, as used in a RADIUS environment, + facilitates authentication replay attacks. + + The use of the EAP authentication protocols described in [DiamEAP] + can offer better security, given a method suitable for the + circumstances. + +13. References + +13.1. Normative References + + [BASE] Calhoun, P., Loughney, J., Guttman, E., Zorn, G., and + J. Arkko, "Diameter Base Protocol", RFC 3588, + September 2003. + + [DiamTrans] Aboba, B. and J. Wood, "Authentication, Authorization + and Accounting (AAA) Transport Profile", RFC 3539, + June 2003. + + [RADIUS] Rigney, C., Willens, S., Rubens, A., and W. Simpson, + "Remote Authentication Dial In User Service (RADIUS)", + RFC 2865, June 2000. + + [RADIUSTypes] IANA, "RADIUS Types", URL: + <http://www.iana.org/assignments/radius-types> + + [RADIUSIPv6] Aboba, B., Zorn, G., and D. Mitton, "RADIUS and IPv6", + RFC 3162, August 2001. + + [IPv6Addr] Nerenberg, L., "IMAP4 Binary Content Extension", RFC + 3516, April 2003. + + [PPPCHAP] Simpson, W., "PPP Challenge Handshake Authentication + Protocol (CHAP)", RFC 1994, August 1996. + + + + + +Calhoun, et al. Standards Track [Page 79] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + [IANAConsid] Narten, T. and H. Alvestrand, "Guidelines for Writing + an IANA Considerations Section in RFCs", BCP 26, RFC + 2434, October 1998. + + [IANA] IANA Assigned Numbers Database, URL: + <http://www.iana.org/numbers.html> + + [Keywords] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [ANITypes] NANPA Number Resource Info, ANI Assignments, URL: + <http://www.nanpa.com/number_resource_info/ + ani_ii_assignments.html> + +13.2. Informative References + + [RADIUSAcct] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000. + + [RADIUSExt] Rigney, C., Willats, W., and P. Calhoun, "RADIUS + Extensions", RFC 2869, June 2000. + + [RADTunnels] Zorn, G., Leifer, D., Rubens, A., Shriver, J., + Holdrege, M., and I. Goyret, "RADIUS Attributes for + Tunnel Protocol Support", RFC 2868, June 2000. + + [RADTunlAcct] Zorn, G., Aboba, B., and D. Mitton, "RADIUS Accounting + Modifications for Tunnel Protocol Support", RFC 2867, + June 2000. + + [RADDynAuth] Chiba, M., Dommety, G., Eklund, M., Mitton, D., and B. + Aboba, "Dynamic Authorization Extensions to Remote + Authentication Dial In User Service (RADIUS)", RFC + 3576, July 2003. + + [RADIUSIANA] Aboba, B., "IANA Considerations for RADIUS (Remote + Authentication Dial In User Service)", RFC 3575, July + 2003. + + [NASModel] Mitton, D. and M. Beadles, "Network Access Server + Requirements Next Generation (NASREQNG) NAS Model", + RFC 2881, July 2000. + + [NASCriteria] Beadles, M. and D. Mitton, "Criteria for Evaluating + Network Access Server Protocols", RFC 3169, September + 2001. + + + + + + +Calhoun, et al. Standards Track [Page 80] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + [AAACriteria] Aboba, B., Calhoun, P., Glass, S., Hiller, T., McCann, + P., Shiino, H., Zorn, G., Dommety, G., Perkins, C., + Patil, B., Mitton, D., Manning, S., Beadles, M., + Walsh, P., Chen, X., Sivalingham, S., Hameed, A., + Munson, M., Jacobs, S., Lim, B., Hirschman, B., Hsu, + R., Xu, Y., Campbell, E., Baba, S., and E. Jaques, + "Criteria for Evaluating AAA Protocols for Network + Access", RFC 2989, November 2000. + + [DiamEAP] Eronen, P., "Diameter EAP Application", Work in + Progress, May 2004. + + [DiamCMS] Calhoun, P., Bulley, W., and S. Farrell, "Diameter CMS + Security Application", Work in Progress, March 2002. + + [DiamMIP] Calhoun, P., Johansson, T., Perkins, C., Hiller, T., + and P. McCann "Diameter Mobile IPv4 Application", RFC + 4004, August 2005. + + [VSA] Mitton, D., "Diameter/RADIUS Vendor Specific AVP + Translation", Work in Progress, April 2005. + + [RAD802.1X] Congdon, P., Aboba, B., Smith, A., Zorn, G., and J. + Roese, "IEEE 802.1X Remote Authentication Dial In User + Service (RADIUS) Usage Guidelines", RFC 3580, + September 2003. + + [CDMA2000] 3GPP2 "P.S0001-B", Wireless IP Network Standard, + October 2002. + http://www.3gpp2.com/Public_html/specs/P.S0001- + B_v1.0.pdf + + [AppleTalk] Sidhu, Gursharan; Andrews, Richard F. & Oppenheimer, + Alan B. "Inside AppleTalk", Second Edition, Apple + Computer., 1990 + + [ARAP] Apple Remote Access Protocol (ARAP) Version 2.0 + External Reference Specification", Apple Computer, + September 1994, R0612LL/B + + [IPX] Novell, Inc., "NetWare System Technical Interface + Overview", June 1989, # 883-000780-001 + + [LAT] Local Area Transport (LAT) Specification V5.0, Digital + Equipment Corp., AA-NL26A-TE, June 1989 + + + + + + +Calhoun, et al. Standards Track [Page 81] + +RFC 4005 Diameter Network Access Server Application August 2005 + + + [DIFFSERV] Nichols, K., Blake, S., Baker, F., and D. Black, + "Definition of the Differentiated Services Field (DS + Field) in the IPv4 and IPv6 Headers", RFC 2474, + December 1998. + + [DIFFSERVAF] Heinanen, J., Baker, F., Weiss, W., and J. Wroclawski, + "Assured Forwarding PHB Group", RFC 2597, June 1999. + + [DIFFSERVEF] Davie, B., Charny, A., Bennet, J.C., Benson, K., Le + Boudec, J., Courtney, W., Davari, S., Firoiu, V., and + D. Stiliadis, "An Expedited Forwarding PHB (Per-Hop + Behavior)", RFC 3246, March 2002. + + [UTF-8] Yergeau, F., "UTF-8, a transformation format of ISO + 10646", STD 63, RFC 3629, November 2003. + + [ISOLatin] ISO 8859. International Standard -- Information + Processing -- 8-bit Single-Byte Coded Graphic + Character Sets -- Part 1: Latin Alphabet No. 1, ISO + 8859-1:1987. URL: + <http://www.iso.ch/cate/d16338.html> + + [PPP] Simpson, W., "The Point-to-Point Protocol (PPP)", STD + 51, RFC 1661, July 1994. + + [PAP] Lloyd, B. and W. Simpson, "PPP Authentication + Protocols", RFC 1334, October 1992. + + [L2TP] Townsley, W., Valencia, A., Rubens, A., Pall, G., + Zorn, G., and B. Palter, "Layer Two Tunneling Protocol + "L2TP"", RFC 2661, August 1999. + + [PPPMP] Sklower, K., Lloyd, B., McGregor, G., Carr, D., and T. + Coradetti, "The PPP Multilink Protocol (MP)", RFC + 1990, August 1996. + + [PPTP] Hamzeh, K., Pall, G., Verthein, W., Taarud, J., + Little, W., and G. Zorn, "Point-to-Point Tunneling + Protocol", RFC 2637, July 1999. + + [IEEE 802.11F] IEEE, "Trial-Use Recommended Practice for Multi-Vendor + Access Point Interoperability via an Inter-Access + Point Protocol Across Distribution Systems Supporting + IEEE 802.11 Operation", IEEE 802.11F-2003, June 2003. + + + + + + + +Calhoun, et al. Standards Track [Page 82] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +14. Acknowledgements + + The authors would like to thank Carl Rigney, Allan C. Rubens, William + Allen Simpson, and Steve Willens for their work on the original + RADIUS [RADIUS], from which many of the concepts in this + specification were derived. Thanks, also, to Carl Rigney for + [RADIUSAcct] and [RADIUSExt]; Ward Willats for [RADIUSExt]; Glen + Zorn, Bernard Aboba, and Dave Mitton for [RADTunlAcct] and + [RADIUSIPv6]; and Dory Leifer, John Shriver, Matt Holdrege, and + Ignacio Goyret for their work on [RADTunnels]. This document stole + text and concepts from both [RADTunnels] and [RADIUSExt]. Thanks go + to Carl Williams for providing IPv6-specific text. + + The authors would also like to acknowledge the following people for + their contributions in the development of the Diameter protocol: + Bernard Aboba, Jari Arkko, William Bulley, Kuntal Chowdhury, Daniel + C. Fox, Lol Grant, Nancy Greene, Jeff Hagg, Peter Heitman, Paul + Krumviede, Fergal Ladley, Ryan Moats, Victor Muslin, Kenneth Peirce, + Sumit Vakil, John R. Vollbrecht, and Jeff Weisberg. + + Finally, Pat Calhoun would like to thank Sun Microsystems, as most of + the effort put into this document was done while he was in their + employ. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 83] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +Authors' Addresses + + Pat Calhoun + Cisco Systems, Inc. + 170 West Tasman Drive + San Jose, CA 95134 + USA + + Phone: +1 408-853-5269 + EMail: [email protected] + + + Glen Zorn + Cisco Systems, Inc. + 500 108th Avenue N.E., Suite 500 + Bellevue, WA 98004 + USA + + Phone: 1 425-471-4861 + EMail: [email protected] + + + David Spence + 3259 Bluett Rd. + Ann Arbor, MI 48105 + USA + + Phone: +1 734 834 6481 + EMail: [email protected] + + + David Mitton + Circular Networks + 733 Turnpike St #154 + North Andover, MA 01845 + + EMail: [email protected] + + + + + + + + + + + + + + +Calhoun, et al. Standards Track [Page 84] + +RFC 4005 Diameter Network Access Server Application August 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Calhoun, et al. Standards Track [Page 85] + diff --git a/lib/diameter/doc/standard/rfc4006.txt b/lib/diameter/doc/standard/rfc4006.txt new file mode 100644 index 0000000000..3f3e5e1d1b --- /dev/null +++ b/lib/diameter/doc/standard/rfc4006.txt @@ -0,0 +1,6387 @@ + + + + + + +Network Working Group H. Hakala +Request for Comments: 4006 L. Mattila +Category: Standards Track Ericsson + J-P. Koskinen + M. Stura + J. Loughney + Nokia + August 2005 + + + Diameter Credit-Control Application + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + This document specifies a Diameter application that can be used to + implement real-time credit-control for a variety of end user services + such as network access, Session Initiation Protocol (SIP) services, + messaging services, and download services. + +Table of Contents + + 1. Introduction................................................. 4 + 1.1. Requirements Language................................. 5 + 1.2. Terminology........................................... 5 + 1.3. Advertising Application Support....................... 7 + 2. Architecture Models.......................................... 7 + 3. Credit-Control Messages...................................... 9 + 3.1. Credit-Control-Request (CCR) Command.................. 9 + 3.2. Credit-Control-Answer (CCA) Command................... 11 + 4. Credit-Control Application Overview.......................... 11 + 4.1. Service-Specific Rating Input and Interoperability.... 13 + 5. Session Based Credit-Control................................. 15 + 5.1. General Principles.................................... 15 + 5.2. First Interrogation................................... 21 + 5.3. Intermediate Interrogation............................ 27 + 5.4. Final Interrogation................................... 29 + + + +Hakala, et al. Standards Track [Page 1] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + 5.5. Server-Initiated Credit Re-Authorization.............. 30 + 5.6. Graceful Service Termination.......................... 32 + 5.7. Failure Procedures.................................... 38 + 6. One Time Event............................................... 41 + 6.1. Service Price Enquiry................................. 42 + 6.2. Balance Check......................................... 42 + 6.3. Direct Debiting....................................... 43 + 6.4. Refund................................................ 44 + 6.5. Failure Procedure..................................... 44 + 7. Credit-Control Application State Machine..................... 46 + 8. Credit-Control AVPs.......................................... 55 + 8.1. CC-Correlation-Id AVP................................. 58 + 8.2. CC-Request-Number AVP................................. 58 + 8.3. CC-Request-Type AVP................................... 58 + 8.4. CC-Session-Failover AVP............................... 59 + 8.5. CC-Sub-Session-Id AVP................................. 59 + 8.6. Check-Balance-Result AVP.............................. 60 + 8.7. Cost-Information AVP.................................. 60 + 8.8. Unit-Value AVP........................................ 61 + 8.9. Exponent AVP.......................................... 61 + 8.10. Value-Digits AVP...................................... 61 + 8.11. Currency-Code AVP..................................... 62 + 8.12. Cost-Unit AVP......................................... 62 + 8.13. Credit-Control AVP.................................... 62 + 8.14. Credit-Control-Failure-Handling AVP................... 62 + 8.15. Direct-Debiting-Failure-Handling AVP.................. 63 + 8.16. Multiple-Services-Credit-Control AVP.................. 64 + 8.17. Granted-Service-Unit AVP.............................. 65 + 8.18. Requested-Service-Unit AVP............................ 66 + 8.19. Used-Service-Unit AVP................................. 66 + 8.20. Tariff-Time-Change AVP................................ 67 + 8.21. CC-Time AVP........................................... 67 + 8.22. CC-Money AVP.......................................... 67 + 8.23. CC-Total-Octets AVP................................... 68 + 8.24. CC-Input-Octets AVP................................... 68 + 8.25. CC-Output-Octets AVP.................................. 68 + 8.26. CC-Service-Specific-Units AVP......................... 68 + 8.27. Tariff-Change-Usage AVP............................... 68 + 8.28. Service-Identifier AVP................................ 69 + 8.29. Rating-Group AVP...................................... 69 + 8.30. G-S-U-Pool-Reference AVP.............................. 69 + 8.31. G-S-U-Pool-Identifier AVP............................. 70 + 8.32. CC-Unit-Type AVP...................................... 70 + 8.33. Validity-Time AVP..................................... 70 + 8.34. Final-Unit-Indication AVP............................. 71 + 8.35. Final-Unit-Action AVP................................. 72 + 8.36. Restriction-Filter-Rule AVP........................... 72 + 8.37. Redirect-Server AVP................................... 73 + + + +Hakala, et al. Standards Track [Page 2] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + 8.38. Redirect-Address-Type AVP............................. 73 + 8.39. Redirect-Server-Address AVP........................... 74 + 8.40. Multiple-Services-Indicator AVP....................... 74 + 8.41. Requested-Action AVP.................................. 74 + 8.42. Service-Context-Id AVP................................ 75 + 8.43. Service-Parameter-Info AVP............................ 76 + 8.44. Service-Parameter-Type AVP............................ 76 + 8.45. Service-Parameter-Value AVP........................... 77 + 8.46. Subscription-Id AVP................................... 77 + 8.47. Subscription-Id-Type AVP.............................. 77 + 8.48. Subscription-Id-Data AVP.............................. 78 + 8.49. User-Equipment-Info AVP............................... 78 + 8.50. User-Equipment-Info-Type AVP.......................... 78 + 8.50. User-Equipment-Info-Value AVP......................... 79 + 9. Result Code AVP Values....................................... 79 + 9.1. Transient Failures.................................... 79 + 9.2. Permanent Failures.................................... 80 + 10. AVP Occurrence Table......................................... 80 + 10.1. Credit-Control AVP Table.............................. 81 + 10.2. Re-Auth-Request/Answer AVP Table...................... 82 + 11. RADIUS/Diameter Credit-Control Interworking Model............ 82 + 12. IANA Considerations.......................................... 85 + 12.1. Application Identifier................................ 86 + 12.2. Command Codes......................................... 86 + 12.3. AVP Codes............................................. 86 + 12.4. Result-Code AVP Values................................ 86 + 12.5. CC-Request-Type AVP................................... 86 + 12.6. CC-Session-Failover AVP............................... 86 + 12.7. CC-Unit-Type AVP...................................... 87 + 12.8. Check-Balance-Result AVP.............................. 87 + 12.9. Credit-Control AVP.................................... 87 + 12.10. Credit-Control-Failure-Handling AVP................... 87 + 12.11. Direct-Debiting-Failure-Handling AVP.................. 87 + 12.12. Final-Unit-Action AVP................................. 87 + 12.13. Multiple-Services-Indicator AVP....................... 87 + 12.14. Redirect-Address-Type AVP............................. 88 + 12.15. Requested-Action AVP.................................. 88 + 12.16. Subscription-Id-Type AVP.............................. 88 + 12.17. Tariff-Change-Usage AVP............................... 88 + 12.18. User-Equipment-Info-Type AVP.......................... 88 + 13. Credit-Control Application Related Parameters................ 88 + 14. Security Considerations...................................... 89 + 14.1. Direct Connection with Redirects...................... 90 + 15. References................................................... 91 + 15.1. Normative References.................................. 91 + 15.2. Informative References................................ 92 + 16. Acknowledgements............................................. 93 + Appendix A Credit-Control Sequences.............................. 94 + + + +Hakala, et al. Standards Track [Page 3] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + A.1. Flow I................................................ 94 + A.2. Flow II............................................... 96 + A.3. Flow III.............................................. 98 + A.4. Flow IV............................................... 99 + A.5. Flow V................................................ 100 + A.6. Flow VI............................................... 102 + A.7. Flow VII.............................................. 103 + A.8. Flow VIII............................................. 105 + A.9. Flow IX............................................... 107 + Authors' Addresses............................................... 112 + Full Copyright Statement......................................... 114 + +1. Introduction + + This document specifies a Diameter application that can be used to + implement real-time credit-control for a variety of end user services + such as network access, Session Initiation Protocol (SIP) services, + messaging services, and download services. It provides a general + solution to real-time cost and credit-control. + + The prepaid model has been shown to be very successful, for instance, + in GSM networks, where network operators offering prepaid services + have experienced a substantial growth of their customer base and + revenues. Prepaid services are now cropping up in many other + wireless and wire line based networks. + + In next generation wireless networks, additional functionality is + required beyond that specified in the Diameter base protocol. For + example, the 3GPP Charging and Billing requirements [3GPPCHARG] state + that an application must be able to rate service information in + real-time. In addition, it is necessary to check that the end user's + account provides coverage for the requested service prior to + initiation of that service. When an account is exhausted or expired, + the user must be denied the ability to compile additional chargeable + events. + + A mechanism has to be provided to allow the user to be informed of + the charges to be levied for a requested service. In addition, there + are services such as gaming and advertising that may credit as well + as debit a user account. + + The other Diameter applications provide service specific + authorization, and they do not provide credit authorization for + prepaid users. The credit authorization shall be generic and + applicable to all the service environments required to support + prepaid services. + + + + + +Hakala, et al. Standards Track [Page 4] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + To fulfill these requirements, it is necessary to facilitate credit- + control communication between the network element providing the + service (e.g., Network Access Server, SIP Proxy, and Application + Server) and a credit-control server. + + The scope of this specification is the credit authorization. Service + specific authorization and authentication is out of the scope. + +1.1. Requirements Language + + In this document, the key words "MAY", "MUST, "MUST NOT", "OPTIONAL", + "RECOMMENDED", "SHOULD", and "SHOULD NOT", are to be interpreted as + described in [KEYWORDS]. + +1.2. Terminology + + AAA + + Authentication, Authorization, and Accounting + + AA answer + + AA answer generically refers to a service specific authorization and + authentication answer. AA answer commands are defined in service + specific authorization applications, e.g., [NASREQ] and [DIAMMIP]. + + AA request + + AA request generically refers to a service specific authorization and + authentication request. AA request commands are defined in service + specific authorization applications e.g., [NASREQ] and [DIAMMIP]. + + Credit-control + + Credit-control is a mechanism that directly interacts in real-time + with an account and controls or monitors the charges related to the + service usage. Credit-control is a process of checking whether + credit is available, credit-reservation, deduction of credit from the + end user account when service is completed and refunding of reserved + credit that is not used. + + Diameter Credit-control Server + + A Diameter credit-control server acts as a prepaid server, performing + real-time rating and credit-control. It is located in the home + domain and is accessed by service elements or Diameter AAA servers in + + + + + +Hakala, et al. Standards Track [Page 5] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + real-time for purpose of price determination and credit-control + before the service event is delivered to the end-user. It may also + interact with business support systems. + + Diameter Credit-control Client + + A Diameter credit-control client is an entity that interacts with a + credit-control server. It monitors the usage of the granted quota + according to instructions returned by credit-control server. + + Interrogation + + The Diameter credit-control client uses interrogation to initiate a + session based credit-control process. During the credit-control + process, it is used to report the used quota and request a new one. + An interrogation maps to a request/answer transaction. + + One-time event + + Basically, a request/answer transaction of type event. + + Rating + + The act of determining the cost of the service event. + + Service + + A type of task performed by a service element for an end user. + + Service Element + + A network element that provides a service to the end users. The + Service Element may include the Diameter credit-control client, or + another entity (e.g., RADIUS AAA server) that can act as a Credit- + control client on behalf of the Service Element. In the latter case, + the interface between the Service Element and the Diameter credit- + control client is outside the scope of this specification. Examples + of the Service Elements include Network Access Server (NAS), SIP + Proxy, and Application Servers such as messaging server, content + server, and gaming server. + + Service Event + + An event relating to a service provided to the end user. + + + + + + + +Hakala, et al. Standards Track [Page 6] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Session based credit-control + + A credit-control process that makes use of several interrogations: + the first, a possible intermediate, and the final. The first + interrogation is used to reserve money from the user's account and to + initiate the process. The intermediate interrogations may be needed + to request new quota while the service is being rendered. The final + interrogation is used to exit the process. The credit-control server + is required to maintain session state for session-based credit- + control. + +1.3. Advertising Application Support + + Diameter nodes conforming to this specification MUST advertise + support by including the value of 4 in the Auth-Application-Id of the + Capabilities-Exchange-Request and Capabilities-Exchange-Answer + command [DIAMBASE]. + +2. Architecture Models + + The current accounting models specified in the Radius Accounting + [RFC2866] and Diameter base [DIAMBASE] are not sufficient for real- + time credit-control, where credit-worthiness is to be determined + prior to service initiation. Also, the existing Diameter + authorization applications, [NASREQ] and [DIAMMIP], only provide + service authorization, but do not provide credit authorization for + prepaid users. In order to support real-time credit-control, a new + type of server is needed in the AAA infrastructure: Diameter credit- + control server. The Diameter credit-control server is the entity + responsible for credit authorization for prepaid subscribers. + + A service element may authenticate and authorize the end user with + the AAA server by using AAA protocols; e.g., RADIUS or a Diameter + base protocol with a possible Diameter application. + + Accounting protocols such as RADIUS accounting and the Diameter base + accounting protocol can be used to provide accounting data to the + accounting server after service is initiated, and to provide possible + interim reports until service completion. However, for real-time + credit-control, these authorization and accounting models are not + sufficient. + + When real-time credit-control is required, the credit-control client + contacts the credit-control server with information about a possible + service event. The credit-control process is performed to determine + potential charges and to verify whether the end user's account + balance is sufficient to cover the cost of the service being + rendered. + + + +Hakala, et al. Standards Track [Page 7] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Figure 1 illustrates the typical credit-control architecture, which + consists of a Service Element with an embedded Diameter credit- + control client, a Diameter credit-control server, and an AAA server. + A Business Support System is usually deployed; it includes at least + the billing functionality. The credit-control server and AAA server + in this architecture model are logical entities. The real + configuration can combine them into a single host. The credit- + control protocol is the Diameter base protocol with the Diameter + credit-control application. + + When an end user requests services such as SIP or messaging, the + request is typically forwarded to a service element (e.g., SIP Proxy) + in the user's home domain. In some cases it might be possible that + the service element in the visited domain can offer services to the + end user; however, a commercial agreement must exist between the + visited domain and the home domain. Network access is an example of + a service offered in the visited domain where the NAS, through an AAA + infrastructure, authenticates and authorizes the user with the user's + home network. + + Service Element AAA and CC + +----------+ +---------+ Protocols+-----------+ +--------+ + | End |<---->|+-------+|<------------>| AAA | |Business| + | User | +->|| CC || | Server |->|Support | + | | | || Client||<-----+ | | |System | + +----------+ | |+-------+| | +-----------+ | | + | +---------+ | ^ +--------+ + +----------+ | | CC Protocol | ^ + | End |<--+ | +-----v----+ | + | User | +------>|Credit- | | + +----------+ Credit-Control |Control |--------+ + Protocol |Server | + +----------+ + + Figure 1: Typical credit-control architecture + + There can be multiple credit-control servers in the system for + redundancy and load balancing. The system can also contain separate + rating server(s), and accounts can be located in a centralized + database. To ensure that the end user's account is not debited or + credited multiple times for the same service event, only one place in + the credit-control system should perform duplicate detection. System + internal interfaces can exist to relay messages between servers and + an account manager. However, the detailed architecture of the + credit-control system and its interfaces are implementation specific + and are out of scope of this specification. + + + + + +Hakala, et al. Standards Track [Page 8] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Protocol transparent Diameter relays can exist between the credit- + control client and credit-control server. Also, Diameter Redirect + agents that refer credit-control clients to credit-control servers + and allow them to communicate directly can exist. These agents + transparently support the Diameter credit-control application. The + different roles of Diameter Agents are defined in Diameter base + [DIAMBASE], section 2.8. + + If Diameter credit-control proxies exist between the credit-control + client and the credit-control server, they MUST advertise the + Diameter credit-control application support. + +3. Credit-Control Messages + + This section defines new Diameter message Command-Code values that + MUST be supported by all Diameter implementations that conform to + this specification. The Command Codes are as follows: + + Command-Name Abbrev. Code Reference + ----------------------------------------------------------- + Credit-Control-Request CCR 272 3.1 + Credit-Control-Answer CCA 272 3.2 + + Diameter Base [DIAMBASE] defines in the section 3.2 the Command Code + ABNF specification. These formats are observed in Credit-Control + messages. + +3.1. Credit-Control-Request (CCR) Command + + The Credit-Control-Request message (CCR) is indicated by the + command-code field being set to 272 and the 'R' bit being set in the + Command Flags field. It is used between the Diameter credit-control + client and the credit-control server to request credit authorization + for a given service. + + The Auth-Application-Id MUST be set to the value 4, indicating the + Diameter credit-control application. + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 9] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Message Format + + <Credit-Control-Request> ::= < Diameter Header: 272, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Service-Context-Id } + { CC-Request-Type } + { CC-Request-Number } + [ Destination-Host ] + [ User-Name ] + [ CC-Sub-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-State-Id ] + [ Event-Timestamp ] + *[ Subscription-Id ] + [ Service-Identifier ] + [ Termination-Cause ] + [ Requested-Service-Unit ] + [ Requested-Action ] + *[ Used-Service-Unit ] + [ Multiple-Services-Indicator ] + *[ Multiple-Services-Credit-Control ] + *[ Service-Parameter-Info ] + [ CC-Correlation-Id ] + [ User-Equipment-Info ] + *[ Proxy-Info ] + *[ Route-Record ] + *[ AVP ] + + + + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 10] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +3.2. Credit-Control-Answer (CCA) Command + + The Credit-Control-Answer message (CCA) is indicated by the command- + code field being set to 272 and the 'R' bit being cleared in the + Command Flags field. It is used between the credit-control server + and the Diameter credit-control client to acknowledge a Credit- + Control-Request command. + + Message Format + + <Credit-Control-Answer> ::= < Diameter Header: 272, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + { Auth-Application-Id } + { CC-Request-Type } + { CC-Request-Number } + [ User-Name ] + [ CC-Session-Failover ] + [ CC-Sub-Session-Id ] + [ Acct-Multi-Session-Id ] + [ Origin-State-Id ] + [ Event-Timestamp ] + [ Granted-Service-Unit ] + *[ Multiple-Services-Credit-Control ] + [ Cost-Information] + [ Final-Unit-Indication ] + [ Check-Balance-Result ] + [ Credit-Control-Failure-Handling ] + [ Direct-Debiting-Failure-Handling ] + [ Validity-Time] + *[ Redirect-Host] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + *[ Proxy-Info ] + *[ Route-Record ] + *[ Failed-AVP ] + *[ AVP ] + +4. Credit-Control Application Overview + + The credit authorization process takes place before and during + service delivery to the end user and generally requires the user's + authentication and authorization before any request is sent to the + credit-control server. The credit-control application defined in + this specification supports two different credit authorization + models: credit authorization with money reservation and credit + + + +Hakala, et al. Standards Track [Page 11] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + authorization with direct debiting. In both models, the credit- + control client requests credit authorization from the credit-control + server prior to allowing any service to be delivered to the end user. + + In the first model, the credit-control server rates the request, + reserves a suitable amount of money from the user's account, and + returns the corresponding amount of credit resources. Note that + credit resources may not imply actual monetary credit; credit + resources may be granted to the credit control client in the form of + units (e.g., data volume or time) to be metered. + + Upon receipt of a successful credit authorization answer with a + certain amount of credit resources, the credit-control client allows + service delivery to the end user and starts monitoring the usage of + the granted resources. When the credit resources granted to the user + have been consumed or the service has been successfully delivered or + terminated, the credit-control client reports back to the server the + used amount. The credit-control server deducts the used amount from + the end user's account; it may perform rating and make a new credit + reservation if the service delivery is continuing. This process is + accomplished with session based credit-control that includes the + first interrogation, possible intermediate interrogations, and the + final interrogation. For session based credit-control, both the + credit control client and the credit-control server are required to + maintain credit-control session state. Session based credit-control + is described in more detail, with more variations, in section 5. + + In contrast, credit authorization with direct debiting is a single + transaction process wherein the credit-control server directly + deducts a suitable amount of money from the user's account as soon as + the credit authorization request is received. Upon receipt of a + successful credit authorization answer, the credit-control client + allows service delivery to the end user. This process is + accomplished with the one-time event. Session state is not + maintained. + + In a multi-service environment, an end user can issue an additional + service request (e.g., data service) during an ongoing service (e.g., + voice call) toward the same account. Alternatively, during an active + multimedia session, an additional media type is added to the session, + causing a new simultaneous request toward same account. + Consequently, this needs to be considered when credit resources are + granted to the services. + + The credit-control application also supports operations such as + service price enquiry, user's balance check, and refund of credit on + the user's account. These operations are accomplished with the one- + time event. Session state is not maintained. + + + +Hakala, et al. Standards Track [Page 12] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + A flexible credit-control application specific failure handling is + defined in which the home service provider can model the credit- + control client behavior according to its own credit risk management + policy. + + The Credit-Control-Failure-Handling AVP and the Direct-Debiting- + Failure-Handling AVP are defined to determine what is done if the + sending of credit-control messages to the credit-control server has + been temporarily prevented. The usage of the Credit-Control- + Failure-Handling AVP and the Direct-Debiting-Failure-Handling AVP + allows flexibility, as failure handling for the credit-control + session and one time event direct debiting may be different. + +4.1. Service-Specific Rating Input and Interoperability + + The Diameter credit-control application defines the framework for + credit-control; it provides generic credit-control mechanisms + supporting multiple service applications. The credit-control + application, therefore, does not define AVPs that could be used as + input in the rating process. Listing the possible services that + could use this Diameter application is out of scope for this generic + mechanism. + + It is reasonable to expect that a service level agreement will exist + between providers of the credit-control client and the credit-control + server covering the charging, services offered, roaming agreements, + agreed rating input (i.e., AVPs), and so on. + + Therefore, it is assumed that a Diameter credit-control server will + provide service only for Diameter credit-control clients that have + agreed beforehand as to the content of credit-control messages. + Naturally, it is possible that any arbitrary Diameter credit-control + client can interchange credit-control messages with any Diameter + credit-control server, but with a higher likelihood that unsupported + services/AVPs could be present in the credit-control message, causing + the server to reject the request with an appropriate result-code. + +4.1.1. Specifying Rating Input AVPs + + There are two ways to provide rating input to the credit-control + server: either by using AVPs or by including them in the Service- + Parameter-Info AVP. The general principles for sending rating + parameters are as follows: + + 1a. The service SHOULD re-use existing AVPs if it can use AVPs + defined in existing Diameter applications (e.g., NASREQ for network + access services). Re-use of existing AVPs is strongly recommended in + [DIAMBASE]. + + + +Hakala, et al. Standards Track [Page 13] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + For AVPs of type Enumerated, the service may require a new value to + be defined. Allocation of new AVP values is done as specified in + [DIAMBASE], section 1.2. + + 1b. New AVPs can be defined if the existing AVPs do not provide + sufficient rating information. In this case, the procedures defined + in [DIAMBASE] for creating new AVPs MUST be followed. + + 1c. For services specific only to one vendor's implementation, a + Vendor-Specific AVP code for Private use can be used. Where a + Vendor-Specific AVP is implemented by more than one vendor, + allocation of global AVPs is encouraged instead; refer to [DIAMBASE]. + + 2. The Service-Parameter-Info AVP MAY be used as a container to pass + legacy rating information in its original encoded form (e.g., ASN.1 + BER). This method can be used to avoid unnecessary conversions from + an existing data format to an AVP format. In this case, the rating + input is embedded in the Service-Parameter-Info AVP as defined in + section 8.43. + + New service applications SHOULD favor the use of explicitly defined + AVPs as described in items 1a and 1b, to simplify interoperability. + +4.1.2. Service-Specific Documentation + + The service specific rating input AVPs, the contents of the Service- + Parameter-Info AVP or Service-Context-Id AVP (defined in section + 8.42) are not within the scope of this document. To facilitate + interoperability, it is RECOMMENDED that the rating input and the + values of the Service-Context-Id be coordinated via an informational + RFC or other permanent and readily available reference. The + specification of another cooperative standardization body (e.g., + 3GPP, OMA, and 3GPP2) SHOULD be used. However, private services may + be deployed that are subject to agreements between providers of the + credit-control server and client. In this case, vendor specific AVPs + can be used. + + This specification, together with the above service specific + documents, governs the credit-control message. Service specific + documents define which existing AVPs or new AVPs are used as input to + the rating process (i.e., those that do not define new credit-control + applications), and thus have to be included in the Credit-Control- + Request command by a Diameter credit-control client supporting a + given service as *[AVP]. Should Service-Parameter-Info be used, then + the service specific document MUST specify the exact content of this + grouped AVP. + + + + + +Hakala, et al. Standards Track [Page 14] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The Service-Context-Id AVP MUST be included at the command level of a + Credit-Control Request to identify the service specific document that + applies to the request. The specific service or rating group the + request relates to is uniquely identified by the combination of + Service-Context-Id and Service-Identifier or Rating-Group. + +4.1.3. Handling of Unsupported/Incorrect Rating Input + + Diameter credit-control implementations are required to support the + Mandatory rating AVPs defined in service specific documentation of + the services they support, according to the 'M' bit rules in + [DIAMBASE]. + + If a rating input required for the rating process is incorrect in the + Credit-control request, or if the credit-control server does not + support the requested service context (identified by the Service- + Context-Id AVP at command level), the Credit-control answer MUST + contain the error code DIAMETER_RATING_FAILED. A CCA message with + this error MUST contain one or more Failed-AVP AVPs containing the + missing and/or unsupported AVPs that caused the failure. A Diameter + credit-control client that receives the error code + DIAMETER_RATING_FAILED in response to a request MUST NOT send similar + requests in the future. + +4.1.4. RADIUS Vendor-Specific Rating Attributes + + When service specific documents include RADIUS vendor specific + attributes that could be used as input in the rating process, the + rules described in [NASREQ] for formatting the Diameter AVP MUST be + followed. + + For example, if the AVP code used is the vendor attribute type code, + the Vendor-Specific flag MUST be set to 1 and the Vendor-ID MUST be + set to the IANA Vendor identification value. The Diameter AVP data + field contains only the attribute value of the RADIUS attribute. + +5. Session Based Credit-Control + +5.1. General Principles + + For a session-based credit-control, several interrogations are + needed: the first, intermediate (optional) and the final + interrogations. This is illustrated in Figures 2 and 3. + + If the credit-control client performs credit-reservation before + granting service to the end user, it MUST use several interrogations + toward the credit-control server (i.e., session based credit- + + + + +Hakala, et al. Standards Track [Page 15] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + control). In this case, the credit-control server MUST maintain the + credit-control session state. + + Each credit-control session MUST have a globally unique Session-Id as + defined in [DIAMBASE], which MUST NOT be changed during the lifetime + of a credit-control session. + + Certain applications require multiple credit-control sub-sessions. + These applications would send messages with a constant Session-Id + AVP, but with a different CC-Sub-Session-Id AVP. If several credit + sub-sessions will be used, all sub-sessions MUST be closed separately + before the main session is closed so that units per sub-session may + be reported. The absence of this AVP implies that no sub-sessions + are in use. + + Note that the service element might send a service specific re- + authorization message to the AAA server due to expiration of the + authorization-lifetime during an ongoing credit-control session. + However, the service specific re-authorization does not influence the + credit authorization that is ongoing between the credit-control + client and credit-control server, as credit authorization is + controlled by the burning rate of the granted quota. + + If service specific re-authorization fails, the user will be + disconnected, and the credit-control client MUST send a final + interrogation to the credit-control server. + + The Diameter credit-control server may seek to control the validity + time of the granted quota and/or the production of intermediate + interrogations. Thus, it MAY include the Validity-Time AVP in the + answer message to the credit-control client. Upon expiration of the + Validity-Time, the credit-control client MUST generate a credit- + control update request and report the used quota to the credit- + control server. It is up to the credit-control server to determine + the value of the Validity-Time to be used for consumption of the + granted service units. If the Validity-Time is used, its value + SHOULD be given as input to set the session supervision timer Tcc + (the session supervision timer MAY be set to two times the value of + the Validity-Time, as defined in section 13). Since credit-control + update requests are also produced at the expiry of granted service + units and/or for mid-session service events, the omission of + Validity-Time does not mean that intermediate interrogation for the + purpose of credit-control is not performed. + + + + + + + + +Hakala, et al. Standards Track [Page 16] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +5.1.1. Basic Tariff-Time Change Support + + The Diameter credit-control server and client MAY optionally support + a tariff change mechanism. The Diameter credit-control server may + include a Tariff-Time-Change AVP in the answer message. Note that + the granted units should be allocated based on the worst-case + scenario in case of forthcoming tariff change, so that the overall + reported used units would never exceed the credit reservation. + + When the Diameter credit-control client reports the used units and a + tariff change has occurred during the reporting period, the Diameter + credit-control client MUST separately itemize the units used before + and after the tariff change. If the client is unable to distinguish + whether units straddling the tariff change were used before or after + the tariff change, the credit-control client MUST itemize those units + in a third category. + + If a client does not support the tariff change mechanism and it + receives a CCA message carrying the Tariff-Time-Change AVP, it MUST + terminate the credit-control session, giving a reason of + DIAMETER_BAD_ANSWER in the Termination-Cause AVP. + + For time based services, the quota is continuously consumed at the + regular rate of 60 seconds per minute. At the time when credit + resources are allocated, the server already knows how many units will + be consumed before the tariff time change and how many units will be + consumed afterward. Similarly, the server can determine the units + consumed at the before rate and the units consumed at the rate + afterward in the event that the end-user closes the session before + the consumption of the allotted quota. There is no need for + additional traffic between client and server in the case of tariff + time changes for continuous time based service. Therefore, the + tariff change mechanism is not used for such services. For time- + based services in which the quota is NOT continuously consumed at a + regular rate, the tariff change mechanism described for volume and + event units MAY be used. + +5.1.2. Credit-Control for Multiple Services within a (sub-)Session + + When multiple services are used within the same user session and each + service or group of services is subject to different cost, it is + necessary to perform credit-control for each service independently. + Making use of credit-control sub-sessions to achieve independent + credit-control will result in increased signaling load and usage of + resources in both the credit-control client and the credit-control + server. For instance, during one network access session the end user + may use several http-services subject to different access cost. The + network access specific attributes such as the quality of service + + + +Hakala, et al. Standards Track [Page 17] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + (QoS) are common to all the services carried within the access + bearer, but the cost of the bearer may vary depending on its content. + + To support these scenarios optimally, the credit-control application + enables independent credit-control of multiple services in a single + credit-control (sub-)session. This is achieved by including the + optional Multiple-Services-Credit-Control AVP in Credit-Control- + Request/Answer messages. It is possible to request and allocate + resources as a credit pool shared between multiple services. The + services can be grouped into rating groups in order to achieve even + further aggregation of credit allocation. It is also possible to + request and allocate quotas on a per service basis. Where quotas are + allocated to a pool by means of the Multiple-Services-Credit-Control + AVP, the quotas remain independent objects that can be re-authorized + independently at any time. Quotas can also be given independent + result codes, validity times, and Final-Unit-Indications. + + A Rating-Group gathers a set of services, identified by a Service- + Identifier, and subject to the same cost and rating type (e.g., + $0.1/minute). It is assumed that the service element is provided + with Rating-Groups, Service-Identifiers, and their associated + parameters that define what has to be metered by means outside the + scope of this specification. (Examples of parameters associated to + Service-Identifiers are IP 5-tuple and HTTP URL.) Service-Identifiers + enable authorization on a per-service based credit as well as + itemized reporting of service usage. It is up to the credit-control + server whether to authorize credit for one or more services or for + the whole rating-group. However, the client SHOULD always report + used units at the finest supported level of granularity. Where quota + is allocated to a rating-group, all the services belonging to that + group draw from the allotted quota. The following is a graphical + representation of the relationship between service-identifiers, + rating-groups, credit pools, and credit-control (sub-)session. + + DCC (Sub-)Session + | + +------------+-----------+-------------+--------------- + + | | | | | + Service-Id a Service-Id b Service-Id c Service-Id d.....Service-Id z + \ / \ / / + \ / \ / / + \ / Rating-Group 1.......Rating-Group n + \ / | | + Quota ---------------Quota Quota + | / | + | / | + Credit-Pool Credit-Pool + + + + +Hakala, et al. Standards Track [Page 18] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + If independent credit-control of multiple services is used, the + validity-time and final-unit-indication SHOULD be present either in + the Multiple-Services-Credit-Control AVP(s) or at command level as + single AVPs. However, the Result-Code AVP MAY be present both on the + command level and within the Multiple-Services-Credit-Control AVP. + If the Result-Code on the command level indicates a value other than + SUCCESS, then the Result-Code on command level takes precedence over + any included in the Multiple-Services-Credit-Control AVP. + + The credit-control client MUST indicate support for independent + credit-control of multiple services within a (sub-)session by + including the Multiple-Services-Indicator AVP in the first + interrogation. A credit-control server not supporting this feature + MUST treat the Multiple-Services-Indicator AVP and any received + Multiple-Services-Credit-Control AVPs as invalid AVPs. + + If the client indicated support for independent credit-control of + multiple services, a credit-control server that wishes to use the + feature MUST return the granted units within the Multiple-Services- + Credit-Control AVP associated to the corresponding service-identifier + and/or rating-group. + + To avoid a situation where several parallel (and typically also + small) credit reservations must be made on the same account (i.e., + credit fragmentation), and also to avoid unnecessary load on the + credit-control server, it is possible to provide service units as a + pool that applies to multiple services or rating groups. This is + achieved by providing the service units in the form of a quota for a + particular service or rating group in the Multiple-Services-Credit- + Control AVP, and also by including a reference to a credit pool for + that unit type. + + The reference includes a multiplier derived from the rating + parameter, which translates from service units of a specific type to + the abstract service units in the pool. For instance, if the rating + parameter for service 1 is $1/MB and the rating parameter for service + 2 is $0.5/MB, the multipliers could be 10 and 5 for services 1 and 2, + respectively. + + If S is the total service units within the pool, M1, M2, ..., Mn are + the multipliers provided for services 1, 2, ..., n, and C1, C2, ..., + Cn are the used resources within the session, then the pool credit is + exhausted and re-authorization MUST be sought when: + + C1*M1 + C2*M2 + ... + Cn*Mn >= S + + + + + + +Hakala, et al. Standards Track [Page 19] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The total credit in the pool, S, is calculated from the quotas, which + are currently allocated to the pool as follows: + + S = Q1*M1 + Q2*M2 + ... + Qn*Mn + + If services or rating groups are added to or removed from the pool, + then the total credit is adjusted appropriately. Note that when the + total credit is adjusted because services or rating groups are + removed from the pool, the value that need to be removed is the + consumed one (i.e., Cx*Mx). + + Re-authorizations for an individual service or rating group may be + sought at any time; for example, if a 'non-pooled' quota is used up + or the Validity-Time expires. + + Where multiple G-S-U-Pool-Reference AVPs (section 8.30) with the same + G-S-U-Pool-Identifier are provided within a Multiple-Services- + Credit-Control AVP (section 8.16) along with the Granted-Service-Unit + AVP, then these MUST have different CC-Unit-Type values, and they all + draw from the credit pool separately. For instance, if one + multiplier for time (M1t) and one multiplier for volume (M1v) are + given, then the used resources from the pool is the sum C1t*M1t + + C1v*M1v, where C1t is the time unit and C1v is the volume unit. + + Where service units are provided within a Multiple-Services-Credit- + Control AVP without a corresponding G-S-U-Pool-Reference AVP, then + these are handled independently from any credit pool and from any + other services or rating groups within the session. + + The credit pool concept is an optimal tool to avoid the over- + reservation effect of the basic single quota tariff time change + mechanism (the mechanism described in section 5.1.1). Therefore, + Diameter credit-control clients and servers implementing the + independent credit-control of multiple services SHOULD leverage the + credit pool concept when supporting the tariff time change. The + Diameter credit-control server SHOULD include both the Tariff-Time- + Change and Tariff-Change-Usage AVPs in two quota allocations in the + answer message (i.e., two instances of the Multiple-Services-Credit- + Control AVP). One of the granted units is allocated to be used + before the potential tariff change, while the second granted units + are for use after a tariff change. Both granted unit quotas MUST + contain the same Service-Identifier and/or Rating-Group. This dual + quota mechanism ensures that the overall reported used units would + never exceed the credit reservation. The Diameter credit-control + client reports both the used units before and after the tariff change + in a single instance of the Multiple-Services-Credit-Control AVP. + + + + + +Hakala, et al. Standards Track [Page 20] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The failure handling for credit-control sessions is defined in + section 5.7 and reflected in the basic credit-control state machine + in section 7. Credit-control clients and servers implementing the + independent credit-control of multiple services in a (sub-)session + functionality MUST ensure failure handling and general behavior fully + consistent with the above mentioned sections, while maintaining the + ability to handle parallel ongoing credit re-authorization within a + (sub-)session. Therefore, it is RECOMMENDED that Diameter credit- + control clients maintain a PendingU message queue and restart the Tx + timer (section 13) every time a CCR message with the value + UPDATE_REQUEST is sent while they are in PendingU state. When + answers to all pending messages are received, the state machine moves + to OPEN state, and Tx is stopped. Naturally, the action performed + when a problem for the session is detected according to section 5.7 + affects all the ongoing services (e.g., failover to a backup server + if possible affect all the CCR messages with the value UPDATE_REQUEST + in the PendingU queue). + + Since the client may send CCR messages with the value UPDATE_REQUEST + while in PendingU (i.e., without waiting for an answer to ongoing + credit re-authorization), the time space between these requests may + be very short, and the server may not have received the previous + request(s) yet. Therefore, in this situation the server may receive + out of sequence requests and SHOULD NOT consider this an error + condition. A proper answer is to be returned to each of those + requests. + +5.2. First Interrogation + + When session based credit-control is required (e.g., the + authentication server indicated a prepaid user), the first + interrogation MUST be sent before the Diameter credit-control client + allows any service event to the end user. The CC-Request-Type is set + to the value INITIAL_REQUEST in the request message. + + If the Diameter credit-control client knows the cost of the service + event (e.g., a content server delivering ringing tones may know their + cost) the monetary amount to be charged is included in the + Requested-Service-Unit AVP. If the Diameter credit-control client + does not know the cost of the service event, the Requested-Service- + Unit AVP MAY contain the number of requested service events. Where + the Multiple-Services-Credit-Control AVP is used, it MUST contain the + Requested-Service-Unit AVP to indicate that the quota for the + associated service/rating-group is requested. In the case of + multiple services, the Service-Identifier AVP or the Rating-Group AVP + within the Multiple-Services-Credit-Control AVP always indicates the + service concerned. Additional service event information to be rated + + + + +Hakala, et al. Standards Track [Page 21] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + MAY be sent as service specific AVPs or MAY be sent within the + Service-Parameter-Info AVP at command level. The Service-Context-Id + AVP indicates the service specific document applicable to the + request. + + The Event-Timestamp AVP SHOULD be included in the request and + contains the time when the service event is requested in the service + element. The Subscription-Id AVP SHOULD be included to identify the + end user in the credit-control server. The credit-control client MAY + include the User-Equipment-Info AVP so that the credit-control server + has some indication of the type and capabilities of the end user + access device. How the credit-control server uses this information + is outside the scope of this document. + + The credit-control server SHOULD rate the service event and make a + credit-reservation from the end user's account that covers the cost + of the service event. If the type of the Requested-Service-Unit AVP + is money, no rating is needed, but the corresponding monetary amount + is reserved from the end user's account. + + The credit-control server returns the Granted-Service-Unit AVP in the + Answer message to the Diameter credit-control client. The Granted- + Service-Unit AVP contains the amount of service units that the + Diameter credit-control client can provide to the end user until a + new Credit-Control-Request MUST be sent to the credit-control server. + If several unit types are sent in the Answer message, the credit- + control client MUST handle each unit type separately. The type of + the Granted-Service-Unit AVP can be time, volume, service specific, + or money, depending on the type of service event. The unit type(s) + SHOULD NOT be changed within an ongoing credit-control session. + + There MUST be a maximum of one instance of the same unit type in one + Answer message. However, if multiple quotas are conveyed to the + credit-control client in the Multiple-Services-Credit-Control AVPs, + it is possible to carry two instances of the same unit type + associated to a service-identifier/rating-group. This is typically + the case when a tariff time change is expected and the credit-control + server wants to make a distinction between the granted quota before + and after tariff change. + + If the credit-control server determines that no further control is + needed for the service, it MAY include the result code indicating + that the credit-control is not applicable (e.g., if the service is + free of charge). This result code at command level implies that the + credit-control session is to be terminated. + + The Credit-Control-Answer message MAY also include the Final-Unit- + Indication AVP to indicate that the answer message contains the final + + + +Hakala, et al. Standards Track [Page 22] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + units for the service. After the end user has consumed these units, + the Diameter credit-control-client MUST behave as described in + section 5.6. + + This document defines two different approaches to perform the first + interrogation to be used in different network architectures. The + first approach uses credit-control messages after the user's + authorization and authentication takes place. The second approach + uses service specific authorization messages to perform the first + interrogation during the user's authorization/authentication phase, + and credit-control messages for the intermediate and final + interrogations. If an implementation of the credit-control client + supports both the methods, determining which method to use SHOULD be + configurable. + + In service environments such as the Network Access Server (NAS), it + is desired to perform the first interrogation as part of the + authorization/authentication process for the sake of protocol + efficiency. Further credit authorizations after the first + interrogation are performed with credit-control commands defined in + this specification. Implementations of credit-control clients + operating in the mentioned environments SHOULD support this method. + If the credit-control server and AAA server are separate physical + entities, the service element sends the request messages to the AAA + server, which then issues an appropriate request or proxies the + received request forward to the credit-control server. + + In other service environments, such as the 3GPP network and some SIP + scenarios, there is a substantial decoupling between + registration/access to the network and the actual service request + (i.e., the authentication/authorization is executed once at + registration/access to the network and is not executed for every + service event requested by the subscriber). In these environments, + it is more appropriate to perform the first interrogation after the + user has been authenticated and authorized. The first, the + intermediate, and the final interrogations are executed with credit- + control commands defined in this specification. + + Other IETF standards or standards developed by other standardization + bodies may define the most suitable method in their architectures. + +5.2.1. First Interrogation after Authorization and Authentication + + The Diameter credit-control client in the service element may get + information from the authorization server as to whether credit- + control is required, based on its knowledge of the end user. If + credit-control is required the credit-control server needs to be + contacted prior to initiating service delivery to the end user. The + + + +Hakala, et al. Standards Track [Page 23] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + accounting protocol and the credit-control protocol can be used in + parallel. The authorization server may also determine whether the + parallel accounting stream is required. + + The following diagram illustrates the case where both protocols are + used in parallel and the service element sends credit-control + messages directly to the credit-control server. More credit-control + sequence examples are given in Annex A. + + Diameter + End User Service Element AAA Server CC Server + (CC Client) + | Registration | AA request/answer(accounting,cc or both)| + |<----------------->|<------------------>| | + | : | | | + | : | | | + | Service Request | | | + |------------------>| | | + | | CCR(Initial,Credit-Control AVPs) | + | +|---------------------------------------->| + | CC stream|| | CCA(Granted-Units)| + | +|<----------------------------------------| + | Service Delivery | | | + |<----------------->| ACR(start,Accounting AVPs) | + | : |------------------->|+ | + | : | ACA || Accounting stream | + | |<-------------------|+ | + | : | | | + | : | | | + | | CCR(Update,Used-Units) | + | |---------------------------------------->| + | | | CCA(Granted-Units)| + | |<----------------------------------------| + | : | | | + | : | | | + | End of Service | | | + |------------------>| CCR(Termination, Used-Units) | + | |---------------------------------------->| + | | | CCA | + | |<----------------------------------------| + | | ACR(stop) | | + | |------------------->| | + | | ACA | | + | |<-------------------| | + + Figure 2: Protocol example with first interrogation after user's + authorization/authentication + + + + +Hakala, et al. Standards Track [Page 24] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +5.2.2. Authorization Messages for First Interrogation + + The Diameter credit-control client in the service element MUST + actively co-operate with the authorization/authentication client in + the construction of the AA request by adding appropriate credit- + control AVPs. The credit-control client MUST add the Credit-Control + AVP to indicate credit-control capabilities and MAY add other + relevant credit-control specific AVPs to the proper + authorization/authentication command to perform the first + interrogation toward the home Diameter AAA server. The Auth- + Application-Id is set to the appropriate value, as defined in the + relevant service specific authorization/authentication application + document (e.g., [NASREQ], [DIAMMIP]). The home Diameter AAA server + authenticates/authorizes the subscriber and determines whether + credit-control is required. + + If credit-control is not required for the subscriber, the home + Diameter AAA server will respond as usual, with an appropriate AA + answer message. If credit-control is required for the subscriber and + the Credit-Control AVP with the value set to CREDIT_AUTHORIZATION was + present in the authorization request, the home AAA server MUST + contact the credit-control server to perform the first interrogation. + If credit-control is required for the subscriber and the Credit- + Control AVP was not present in the authorization request, the home + AAA server MUST send an authorization reject answer message. + + The Diameter AAA server supporting credit-control is required to send + the Credit-Control-Request command (CCR) defined in this document to + the credit-control server. The Diameter AAA server populates the CCR + based on service specific AVPs used for input to the rating process, + and possibly on credit-control AVPs received in the AA request. The + credit-control server will reserve money from the user's account, + will rate the request and will send a Credit-Control-Answer message + to the home Diameter AAA server. The answer message includes the + Granted-Service-Unit AVP(s) and MAY include other credit-control + specific AVPs, as appropriate. Additionally, the credit-control + server MAY set the Validity-Time and MAY include the Credit-Control- + Failure-Handling AVP and the Direct-Debiting-Failure-Handling AVP to + determine what to do if the sending of credit-control messages to the + credit-control server has been temporarily prevented. + + Upon receiving the Credit-Control-Answer message from the credit- + control server, the home Diameter AAA server will populate the AA + answer with the received credit-control AVPs and with the appropriate + service attributes according to the authorization/authentication + specific application (e.g., [NASREQ], [DIAMMIP]). It will then + forward the packet to the credit-control client. If the home + Diameter AAA server receives a credit-control reject message, it will + + + +Hakala, et al. Standards Track [Page 25] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + simply generate an appropriate authorization reject message to the + credit-control client, including the credit-control specific error + code. + + In this model, the credit-control client sends further credit-control + messages to the credit-control server via the home Diameter AAA + server. Upon receiving a successful authorization answer message + with the Granted-Service-Unit AVP(s), the credit-control client will + grant the service to the end user and will generate an intermediate + credit-control request, as required by using credit-control commands. + The CC-Request-Number of the first UPDATE_REQUEST MUST be set to 1 + (for how to produce unique value for the CC-Request-Number AVP, see + section 8.2). + + If service specific re-authorization is performed (i.e., + authorization-lifetime expires), the credit-control client MUST add + to the service specific re-authorization request the Credit-Control + AVP with a value set to RE_AUTHORIZATION to indicate that the + credit-control server MUST NOT be contacted. When session based + credit-control is used for the subscriber, a constant credit-control + message stream flows through the home Diameter AAA server. The home + Diameter AAA server can make use of this credit-control message flow + to deduce that the user's activity is ongoing; therefore, it is + recommended to set the authorization-lifetime to a reasonably high + value when credit-control is used for the subscriber. + + In this scenario, the home Diameter AAA server MUST advertise support + for the credit-control application to its peers during the capability + exchange process. + + + + + + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 26] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The following diagram illustrates the use of + authorization/authentication messages to perform the first + interrogation. The parallel accounting stream is not shown in the + figure. + + Service Element Diameter + End User (CC Client) AAA Server CC Server + | Service Request | AA Request (CC AVPs) | + |------------------>|------------------->| | + | | | CCR(Initial, CC AVPs) + | | |------------------->| + | | | CCA(Granted-Units) + | | |<-------------------| + | | AA Answer(Granted-Units) | + | Service Delivery |<-------------------| | + |<----------------->| | | + | : | | | + | : | | | + | : | | | + | | | | + | | CCR(Update,Used-Units) | + | |------------------->| CCR(Update,Used-Units) + | | |------------------->| + | | | CCA(Granted-Units)| + | | CCA(Granted-Units)|<-------------------| + | |<-------------------| | + | : | | | + | : | | | + | End of Service | | | + |------------------>| CCR(Termination,Used-Units) | + | |------------------->| CCR(Term.,Used-Units) + | | |------------------->| + | | | CCA | + | | CCA |<-------------------| + | |<-------------------| | + + Figure 3: Protocol example with use of the + authorization messages for the first interrogation + +5.3. Intermediate Interrogation + + When all the granted service units for one unit type are spent by the + end user or the Validity-Time is expired, the Diameter credit-control + client MUST send a new Credit-Control-Request to the credit-control + server. In the event that credit-control for multiple services is + applied in one credit-control session (i.e., units associated to + Service-Identifier(s) or Rating-Group are granted), a new Credit- + Control-Request MUST be sent to the credit-control server when the + + + +Hakala, et al. Standards Track [Page 27] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + credit reservation has been wholly consumed, or upon expiration of + the Validity-Time. It is always up to the Diameter credit-control + client to send a new request well in advance of the expiration of the + previous request in order to avoid interruption in the service + element. Even if the granted service units reserved by the credit- + control server have not been spent upon expiration of the Validity- + Time, the Diameter credit-control client MUST send a new Credit- + Control-Request to the credit-control server. + + There can also be mid-session service events, which might affect the + rating of the current service events. In this case, a spontaneous + updating (a new Credit-Control-Request) SHOULD be sent including + information related to the service event even if all the granted + service units have not been spent or the Validity-Time has not + expired. + + When the used units are reported to the credit-control server, the + credit-control client will not have any units in its possession + before new granted units are received from the credit-control server. + When the new granted units are received, these units apply from the + point where the measurement of the reported used units stopped. + Where independent credit-control of multiple services is supported, + this process may be executed for one or more services, a single + rating-group, or a pool within the (sub)session. + + The CC-Request-Type AVP is set to the value UPDATE_REQUEST in the + intermediate request message. The Subscription-Id AVP SHOULD be + included in the intermediate message to identify the end user in the + credit-control server. The Service-Context-Id AVP indicates the + service specific document applicable to the request. + + The Requested-Service-Unit AVP MAY contain the new amount of + requested service units. Where the Multiple-Services-Credit-Control + AVP is used, it MUST contain the Requested-Service-Unit AVP if a new + quota is requested for the associated service/rating-group. The + Used-Service-Unit AVP contains the amount of used service units + measured from the point when the service became active or, if interim + interrogations are used during the session, from the point when the + previous measurement ended. The same unit types used in the previous + message SHOULD be used. If several unit types were included in the + previous answer message, the used service units for each unit type + MUST be reported. + + The Event-Timestamp AVP SHOULD be included in the request and + contains the time of the event that triggered the sending of the new + Credit-Control-Request. + + + + + +Hakala, et al. Standards Track [Page 28] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The credit-control server MUST deduct the used amount from the end + user's account. It MAY rate the new request and make a new credit- + reservation from the end user's account that covers the cost of the + requested service event. + + A Credit-Control-Answer message with the CC-Request-Type AVP set to + the value UPDATE_REQUEST MAY include the Cost-Information AVP + containing the accumulated cost estimation for the session, without + taking any credit-reservation into account. + + The Credit-Control-Answer message MAY also include the Final-Unit- + Indication AVP to indicate that the answer message contains the final + units for the service. After the end user has consumed these units, + the Diameter credit-control-client MUST behave as described in + section 5.6. + + There can be several intermediate interrogations within a session. + +5.4. Final Interrogation + + When the end user terminates the service session, or when the + graceful service termination described in section 5.6 takes place, + the Diameter credit-control client MUST send a final Credit-Control- + Request message to the credit-control server. The CC-Request-Type + AVP is set to the value TERMINATION_REQUEST. The Service-Context-Id + AVP indicates the service specific document applicable to the + request. + + The Event-Timestamp AVP SHOULD be included in the request and + contains the time when the session was terminated. + + The Used-Service-Unit AVP contains the amount of used service units + measured from the point when the service became active or, if interim + interrogations are used during the session, from the point when the + previous measurement ended. If several unit types were included in + the previous answer message, the used service units for each unit + type MUST be reported. + + After final interrogation, the credit-control server MUST refund the + reserved credit amount not used to the end user's account and deduct + the used monetary amount from the end user's account. + + A Credit-Control-Answer message with the CC-Request-Type set to the + value TERMINATION_REQUEST MAY include the Cost-Information AVP + containing the estimated total cost for the session in question. + + If the user logs off during an ongoing credit-control session, or if + some other reason causes the user to become logged off (e.g., final- + + + +Hakala, et al. Standards Track [Page 29] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + unit indication causes user logoff according to local policy), the + service element, according to application specific policy, may send a + Session-Termination-Request (STR) to the home Diameter AAA server as + usual [DIAMBASE]. Figure 4 illustrates the case when the final-unit + indication causes user logoff upon consumption of the final granted + units and the generation of STR. + + Service Element AAA Server CC Server + End User (CC Client) + | Service Delivery | | | + |<----------------->| | | + | : | | | + | : | | | + | : | | | + | | | | + | | CCR(Update,Used-Units) | + | |------------------->| CCR(Update,Used-Units) + | | |------------------->| + | | CCA(Final-Unit, Terminate) + | CCA(Final-Unit, Terminate)|<-------------------| + | |<-------------------| | + | : | | | + | : | | | + | Disconnect user | | | + |<------------------| CCR(Termination,Used-Units) | + | |------------------->| CCR(Term.,Used-Units) + | | |------------------->| + | | | CCA | + | | CCA |<-------------------| + | |<-------------------| | + | | STR | | + | |------------------->| | + | | STA | | + | |<-------------------| | + + Figure 4: User disconnected due to exhausted account + +5.5. Server-Initiated Credit Re-Authorization + + The Diameter credit-control application supports server-initiated + re-authorization. The credit-control server MAY optionally initiate + the credit re-authorization by issuing a Re-Auth-Request (RAR) as + defined in the Diameter base protocol [DIAMBASE]. The Auth- + Application-Id in the RAR message is set to 4 to indicate Diameter + Credit Control, and the Re-Auth-Request-Type is set to + AUTHORIZE_ONLY. + + + + + +Hakala, et al. Standards Track [Page 30] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Section 5.1.2 defines the feature to enable credit-control for + multiple services within a single (sub-)session where the server can + authorize credit usage at a different level of granularity. Further, + the server may provide credit resources to multiple services or + rating groups as a pool (see section 5.1.2 for details and + definitions). Therefore, the server, based on its service logic and + its knowledge of the ongoing session, can decide to request credit + re-authorization for a whole (sub-)session, a single credit pool, a + single service, or a single rating-group. To request credit re- + authorization for a credit pool, the server includes in the RAR + message the G-S-U-Pool-Identifier AVP indicating the affected pool. + To request credit re-authorization for a service or a rating-group, + the server includes in the RAR message the Service-Identifier AVP or + the Rating-Group AVP, respectively. To request credit re- + authorization for all the ongoing services within the (sub-)session, + the server includes none of the above mentioned AVPs in the RAR + message. + + If a credit re-authorization is not already ongoing (i.e., the + credit-control session is in Open state), a credit control client + that receives an RAR message with Session-Id equal to a currently + active credit-control session MUST acknowledge the request by sending + the Re-Auth-Answer (RAA) message and MUST initiate the credit re- + authorization toward the server by sending a Credit-Control-Request + message with the CC-Request-Type AVP set to the value UPDATE_REQUEST. + The Result-Code 2002 (DIAMETER_LIMITED_SUCCESS) SHOULD be used in the + RAA message to indicate that an additional message (i.e., CCR message + with the value UPDATE_REQUEST) is required to complete the procedure. + If a quota was allocated to the service, the credit-control client + MUST report the used quota in the Credit-Control-Request. Note that + the end user does not need to be prompted for the credit re- + authorization, since the credit re-authorization is transparent to + the user (i.e., it takes place exclusively between the credit-control + client and the credit-control server). + + Where multiple services in a user's session are supported, the + procedure in the above paragraph will be executed at the granularity + requested by the server in the RAR message. + + If credit re-authorization is ongoing at the time when the RAR + message is received (i.e., RAR-CCR collision), the credit-control + client successfully acknowledges the request but does not initiate a + new credit re-authorization. The Result-Code 2001 (DIAMETER_SUCCESS) + SHOULD be used in the RAA message to indicate that a credit re- + authorization procedure is already ongoing (i.e., the client was in + PendingU state when the RAR was received). The credit-control server + SHOULD process the Credit-Control-Request as if it was received in + answer to the server initiated credit re-authorization, and should + + + +Hakala, et al. Standards Track [Page 31] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + consider the server initiated credit re-authorization process + successful upon reception of the Re-Auth-Answer message. + + When multiple services are supported in a user's session, the server + may request credit re-authorization for a credit pool (or for the + (sub-)session) while a credit re-authorization is already ongoing for + some of the services or rating-groups. In this case, the client + acknowledges the server request with an RAA message and MUST send a + new Credit-Control-Request message to perform re-authorization for + the remaining services/rating-groups. The Result-Code 2002 + (DIAMETER_LIMITED_SUCCESS) SHOULD be used in the RAA message to + indicate that an additional message (i.e., CCR message with value + UPDATE_REQUEST) is required to complete the procedure. The server + processes the received requests and returns an appropriate answer to + both requests. + + The above-defined procedures are enabled for each of the possibly + active Diameter credit-control sub-sessions. The server MAY request + re-authorization for an active sub-session by including the CC-Sub- + Session-Id AVP in the RAR message in addition to the Session-Id AVP. + +5.6. Graceful Service Termination + + When the user's account runs out of money, the user may not be + allowed to compile additional chargeable events. However, the home + service provider may offer some services; for instance, access to a + service portal where it is possible to refill the account, for which + the user is allowed to benefit for a limited time. The length of + this time is usually dependent on the home service provider policy. + + This section defines the optional graceful service termination + feature that MAY be supported by the credit-control server. Credit- + control client implementations MUST support the Final-Unit-Indication + with at least the teardown of the ongoing service session once the + subscriber has consumed all the final granted units. + + Where independent credit-control of multiple services in a single + credit-control (sub-)session is supported, it is possible to use the + graceful service termination for each of the services/rating-groups + independently. Naturally, the graceful service termination process + defined in the following sub-sections will apply to the specific + service/rating-group as requested by the server. + + In some service environments (e.g., NAS), the graceful service + termination may be used to redirect the subscriber to a service + portal for online balance refill or other services offered by the + home service provider. In this case, the graceful termination + process installs a set of packet filters to restrict the user's + + + +Hakala, et al. Standards Track [Page 32] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + access capability only to/from the specified destinations. All the + IP packets not matching the filters will be dropped or, possibly, + re-directed to the service portal. The user may also be sent an + appropriate notification as to why the access has been limited. + These actions may be communicated explicitly from the server to the + client or may be configured per-service at the client. Explicitly + signaled redirect or restrict instructions always take precedence + over configured ones. + + It is also possible use the graceful service termination to connect + the prepaid user to a top-up server that plays an announcement and + prompts the user to replenish the account. In this case, the + credit-control server sends only the address of the top-up server + where the prepaid user shall be connected after the final granted + units have been consumed. An example of this is given in Appendix A + (Flow VII). + + The credit-control server MAY initiate the graceful service + termination by including the Final-Unit-Indication AVP in the + Credit-Control-Answer to indicate that the message contains the final + units for the service. + + When the credit-control client receives the Final-Unit-Indication AVP + in the answer from the server, its behavior depends on the value + indicated in the Final-Unit-Action AVP. The server may request the + following actions: TERMINATE, REDIRECT, or RESTRICT_ACCESS. + + A following figure illustrates the graceful service termination + procedure described in the following sub-sections. + + + + + + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 33] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Diameter + End User Service Element AAA Server CC Server + (CC Client) + | Service Delivery | | | + |<----------------->| | | + | |CCR(Update,Used-Units) | + | |------------------->|CCR(Update,Used-Units) + | : | |------------------->| + | : | |CCA(Final-Unit,Action) + | : | |<-------------------| + | |CCA(Final-Unit,Action) | + | |<-------------------| | + | | | | + | : | | | + | : | | | + | : | | | + | /////////////// |CCR(Update,Used-Units) | + |/Final Units End/->|------------------->|CCR(Update,Used-Units) + |/Action and // | |------------------->| + |/Restrictions // | | CCA(Validity-Time)| + |/Start // | CCA(Validity-Time)|<-------------------| + | ///////////// |<-------------------| | + | : | | | + | : | | | + | Replenish Account +-------+ | + |<-------------------------------------------->|Account| | + | | | +-------+ | + | | | RAR | + | + | RAR |<===================| + | | |<===================| | + | | | RAA | | + | ///////////// | |===================>| RAA | + | /If supported / | | CCR(Update) |===================>| + | /by CC Server/ | |===================>| CCR(Update) | + | ///////////// | | |===================>| + | | | | CCA(Granted-Unit)| + | | | CCA(Granted-Unit)|<===================| + | Restrictions ->+ |<===================| | + | removed | | | + | : | | | + | OR | CCR(Update) | | + | Validity-Time ->|------------------->| CCR(Update) | + | expires | |------------------->| + | | | CCA(Granted-Unit)| + | | CCA(Granted-Unit)|<-------------------| + | Restrictions ->|<-------------------| | + | removed | | | + + + + +Hakala, et al. Standards Track [Page 34] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Figure 5: Optional graceful service termination procedure + +5.6.1. Terminate Action + + The Final-Unit-Indication AVP with Final-Unit-Action TERMINATE does + not include any other information. When the subscriber has consumed + the final granted units, the service element MUST terminate the + service. This is the default handling applicable whenever the + credit-control client receives an unsupported Final-Unit-Action value + and MUST be supported by all the Diameter credit-control client + implementations conforming to this specification. A final Credit- + Control-Request message to the credit-control server MUST be sent if + the Final-Unit-Indication AVP indicating action TERMINATE was present + at command level. The CC-Request-Type AVP in the request is set to + the value TERMINATION_REQUEST. + +5.6.2. Redirect Action + + The Final-Unit-Indication AVP with Final-Unit-Action REDIRECT + indicates to the service element supporting this action that, upon + consumption of the final granted units, the user MUST be re-directed + to the address specified in the Redirect-Server AVP as follows. + + The credit-control server sends the Redirect-Server AVP in the + Credit-Control-Answer message. In such a case, the service element + MUST redirect or connect the user to the destination specified in the + Redirect-Server AVP, if possible. When the end user is redirected + (by using protocols others than Diameter) to the specified server or + connected to the top-up server, an additional authorization (and + possibly authentication) may be needed before the subscriber can + replenish the account; however, this is out of the scope of this + specification. + + In addition to the Redirect-Server AVP, the credit-control server MAY + include one or more Restriction-Filter-Rule AVPs or one or more + Filter-Id AVPs in the Credit-Control-Answer message to enable the + user to access other services (for example, zero-rated services). In + such a case, the access device MUST drop all the packets not matching + the IP filters specified in the Credit-Control-Answer message and, if + possible, redirect the user to the destination specified in the + Redirect-Server AVP. + + An entity other than the credit-control server may provision the + access device with appropriate IP packet filters to be used in + conjunction with the Diameter credit-control application. This case + is considered in section 5.6.3. + + + + + +Hakala, et al. Standards Track [Page 35] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + When the final granted units have been consumed, the credit-control + client MUST perform an intermediate interrogation. The purpose of + this interrogation is to indicate to the credit-control server that + the specified action started and to report the used units. The + credit-control server MUST deduct the used amount from the end user's + account but MUST NOT make a new credit reservation. The credit- + control client, however, may send intermediate interrogations before + all the final granted units have been consumed for which rating and + money reservation may be needed; for instance, upon Validity-Time + expires or upon mid-session service events that affect the rating of + the current service. Therefore, the credit-control client MUST NOT + include any rating related AVP in the request sent once all the final + granted units have been consumed as an indication to the server that + the requested final unit action started, rating and money reservation + are not required (when the Multiple-Services-Credit-Control AVP is + used, the Service-Identifier or Rating-Group AVPs is included to + indicate the concerned services). Naturally, the Credit-Control- + Answer message does not contain any granted service unit and MUST + include the Validity-Time AVP to indicate to the credit-control + client how long the subscriber is allowed to use network resources + before a new intermediate interrogation is sent to the server. + + At the expiry of Validity-Time, the credit-control client sends a + Credit-Control-Request (UPDATE_REQUEST) as usual. This message does + not include the Used-Service-Unit AVP, as there is no allotted quota + to report. The credit-control server processes the request and MUST + perform the credit reservation. If during this time the subscriber + did not replenish his/her account, whether he/she will be + disconnected or will be granted access to services not controlled by + a credit-control server for an unlimited time is dependent on the + home service provider policy (note: the latter option implies that + the service element should not remove the restriction filters upon + termination of the credit-control). The server will return the + appropriate Result-Code (see section 9.1) in the Credit-Control- + Answer message in order to implement the policy-defined action. + Otherwise, new quota will be returned, the service element MUST + remove all the possible restrictions activated by the graceful + service termination process and continue the credit-control session + and service session as usual. + + The credit-control client may not wait until the expiration of the + Validity-Time and may send a spontaneous update (a new Credit- + Control-Request) if the service element can determine, for instance, + that communication between the end user and the top-up server took + place. An example of this is given in Appendix A (Figure A.8). + + + + + + +Hakala, et al. Standards Track [Page 36] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Note that the credit-control server may already have initiated the + above-described process for the first interrogation. However, the + user's account might be empty when this first interrogation is + performed. In this case, the subscriber can be offered a chance to + replenish the account and continue the service. The credit-control + client receives a Credit-Control-Answer or service specific + authorization answer with the Final-Unit-Indication and Validity-Time + AVPs but no Granted-Service-Unit. It immediately starts the graceful + service termination without sending any message to the server. An + example of this case is illustrated in Appendix A. + +5.6.3. Restrict Access Action + + A Final-Unit-Indication AVP with the Final-Unit-Action + RESTRICT_ACCESS indicates to the device supporting this action that + the user's access MUST be restricted according to the IP packet + filters given in the Restriction-Filter-Rule AVP(s) or according to + the IP packet filters identified by the Filter-Id AVP(s). The + credit-control server SHOULD include either the Restriction-Filter- + Rule AVP or the Filter-Id AVP in the Credit-Control-Answer message. + + An entity other than the credit-control server may provision the + access device with appropriate IP packet filters to be used in + conjunction with the Diameter credit-control application. Such an + entity may, for instance, configure the access device with IP flows + to be passed when the Diameter credit-control application indicates + RESTRICT_ACCESS or REDIRECT. The access device passes IP packets + according to the filter rules that may have been received in the + Credit-Control-Answer message in addition to those that may have been + configured by the other entity. However, when the user's account + cannot cover the cost of the requested service, the action taken is + the responsibility of the credit-control server that controls the + prepaid subscriber. + + If another entity working in conjunction with the Diameter credit- + control application already provisions the access device with all the + required filter rules for the end user, the credit-control server + presumably need not send any additional filter. Therefore, it is + RECOMMENDED that credit-control server implementations supporting the + graceful service termination be configurable for sending the + Restriction-Filter-Rule AVP, the Filter-Id AVP, or none of the above. + + When the final granted units have been consumed, the credit-control + client MUST perform an intermediate interrogation. The credit- + control client and the credit-control server process this + intermediate interrogation and execute subsequent procedures, as + specified in the previous section for the REDIRECT action. + + + + +Hakala, et al. Standards Track [Page 37] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The credit-control server may initiate the graceful service + termination with action RESTRICT_ACCESS already for the first + interrogation, as specified in the previous section for the REDIRECT + action. + +5.6.4. Usage of the Server-Initiated Credit Re-Authorization + + Once the subscriber replenishes the account, she presumably expects + all the restrictions placed by the graceful termination procedure to + be removed immediately and unlimited service' access to be resumed. + For the best user experience, the credit-control server + implementation MAY support the server-initiated credit re- + authorization (see section 5.5). In such a case, upon the successful + account top-up, the credit-control server sends the Re-Auth-Request + (RAR) message to solicit the credit re-authorization. The credit- + control client initiates the credit re-authorization by sending the + Credit-Control-Request message with the CC-Request-Type AVP set to + the value UPDATE_REQUEST. The Used-Service-Unit AVP is not included + in the request, as there is no allotted quota to report. The + Requested-Service-Unit AVP MAY be included in the request. After the + credit-control client successfully receives the Credit-Control-Answer + with new Granted-Service-Unit, all the possible restrictions + activated for the purpose of the graceful service termination MUST be + removed in the service element. The credit-control session and the + service session continue as usual. + +5.7. Failure Procedures + + The Credit-Control-Failure-Handling AVP (CCFH), as described in this + section, determines the behavior of the credit-control client in + fault situations. The CCFH may be received from the Diameter home + AAA server, from the credit-control server, or may be configured + locally. The CCFH value received from the home AAA server overrides + the locally configured value. The CCFH value received from the + credit-control server in the Credit-Control-Answer message always + overrides any existing value. + + The authorization server MAY include the Accounting-Realtime-Required + AVP to determine what to do if the sending of accounting records to + the accounting server has been temporarily prevented, as defined in + [DIAMBASE]. It is RECOMMENDED that the client complement the + credit-control failure procedures with backup accounting flow toward + an accounting server. By using different combinations of + Accounting-Realtime-Required and Credit-Control-Failure-Handling + AVPs, different safety levels can be built. For example, by choosing + a Credit-Control-Failure-Handling AVP equal to CONTINUE for the + credit-control flow and a Accounting-Realtime-Required AVP equal to + DELIVER_AND_GRANT for the accounting flow, the service can be granted + + + +Hakala, et al. Standards Track [Page 38] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + to the end user even if the connection to the credit-control server + is down, as long as the accounting server is able to collect the + accounting information and information exchange is taking place + between the accounting server and credit-control server. + + As the credit-control application is based on real-time bi- + directional communication between the credit-control client and the + credit-control server, the usage of alternative destinations and the + buffering of messages may not be sufficient in the event of + communication failures. Because the credit-control server has to + maintain session states, moving the credit-control message stream to + a backup server requires a complex context transfer solution. + Whether the credit-control message stream is moved to a backup + credit-control server during an ongoing credit-control session + depends on the value of the CC-Session-Failover AVP. However, + failover may occur at any point in the path between the credit- + control client and the credit-control server if a transport failure + is detected with a peer, as described in [DIAMBASE]. As a + consequence, the credit-control server might receive duplicate + messages. These duplicates or out of sequence messages can be + detected in the credit-control server based on the credit-control + server session state machine (section 7), Session-Id AVP, and CC- + Request-Number AVP. + + If a failure occurs during an ongoing credit-control session, the + credit-control client may move the credit-control message stream to + an alternative server if the CC-server indicated FAILOVER_SUPPORTED + in the CC-Session-Failover AVP. A secondary credit-control server + name, either received from the home Diameter AAA server or configured + locally, can be used as an address of the backup server. If the CC- + Session-Failover AVP is set to FAILOVER_NOT_SUPPORTED, the credit- + control message stream MUST NOT be moved to a backup server. + + For new credit-control sessions, failover to an alternative credit- + control server SHOULD be performed if possible. For instance, if an + implementation of the credit-control client can determine primary + credit-control server unavailability, it can establish the new + credit-control sessions with a possibly available secondary credit- + control server. + + The AAA transport profile [AAATRANS] defines the application layer + watchdog algorithm that enables failover from a peer that has failed + and is controlled by a watchdog timer (Tw) defined in [AAATRANS]. + The recommended default initial value for Tw (Twinit) is 30 seconds. + Twinit may be set as low as 6 seconds; however, according to + [AAATRANS], setting too low a value for Twinit is likely to result in + an increased probability of duplicates, as well as an increase in + spurious failover and failback attempts. The Diameter base protocol + + + +Hakala, et al. Standards Track [Page 39] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + is common to several different types of Diameter AAA applications + that may be run in the same service element. Therefore, tuning the + timer Twinit to a lower value in order to satisfy the requirements of + real-time applications, such as the Diameter credit-control + application, will certainly cause the above mentioned problems. For + prepaid services, however, the end user expects an answer from the + network in a reasonable time. Thus, the Diameter credit-control + client will react faster than would the underlying base protocol. + Therefore this specification defines the timer Tx that is used by the + credit-control client (as defined in section 13) to supervise the + communication with the credit-control server. When the timer Tx + elapses, the credit-control client takes an action to the end user + according to the Credit-Control-Failure-Handling AVP. + + When Tx expires, the Diameter credit-control client always terminates + the service if the Credit-Control-Failure-Handling (CCFH) AVP is set + to the value TERMINATE. The credit-control session may be moved to + an alternative server only if a protocol error DIAMETER_TOO_BUSY or + DIAMETER_UNABLE_TO_DELIVER is received before Tx expires. Therefore, + the value TERMINATE is not appropriate if proper failover behavior is + desired. + + If the Credit-Control-Failure-Handling AVP is set to the value + CONTINUE or RETRY_AND_TERMINATE, the service will be granted to the + end user when the timer Tx expires. An answer message with granted- + units may arrive later if the base protocol transport failover + occurred in the path to the credit-control server. (The Twinit + default value is 3 times more than the Tx recommended value.) The + credit-control client SHOULD grant the service to the end user, start + monitoring the resource usage, and wait for the possible late answer + until the timeout of the request (e.g., 120 seconds). If the request + fails and the CC-Session-Failover AVP is set to + FAILOVER_NOT_SUPPORTED, the credit-control client terminates or + continues the service depending on the value set in the CCFH and MUST + free all the reserved resources for the credit-control session. If + the protocol error DIAMETER_UNABLE_TO_DELIVER or DIAMETER_TOO_BUSY is + received or the request times out and the CC-Session-Failover AVP is + set to FAILOVER_SUPPORTED, the credit-control client MAY send the + request to a backup server, if possible. If the credit-control + client receives a successful answer from the backup server, it + continues the credit-control session with such a server. If the re- + transmitted request also fails, the credit-control client terminates + or continues the service depending on the value set in the CCFH and + MUST free all the reserved resources for the credit-control session. + + If a communication failure occurs during the graceful service + termination procedure, the service element SHOULD always terminate + the ongoing service session. + + + +Hakala, et al. Standards Track [Page 40] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + If the credit-control server detects a failure during an ongoing + credit-control session, it will terminate the credit-control session + and return the reserved units back to the end user's account. + + The supervision session timer Tcc (as defined in section 13) is used + in the credit-control server to supervise the credit-control session. + + In order to support failover between credit-control servers, + information transfer about the credit-control session and account + state SHOULD take place between the primary and the secondary + credit-control server. Implementations supporting the credit-control + session failover MUST also ensure proper detection of duplicate or + out of sequence messages. The communication between the servers is + regarded as an implementation issue and is outside of the scope of + this specification. + +6. One Time Event + + The one-time event is used when there is no need to maintain any + state in the Diameter credit-control server; for example, enquiring + about the price of the service. The use of a one-time event implies + that the user has been authenticated and authorized beforehand. + + The one time event can be used when the credit-control client wants + to know the cost of the service event or to check the account balance + without any credit-reservation. It can also be used for refunding + service units on the user's account or for direct debiting without + any credit-reservation. The one time event is shown in Figure 6. + + Diameter + End User Service Element AAA Server CC Server + (CC Client) + | Service Request | | | + |------------------>| | | + | | CCR(Event) | | + | |------------------->| CCR(Event) | + | | |------------------->| + | | | CCA(Granted-Units)| + | | CCA(Granted-Units)|<-------------------| + | Service Delivery |<-------------------| | + |<----------------->| | | + + Figure 6: One time event + + In environments such as the 3GPP architecture, the one time event can + be sent from the service element directly to the credit-control + server. + + + + +Hakala, et al. Standards Track [Page 41] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +6.1. Service Price Enquiry + + The credit-control client may need to know the price of the service + event. Services offered by application service providers whose + prices are not known in the credit-control client might exist. The + end user might also want to get an estimation of the price of a + service event before requesting it. + + A Diameter credit-control client requesting the cost information MUST + set the CC-Request-Type AVP equal to EVENT_REQUEST, include the + Requested-Action AVP set to PRICE_ENQUIRY, and set the requested + service event information into the Service-Identifier AVP in the + Credit-Control-Request message. Additional service event information + may be sent as service specific AVPs or within the Service- + Parameter-Info AVP. The Service-Context-Id AVP indicates the service + specific document applicable to the request. + + The credit-control server calculates the cost of the requested + service event, but it does not perform any account balance check or + credit-reservation from the account. + + The estimated cost of the requested service event is returned to the + credit-control client in the Cost-Information AVP in the Credit- + Control-Answer message. + +6.2. Balance Check + + The Diameter credit-control client may only have to verify that the + end user's account balance covers the cost of a certain service + without reserving any units from the account at the time of the + inquiry. This method does not guarantee that credit would be left + when the Diameter credit-control client requests the debiting of the + account with a separate request. + + A Diameter credit-control client requesting the balance check MUST + set the CC-Request-Type AVP equal to EVENT_REQUEST, include a + Requested-Action AVP set to CHECK_BALANCE, and include the + Subscription-Id AVP in order to identify the end user in the credit- + control server. The Service-Context-Id AVP indicates the service + specific document applicable to the request. + + The credit-control server makes the balance check, but it does not + make any credit-reservation from the account. + + The result of balance check (ENOUGH_CREDIT/NO_CREDIT) is returned to + the credit-control client in the Check-Balance-Result AVP in the + Credit-Control-Answer message. + + + + +Hakala, et al. Standards Track [Page 42] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +6.3. Direct Debiting + + There are certain service events for which service execution is + always successful in the service environment. The delay between the + service invocation and the actual service delivery to the end user + can be sufficiently long that the use of the session-based credit- + control would lead to unreasonably long credit-control sessions. In + these cases, the Diameter credit-control client can use the one-time + event scenario for direct debiting. The Diameter credit-control + client SHOULD be sure that the requested service event execution + would be successful when this scenario is used. + + In the Credit-Control-Request message, the CC-Request-Type is set to + the value EVENT_REQUEST and the Requested-Action AVP is set to + DIRECT_DEBITING. The Subscription-Id AVP SHOULD be included to + identify the end user in the credit-control server. The Event- + Timestamp AVP SHOULD be included in the request and contain the time + when the service event is requested in the service element. The + Service-Context-Id AVP indicates the service specific document + applicable to the request. + + The Diameter credit-control client MAY include the monetary amount to + be charged in the Requested-Service-Unit AVP, if it knows the cost of + the service event. If the Diameter credit-control client does not + know the cost of the service event, the Requested-Service-Unit AVP + MAY contain the number of requested service events. The Service- + Identifier AVP always indicates the service concerned. Additional + service event information to be rated MAY be sent as service specific + AVPs or within the Service-Parameter-Info AVP. + + The credit-control server SHOULD rate the service event and deduct + the corresponding monetary amount from the end user's account. If + the type of the Requested-Service-Unit AVP is money, no rating is + needed, but the corresponding monetary amount is deducted from the + end user's account. + + The credit-control server returns the Granted-Service-Unit AVP in the + Credit-Control-Answer message to the Diameter credit-control client. + The Granted-Service-Unit AVP contains the amount of service units + that the Diameter credit-control client can provide to the end user. + The type of the Granted-Service-Unit can be time, volume, service + specific, or money, depending on the type of service event. + + If the credit-control server determines that no credit-control is + needed for the service, it can include the result code indicating + that the credit-control is not applicable (e.g., service is free of + charge). + + + + +Hakala, et al. Standards Track [Page 43] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + For informative purposes, the Credit-Control-Answer message MAY also + include the Cost-Information AVP containing the estimated total cost + of the requested service. + +6.4. Refund + + Some services may refund service units to the end user's account; for + example, gaming services. + + The credit-control client MUST set CC-Request-Type to the value + EVENT_REQUEST and the Requested-Action AVP to REFUND_ACCOUNT in the + Credit-Control-Request message. The Subscription-Id AVP SHOULD be + included to identify the end user in the credit-control server. The + Service-Context-Id AVP indicates the service specific document + applicable to the request. + + The Diameter credit-control client MAY include the monetary amount to + be refunded in the Requested-Service-Unit AVP. The Service- + Identifier AVP always indicates the concerned service. If the + Diameter credit-control client does not know the monetary amount to + be refunded, in addition to the Service-Identifier AVP it MAY send + service specific AVPs or the Service-Parameter-Info AVP containing + additional service event information to be rated. + + For informative purposes, the Credit-Control-Answer message MAY also + include the Cost-Information AVP containing the estimated monetary + amount of refunded unit. + +6.5. Failure Procedure + + Failover to an alternative credit-control server is allowed for a one + time event, as the server is not maintaining session states. For + instance, if the credit-control client receives a protocol error + DIAMETER_UNABLE_TO_DELIVER or DIAMETER_TOO_BUSY, it can re-send the + request to an alternative server, if possible. There MAY be protocol + transparent Diameter relays and redirect agents or Diameter credit- + control proxies between the credit-control client and credit-control + server. Failover may occur at any point in the path between the + credit-control client and the credit-control server if a transport + failure is detected with a peer, as described in [DIAMBASE]. Because + there can be duplicate requests for various reasons, the credit- + control server is responsible for real time duplicate detection. + Implementation issues for duplicate detection are discussed in + [DIAMBASE], Appendix C. + + When the credit-control client detects a communication failure with + the credit-control server, its behavior depends on the requested + action. The timer Tx (as defined in section 13) is used in the + + + +Hakala, et al. Standards Track [Page 44] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + credit-control client to supervise the communication with the + credit-control server. + + If the requested action is PRICE_ENQUIRY or CHECK_BALANCE and + communication failure is detected, the credit-control client SHOULD + forward the request messages to an alternative credit-control server, + if possible. The secondary credit-control server name, if received + from the home Diameter AAA server, can be used as an address of + backup server. + + If the requested action is DIRECT_DEBITING, the Direct-Debiting- + Failure-Handling AVP (DDFH) controls the credit-control client's + behavior. The DDFH may be received from the home Diameter AAA server + or may be locally configured. The credit-control server may also + send the DDFH in any CCA message to be used for direct debiting + events compiled thereafter. The DDFH value received from the home + Diameter AAA server overrides the locally configured value, and the + DDFH value received from the credit-control server in a Credit- + Control-Answer message always overrides any existing value. + + If the DDFH is set to TERMINATE_OR_BUFFER, the credit-control client + SHOULD NOT grant the service if it can determine, eventually after a + possible re-transmission attempt to an alternative credit-control + server, from the result code or error code in the answer message that + units have not been debited. Otherwise, the credit-control client + SHOULD grant the service to the end user and store the request in the + credit-control application level non-volatile storage. (Note that + re-sending the request at a later time is not a guarantee that the + service will be debited, as the user's account may be empty when the + server successfully processes the request.) The credit-control + client MUST mark these request messages as possible duplicates by + setting the T-flag in the command header as described in [DIAMBASE], + section 3. + + If the Direct-Debiting-Failure-Handling AVP is set to CONTINUE, the + service SHOULD be granted, even if credit-control messages cannot be + delivered and messages are not buffered. + + If the timer Tx expires, the credit-control client MUST continue the + service and wait for a possible late answer. If the request times + out, the credit-control client re-transmits the request (marked with + T-flag) to a backup credit-control server, if possible. If the re- + transmitted request also times out, or if a temporary error is + received in answer, the credit-control client buffers the request if + the value of the Direct-Debiting-Failure-Handling AVP is set to + TERMINATE_OR_BUFFER. If a failed answer is received for the + + + + + +Hakala, et al. Standards Track [Page 45] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + re-transmitted request, the credit-control client frees all the + resources reserved for the event message and deletes the request + regardless of the value of the DDFH. + + The Credit-Control-Request with the requested action REFUND_ACCOUNT + should always be stored in the credit-control application level non- + volatile storage in case of temporary failure. The credit-control + client MUST mark the re-transmitted request message as a possible + duplicate by setting the T-flag in the command header as described in + [DIAMBASE], section 3. + + For stored requests, the implementation may choose to limit the + number of re-transmission attempts and to define a re-transmission + interval. + + Note that only one place in the credit-control system SHOULD be + responsible for duplicate detection. If there is only one credit- + control server within the given realm, the credit-control server may + perform duplicate detection. If there is more than one credit- + control server in a given realm, only one entity in the credit- + control system should be responsible, to ensure that the end user's + account is not debited or credited multiple times for the same + service event. + +7. Credit-Control Application State Machine + + This section defines the credit-control application state machine. + + The first four state machines are to be observed by credit-control + clients. The first one describes the session-based credit-control + when the first interrogation is executed as part of the + authorization/authentication process. The second describes the + session-based credit-control when the first interrogation is executed + after the authorization/authentication process. The requirements as + to what state machines have to be supported are discussed in section + 5.2. + + The third state machine describes the session-based credit-control + for the intermediate and final interrogations. The fourth one + describes the event-based credit-control. These latter state + machines are to be observed by all implementations that conform to + this specification. + + The fifth state machine describes the credit-control session from a + credit-control server perspective. + + + + + + +Hakala, et al. Standards Track [Page 46] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Any event not listed in the state machines MUST be considered an + error condition, and a corresponding answer, if applicable, MUST be + returned to the originator of the message. + + In the state table, the event 'Failure to send' means that the + Diameter credit-control client is unable to communicate with the + desired destination or, if failover procedure is supported, with a + possibly defined alternative destination (e.g., the request times out + and the answer message is not received). This could be due to the + peer being down, or due to a physical link failure in the path to or + from the credit-control server. + + The event 'Temporary error' means that the Diameter credit-control + client received a protocol error notification (DIAMETER_TOO_BUSY, + DIAMETER_UNABLE_TO_DELIVER, or DIAMETER_LOOP_DETECTED) in the + Result-Code AVP of the Credit-Control-Answer command. The above + protocol error notification may ultimately be received in answer to + the re-transmitted request to a defined alternative destination, if + failover is supported. + + The event 'Failed answer' means that the Diameter credit-control + client received non-transient failure (permanent failure) + notification in the Credit-Control-Answer command. The above + permanent failure notification may ultimately be received in answer + to the re-transmitted request to a defined alternative destination, + if failover is supported. + + The action 'store request' means that a request is stored in the + credit-control application level non-volatile storage. + + The event 'Not successfully processed' means that the credit-control + server could not process the message; e.g., due to an unknown end + user, account being empty, or errors defined in [DIAMBASE]. + + The event 'User service terminated' can be triggered by various + reasons, e.g., normal user termination, network failure, and ASR + (Abort-Session-Request). The Termination-Cause AVP contains + information about the termination reason, as specified in [DIAMBASE]. + + The Tx timer, which is used to control the waiting time in the + credit-control client in the Pending state, is stopped upon exit of + the Pending state. The stopping of the Tx timer is omitted in the + state machine when the new state is Idle, as moving to Idle state + implies the clearing of the session and all the variables associated + to it. + + + + + + +Hakala, et al. Standards Track [Page 47] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The states PendingI, PendingU, PendingT, PendingE, and PendingB stand + for pending states to wait for an answer to a credit-control request + related to Initial, Update, Termination, Event, or Buffered request, + respectively. + + The acronyms CCFH and DDFH stand for Credit-Control-Failure-Handling + and Direct-Debiting-Failure-Handling, respectively. + + In the following state machine table, the failover to a secondary + server upon 'Temporary error' or 'Failure to send' is not explicitly + described. Moving an ongoing credit-control message stream to an + alternative server is, however, possible if the CC-Session-Failover + AVP is set to FAILOVER_SUPPORTED, as described in section 5.7. + + Re-sending a credit-control event to an alternative server is + supported as described in section 6.5. + + CLIENT, SESSION BASED for the first interrogation with AA request + + State Event Action New State + --------------------------------------------------------------- + Idle Client or device requests Send PendingI + access/service AA request + with added + CC AVPs, + start Tx + + PendingI Successful AA req. Grant Open + answer received service to + end user, + stop Tx + + PendingI Tx expired Disconnect Idle + user/dev + + PendingI Failed AA answer received Disconnect Idle + user/dev + + PendingI AA answer Grant Idle + received with result code service + equal to CREDIT_CONTROL_ to end user + NOT_APPLICABLE + + PendingI User service terminated Queue PendingI + termination + event + + + + + +Hakala, et al. Standards Track [Page 48] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + PendingI Change in rating condition Queue PendingI + changed + rating + condition + event + + CLIENT, SESSION BASED for the first interrogation with CCR + + State Event Action New State + ---------------------------------------------------------------- + + + Idle Client or device requests Send PendingI + access/service CC initial + req., + start Tx + + PendingI Successful CC initial Stop Tx Open + answer received + + PendingI Failure to send, or Grant Idle + temporary error and service to + CCFH equal to CONTINUE end user + + PendingI Failure to send, or Terminate Idle + temporary error and end user's + CCFH equal to TERMINATE service + or to RETRY_AND_TERMINATE + + PendingI Tx expired and CCFH Terminate Idle + equal to TERMINATE end user's + service + + PendingI Tx expired and CCFH equal Grant PendingI + to CONTINUE or to service to + RETRY_AND_TERMINATE end user + + PendingI CC initial answer Terminate Idle + received with result code end user's + END_USER_SERVICE_DENIED or service + USER_UNKNOWN + + PendingI CC initial answer Grant Idle + received with result code service + equal to CREDIT_CONTROL_ to end user + NOT_APPLICABLE + + + + + +Hakala, et al. Standards Track [Page 49] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + PendingI Failed CC initial answer Grant Idle + received and CCFH equal to service to + CONTINUE end user + + PendingI Failed CC initial answer Terminate Idle + received and CCFH equal end user's + to TERMINATE or to service + RETRY_AND_TERMINATE + + PendingI User service terminated Queue PendingI + termination + event + + PendingI Change in rating condition Queue PendingI + changed + rating + condition + event + + CLIENT, SESSION BASED for intermediate and final interrogations + + State Event Action New State + ---------------------------------------------------------------- + + Open Granted unit elapses Send PendingU + and no final unit CC update + indication received req., + start Tx + + Open Granted unit elapses Terminate PendingT + and final unit action end user's + equal to TERMINATE service, send + received CC termination + req. + + Open Change in rating condition Send PendingU + in queue CC update + req., + Start Tx + + Open Service terminated in queue Send PendingT + CC termination + req. + + Open Change in rating condition Send PendingU + or Validity-Time elapses CC update + req., + Start Tx + + + +Hakala, et al. Standards Track [Page 50] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Open User service terminated Send PendingT + CC termination + req. + + Open RAR received Send RAA PendingU + followed by + CC update req., + start Tx + + PendingU Successful CC update Stop Tx Open + answer received + + PendingU Failure to send, or Grant Idle + temporary error and service to + CCFH equal to CONTINUE end user + + PendingU Failure to send, or Terminate Idle + temporary error and end user's + CCFH equal to TERMINATE service + or to RETRY_AND_TERMINATE + + PendingU Tx expired and CCFH Terminate Idle + equal to TERMINATE end user's + service + + PendingU Tx expired and CCFH equal Grant PendingU + to CONTINUE or to service to + RETRY_AND_TERMINATE end user + + PendingU CC update answer Terminate Idle + received with result code end user's + END_USER_SERVICE_DENIED service + + PendingU CC update answer Grant Idle + received with result code service + equal to CREDIT_CONTROL_ to end user + NOT_APPLICABLE + + PendingU Failed CC update Grant Idle + answer received and service to + CCFH equal to CONTINUE end user + + PendingU Failed CC update Terminate Idle + answer received and CCFH end user's + equal to TERMINATE or service + to RETRY_AND_TERMINATE + + + + + +Hakala, et al. Standards Track [Page 51] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + PendingU User service terminated Queue PendingU + termination + event + + PendingU Change in rating Queue PendingU + condition changed + rating + condition + event + + PendingU RAR received Send RAA PendingU + + PendingT Successful CC Idle + termination answer received + + PendingT Failure to send, temporary Idle + error, or failed answer + + PendingT Change in rating condition PendingT + + CLIENT, EVENT BASED + + State Event Action New State + ---------------------------------------------------------------- + Idle Client or device requests Send PendingE + a one-time service CC event + req., + Start Tx + + Idle Request in storage Send PendingB + stored + request + + PendingE Successful CC event Grant Idle + answer received service to + end user + + PendingE Failure to send, temporary Indicate Idle + error, failed CC event service + answer received, or error + Tx expired; requested + action CHECK_BALANCE or + PRICE_ENQUIRY + + PendingE CC event answer Terminate Idle + received with result code end user's + END_USER_SERVICE_DENIED or service + USER_UNKNOWN and Tx running + + + +Hakala, et al. Standards Track [Page 52] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + PendingE CC event answer Grant Idle + received with result code service + CREDIT_CONTROL_NOT_APPLICABLE; to end + requested action user + DIRECT_DEBITING + + PendingE Failure to send, temporary Grant Idle + error, or failed CC event service + answer received; requested to end + action DIRECT_DEBITING; user + DDFH equal to CONTINUE + + PendingE Failed CC event Terminate Idle + answer received or temporary end user's + error; requested action service + DIRECT_DEBITING; + DDFH equal to + TERMINATE_OR_BUFFER and + Tx running + + PendingE Tx expired; requested Grant PendingE + action DIRECT_DEBITING service + to end + user + + PendingE Failure to send; requested Store Idle + action DIRECT_DEBITING; request with + DDFH equal to T-flag + TERMINATE_OR_BUFFER + + PendingE Temporary error; requested Store Idle + action DIRECT_DEBITING; request + DDFH equal to + TERMINATE_OR_BUFFER; + Tx expired + + PendingE Failed answer or answer Idle + received with result code + END_USER_SERVICE DENIED or + USER_UNKNOWN; requested action + DIRECT_DEBITING; Tx expired + + PendingE Failed CC event answer Indicate Idle + received; requested service + action REFUND_ACCOUNT error and + delete request + + + + + +Hakala, et al. Standards Track [Page 53] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + PendingE Failure to send or Store Idle + Tx expired; requested request + action REFUND_ACCOUNT with T-flag + + PendingE Temporary error, Store Idle + and requested action request + REFUND_ACCOUNT + + PendingB Successful CC answer Delete Idle + received request + + PendingB Failed CC answer Delete Idle + received request + + PendingB Failure to send or Idle + temporary error + + SERVER, SESSION AND EVENT BASED + + State Event Action New State + ---------------------------------------------------------------- + + Idle CC initial request Send Open + received and successfully CC initial + processed answer, + reserve units, + start Tcc + + Idle CC initial request Send Idle + received but not CC initial + successfully processed answer with + Result-Code + != SUCCESS + + Idle CC event request Send Idle + received and successfully CC event + processed answer + + Idle CC event request Send Idle + received but not CC event + successfully processed answer with + Result-Code + != SUCCESS + + + + + + + + +Hakala, et al. Standards Track [Page 54] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Open CC update request Send CC Open + received and successfully update answer, + processed debit used + units, + reserve + new units, + restart Tcc + + Open CC update request Send Idle + received but not CC update + successfully processed answer with + Result-Code + != SUCCESS, + debit used + units + + Open CC termination request Send Idle + received and successfully CC termin. + processed answer, + Stop Tcc, + debit used + units + + Open CC termination request Send Idle + received but not CC termin. + successfully processed answer with + Result-Code + != SUCCESS, + debit used + units + + Open Session supervision timer Tcc Release Idle + expired reserved + units + +8. Credit-Control AVPs + + This section defines the credit-control AVPs that are specific to + Diameter credit-control application and that MAY be included in the + Diameter credit-control messages. + + The AVPs defined in this section MAY also be included in + authorization commands defined in authorization-specific + applications, such as [NASREQ] and [DIAMMIP], if the first + interrogation is performed as part of the + authorization/authentication process, as described in section 5.2. + + + + + +Hakala, et al. Standards Track [Page 55] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The Diameter AVP rules are defined in the Diameter Base [DIAMBASE], + section 4. These AVP rules are observed in AVPs defined in this + section. + + The following table describes the Diameter AVPs defined in the + credit-control application, their AVP Code values, types, possible + flag values, and whether the AVP MAY be encrypted. The Diameter base + [DIAMBASE] specifies the AVP Flag rules for AVPs in section 4.5. + + +--------------------+ + | AVP Flag rules | + |----+-----+----+----|----+ + AVP Section | | |SHLD|MUST| | + Attribute Name Code Defined Data Type |MUST| MAY | NOT|NOT |Encr| + -----------------------------------------|----+-----+----+----|----| + CC-Correlation-Id 411 8.1 OctetString| | P,M | | V | Y | + CC-Input-Octets 412 8.24 Unsigned64 | M | P | | V | Y | + CC-Money 413 8.22 Grouped | M | P | | V | Y | + CC-Output-Octets 414 8.25 Unsigned64 | M | P | | V | Y | + CC-Request-Number 415 8.2 Unsigned32 | M | P | | V | Y | + CC-Request-Type 416 8.3 Enumerated | M | P | | V | Y | + CC-Service- 417 8.26 Unsigned64 | M | P | | V | Y | + Specific-Units | | | | | | + CC-Session- 418 8.4 Enumerated | M | P | | V | Y | + Failover | | | | | | + CC-Sub-Session-Id 419 8.5 Unsigned64 | M | P | | V | Y | + CC-Time 420 8.21 Unsigned32 | M | P | | V | Y | + CC-Total-Octets 421 8.23 Unsigned64 | M | P | | V | Y | + CC-Unit-Type 454 8.32 Enumerated | M | P | | V | Y | + Check-Balance- 422 8.6 Enumerated | M | P | | V | Y | + Result | | | | | | + Cost-Information 423 8.7 Grouped | M | P | | V | Y | + Cost-Unit 424 8.12 UTF8String | M | P | | V | Y | + Credit-Control 426 8.13 Enumerated | M | P | | V | Y | + Credit-Control- 427 8.14 Enumerated | M | P | | V | Y | + Failure-Handling | | | | | | + Currency-Code 425 8.11 Unsigned32 | M | P | | V | Y | + Direct-Debiting- 428 8.15 Enumerated | M | P | | V | Y | + Failure-Handling | | | | | | + Exponent 429 8.9 Integer32 | M | P | | V | Y | + Final-Unit-Action 449 8.35 Enumerated | M | P | | V | Y | + Final-Unit- 430 8.34 Grouped | M | P | | V | Y | + Indication | | | | | | + Granted-Service- 431 8.17 Grouped | M | P | | V | Y | + Unit | | | | | | + G-S-U-Pool- 453 8.31 Unsigned32 | M | P | | V | Y | + Identifier | | | | | | + + + + +Hakala, et al. Standards Track [Page 56] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + G-S-U-Pool- 457 8.30 Grouped | M | P | | V | Y | + Reference | | | | | | + Multiple-Services 456 8.16 Grouped | M | P | | V | Y | + -Credit-Control | | | | | | + Multiple-Services 455 8.40 Enumerated | M | P | | V | Y | + -Indicator | | | | | | + Rating-Group 432 8.29 Unsigned32 | M | P | | V | Y | + Redirect-Address 433 8.38 Enumerated | M | P | | V | Y | + -Type | | | | | | + Redirect-Server 434 8.37 Grouped | M | P | | V | Y | + Redirect-Server 435 8.39 UTF8String | M | P | | V | Y | + -Address | | | | | | + Requested-Action 436 8.41 Enumerated | M | P | | V | Y | + Requested-Service 437 8.18 Grouped | M | P | | V | Y | + -Unit | | | | | | + Restriction 438 8.36 IPFiltrRule| M | P | | V | Y | + -Filter-Rule | | | | | | + Service-Context 461 8.42 UTF8String | M | P | | V | Y | + -Id | | | | | | + Service- 439 8.28 Unsigned32 | M | P | | V | Y | + Identifier | | | | | | + Service-Parameter 440 8.43 Grouped | | P,M | | V | Y | + -Info | | | | | | + Service- 441 8.44 Unsigned32 | | P,M | | V | Y | + Parameter-Type | | | | | | + Service- 442 8.45 OctetString| | P,M | | V | Y | + Parameter-Value | | | | | | + Subscription-Id 443 8.46 Grouped | M | P | | V | Y | + Subscription-Id 444 8.48 UTF8String | M | P | | V | Y | + -Data | | | | | | + Subscription-Id 450 8.47 Enumerated | M | P | | V | Y | + -Type | | | | | | + Tariff-Change 452 8.27 Enumerated | M | P | | V | Y | + -Usage | | | | | | + Tariff-Time 451 8.20 Time | M | P | | V | Y | + -Change | | | | | | + Unit-Value 445 8.8 Grouped | M | P | | V | Y | + Used-Service-Unit 446 8.19 Grouped | M | P | | V | Y | + User-Equipment 458 8.49 Grouped | | P,M | | V | Y | + -Info | | | | | | + User-Equipment 459 8.50 Enumerated | | P,M | | V | Y | + -Info-Type | | | | | | + User-Equipment 460 8.51 OctetString| | P,M | | V | Y | + -Info-Value | | | | | | + Value-Digits 447 8.10 Integer64 | M | P | | V | Y | + Validity-Time 448 8.33 Unsigned32 | M | P | | V | Y | + + + + + +Hakala, et al. Standards Track [Page 57] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +8.1. CC-Correlation-Id AVP + + The CC-Correlation-Id AVP (AVP Code 411) is of type OctetString and + contains information to correlate credit-control requests generated + for different components of the service; e.g., transport and service + level. The one who allocates the Service-Context-Id (i.e., unique + identifier of a service specific document) is also responsible for + defining the content and encoding of the CC-Correlation-Id AVP. + +8.2. CC-Request-Number AVP + + The CC-Request-Number AVP (AVP Code 415) is of type Unsigned32 and + identifies this request within one session. As Session-Id AVPs are + globally unique, the combination of Session-Id and CC-Request-Number + AVPs is also globally unique and can be used in matching credit- + control messages with confirmations. An easy way to produce unique + numbers is to set the value to 0 for a credit-control request of type + INITIAL_REQUEST and EVENT_REQUEST and to set the value to 1 for the + first UPDATE_REQUEST, to 2 for the second, and so on until the value + for TERMINATION_REQUEST is one more than for the last UPDATE_REQUEST. + +8.3. CC-Request-Type AVP + + The CC-Request-Type AVP (AVP Code 416) is of type Enumerated and + contains the reason for sending the credit-control request message. + It MUST be present in all Credit-Control-Request messages. The + following values are defined for the CC-Request-Type AVP: + + INITIAL_REQUEST 1 + An Initial request is used to initiate a credit-control session, + and contains credit control information that is relevant to the + initiation. + + UPDATE_REQUEST 2 + An Update request contains credit-control information for an + existing credit-control session. Update credit-control requests + SHOULD be sent every time a credit-control re-authorization is + needed at the expiry of the allocated quota or validity time. + Further, additional service-specific events MAY trigger a + spontaneous Update request. + + TERMINATION_REQUEST 3 + A Termination request is sent to terminate a credit-control + session and contains credit-control information relevant to the + existing session. + + + + + + +Hakala, et al. Standards Track [Page 58] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + EVENT_REQUEST 4 + An Event request is used when there is no need to maintain any + credit-control session state in the credit-control server. This + request contains all information relevant to the service, and is + the only request of the service. The reason for the Event request + is further detailed in the Requested-Action AVP. The Requested- + Action AVP MUST be included in the Credit-Control-Request message + when CC-Request-Type is set to EVENT_REQUEST. + +8.4. CC-Session-Failover AVP + + The CC-Session-Failover AVP (AVP Code 418) is type of Enumerated and + contains information as to whether moving the credit-control message + stream to a backup server during an ongoing credit-control session is + supported. In communication failures, the credit-control message + streams can be moved to an alternative destination if the credit- + control server supports failover to an alternative server. The + secondary credit-control server name, if received from the home + Diameter AAA server, can be used as an address of the backup server. + An implementation is not required to support moving a credit-control + message stream to an alternative server, as this also requires moving + information related to the credit-control session to backup server. + + The following values are defined for the CC-Session-Failover AVP: + + FAILOVER_NOT_SUPPORTED 0 + When the CC-Session-Failover AVP is set to FAILOVER_NOT_SUPPORTED, + the credit-control message stream MUST NOT to be moved to an + alternative destination in the case of communication failure. + + This is the default behavior if the AVP isn't included in the + reply from the authorization or credit-control server. + + FAILOVER_SUPPORTED 1 + When the CC-Session-Failover AVP is set to FAILOVER_SUPPORTED, the + credit-control message stream SHOULD be moved to an alternative + destination in the case of communication failure. Moving the + credit-control message stream to a backup server MAY require that + information related to the credit-control session should also be + forwarded to alternative server. + +8.5. CC-Sub-Session-Id AVP + + The CC-Sub-Session-Id AVP (AVP Code 419) is of type Unsigned64 and + contains the credit-control sub-session identifier. The combination + of the Session-Id and this AVP MUST be unique per sub-session, and + + + + + +Hakala, et al. Standards Track [Page 59] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + the value of this AVP MUST be monotonically increased by one for all + new sub-sessions. The absence of this AVP implies that no sub- + sessions are in use. + +8.6. Check-Balance-Result AVP + + The Check Balance Result AVP (AVP Code 422) is of type Enumerated and + contains the result of the balance check. This AVP is applicable + only when the Requested-Action AVP indicates CHECK_BALANCE in the + Credit-Control-Request command. + + The following values are defined for the Check-Balance-Result AVP. + + ENOUGH_CREDIT 0 + There is enough credit in the account to cover the requested + service. + + NO_CREDIT 1 + There isn't enough credit in the account to cover the requested + service. + +8.7. Cost-Information AVP + + The Cost-Information AVP (AVP Code 423) is of type Grouped, and it is + used to return the cost information of a service, which the credit- + control client can transfer transparently to the end user. The + included Unit-Value AVP contains the cost estimate (always type of + money) of the service, in the case of price enquiry, or the + accumulated cost estimation, in the case of credit-control session. + + The Currency-Code specifies in which currency the cost was given. + The Cost-Unit specifies the unit when the service cost is a cost per + unit (e.g., cost for the service is $1 per minute). + + When the Requested-Action AVP with value PRICE_ENQUIRY is included in + the Credit-Control-Request command, the Cost-Information AVP sent in + the succeeding Credit-Control-Answer command contains the cost + estimation of the requested service, without any reservation being + made. + + The Cost-Information AVP included in the Credit-Control-Answer + command with the CC-Request-Type set to UPDATE_REQUEST contains the + accumulated cost estimation for the session, without taking any + credit reservation into account. + + + + + + + +Hakala, et al. Standards Track [Page 60] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The Cost-Information AVP included in the Credit-Control-Answer + command with the CC-Request-Type set to EVENT_REQUEST or + TERMINATION_REQUEST contains the estimated total cost for the + requested service. + + It is defined as follows (per the grouped-avp-def of + RFC 3588 [DIAMBASE]): + + Cost-Information ::= < AVP Header: 423 > + { Unit-Value } + { Currency-Code } + [ Cost-Unit ] + +8.8. Unit-Value AVP + + Unit-Value AVP is of type Grouped (AVP Code 445) and specifies the + units as decimal value. The Unit-Value is a value with an exponent; + i.e., Unit-Value = Value-Digits AVP * 10^Exponent. This + representation avoids unwanted rounding off. For example, the value + of 2,3 is represented as Value-Digits = 23 and Exponent = -1. The + absence of the exponent part MUST be interpreted as an exponent equal + to zero. + + It is defined as follows (per the grouped-avp-def of + RFC 3588 [DIAMBASE]): + + Unit-Value ::= < AVP Header: 445 > + { Value-Digits } + [ Exponent ] + +8.9. Exponent AVP + + Exponent AVP is of type Integer32 (AVP Code 429) and contains the + exponent value to be applied for the Value-Digit AVP within the + Unit-Value AVP. + +8.10. Value-Digits AVP + + The Value-Digits AVP is of type Integer64 (AVP Code 447) and contains + the significant digits of the number. If decimal values are needed + to present the units, the scaling MUST be indicated with the related + Exponent AVP. For example, for the monetary amount $ 0.05 the value + of Value-Digits AVP MUST be set to 5, and the scaling MUST be + indicated with the Exponent AVP set to -2. + + + + + + + +Hakala, et al. Standards Track [Page 61] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +8.11. Currency-Code AVP + + The Currency-Code AVP (AVP Code 425) is of type Unsigned32 and + contains a currency code that specifies in which currency the values + of AVPs containing monetary units were given. It is specified by + using the numeric values defined in the ISO 4217 standard [ISO4217]. + +8.12. Cost-Unit AVP + + The Cost-Unit AVP (AVP Code 424) is of type UTF8String, and it is + used to display a human readable string to the end user. It + specifies the applicable unit to the Cost-Information when the + service cost is a cost per unit (e.g., cost of the service is $1 per + minute). The Cost-Unit can be minutes, hours, days, kilobytes, + megabytes, etc. + +8.13. Credit-Control AVP + + The Credit-Control AVP (AVP Code 426) is of type Enumerated and MUST + be included in AA requests when the service element has credit- + control capabilities. + + CREDIT_AUTHORIZATION 0 + If the home Diameter AAA server determines that the user has + prepaid subscription, this value indicates that the credit-control + server MUST be contacted to perform the first interrogation. The + value of the Credit-Control AVP MUST always be set to 0 in an AA + request sent to perform the first interrogation and to initiate a + new credit-control session. + + RE_AUTHORIZATION 1 + This value indicates to the Diameter AAA server that a credit- + control session is ongoing for the subscriber and that the + credit-control server MUST not be contacted. The Credit-Control + AVP set to the value of 1 is to be used only when the first + interrogation has been successfully performed and the credit- + control session is ongoing (i.e., re-authorization triggered by + Authorization-Lifetime). This value MUST NOT be used in an AA + request sent to perform the first interrogation. + +8.14. Credit-Control-Failure-Handling AVP + + The Credit-Control-Failure-Handling AVP (AVP Code 427) is of type + Enumerated. The credit-control client uses information in this AVP + to decide what to do if sending credit-control messages to the + credit-control server has been, for instance, temporarily prevented + due to a network problem. Depending on the service logic, the + credit-control server can order the client to terminate the service + + + +Hakala, et al. Standards Track [Page 62] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + immediately when there is a reason to believe that the service cannot + be charged, or to try failover to an alternative server, if possible. + Then the server could either terminate or grant the service, should + the alternative connection also fail. + + TERMINATE 0 + When the Credit-Control-Failure-Handling AVP is set to TERMINATE, + the service MUST only be granted for as long as there is a + connection to the credit-control server. If the credit-control + client does not receive any Credit-Control-Answer message within + the Tx timer (as defined in section 13), the credit-control + request is regarded as failed, and the end user's service session + is terminated. + + This is the default behavior if the AVP isn't included in the + reply from the authorization or credit-control server. + + CONTINUE 1 + When the Credit-Control-Failure-Handling AVP is set to CONTINUE, + the credit-control client SHOULD re-send the request to an + alternative server in the case of transport or temporary failures, + provided that a failover procedure is supported in the credit- + control server and the credit-control client, and that an + alternative server is available. Otherwise, the service SHOULD be + granted, even if credit-control messages can't be delivered. + + RETRY_AND_TERMINATE 2 + When the Credit-Control-Failure-Handling AVP is set to + RETRY_AND_TERMINATE, the credit-control client SHOULD re-send the + request to an alternative server in the case of transport or + temporary failures, provided that a failover procedure is + supported in the credit-control server and the credit-control + client, and that an alternative server is available. Otherwise, + the service SHOULD not be granted when the credit-control messages + can't be delivered. + +8.15. Direct-Debiting-Failure-Handling AVP + + The Direct-Debiting-Failure-Handling AVP (AVP Code 428) is of type + Enumerated. The credit-control client uses information in this AVP + to decide what to do if sending credit-control messages (Requested- + Action AVP set to DIRECT_DEBITING) to the credit-control server has + been, for instance, temporarily prevented due to a network problem. + + TERMINATE_OR_BUFFER 0 + When the Direct-Debiting-Failure-Handling AVP is set to + TERMINATE_OR_BUFFER, the service MUST be granted for as long as + there is a connection to the credit-control server. If the + + + +Hakala, et al. Standards Track [Page 63] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + credit-control client does not receive any Credit-Control-Answer + message within the Tx timer (as defined in section 13) the + credit-control request is regarded as failed. The client SHOULD + terminate the service if it can determine from the failed answer + that units have not been debited. Otherwise the credit-control + client SHOULD grant the service, store the request in application + level non-volatile storage, and try to re-send the request. These + requests MUST be marked as possible duplicates by setting the T- + flag in the command header as described in [DIAMBASE] section 3. + + This is the default behavior if the AVP isn't included in the + reply from the authorization server. + + CONTINUE 1 + When the Direct-Debiting-Failure-Handling AVP is set to CONTINUE, + the service SHOULD be granted, even if credit-control messages + can't be delivered, and the request should be deleted. + +8.16. Multiple-Services-Credit-Control AVP + + Multiple-Services-Credit-Control AVP (AVP Code 456) is of type + Grouped and contains the AVPs related to the independent credit- + control of multiple services feature. Note that each instance of + this AVP carries units related to one or more services or related to + a single rating group. + + The Service-Identifier and the Rating-Group AVPs are used to + associate the granted units to a given service or rating group. If + both the Service-Identifier and the Rating-Group AVPs are included, + the target of the service units is always the service(s) indicated by + the value of the Service-Identifier AVP(s). If only the Rating- + Group-Id AVP is present, the Multiple-Services-Credit-Control AVP + relates to all the services that belong to the specified rating + group. + + The G-S-U-Pool-Reference AVP allows the server to specify a G-S-U- + Pool-Identifier identifying a credit pool within which the units of + the specified type are considered pooled. If a G-S-U-Pool-Reference + AVP is present, then actual service units of the specified type MUST + also be present. For example, if the G-S-U-Pool-Reference AVP + specifies Unit-Type TIME, then the CC-Time AVP MUST be present. + + The Requested-Service-Unit AVP MAY contain the amount of requested + service units or the requested monetary value. It MUST be present in + the initial interrogation and within the intermediate interrogations + in which new quota is requested. If the credit-control client does + not include the Requested-Service-Unit AVP in a request command, + because for instance, it has determined that the end-user terminated + + + +Hakala, et al. Standards Track [Page 64] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + the service, the server MUST debit the used amount from the user's + account but MUST NOT return a new quota in the corresponding answer. + The Validity-Time, Result-Code, and Final-Unit-Indication AVPs MAY be + present in an answer command as defined in sections 5.1.2 and 5.6 for + the graceful service termination. + + When both the Tariff-Time-Change and Tariff-Change-Usage AVPs are + present, the server MUST include two separate instances of the + Multiple-Services-Credit-Control AVP with the Granted-Service-Unit + AVP associated to the same service-identifier and/or rating-group. + Where the two quotas are associated to the same pool or to different + pools, the credit pooling mechanism defined in section 5.1.2 applies. + The Tariff-Change-Usage AVP MUST NOT be included in request commands + to report used units before, and after tariff time change the Used- + Service-Unit AVP MUST be used. + + A server not implementing the independent credit-control of multiple + services functionality MUST treat the Multiple-Services-Credit- + Control AVP as an invalid AVP. + + The Multiple-Services-Control AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [DIAMBASE]): + + Multiple-Services-Credit-Control ::= < AVP Header: 456 > + [ Granted-Service-Unit ] + [ Requested-Service-Unit ] + *[ Used-Service-Unit ] + [ Tariff-Change-Usage ] + *[ Service-Identifier ] + [ Rating-Group ] + *[ G-S-U-Pool-Reference ] + [ Validity-Time ] + [ Result-Code ] + [ Final-Unit-Indication ] + *[ AVP ] + +8.17. Granted-Service-Unit AVP + + Granted-Service-Unit AVP (AVP Code 431) is of type Grouped and + contains the amount of units that the Diameter credit-control client + can provide to the end user until the service must be released or the + new Credit-Control-Request must be sent. A client is not required to + implement all the unit types, and it must treat unknown or + unsupported unit types in the answer message as an incorrect CCA + answer. In this case, the client MUST terminate the credit-control + session and indicate in the Termination-Cause AVP reason + DIAMETER_BAD_ANSWER. + + + + +Hakala, et al. Standards Track [Page 65] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The Granted-Service-Unit AVP is defined as follows (per the grouped- + avp-def of RFC 3588 [DIAMBASE]): + + Granted-Service-Unit ::= < AVP Header: 431 > + [ Tariff-Time-Change ] + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + *[ AVP ] + +8.18. Requested-Service-Unit AVP + + The Requested-Service-Unit AVP (AVP Code 437) is of type Grouped and + contains the amount of requested units specified by the Diameter + credit-control client. A server is not required to implement all the + unit types, and it must treat unknown or unsupported unit types as + invalid AVPs. + + The Requested-Service-Unit AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [DIAMBASE]): + + Requested-Service-Unit ::= < AVP Header: 437 > + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + *[ AVP ] + +8.19. Used-Service-Unit AVP + + The Used-Service-Unit AVP is of type Grouped (AVP Code 446) and + contains the amount of used units measured from the point when the + service became active or, if interim interrogations are used during + the session, from the point when the previous measurement ended. + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 66] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The Used-Service-Unit AVP is defined as follows (per the grouped- + avp-def of RFC 3588 [DIAMBASE]): + + Used-Service-Unit ::= < AVP Header: 446 > + [ Tariff-Change-Usage ] + [ CC-Time ] + [ CC-Money ] + [ CC-Total-Octets ] + [ CC-Input-Octets ] + [ CC-Output-Octets ] + [ CC-Service-Specific-Units ] + *[ AVP ] + +8.20. Tariff-Time-Change AVP + + The Tariff-Time-Change AVP (AVP Code 451) is of type Time. It is + sent from the server to the client and includes the time in seconds + since January 1, 1900, 00:00 UTC, when the tariff of the service will + be changed. + + The tariff change mechanism is optional for the client and server, + and it is not used for time-based services defined in section 5. If + a client does not support the tariff time change mechanism, it MUST + treat Tariff-Time-Change AVP in the answer message as an incorrect + CCA answer. In this case, the client terminates the credit-control + session and indicates in the Termination-Cause AVP reason + DIAMETER_BAD_ANSWER. + + Omission of this AVP means that no tariff change is to be reported. + +8.21. CC-Time AVP + + The CC-Time AVP (AVP Code 420) is of type Unsigned32 and indicates + the length of the requested, granted, or used time in seconds. + +8.22. CC-Money AVP + + The CC-Money AVP (AVP Code 413) is of type Grouped and specifies the + monetary amount in the given currency. The Currency-Code AVP SHOULD + be included. It is defined as follows (per the grouped-avp-def of + RFC 3588 [DIAMBASE]): + + CC-Money ::= < AVP Header: 413 > + { Unit-Value } + [ Currency-Code ] + + + + + + +Hakala, et al. Standards Track [Page 67] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +8.23. CC-Total-Octets AVP + + The CC-Total-Octets AVP (AVP Code 421) is of type Unsigned64 and + contains the total number of requested, granted, or used octets + regardless of the direction (sent or received). + +8.24. CC-Input-Octets AVP + + The CC-Input-Octets AVP (AVP Code 412) is of type Unsigned64 and + contains the number of requested, granted, or used octets that can + be/have been received from the end user. + +8.25. CC-Output-Octets AVP + + The CC-Output-Octets AVP (AVP Code 414) is of type Unsigned64 and + contains the number of requested, granted, or used octets that can + be/have been sent to the end user. + +8.26. CC-Service-Specific-Units AVP + + The CC-Service-Specific-Units AVP (AVP Code 417) is of type + Unsigned64 and specifies the number of service-specific units (e.g., + number of events, points) given in a selected service. The service- + specific units always refer to the service identified in the + Service-Identifier AVP (or Rating-Group AVP when the Multiple- + Services-Credit-Control AVP is used). + +8.27. Tariff-Change-Usage AVP + + The Tariff-Change-Usage AVP (AVP Code 452) is of type Enumerated and + defines whether units are used before or after a tariff change, or + whether the units straddled a tariff change during the reporting + period. Omission of this AVP means that no tariff change has + occurred. + + In addition, when present in answer messages as part of the + Multiple-Services-Credit-Control AVP, this AVP defines whether units + are allocated to be used before or after a tariff change event. + + When the Tariff-Time-Change AVP is present, omission of this AVP in + answer messages means that the single quota mechanism applies. + + Tariff-Change-Usage can be one of the following: + + UNIT_BEFORE_TARIFF_CHANGE 0 + When present in the Multiple-Services-Credit-Control AVP, this + value indicates the amount of the units allocated for use before a + tariff change occurs. + + + +Hakala, et al. Standards Track [Page 68] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + When present in the Used-Service-Unit AVP, this value indicates + the amount of resource units used before a tariff change had + occurred. + + UNIT_AFTER_TARIFF_CHANGE 1 + When present in the Multiple-Services-Credit-Control AVP, this + value indicates the amount of the units allocated for use after a + tariff change occurs. + + When present in the Used-Service-Unit AVP, this value indicates + the amount of resource units used after tariff change had + occurred. + + UNIT_INDETERMINATE 2 + The used unit contains the amount of units that straddle the + tariff change (e.g., the metering process reports to the credit- + control client in blocks of n octets, and one block straddled the + tariff change). This value is to be used only in the Used- + Service-Unit AVP. + +8.28. Service-Identifier AVP + + The Service-Identifier AVP is of type Unsigned32 (AVP Code 439) and + contains the identifier of a service. The specific service the + request relates to is uniquely identified by the combination of + Service-Context-Id and Service-Identifier AVPs. + + A usage example of this AVP is illustrated in Appendix A (Flow IX). + +8.29. Rating-Group AVP + + The Rating-Group AVP is of type Unsigned32 (AVP Code 432) and + contains the identifier of a rating group. All the services subject + to the same rating type are part of the same rating group. The + specific rating group the request relates to is uniquely identified + by the combination of Service-Context-Id and Rating-Group AVPs. + + A usage example of this AVP is illustrated in Appendix A (Flow IX). + +8.30. G-S-U-Pool-Reference AVP + + The G-S-U-Pool-Reference AVP (AVP Code 457) is of type Grouped. It + is used in the Credit-Control-Answer message, and associates the + Granted-Service-Unit AVP within which it appears with a credit pool + within the session. + + The G-S-U-Pool-Identifier AVP specifies the credit pool from which + credit is drawn for this unit type. + + + +Hakala, et al. Standards Track [Page 69] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The CC-Unit-Type AVP specifies the type of units for which credit is + pooled. + + The Unit-Value AVP specifies the multiplier, which converts between + service units of type CC-Unit-Type and abstract service units within + the credit pool (and thus to service units of any other service or + rating group associated with the same pool). + + The G-S-U-Pool-Reference AVP is defined as follows (per the grouped- + avp-def of RFC 3588 [DIAMBASE]): + + G-S-U-Pool-Reference ::= < AVP Header: 457 > + { G-S-U-Pool-Identifier } + { CC-Unit-Type } + { Unit-Value } + +8.31. G-S-U-Pool-Identifier AVP + + The G-S-U-Pool-Identifier AVP (AVP Code 453) is of type Unsigned32 + and identifies a credit pool within the session. + +8.32. CC-Unit-Type AVP + + The CC-Unit-Type AVP (AVP Code 454) is of type Enumerated and + specifies the type of units considered to be pooled into a credit + pool. + + The following values are defined for the CC-Unit-Type AVP: + + TIME 0 + MONEY 1 + TOTAL-OCTETS 2 + INPUT-OCTETS 3 + OUTPUT-OCTETS 4 + SERVICE-SPECIFIC-UNITS 5 + +8.33. Validity-Time AVP + + The Validity-Time AVP is of type Unsigned32 (AVP Code 448). It is + sent from the credit-control server to the credit-control client. + The AVP contains the validity time of the granted service units. The + measurement of the Validity-Time is started upon receipt of the + Credit-Control-Answer Message containing this AVP. If the granted + service units have not been consumed within the validity time + specified in this AVP, the credit-control client MUST send a Credit- + Control-Request message to the server, with CC-Request-Type set to + UPDATE_REQUEST. The value field of the Validity-Time AVP is given in + seconds. + + + +Hakala, et al. Standards Track [Page 70] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The Validity-Time AVP is also used for the graceful service + termination (see section 5.6) to indicate to the credit-control + client how long the subscriber is allowed to use network resources + after the specified action (i.e., REDIRECT or RESTRICT_ACCESS) + started. When the Validity-Time elapses, a new intermediate + interrogation is sent to the server. + +8.34. Final-Unit-Indication AVP + + The Final-Unit-Indication AVP (AVP Code 430) is of type Grouped and + indicates that the Granted-Service-Unit AVP in the Credit-Control- + Answer, or in the AA answer, contains the final units for the + service. After these units have expired, the Diameter credit-control + client is responsible for executing the action indicated in the + Final-Unit-Action AVP (see section 5.6). + + If more than one unit type is received in the Credit-Control-Answer, + the unit type that first expired SHOULD cause the credit-control + client to execute the specified action. + + In the first interrogation, the Final-Unit-Indication AVP with + Final-Unit-Action REDIRECT or RESTRICT_ACCESS can also be present + with no Granted-Service-Unit AVP in the Credit-Control-Answer or in + the AA answer. This indicates to the Diameter credit-control client + to execute the specified action immediately. If the home service + provider policy is to terminate the service, naturally, the server + SHOULD return the appropriate transient failure (see section 9.1) in + order to implement the policy-defined action. + + The Final-Unit-Action AVP defines the behavior of the service element + when the user's account cannot cover the cost of the service and MUST + always be present if the Final-Unit-Indication AVP is included in a + command. + + If the Final-Unit-Action AVP is set to TERMINATE, no other AVPs MUST + be present. + + If the Final-Unit-Action AVP is set to REDIRECT at least the + Redirect-Server AVP MUST be present. The Restriction-Filter-Rule AVP + or the Filter-Id AVP MAY be present in the Credit-Control-Answer + message if the user is also allowed to access other services that are + not accessible through the address given in the Redirect-Server AVP. + + If the Final-Unit-Action AVP is set to RESTRICT_ACCESS, either the + Restriction-Filter-Rule AVP or the Filter-Id AVP SHOULD be present. + + + + + + +Hakala, et al. Standards Track [Page 71] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The Filter-Id AVP is defined in [NASREQ]. The Filter-Id AVP can be + used to reference an IP filter list installed in the access device by + means other than the Diameter credit-control application, e.g., + locally configured or configured by another entity. + + The Final-Unit-Indication AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [DIAMBASE]): + + Final-Unit-Indication ::= < AVP Header: 430 > + { Final-Unit-Action } + *[ Restriction-Filter-Rule ] + *[ Filter-Id ] + [ Redirect-Server ] + +8.35. Final-Unit-Action AVP + + The Final-Unit-Action AVP (AVP Code 449) is of type Enumerated and + indicates to the credit-control client the action to be taken when + the user's account cannot cover the service cost. + + The Final-Unit-Action can be one of the following: + + TERMINATE 0 + The credit-control client MUST terminate the service session. + This is the default handling, applicable whenever the credit- + control client receives an unsupported Final-Unit-Action value, + and it MUST be supported by all the Diameter credit-control client + implementations conforming to this specification. + + REDIRECT 1 + The service element MUST redirect the user to the address + specified in the Redirect-Server-Address AVP. The redirect action + is defined in section 5.6.2. + + RESTRICT_ACCESS 2 + The access device MUST restrict the user access according to the + IP packet filters defined in the Restriction-Filter-Rule AVP or + according to the IP packet filters identified by the Filter-Id + AVP. All the packets not matching the filters MUST be dropped + (see section 5.6.3). + +8.36. Restriction-Filter-Rule AVP + + The Restriction-Filter-Rule AVP (AVP Code 438) is of type + IPFilterRule and provides filter rules corresponding to services that + are to remain accessible even if there are no more service units + granted. The access device has to configure the specified filter + + + + +Hakala, et al. Standards Track [Page 72] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + rules for the subscriber and MUST drop all the packets not matching + these filters. Zero, one, or more such AVPs MAY be present in a + Credit-Control-Answer message or in an AA answer message. + +8.37. Redirect-Server AVP + + The Redirect-Server AVP (AVP Code 434) is of type Grouped and + contains the address information of the redirect server (e.g., HTTP + redirect server, SIP Server) with which the end user is to be + connected when the account cannot cover the service cost. It MUST be + present when the Final-Unit-Action AVP is set to REDIRECT. + + It is defined as follows (per the grouped-avp-def of RFC 3588 + [DIAMBASE]): + + Redirect-Server ::= < AVP Header: 434 > + { Redirect-Address-Type } + { Redirect-Server-Address } + +8.38. Redirect-Address-Type AVP + + The Redirect-Address-Type AVP (AVP Code 433) is of type Enumerated + and defines the address type of the address given in the Redirect- + Server-Address AVP. + + The address type can be one of the following: + + IPv4 Address 0 + The address type is in the form of "dotted-decimal" IPv4 address, + as defined in [IPv4]. + + IPv6 Address 1 + The address type is in the form of IPv6 address, as defined in + [IPv6Addr]. The address is a text representation of the address + in either the preferred or alternate text form [IPv6Addr]. + Conformant implementations MUST support the preferred form and + SHOULD support the alternate text form for IPv6 addresses. + + URL 2 + The address type is in the form of Uniform Resource Locator, as + defined in [URL]. + + SIP URI 3 + The address type is in the form of SIP Uniform Resource + Identifier, as defined in [SIP]. + + + + + + +Hakala, et al. Standards Track [Page 73] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +8.39. Redirect-Server-Address AVP + + The Redirect-Server-Address AVP (AVP Code 435) is of type UTF8String + and defines the address of the redirect server (e.g., HTTP redirect + server, SIP Server) with which the end user is to be connected when + the account cannot cover the service cost. + +8.40. Multiple-Services-Indicator AVP + + The Multiple-Services-Indicator AVP (AVP Code 455) is of type + Enumerated and indicates whether the Diameter credit-control client + is capable of handling multiple services independently within a + (sub-) session. The absence of this AVP means that independent + credit-control of multiple services is not supported. + + A server not implementing the independent credit-control of multiple + services MUST treat the Multiple-Services-Indicator AVP as an invalid + AVP. + + The following values are defined for the Multiple-Services-Indicator + AVP: + + MULTIPLE_SERVICES_NOT_SUPPORTED 0 + Client does not support independent credit-control of multiple + services within a (sub-)session. + + MULTIPLE_SERVICES_SUPPORTED 1 + Client supports independent credit-control of multiple services + within a (sub-)session. + +8.41. Requested-Action AVP + + The Requested-Action AVP (AVP Code 436) is of type Enumerated and + contains the requested action being sent by Credit-Control-Request + command where the CC-Request-Type is set to EVENT_REQUEST. The + following values are defined for the Requested-Action AVP: + + DIRECT_DEBITING 0 + This indicates a request to decrease the end user's account + according to information specified in the Requested-Service-Unit + AVP and/or Service-Identifier AVP (additional rating information + may be included in service-specific AVPs or in the Service- + Parameter-Info AVP). The Granted-Service-Unit AVP in the Credit- + Control-Answer command contains the debited units. + + + + + + + +Hakala, et al. Standards Track [Page 74] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + REFUND_ACCOUNT 1 + This indicates a request to increase the end user's account + according to information specified in the Requested-Service-Unit + AVP and/or Service-Identifier AVP (additional rating information + may be included in service-specific AVPs or in the Service- + Parameter-Info AVP). The Granted-Service-Unit AVP in the Credit- + Control-Answer command contains the refunded units. + + CHECK_BALANCE 2 + This indicates a balance check request. In this case, the + checking of the account balance is done without any credit + reservation from the account. The Check-Balance-Result AVP in the + Credit-Control-Answer command contains the result of the balance + check. + + PRICE_ENQUIRY 3 + This indicates a price enquiry request. In this case, neither + checking of the account balance nor reservation from the account + will be done; only the price of the service will be returned in + the Cost-Information AVP in the Credit-Control-Answer Command. + +8.42. Service-Context-Id AVP + + The Service-Context-Id AVP is of type UTF8String (AVP Code 461) and + contains a unique identifier of the Diameter credit-control service + specific document that applies to the request (as defined in section + 4.1.2). This is an identifier allocated by the service provider, by + the service element manufacturer, or by a standardization body, and + MUST uniquely identify a given Diameter credit-control service + specific document. The format of the Service-Context-Id is: + + "service-context" "@" "domain" + + service-context = Token + + The Token is an arbitrary string of characters and digits. + + 'domain' represents the entity that allocated the Service-Context-Id. + It can be ietf.org, 3gpp.org, etc., if the identifier is allocated by + a standardization body, or it can be the FQDN of the service provider + (e.g., provider.example.com) or of the vendor (e.g., + vendor.example.com) if the identifier is allocated by a private + entity. + + This AVP SHOULD be placed as close to the Diameter header as + possible. + + + + + +Hakala, et al. Standards Track [Page 75] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Service-specific documents that are for private use only (i.e., to + one provider's own use, where no interoperability is deemed useful) + may define private identifiers without need of coordination. + However, when interoperability is wanted, coordination of the + identifiers via, for example, publication of an informational RFC is + RECOMMENDED in order to make Service-Context-Id globally available. + +8.43. Service-Parameter-Info AVP + + The Service-Parameter-Info AVP (AVP Code 440) is of type Grouped and + contains service-specific information used for price calculation or + rating. The Service-Parameter-Type AVP defines the service parameter + type, and the Service-Parameter-Value AVP contains the parameter + value. The actual contents of these AVPs are not within the scope of + this document and SHOULD be defined in another Diameter application, + in standards written by other standardization bodies, or in service- + specific documentation. + + In the case of an unknown service request (e.g., unknown Service- + Parameter-Type), the corresponding answer message MUST contain the + error code DIAMETER_RATING_FAILED. A Credit-Control-Answer message + with this error MUST contain one or more Failed-AVP AVPs containing + the Service-Parameter-Info AVPs that caused the failure. + + It is defined as follows (per the grouped-avp-def of RFC 3588 + [DIAMBASE]): + + Service-Parameter-Info ::= < AVP Header: 440 > + { Service-Parameter-Type } + { Service-Parameter-Value } + +8.44. Service-Parameter-Type AVP + + The Service-Parameter-Type AVP is of type Unsigned32 (AVP Code 441) + and defines the type of the service event specific parameter (e.g., + it can be the end-user location or service name). The different + parameters and their types are service specific, and the meanings of + these parameters are not defined in this document. Whoever allocates + the Service-Context-Id (i.e., unique identifier of a service-specific + document) is also responsible for assigning Service-Parameter-Type + values for the service and ensuring their uniqueness within the given + service. The Service-Parameter-Value AVP contains the value + associated with the service parameter type. + + + + + + + + +Hakala, et al. Standards Track [Page 76] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +8.45. Service-Parameter-Value AVP + + The Service-Parameter-Value AVP is of type OctetString (AVP Code 442) + and contains the value of the service parameter type. + +8.46. Subscription-Id AVP + + The Subscription-Id AVP (AVP Code 443) is used to identify the end + user's subscription and is of type Grouped. The Subscription-Id AVP + includes a Subscription-Id-Data AVP that holds the identifier and a + Subscription-Id-Type AVP that defines the identifier type. + + It is defined as follows (per the grouped-avp-def of RFC 3588 + [DIAMBASE]): + + Subscription-Id ::= < AVP Header: 443 > + { Subscription-Id-Type } + { Subscription-Id-Data } + +8.47. Subscription-Id-Type AVP + + The Subscription-Id-Type AVP (AVP Code 450) is of type Enumerated, + and it is used to determine which type of identifier is carried by + the Subscription-Id AVP. + + This specification defines the following subscription identifiers. + However, new Subscription-Id-Type values can be assigned by an IANA + designated expert, as defined in section 12. A server MUST implement + all the Subscription-Id-Types required to perform credit + authorization for the services it supports, including possible future + values. Unknown or unsupported Subscription-Id-Types MUST be treated + according to the 'M' flag rule, as defined in [DIAMBASE]. + + END_USER_E164 0 + The identifier is in international E.164 format (e.g., MSISDN), + according to the ITU-T E.164 numbering plan defined in [E164] and + [CE164]. + + END_USER_IMSI 1 + The identifier is in international IMSI format, according to the + ITU-T E.212 numbering plan as defined in [E212] and [CE212]. + + END_USER_SIP_URI 2 + The identifier is in the form of a SIP URI, as defined in [SIP]. + + END_USER_NAI 3 + The identifier is in the form of a Network Access Identifier, as + defined in [NAI]. + + + +Hakala, et al. Standards Track [Page 77] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + END_USER_PRIVATE 4 + The Identifier is a credit-control server private identifier. + +8.48. Subscription-Id-Data AVP + + The Subscription-Id-Data AVP (AVP Code 444) is used to identify the + end user and is of type UTF8String. The Subscription-Id-Type AVP + defines which type of identifier is used. + +8.49. User-Equipment-Info AVP + + The User-Equipment-Info AVP (AVP Code 458) is of type Grouped and + allows the credit-control client to indicate the identity and + capability of the terminal the subscriber is using for the connection + to network. + + It is defined as follows (per the grouped-avp-def of RFC 3588 + [DIAMBASE]): + + User-Equipment-Info ::= < AVP Header: 458 > + { User-Equipment-Info-Type } + { User-Equipment-Info-Value } + +8.50. User-Equipment-Info-Type AVP + + The User-Equipment-Info-Type AVP is of type Enumerated (AVP Code + 459) and defines the type of user equipment information contained in + the User-Equipment-Info-Value AVP. + + This specification defines the following user equipment types. + However, new User-Equipment-Info-Type values can be assigned by an + IANA designated expert, as defined in section 12. + + IMEISV 0 + The identifier contains the International Mobile Equipment + Identifier and Software Version in the international IMEISV format + according to 3GPP TS 23.003 [3GPPIMEI]. + + MAC 1 + The 48-bit MAC address is formatted as described in [RAD802.1X]. + + EUI64 2 + The 64-bit identifier used to identify hardware instance of the + product, as defined in [EUI64]. + + + + + + + +Hakala, et al. Standards Track [Page 78] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + MODIFIED_EUI64 3 + There are a number of types of terminals that have identifiers + other than IMEI, IEEE 802 MACs, or EUI-64. These identifiers can + be converted to modified EUI-64 format as described in [IPv6Addr] + or by using some other methods referred to in the service-specific + documentation. + +8.51. User-Equipment-Info-Value AVP + + The User-Equipment-Info-Value AVP (AVP Code 460) is of type + OctetString. The User-Equipment-Info-Type AVP defines which type of + identifier is used. + +9. Result Code AVP Values + + This section defines new Result-Code AVP [DIAMBASE] values that must + be supported by all Diameter implementations that conform to this + specification. + + The Credit-Control-Answer message includes the Result-Code AVP, which + may indicate that an error was present in the Credit-Control-Request + message. A rejected Credit-Control-Request message SHOULD cause the + user's session to be terminated. + +9.1. Transient Failures + + Errors that fall within the transient failures category are used to + inform a peer that the request could not be satisfied at the time it + was received, but that the request MAY be able to be satisfied in the + future. + + DIAMETER_END_USER_SERVICE_DENIED 4010 + The credit-control server denies the service request due to + service restrictions. If the CCR contained used-service-units, + they are deducted, if possible. + + DIAMETER_CREDIT_CONTROL_NOT_APPLICABLE 4011 + The credit-control server determines that the service can be + granted to the end user but that no further credit-control is + needed for the service (e.g., service is free of charge). + + DIAMETER_CREDIT_LIMIT_REACHED 4012 + The credit-control server denies the service request because the + end user's account could not cover the requested service. If the + CCR contained used-service-units they are deducted, if possible. + + + + + + +Hakala, et al. Standards Track [Page 79] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +9.2. Permanent Failures + + Errors that fall within the permanent failure category are used to + inform the peer that the request failed and should not be attempted + again. + + DIAMETER_USER_UNKNOWN 5030 + The specified end user is unknown in the credit-control server. + + DIAMETER_RATING_FAILED 5031 + This error code is used to inform the credit-control client that + the credit-control server cannot rate the service request due to + insufficient rating input, an incorrect AVP combination, or an AVP + or an AVP value that is not recognized or supported in the rating. + The Failed-AVP AVP MUST be included and contain a copy of the + entire AVP(s) that could not be processed successfully or an + example of the missing AVP complete with the Vendor-Id if + applicable. The value field of the missing AVP should be of + correct minimum length and contain zeros. + +10. AVP Occurrence Table + + The following table presents the AVPs defined in this document and + specifies in which Diameter messages they MAY or MAY NOT be present. + Note that AVPs that can only be present within a Grouped AVP are not + represented in this table. + + The table uses the following symbols: + + 0 The AVP MUST NOT be present in the message. + 0+ Zero or more instances of the AVP MAY be present in the + message. + 0-1 Zero or one instance of the AVP MAY be present in the + message. It is considered an error if there is more + than one instance of the AVP. + 1 One instance of the AVP MUST be present in the message. + 1+ At least one instance of the AVP MUST be present in the + message. + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 80] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +10.1. Credit-Control AVP Table + + The table in this section is used to represent which credit-control + applications specific AVPs defined in this document are to be present + in the credit-control messages. + + +-----------+ + | Command | + | Code | + |-----+-----+ + Attribute Name | CCR | CCA | + ------------------------------|-----+-----+ + Acct-Multi-Session-Id | 0-1 | 0-1 | + Auth-Application-Id | 1 | 1 | + CC-Correlation-Id | 0-1 | 0 | + CC-Session-Failover | 0 | 0-1 | + CC-Request-Number | 1 | 1 | + CC-Request-Type | 1 | 1 | + CC-Sub-Session-Id | 0-1 | 0-1 | + Check-Balance-Result | 0 | 0-1 | + Cost-Information | 0 | 0-1 | + Credit-Control-Failure- | 0 | 0-1 | + Handling | | | + Destination-Host | 0-1 | 0 | + Destination-Realm | 1 | 0 | + Direct-Debiting-Failure- | 0 | 0-1 | + Handling | | | + Event-Timestamp | 0-1 | 0-1 | + Failed-AVP | 0 | 0+ | + Final-Unit-Indication | 0 | 0-1 | + Granted-Service-Unit | 0 | 0-1 | + Multiple-Services-Credit- | 0+ | 0+ | + Control | | | + Multiple-Services-Indicator | 0-1 | 0 | + Origin-Host | 1 | 1 | + Origin-Realm | 1 | 1 | + Origin-State-Id | 0-1 | 0-1 | + Proxy-Info | 0+ | 0+ | + Redirect-Host | 0 | 0+ | + Redirect-Host-Usage | 0 | 0-1 | + Redirect-Max-Cache-Time | 0 | 0-1 | + Requested-Action | 0-1 | 0 | + Requested-Service-Unit | 0-1 | 0 | + Route-Record | 0+ | 0+ | + Result-Code | 0 | 1 | + Service-Context-Id | 1 | 0 | + Service-Identifier | 0-1 | 0 | + Service-Parameter-Info | 0+ | 0 | + + + +Hakala, et al. Standards Track [Page 81] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Session-Id | 1 | 1 | + Subscription-Id | 0+ | 0 | + Termination-Cause | 0-1 | 0 | + User-Equipment-Info | 0-1 | 0 | + Used-Service-Unit | 0+ | 0 | + User-Name | 0-1 | 0-1 | + Validity-Time | 0 | 0-1 | + ------------------------------|-----+-----+ + +10.2. Re-Auth-Request/Answer AVP Table + + This section defines AVPs that are specific to the Diameter credit- + control application and that MAY be included in the Diameter Re- + Auth-Request/Answer (RAR/RAA) message [DIAMBASE]. + + Re-Auth-Request/Answer command MAY include the following additional + AVPs: + + +---------------+ + | Command Code | + |-------+-------+ + Attribute Name | RAR | RAA | + ------------------------------+-------+-------+ + CC-Sub-Session-Id | 0-1 | 0-1 | + G-S-U-Pool-Identifier | 0-1 | 0-1 | + Service-Identifier | 0-1 | 0-1 | + Rating-Group | 0-1 | 0-1 | + ------------------------------+-------+-------+ + +11. RADIUS/Diameter Credit-Control Interworking Model + + This section defines the basic principles for the Diameter credit- + control/RADIUS prepaid inter-working model; that is, a message + translation between a RADIUS based prepaid solution and a Diameter + credit-control application. A complete description of the protocol + translations between RADIUS and the Diameter credit-control + application is beyond the scope of this specification and SHOULD be + addressed in another appropriate document, such as the RADIUS prepaid + specification. + + The Diameter credit-control architecture may have a Translation Agent + capable of translation between RADIUS prepaid and Diameter credit- + control protocols. An AAA server (usually the home AAA server) may + act as a Translation Agent and as a Diameter credit-control client + for service elements that use credit-control mechanisms other than + Diameter credit control for instance, RADIUS prepaid. In this case, + the home AAA server contacts the Diameter credit-control server as + part of the authorization process. The interworking architecture is + + + +Hakala, et al. Standards Track [Page 82] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + illustrated in Figure 7, and interworking flow in Figure 8. In a + roaming situation the service element (e.g., the NAS) may be located + in the visited network, and a visited AAA server is usually + contacted. The visited AAA server connects then to the home AAA + server. + + RADIUS Prepaid + +--------+ +---------+ protocol +------------+ +--------+ + | End |<----->| Service |<---------->| Home AAA | |Business| + | User | | Element | | Server | |Support | + +--------+ +-->| | |+----------+|->|System | + | +---------+ ||CC Client || | | + | |+----------+| | | + +--------+ | +------^-----+ +----^---+ + | End |<--+ Credit-Control | | + | User | Protocol | | + +--------+ +-------V--------+ | + |Credit-Control |----+ + | Server | + +----------------+ + + Figure 7: Credit-control architecture with service element + containing translation agent, translating RADIUS + prepaid to Diameter credit-control protocol + + When the AAA server acting as a Translation Agent receives an initial + RADIUS Access-Request message from service element (e.g., NAS + access), it performs regular authentication and authorization. If + the RADIUS Access-Request message indicates that the service element + is capable of credit-control, and if the home AAA server finds that + the subscriber is a prepaid subscriber, then a Diameter credit- + control request SHOULD be sent toward the credit-control server to + perform credit authorization and to establish a credit-control + session. After the Diameter credit-control server checks the end + user's account balance, rates the service, and reserves credit from + the end user's account, the reserved quota is returned to the home + AAA server in the Diameter Credit-Control-Answer. Then the home AAA + server sends the reserved quota to the service element in the RADIUS + Access-Accept. + + At the expiry of the allocated quota, the service element sends a new + RADIUS Access-Request containing the units used this far to the home + AAA server. The home AAA server shall map a RADIUS Access-Request + containing the reported units to the Diameter credit-control server + in a Diameter Credit-Control-Request (UPDATE_REQUEST). The Diameter + credit-control server debits the used units from the end user's + account and allocates a new quota that is returned to the home AAA + server in the Diameter Credit-Control-Answer. The quota is + + + +Hakala, et al. Standards Track [Page 83] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + transferred to the service element in the RADIUS Access-Accept. When + the end user terminates the service, or when the entire quota has + been used, the service element sends a RADIUS Access-Request. To + debit the used units from the end user's account and to stop the + credit-control session, the home AAA server sends a Diameter Credit- + Control-Request (TERMINATION_REQUEST) to the credit-control server. + The Diameter credit-control server acknowledges the session + termination by sending a Diameter Credit-Control-Answer to the home + AAA server. The RADIUS Access-Accept is sent to the NAS. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 84] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + A following diagram illustrates a RADIUS prepaid - Diameter credit- + control interworking sequence. + + Service Element Translation Agent + (e.g., NAS) (CC Client) CC Server + | Access-Request | | + |----------------------->| | + | | CCR (initial) | + | |----------------------->| + | | CCA (Granted-Units) | + | |<-----------------------| + | Access-Accept | | + | (Granted-Units) | | + |<-----------------------| | + : : : + | Access-Request | | + | (Used-Units) | | + |----------------------->| | + | | CCR (update, | + | | Used-Units) | + | |----------------------->| + | | CCA (Granted-Units) | + | |<-----------------------| + | Access-Accept | | + | (Granted-Units) | | + |<-----------------------| | + : : : + | Access-Request | | + |----------------------->| | + | | CCR (terminate, | + | | Used-Units) | + | |----------------------->| + | | CCA | + | |<-----------------------| + | Access-Accept | | + |<-----------------------| | + | | | + + Figure 8: Message flow example with RADIUS prepaid - + Diameter credit-control interworking + +12. IANA Considerations + + This section contains the namespaces that have either been created in + this specification, or the values assigned to existing namespaces + managed by IANA. + + + + + +Hakala, et al. Standards Track [Page 85] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + In the subsections below, when we speak about review by a Designated + Expert, please note that the designated expert will be assigned by + the IESG. Initially, such Expert discussions take place on the AAA + WG mailing list. + +12.1. Application Identifier + + This specification assigns the value 4, 'Diameter Credit Control', to + the Application Identifier namespace defined in [DIAMBASE]. See + section 1.3 for more information. + +12.2. Command Codes + + This specification uses the value 272 from the Command code namespace + defined in [DIAMBASE] for the Credit-Control-Request (CCR) and + Credit-Control-Answer (CCA) commands. + +12.3. AVP Codes + + This specification assigns the values 411 - 461 from the AVP code + namespace defined in [DIAMBASE]. See section 8 for the assignment of + the namespace in this specification. + +12.4. Result-Code AVP Values + + This specification assigns the values 4010, 4011, 4012, 5030, 5031 + from the Result-Code AVP value namespace defined in [DIAMBASE]. See + section 9 for the assignment of the namespace in this specification. + +12.5. CC-Request-Type AVP + + As defined in section 8.3, the CC-Request-Type AVP includes + Enumerated type values 1 - 4. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +12.6. CC-Session-Failover AVP + + As defined in section 8.4, the CC-Failover-Supported AVP includes + Enumerated type values 0 - 1. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + + + + + + + + + +Hakala, et al. Standards Track [Page 86] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +12.7. CC-Unit-Type AVP + + As defined in section 8.32, the CC-Unit-Type AVP includes Enumerated + type values 0 - 5. IANA has created and is maintaining a namespace + for this AVP. All remaining values are available for assignment by a + Designated Expert [IANA]. + +12.8. Check-Balance-Result AVP + + As defined in section 8.6, the Check-Balance-Result AVP includes + Enumerated type values 0 - 1. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +12.9. Credit-Control AVP + + As defined in section 8.13, the Credit-Control AVP includes + Enumerated type values 0 - 1. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +12.10. Credit-Control-Failure-Handling AVP + + As defined in section 8.14, the Credit-Control-Failure-Handling AVP + includes Enumerated type values 0 - 2. IANA has created and is + maintaining a namespace for this AVP. All remaining values are + available for assignment by a Designated Expert [IANA]. + +12.11. Direct-Debiting-Failure-Handling AVP + + As defined in section 8.15, the Direct-Debiting-Failure-Handling AVP + includes Enumerated type values 0 - 1. IANA has created and is + maintaining a namespace for this AVP. All remaining values are + available for assignment by a Designated Expert [IANA]. + +12.12. Final-Unit-Action AVP + + As defined in section 8.35, the Final-Unit-Action AVP includes + Enumerated type values 0 - 2. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +12.13. Multiple-Services-Indicator AVP + + As defined in section 8.40, the Multiple-Services-Indicator AVP + includes Enumerated type values 0 - 1. IANA has created and is + maintaining a namespace for this AVP. All remaining values are + available for assignment by a Designated Expert [IANA]. + + + +Hakala, et al. Standards Track [Page 87] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +12.14. Redirect-Address-Type AVP + + As defined in section 8.38, the Redirect-Address-Type AVP includes + Enumerated type values 0 - 3. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +12.15. Requested-Action AVP + + As defined in section 8.41, the Requested-Action AVP includes + Enumerated type values 0 - 3. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +12.16. Subscription-Id-Type AVP + + As defined in section 8.47, the Subscription-Id-Type AVP includes + Enumerated type values 0 - 4. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +12.17. Tariff-Change-Usage AVP + + As defined in section 8.27, the Tariff-Change-Usage AVP includes + Enumerated type values 0 - 2. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +12.18. User-Equipment-Info-Type AVP + + As defined in section 8.50, the User-Equipment-Info-Type AVP includes + Enumerated type values 0 - 3. IANA has created and is maintaining a + namespace for this AVP. All remaining values are available for + assignment by a Designated Expert [IANA]. + +13. Credit-Control Application Related Parameters + + Tx timer + + When real-time credit-control is required, the credit-control + client contacts the credit-control server before and while the + service is provided to an end user. Due to the real-time nature + of the application, the communication delays SHOULD be minimized; + e.g., to avoid an overly long service setup time experienced by + the end user. The Tx timer is introduced to control the waiting + time in the client in the Pending state. When the Tx timer + elapses, the credit-control client takes an action to the end user + according to the value of the Credit-Control-Failure-Handling AVP + + + +Hakala, et al. Standards Track [Page 88] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + or Direct-Debiting-Failure-Handling AVP. The recommended value is + 10 seconds. + + Tcc timer + + The Tcc timer supervises an ongoing credit-control session in the + credit-control server. It is RECOMMENDED to use the Validity-Time + as input to set the Tcc timer value. In case of transient + failures in the network, the Diameter credit-control server might + change to Idle state. To avoid this, the Tcc timer MAY be set so + that Tcc equals to 2 x Validity-Time. + + Credit-Control-Failure-Handling and Direct-Debiting-Failure-Handling + + Client implementations may offer the possibility of locally + configuring these AVPs. In such a case their value and behavior + is defined in section 5.7 for the Credit-Control-Failure-Handling + and in section 6.5 for the Direct-Debiting-Failure-Handling. + +14. Security Considerations + + The Diameter base protocol [DIAMBASE] requires that each Diameter + implementation use underlying security; i.e., IPsec or TLS. These + mechanisms are believed to provide sufficient protection under the + normal Internet threat model; that is, assuming that the authorized + nodes engaging in the protocol have not been compromised, but that + the attacker has complete control over the communication channels + between them. This includes eavesdropping, message modification, + insertion, and man-in-the-middle and replay attacks. Note also that + this application includes a mechanism for application layer replay + protection by means of the Session-Id from [DIAMBASE] and CC- + Request-Number, which is specified in this document. The Diameter + credit-control application is often used within one domain, and there + may be a single hop between the peers. In these environments, the + use of TLS or IPsec is sufficient. The details of TLS and IPsec + related security considerations are discussed in the [DIAMBASE]. + + Because this application handles monetary transactions (directly or + indirectly), it increases the interest for various security attacks. + Therefore, all parties communicating with each other MUST be + authenticated, including, for instance, TLS client-side + authentication. In addition, authorization of the client SHOULD be + emphasized; i.e., that the client is allowed to perform credit- + control for a certain user. The specific means of authorization are + outside of the scope of this specification but can be, for instance, + manual configuration. + + + + + +Hakala, et al. Standards Track [Page 89] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Another kind of threat is malicious modification, injection, or + deletion of AVPs or complete credit-control messages. The credit- + control messages contain sensitive billing related information (such + as subscription Id, granted units, used units, cost information) + whose malicious modification can have financial consequences. + Sometimes simply delaying the credit-control messages can cause + disturbances in the credit-control client or server. + + Even without any modification to the messages, an adversary can + invite a security threat by eavesdropping, as the transactions + contain private information about the user. Also, by monitoring the + credit-control messages one can collect information about the + credit-control server's billing models and business relationships. + + When third-party relays or proxy are involved, the hop-by-hop + security does not necessarily provide sufficient protection for + Diameter user session. In some cases, it may be inappropriate to + send Diameter messages, such as CCR and CCA, containing sensitive + AVPs via untrusted Diameter proxy agents, as there are no assurances + that third-party proxies will not modify the credit-control commands + or AVP values. + +14.1. Direct Connection with Redirects + + A Diameter credit-control agent cannot always know whether agents + between it and the end user's Diameter credit-control server are + reliable. In this case, the Diameter credit-control agent doesn't + have a routing entry in its Diameter Routing Table (defined in + [DIAMBASE], section 2.7) for the realm of the credit-control server + in the end user's home domain. The Diameter credit-control agent can + have a default route configured to a local Redirect agent, and it + redirects the CCR message to the redirect agent. The local Redirect + agent then returns a redirect notification (Result-code 3006, + DIAMETER_REDIRECT_INDICATION) to the credit-control agent, as well as + Diameter credit-control server(s) information (Redirect-Host AVP) and + information (Redirect-Host-Usage AVP) about how the routing entry + resulting from the Redirect-Host is to be used. The Diameter + credit-control agent then forwards the CCR message directly to one of + the hosts identified by the CCA message from the redirect agent. If + the value of the Redirect-Host-Usage AVP is unequal to zero, all + following messages are sent to the host specified in the Redirect- + Host AVP until the time specified by the Redirect-Max-Cache-Time AVP + is expired. + + There are some authorization issues even with redirects. There may + be attacks toward nodes that have been properly authorized, but that + abuse their authorization or have been compromised. These issues are + discussed more widely in [DIAMEAP], section 8. + + + +Hakala, et al. Standards Track [Page 90] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +15. References + +15.1. Normative References + + [DIAMBASE] Calhoun, P., Loughney, J., Guttman, E., Zorn, G., and J. + Arkko, "Diameter Base Protocol", RFC 3588, September + 2003. + + [3GPPCHARG] 3rd Generation Partnership Project; Technical + Specification Group Services and System Aspects, Service + aspects; Charging and Billing, (release 5), 3GPP TS + 22.115 v. 5.2.1, 2002-03. + + [SIP] Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston, + A., Peterson, J., Sparks, R., Handley, M., and E. + Schooler, "SIP: Session Initiation Protocol", RFC 3261, + June 2002. + + [NAI] Aboba, B. and M. Beadles, "The Network Access + Identifier", RFC 2486, January 1999. + + [E164] Recommendation E.164/I.331 (05/97): The International + Public Telecommunication Numbering Plan. 1997. + + [CE164] Complement to ITU-T Recommendation E.164 (05/1997):"List + of ITU-T Recommendation E.164 assigned country codes", + June 2000. + + [E212] Recommendation E.212 (11/98): The international + identification plan for mobile terminals and mobile + users. 1998. + + [CE212] Complement to ITU-T Recommendation E.212 (11/1997):" List + of mobile country or geographical area codes", February + 1999. + + [IANA] Narten, T. and H. Alvestrand, "Guidelines for Writing an + IANA Considerations Section in RFCs", BCP 26, RFC 2434, + October 1998. + + [IPv4] Postel, J., "Internet Protocol", STD 5, RFC 791, + September 1981. + + [IPv6Addr] Hinden, R. and S. Deering, "Internet Protocol Version 6 + (IPv6) Addressing Architecture", RFC 3513, April 2003. + + [KEYWORDS] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + + +Hakala, et al. Standards Track [Page 91] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + [ISO4217] Codes for the representation of currencies and funds, + International Standard ISO 4217,2001 + + [NASREQ] Calhoun, P., Zorn, G., Spence, D., and D. Mitton, + "Diameter Network Access Server Application", RFC 4005, + August 2005. + + [AAATRANS] Aboba, B. and J. Wood, "Authentication, Authorization and + Accounting (AAA) Transport Profile", RFC 3539, June 2003. + + [URL] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform + Resource Locators (URL)", RFC 1738, December 1994. + + [RAD802.1X] Congdon, P., Aboba, B., Smith, A., Zorn, G., and J. + Roese, "IEEE 802.1X Remote Authentication Dial In User + Service (RADIUS) Usage Guidelines", RFC 3580, September + 2003. + + [EUI64] IEEE, "Guidelines for 64-bit Global Identifier (EUI-64) + Registration Authority", + http://standards.ieee.org/regauth/oui/tutorials/ + EUI64.html March 1997. + + [3GPPIMEI] 3rd Generation Partnership Project; Technical + Specification Group Core Network, Numbering, addressing + and identification, (release 5), 3GPP TS 23.003 v. 5.8.0, + 2003-12 + +15.2. Informative References + + [RFC2866] Rigney, C., "RADIUS Accounting", RFC 2866, June 2000. + + [DIAMMIP] Calhoun, P., Johansson, T., Perkins, C., Hiller, T., and + P. McCann, "Diameter Mobile IPv4 Application", RFC 4004, + August 2005. + + [DIAMEAP] Eronen, P., Hiller, T., and G. Zorn, "Diameter Extensible + Authentication Protocol (EAP) Application", Work in + Progress. + + [RFC3725] Rosenberg, J., Peterson, J., Schulzrinne, H., and G. + Camarillo, "Best Current Practices for Third Party Call + Control (3pcc) in the Session Initiation Protocol (SIP)", + BCP 85, RFC 3725, April 2004. + + + + + + + +Hakala, et al. Standards Track [Page 92] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +16. Acknowledgements + + The authors would like to thank Bernard Aboba, Jari Arkko, Robert + Ekblad, Pasi Eronen, Benny Gustafsson, Robert Karlsson, Avi Lior, + Paco Marin, Jussi Maki, Jeff Meyer, Anne Narhi, John Prudhoe, + Christopher Richards, Juha Vallinen, and Mark Watson for their + comments and suggestions. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 93] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +Appendix A. Credit-Control Sequences + +A.1. Flow I + + NAS + End User (CC Client) AAA Server CC Server + |(1)User Logon |(2)AA Request (CC AVPs) | + |------------------>|------------------->| | + | | |(3)CCR(initial, CC AVPs) + | | |------------------->| + | | | (4)CCA(Granted-Units) + | | |<-------------------| + | |(5)AA Answer(Granted-Units) | + |(6)Access granted |<-------------------| | + |<----------------->| | | + | | | | + : : : : + | |(7)CCR(update,Used-Units) | + | |------------------->|(8)CCR | + | | | (update,Used-Units) + | | |------------------->| + | | |(9)CCA(Granted-Units) + | |(10)CCA(Granted-Units)<------------------| + | |<-------------------| | + : : : : + | (Auth. lifetime expires) | | + | |(11) AAR (CC AVP) | | + | |------------------->| | + | | (12) AAA | | + | |<-------------------| | + : : : : + : : : : + |(13) User logoff | | | + |------------------>|(14)CCR(term.,Used-Units) | + | |------------------->|(15)CCR | + | | | (term.,Used-Units) + | | |------------------->| + | | | (16)CCA | + | | (17)CCA |<-------------------| + | |<-------------------| | + | |(18)STR | | + | |------------------->| | + | | (19)STA | | + | |<-------------------| | + + Figure A.1: Flow I + + + + + +Hakala, et al. Standards Track [Page 94] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + A credit-control flow for Network Access Services prepaid is shown in + Figure A.1. The Diameter [NASREQ] is implemented in the Network + Access Server (NAS). The focus of this flow is in the credit + authorization. + + The user logs on to the network (1). The Diameter NAS sends a + Diameter AA-Request (AAR) to the home Diameter AAA server. The + credit-control client populates the AAR with the Credit-Control AVP + set to CREDIT_AUTHORIZATION, and service-specific AVPs are included, + as usual [NASREQ]. The home Diameter AAA server performs service- + specific Authentication and Authorization, as usual. The home + Diameter AAA server determines that the user is a prepaid user and + notices from the Credit-Control AVP that the NAS has credit-control + capabilities. It sends a Diameter Credit-Control-Request with CC- + Request-Type set to INITIAL_REQUEST to the Diameter credit-control + server to perform credit authorization (3) and to establish a + credit-control session. (The home Diameter AAA server may forward + service-specific AVPs received from the NAS as input for the rating + process.) The Diameter credit-control server checks the end user's + account balance, rates the service, and reserves credit from the end + user's account. The reserved quota is returned to the home Diameter + AAA server in the Diameter Credit-Control-Answer (4). The home + Diameter AAA server sends the reserved quota to the NAS in the + Diameter AA-Answer (AAA). Upon successful AAA, the NAS starts the + credit-control session and starts monitoring the granted units (5). + The NAS grants access to the end user (6). At the expiry of the + allocated quota, the NAS sends a Diameter Credit-Control-Request with + CC-Request-Type set to UPDATE_REQUEST to the Home Diameter AAA server + (7). This message contains the units used thus far. The home + Diameter AAA server forwards the CCR to the Diameter credit-control + server (8). The Diameter credit-control server debits the used units + from the end user's account and allocates a new quota that is + returned to the home Diameter AAA server in the Diameter Credit- + Control-Answer (9). The message is forwarded to the NAS (10). + During the ongoing credit-control session, the authorization lifetime + expires, and the authorization/authentication client in the NAS + performs service specific re-authorization to the home Diameter AAA + server, as usual. The credit-control client populates the AAR with + the Credit-Control AVP set to RE_AUTHORIZATION, indicating that the + credit-control server shall not be contacted, as the credit + authorization is controlled by the burning rate of the granted units + (11). The home Diameter AAA server performs service-specific re- + authorization as usual and returns the AA-Answer to the NAS (12). + The end user logs off from the network (13). To debit the used units + from the end user's account and to stop the credit-control session, + the NAS sends a Diameter Credit-Control-Request with CC-Request-Type + set to TERMINATION_REQUEST to the home Diameter AAA server (14). The + home Diameter AAA server forwards the CCR to the credit-control + + + +Hakala, et al. Standards Track [Page 95] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + server (15). The Diameter credit-control server acknowledges the + session termination by sending a Diameter Credit-Control-Answer to + the home Diameter AAA server (16). The home Diameter AAA server + forwards the answer to the NAS (17). STR/STA takes place between the + NAS and home Diameter AAA server, as usual (18-19). + +A.2. Flow II + + SIP Proxy/Registrar AAA + A (CC Client) Server B CC Server + |(i) REGISTER | | | | + |------------->|(ii) | | | + | |------------->| | | + | |authentication & | | + | |authorization | | | + | |<-------------| | | + |(iii)200 OK | | | + |<-------------| | | + : : : : + |(1) INVITE | : + |------------->| + | |(2) CCR (Initial, SIP specific AVP) | + | |------------------------------------------->| + | |(3) CCA (Granted-Units) | + | |<-------------------------------------------| + | |(4) INVITE | | + | |---------------------------->| | + : : : : + | |(5) CCR (update, Used-Units) | + | |------------------------------------------->| + | |(6) CCA (Granted-Units) | + | |<-------------------------------------------| + : : : : + |(7) BYE | | | + |------------->| | | + | |(8) BYE | | + | |---------------------------->| | + | |(9) CCR (termination, Used-Units) | + | |------------------------------------------->| + | |(10) CCA () | + | |<-------------------------------------------| + | | | | + + Figure A.2: Flow II + + + + + + + +Hakala, et al. Standards Track [Page 96] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + This is an example of Diameter credit-control for SIP sessions. + Although the flow focuses on illustrating the usage of credit-control + messages, the SIP signaling is inaccurate, and the diagram is not by + any means an attempt to define a service provider's SIP network. + However, for the sake of this example, some assumptions are made + below. + + Typically, prepaid services based, for example, on time usage for SIP + session require an entity in the service provider network to + intercept all the requests within the SIP dialog in order to detect + events, such as session establishment and session release, that are + essential to perform credit-control operations with the credit- + control server. Therefore, in this example, it is assumed that the + SIP Proxy adds a Record-Route header in the initial SIP INVITE to + make sure that all the future requests in the created dialog traverse + through it (for the definitions of 'Record-Route' and 'dialog' please + refer to [SIP]). Finally, the degree of credit-control measuring of + the media by the proxy depends on the business model design used in + setting up the end system and proxies in the SIP network. + + The end user (SIP User Agent A) sends REGISTER with credentials (i). + The SIP Proxy sends a request to the home AAA server to perform + Multimedia authentication and authorization by using, for instance, + Diameter Multimedia application (ii). The home AAA server checks + that the credentials are correct and checks the user profile. + Eventually, 200 OK response (iii) is sent to the UA. Note that the + Authentication and Authorization is valid for the registration + validity period duration (i.e., until re-registration is performed). + Several SIP sessions may be established without re-authorization. + + UA A sends an INVITE (1). The SIP Proxy sends a Diameter Credit- + Control-Request (INITIAL_REQUEST) to the Diameter credit-control + server (2). The Credit-Control-Request contains information obtained + from the SIP signaling describing the requested service (e.g., + calling party, called party, Session Description Protocol + attributes). The Diameter credit-control server checks the end + user's account balance, rates the service, and reserves credit from + the end user's account. The reserved quota is returned to the SIP + Proxy in the Diameter Credit-Control-Answer (3). The SIP Proxy + forwards the SIP INVITE to UA B (4). B's phone rings, and B answers. + The media flows between them, and the SIP Proxy starts measuring the + quota. At the expiry of the allocated quota, the SIP Proxy sends a + Diameter Credit-Control-Request (UPDATE_REQUEST) to the Diameter + credit-control server (5). This message contains the units used thus + far. The Diameter credit-control server debits the used units from + the end user's account and allocates new credit that is returned to + the SIP Proxy in the Diameter Credit-Control-Answer (6). The end + user terminates the service by sending a BYE (7). The SIP Proxy + + + +Hakala, et al. Standards Track [Page 97] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + forwards the BYE message to UA B (8) and sends a Diameter Credit- + Control-Request (TERMINATION_REQUEST) to the credit-control server + (9). The Diameter credit-control server acknowledges the session + termination by sending a Diameter Credit-Control-Answer to the SIP + Proxy (10). + +A.3. Flow III + + MMS Server + A (CC Client) B CC Server + |(1) Send MMS | | | + |--------------->| | | + | |(2) CCR (event, DIRECT_DEBITING,| + | | MMS specific AVP) | + | |-------------------------------->| + | |(3) CCA (Granted-Units) | + | |<--------------------------------| + |(4) Send MMS Ack| | | + |<---------------| | | + | |(5) Notify MMS | | + | |--------------->| | + : : : : + | |(6) Retrieve MMS| | + | |<---------------| | + | |(7) Retrieve MMS| | + | | Ack | | + | |--------------->| | + | | | | + + Figure A.3: Flow III + + A credit-control flow for Multimedia Messaging Services is shown in + Figure A.3. The sender is charged as soon as the messaging server + successfully stores the message. + + The end user A sends a Multimedia Message (MMS) to the MMS server + (1). The MMS server stores the message and sends a Diameter Credit- + Control-Request (EVENT_REQUEST with Requested-Action DIRECT_DEBITING) + to the Diameter credit-control server (2). The Credit-Control- + Request contains information about the MMS message (e.g., size, + recipient address, image coding type). The Diameter credit-control + server checks the end user's account balance, rates the service, and + debits the service from the end user's account. The granted quota is + returned to the MMS server in the Diameter Credit-Control-Answer (3). + The MMS server acknowledges the successful reception of the MMS + message (4). The MMS Server notifies the recipient about the new MMS + (5), and end user B retrieves the message from the MMS message store + (6),(7). + + + +Hakala, et al. Standards Track [Page 98] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +A.4. Flow IV + + MMS Server + Content Server (CC Client) B CC Server + |(1) Send MMS | | | + |--------------->| | | + | |(2) CCR (event, CHECK_BALANCE, | + | | MMS specific AVP) | + | |-------------------------------->| + | |(3) CCA (ENOUGH_CREDIT) | + | |<--------------------------------| + |(4) Send MMS Ack| | | + |<---------------| | | + | |(5) Notify MMS | | + | |--------------->| | + : : : : + | |(6) Retrieve MMS| | + | |<---------------| | + | |(7) CCR (event, DIRECT_DEBITING,| + | | MMS specific AVP) | + | |-------------------------------->| + | |(8) CCA (Granted-Units) | + | |<--------------------------------| + | |(9) Retrieve MMS| | + | | Ack | | + | |--------------->| | + | | | | + + Figure A.4: Flow IV + + This is an example of Diameter credit-control for direct debiting + using the Multimedia Messaging Service environment. Although the + flow focuses on illustrating the usage of credit-control messages, + the MMS signaling is inaccurate, and the diagram is not by any means + an attempt to define any service provider's MMS configuration or + billing model. + + A credit-control flow for Multimedia Messaging Service is shown in + Figure A.4. The recipient is charged at the message delivery. + + A content server sends a Multimedia Message (MMS) to the MMS server + (1) that stores the message. The message recipient will be charged + for the MMS message in this case. As there can be a substantially + long time between the receipt of the message at the MMS server and + the actual retrieval of the message, the MMS server does not + establish any credit-control session to the Diameter credit-control + server but performs first only a balance check (without any credit + reservation) by sending a Diameter Credit-Control-Request + + + +Hakala, et al. Standards Track [Page 99] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + (EVENT_REQUEST with Requested-Action CHECK_BALANCE) to verify that + end user B can cover the cost for the MMS (2). The Diameter credit- + control server checks the end user's account balance and returns the + answer to the MMS server in the Diameter Credit-Control-Answer (3). + The MMS server acknowledges the successful reception of the MMS + message (4). The MMS server notifies the recipient of the new MMS + (5), and after some time end user B retrieves the message from the + MMS message store (6). The MMS server sends a Diameter Credit- + Control-Request (EVENT_REQUEST with Requested-Action: + DIRECT_DEBITING) to the Diameter credit-control server (7). The + Credit-Control-Request contains information about the MMS message + (e.g., size, recipient address, coding type). The Diameter credit- + control server checks the end user's account balance, rates the + service, and debits the service from the end user's account. The + granted quota is returned to the MMS server in the Diameter Credit- + Control-Request (8). The MMS is transferred to end user B (9). + + Note that the transfer of the MMS message can take an extended time + and can fail, in which case a recovery action is needed. The MMS + server should return the already debited units to the user's account + by using the REFUND action described in section 6.4. + +A.5. Flow V + + SIP Controller + A (CC Client) B CC Server + |(1)INVITE B(SDP)| | | + |--------------->| | | + | |(2) CCR (event, PRICE_ENQUIRY, | + | | SIP specific AVPs) | + | |-------------------------------->| + | |(3) CCA (Cost-Information) | + | |<--------------------------------| + | (4)MESSAGE(URL)| | | + |<---------------| | | + |(5)HTTP GET | | | + |--------------->| | | + |(6)HTTP POST | | | + |--------------->|(7)INVITE(SDP) | | + | |--------------->| | + | | (8)200 OK | | + | (9)200 OK |<---------------| | + |<---------------| | | + + Figure A.5: Flow V + + + + + + +Hakala, et al. Standards Track [Page 100] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + This is an example of Diameter credit-control for SIP sessions. + Although the flow focuses on illustrating the usage of credit-control + messages, the SIP signaling is inaccurate, and the diagram is not by + any means an attempt to define a service provider's SIP network. + + Figure A.5 is an example of Advice of Charge (AoC) service for SIP + call. User A can be either a postpaid or prepaid subscriber using + the AoC service. It is assumed that the SIP controller also has HTTP + capabilities and delivers an interactive AoC web page with, for + instance, the cost information, the details of the call derived from + the SDP, and a button to accept/not accept the charges. (There may + be many other ways to deliver AoC information; however, this flow + focuses on the use of the credit-control messages.) The user has + been authenticated and authorized prior to initiating the call and + subscribed to AoC service. + + UA A sends an INVITE with SDP to B (1). The SIP controller + determines that the user is subscribed to AoC service and sends a + Diameter Credit-Control-Request (EVENT_REQUEST with Requested-Action: + PRICE_ENQUIRY) to the Diameter credit-control server (2). The + Credit-Control-Request contains SIP specific AVPs derived from the + SIP signaling, describing the requested service (e.g., calling party, + called party, Session Description Protocol attributes). The Diameter + credit-control server determines the cost of the service and returns + the Credit-Control-Answer including the Cost-Information AVP (3). + The SIP controller manufactures the AoC web page with information + received in SIP signaling and with the cost information received from + the credit-control server. Then it sends a SIP MESSAGE that contains + a URL pointing to the AoC information web page (4). At the receipt + of the SIP MESSAGE, A's UA automatically invokes the web browser that + retrieves the AoC information (5). The user clicks on a proper + button and accepts the charges (6). The SIP controller continues the + session and sends the INVITE to the B party, which accepts the call + (7,8,9). + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 101] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +A.6. Flow VI + + Gaming Server + End User (CC Client) CC Server + | (1)Service Delivery | | + |<---------------------->| | + : : : + : : : + | |(2)CCR(event,REFUND,Requested- + | |Service-Unit,Service-Parameter-Info) + | |----------------------->| + | | (3)CCA(Cost-Information) + | |<-----------------------| + | (4)Notification | | + |<-----------------------| | + + Figure A.6: Flow VI + + Figure A.6 illustrates a credit-control flow for the REFUND case. It + is assumed that there is a trusted relationship and secure connection + between the Gaming server and the Diameter credit-control server. + The end user may be a prepaid subscriber or a postpaid subscriber. + + While the end user is playing the game (1), she enters a new level + that entitles her to a bonus. The Gaming server sends a Diameter + Credit-Control-Request (EVENT_REQUEST with Requested-Action: + REFUND_ACCOUNT) to the Diameter credit-control server (2). The + Credit-Control-Request Request contains the Requested-Service-Unit + AVP with the CC-Service-Specific-Units containing the number of + points the user just won. The Service-Parameter-Info AVP is also + included in the request and specifies the service event to be rated + (e.g., Tetris Bonus). From information received, the Diameter + credit-control server determines the amount to be credited, refunds + the user's account, and returns the Credit-Control-Answer, including + the Cost-Information AVP (3). The Cost-Information indicates the + credited amount. At the first opportunity, the Gaming server + notifies the end user of the credited amount (4). + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 102] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +A.7. Flow VII + + SIP Controller Top-Up + A (CC Client) Server B CC Server + | | | | | + | | (1) CCR(Update,Used-Unit) | | + | |------------------------------------------>| + | | (2) CCA(Final-Unit, Redirect)| + | |<------------------------------------------| + : : : : : + : : : : : + | | (3) CCR(Update, Used-Units)| | + | |------------------------------------------>| + | | (3a)INVITE("hold") | | + | |--------------------------->| | + | | | (4) CCA(Validity-Time)| + | |<------------------------------------------| + | (5)INVITE | (6)INVITE | | | + |<--------------|------------->| | | + | (7)RTP | | | + |..............................| | | + | | (8)BYE | | | + | |<-------------| | | + | | (9)CCR(Update) | | + | |------------------------------------------>| + | | (10)CCA(Granted-Unit) | + | |<------------------------------------------| + | (12)INVITE | (11)INVITE | | + |<--------------|--------------------------->| | + + Figure A.7: Flow VII + + Figure A.7 is an example of the graceful service termination for a + SIP call. It is assumed that the call is set up so that the + controller is in the call as a B2BUA (Back to Back User Agent) + performing third-party call control (3PCC). Note that the SIP + signaling is inaccurate, as the focus of this flow is in the graceful + service termination and credit-control authorization. The best + practice for 3PCC is defined in [RFC3725]. + + The call is ongoing between users A and B; user A has a prepaid + subscription. At the expiry of the allocated quota, the SIP + controller sends a Diameter Credit-Control-Request (UPDATE_REQUEST) + to the Diameter credit-control server (1). This message contains the + units used thus far. The Diameter credit-control server debits the + used units from the end user's account and allocates the final quota + returned to the SIP controller in the Diameter Credit-Control-Answer + (2). This message contains the Final-Unit-Indication AVP with the + + + +Hakala, et al. Standards Track [Page 103] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Final-Unit-Action set to REDIRECT, the Redirect-Address-Type set to + SIP URI, and the Redirect-Server-Address set to the Top-up server + name (e.g., sip:[email protected]). At the expiry of the + final allocated quota, the SIP controller sends a Diameter Credit- + Control-Request (UPDATE_REQUEST) to the Diameter credit-control + server (3) and places the called party on "hold" by sending an INVITE + with the appropriate connection address in the SDP (3a). The + Credit-Control-Request message contains the units used thus far. The + Diameter credit-control server debits the used units from the end + user's account but does not make any credit reservation. The + Credit-Control-Answer message, which contains the Validity-Time to + supervise the graceful service termination, is returned to the SIP + controller (4). The SIP controller establishes a SIP session between + the prepaid user and the Top-up server (5, 6). The Top-up server + plays an announcement and prompts the user to enter a credit card + number and the amount of money to be used to replenish the account + (7). The Top-up server validates the credit card number and + replenishes the user's account (using some means outside the scope of + this specification) and releases the SIP session (8). The SIP + controller can now assume that communication between the prepaid user + and the Top-up server took place. It sends a spontaneous Credit- + Control-Request (UPDATE_REQUEST) to the Diameter credit-control + server to check whether the account has been replenished (9). The + Diameter credit-control server reserves credit from the end user's + account and returns the reserved quota to the SIP controller in the + Credit-Control-Answer (10). At this point, the SIP controller re- + connects the caller and the called party (11,12). + + + + + + + + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 104] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +A.8. Flow VIII + + NAS Top-up CC + End-User (CC Client) AAA Server Server Server + |(1)User Logon |(2)AA Request (CC AVPs) | | + |------------------>|------------------->| | | + | | |(3)CCR(initial, CC AVPs) + | | |------------------->| + | | |(4)CCA(Final-Unit, | + | | | Validity-Time)| + | | |<-------------------| + | |(5)AA Answer(Final-Unit,Validity-Time) | + |(6)Limited Access |<-------------------| | | + | granted | | | | + |<----------------->| | | | + | | | | | + | (7)TCP/HTTP | (8)TCP/HTTP | | + |<----------------->|<----------------------------->| | + | (9) Replenish account | | + |<------------------------------------------------->| | + | | | (10)RAR | + | |<-------------------|<-------------------| + | | (11) RAA | | + | |------------------->|------------------->| + | |(12)CCR(update) | | + | |------------------->|(13)CCR(Update) | + | | |------------------->| + | | |(14)CCA(Granted-Units) + | |(15)CCA(Granted-Units)<------------------| + | |<-------------------| | + + Figure A.8: Flow VIII + + Figure A.8 is an example of the graceful service termination + initiated when the first interrogation takes place because the user's + account is empty. In this example, the credit-control server + supports the server-initiated credit re-authorization. The Diameter + [NASREQ] is implemented in the Network Access Server (NAS). + + The user logs on to the network (1). The Diameter NAS sends a + Diameter AA-Request to the home Diameter AAA server. The credit- + control client populates the AAR with the Credit-Control AVP set to + CREDIT_AUTHORIZATION, and service specific AVPs are included, as + usual [NASREQ]. The home Diameter AAA server performs service + specific Authentication and Authorization, as usual. The home + Diameter AAA server determines that the user has a prepaid + subscription and notices from the Credit-Control AVP that the NAS has + credit-control capabilities. It sends a Diameter Credit-Control- + + + +Hakala, et al. Standards Track [Page 105] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Request with CC-Request-Type set to INITIAL_REQUEST to the Diameter + credit-control server to perform credit authorization (3) and to + establish a credit-control session. (The home Diameter AAA server + may forward service specific AVPs received from the NAS as input for + the rating process.) The Diameter credit-control server checks the + end user's account balance, determines that the account cannot cover + the cost of the service, and initiates the graceful service + termination. The Credit-Control-Answer is returned to the home + Diameter AAA server (4). This message contains the Final-Unit- + Indication AVP and the Validity-Time AVP set to a reasonable amount + of time to give the user a chance to replenish his/her account (e.g., + 10 minutes). The Final-Unit-Indication AVP includes the Final-Unit- + Action set to REDIRECT, the Redirect-Address-Type set to URL, and the + Redirect-Server-Address set to the HTTP Top-up server name. The home + Diameter AAA server sends the received credit-control AVPs to the NAS + in the Diameter AA-Answer (5). Upon successful AAA, the NAS starts + the credit-control session and immediately starts the graceful + service termination, as instructed by the server. The NAS grants + limited access to the user (6). The HTTP client software running in + the user's device opens the transport connection redirected by the + NAS to the Top-up server (7,8). The user is displayed an appropriate + web page on which to enter the credit card number, and the amount of + money to be used to replenish the account, and with a notification + message that she is granted unlimited access if the replenishment + operation will be successfully executed within the next, for example, + 10 minutes. The Top-up server validates the credit card number and + replenishes the user's account (using some means outside the scope of + this specification)(9). After successful account top-up, the + credit-control server sends a Re-Auth-Request message to the NAS + (10). The NAS acknowledges the request by returning the Re-Auth- + Answer message (11) and initiates the credit re-authorization by + sending a Credit-Control-request (UPDATE_REQUEST) to the Diameter + credit-control server (12,13). + + The Diameter credit-control server reserves credit from the end + user's account and returns the reserved quota to the NAS via the home + Diameter AAA server in the Credit-Control-Answer (14,15). The NAS + removes the restriction placed by the graceful service termination + and starts monitoring the granted units. + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 106] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +A.9. Flow IX + + The Diameter credit-control application defines the Multiple- + Services-Credit-Control AVP that can be used to support independent + credit-control of multiple services in a single credit-control (sub-) + session for service elements that have such capabilities. It is + possible to request and allocate resources as a credit pool that is + shared between services or rating groups. + + The flow example hereafter illustrates a usage scenario where the + credit-control client and server support independent credit-control + of multiple services, as defined in section 5.1.2. It is assumed + that Service-Identifiers, Rating-Groups, and their associated + parameters (e.g., IP 5-tuple) are locally configured in the service + element or provisioned by an entity other than the credit-control + server. + + End User Service Element CC Server + (CC client) + |(1)User logon | | + |------------------>|(2)CCR(initial, Service-Id access, | + | | Access specific AVPs, | + | | Multiple-Service-Indicator) | + | |---------------------------------------->| + | |(3)CCA(Multiple-Services-CC ( | + | | Granted-Units(Total-Octets), | + | | Service-Id access, | + | | Validity-time, | + | | G-S-U-Pool-Reference(Pool-Id 1, | + | | Multiplier 10))) | + | |<----------------------------------------| + : : : + |(4)Service-Request (Service 1) | + |------------------>|(5)CCR(update, Multiple-Services-CC( | + | | Requested-Units(), Service-Id 1, | + | | Rating-Group 1)) | + | |---------------------------------------->| + | |(6)CCA(Multiple-Services-CC ( | + | | Granted-Units(Time), | + | | Rating-Group 1, | + | | G-S-U-Pool-Reference(Pool-Id 1, | + | | Multiplier 1))) | + | |<----------------------------------------| + : : : + |(7)Service-Request (Service 2) | + |------------------>| | + + + + + +Hakala, et al. Standards Track [Page 107] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + : : : + : : : + |(8)Service-Request (Service 3&4) | + |------------------>|(9)CCR(update, Multiple-Services-CC ( | + | | Requested-Units(), Service-Id 3, | + | | Rating-Group 2), | + | | Multiple-Services-CC ( | + | | Requested-Units(), Service-Id 4, | + | | Rating-Group 3)) | + | |---------------------------------------->| + | |(10)CCA(Multiple-Services-CC ( | + | | Granted-Units(Total-Octets), | + | | Service-Id 3, Rating-Group 2, | + | | Validity-time, | + | | G-S-U-Pool-Reference(Pool-Id 2, | + | | Multiplier 2)), | + | | Multiple-Services-CC ( | + | | Granted-Units(Total-Octets), | + | | Service-Id 4, Rating-Group 3 | + | | Validity-Time, | + | | Final-Unit-Ind.(Terminate), | + | | G-S-U-Pool-Reference(Pool-Id 2, | + | | Multiplier 5))) | + | |<----------------------------------------| + : : : + : : : + | +--------------+ | | + | |Validity time | |(11)CCR(update, | + | |expires for | | Multiple-Services-CC ( | + | |Service-Id | | Requested-Unit(), | + | | access | | Used-Units(In-Octets,Out-Octets),| + | +--------------+ | Service-Id access)) | + | |---------------------------------------->| + | |(12)CCA(Multiple-Services-CC ( | + | | Granted-Units(Total-Octets), | + | | Service-Id access, | + | | Validity-Time, | + | | G-S-U-Pool-Reference(Pool-Id 1, | + | | Multiplier 10))) | + | |<----------------------------------------| + : : : + : : : + + + + + + + + + +Hakala, et al. Standards Track [Page 108] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + | +--------------+ | | + | |Total Quota | |(13)CCR(update, | + | |elapses for | | Multiple-Services-CC ( | + | |pool 2: | | Requested-Unit(), | + | |service 4 not | | Used-Units(In-Octets,Out-Octets),| + | |allowed, | | Service-Id 3, Rating-group 2), | + | |service 3 cont| | Multiple-Services-CC ( | + | +--------------+ | Used-Units(In-Octets,Out-Octets),| + | | Service-Id 4, Rating-Group 3)) | + | |---------------------------------------->| + | |(14)CCA(Multiple-Services-CC ( | + | | Result-Code 4011, | + | | Service-Id 3)) | + | |<----------------------------------------| + : : : + : : : + |(15) User logoff | | + |------------------>|(16)CCR(term, | + | | Multiple-Services-CC ( | + | | Used-Units(In-Octets,Out-Octets),| + | | Service-Id access), | + | | Multiple-Services-CC ( | + | | Used-Units(Time), | + | | Service-Id 1, Rating-Group 1), | + | | Multiple-Services-CC ( | + | | Used-Units(Time), | + | | Service-Id 2, Rating-Group 1)) | + | |---------------------------------------->| + | |(17)CCA(term) | + | |<----------------------------------------| + + Figure A.9: Flow example independent credit-control of multiple + services in a credit-control (sub-)Session + + The user logs on to the network (1). The service element sends a + Diameter Credit-Control-Request with CC-Request-Type set to + INITIAL_REQUEST to the Diameter credit-control server to perform + credit authorization for the bearer service (e.g., Internet access + service) and to establish a credit-control session (2). In this + message, the credit-control client indicates support for independent + credit-control of multiple services within the session by including + the Multiple-Service-Indicator AVP. The Diameter credit-control + server checks the end user's account balance, with rating information + received from the client (i.e., Service-Id and access specific AVPs), + rates the request, and reserves credit from the end user's account. + Suppose that the server reserves $5 and determines that the cost is + $1/MB. It then returns to the service element a Credit-Control- + Answer message that includes the Multiple-Services-Credit-Control AVP + + + +Hakala, et al. Standards Track [Page 109] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + with a quota of 5MB associated to the Service-Id (access), to a + multiplier value of 10, and to the Pool-Id 1 (3). + + The user uses Service 1 (4). The service element sends a Diameter + Credit-Control-Request with CC-Request-Type set to UPDATE_REQUEST to + the credit-control server to perform credit authorization for service + 1 (5). This message includes the Multiple-Services-Credit-Control + AVP to request service units for Service 1 that belong to Rating- + Group 1. The Diameter credit-control server determines that Service + 1 draws credit resources from the same account as the access service + (i.e., pool 1). It rates the request according to Service- + Id/Rating-Group and updates the existing reservation by requesting + more credit. Suppose that the server reserves $5 more (now the + reservation is $10) and determines that the cost is $0.1/minute. The + server authorizes the whole Rating-Group. It then returns to the + service element a Credit-Control-Answer message that includes the + Multiple-Services-Credit-Control AVP with a quota of 50min. + associated to the Rating-Group 1, to a multiplier value of 1, and to + the Pool-Id 1 (6). The client adjusts the total amount of resources + for pool 1 according the received quota, which gives S for Pool 1 = + 100. + + The user uses Service 2, which belongs to the authorized Rating- + Group, 1 (7). Resources are then consumed from the pool 1. + + The user now requests Services 3 and 4 as well, which are not + authorized (8). The service element sends a Diameter Credit- + Control-Request with CC-Request-Type set to UPDATE_REQUEST to the + credit-control server in order to perform credit authorization for + Services 3 and 4 (9). This message includes two instances of the + Multiple-Services-Credit-Control AVP to request service units for + Service 3 that belong to Rating-Group 2 and for Service 4 that belong + to Rating-Group 3. The Diameter credit-control server determines + that Services 3 and 4 draw credit resources from another account + (i.e., pool 2). It checks the end user's account balance and, + according to Service-Ids/Rating-Groups information, rates the + request. Then it reserves credit from pool 2. + + For example, the server reserves $5 and determines that Service 3 + costs $0.2/MB and Service 4 costs $0.5/MB. The server authorizes + only Services 3 and 4. It returns to the service element a Credit- + Control-Answer message that includes two instances of the Multiple- + Services-Credit-Control AVP (10). One instance grants a quota of + 12.5MB associated to the Service-Id 3 to a multiplier value of 2 and + to the Pool-Id 2. The other instance grants a quota of 5 MB + associated to the Service-Id 4 to a multiplier value of 5 and to the + Pool-Id 2. + + + + +Hakala, et al. Standards Track [Page 110] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + The server also determines that pool 2 is exhausted and Service 4 is + not allowed to continue after these units will be consumed. + Therefore the Final-Unit-Indication AVP with action TERMINATE is + associated to the Service-Id 4. The client calculates the total + amount of resources that can be used for pool 2 according the + received quotas and multipliers, which gives S for Pool 2 = 50. + + The Validity-Time for the access service expires. The service + element sends a Credit-Control-Request message to the server in order + to perform credit re-authorization for Service-Id (access) (11). + This message carries one instance of the Multiple-Services-Credit- + Control AVP that includes the units used by this service. Suppose + that the total amount of used units is 4MB. The client adjusts the + total amount of resources for pool 1 accordingly, which gives S for + Pool 1 = 60. + + The server deducts $4 from the user's account and updates the + reservation by requesting more credit. Suppose that the server + reserves $5 more (now the reservation is $11) and already knows the + cost of the Service-Id (access), which is $1/MB. It then returns to + the service element a Credit-Control-Answer message that includes the + Multiple-Services-Credit-Control AVP with a quota of 5 MB associated + to the Service-Id (access), to a multiplier value of 10, and to the + Pool-Id 1 (12). The client adjusts the total amount of resources for + pool 1 according the received quota, which gives S for Pool 1 = 110. + + Services 3 and 4 consume the total amount of pool 2 credit resources + (i.e., C1*2 + C2*5 >= S). The service element immediately starts the + TERMINATE action concerning Service 4 and sends a Credit-Control- + Request message with CC-Request-Type set to UPDATE_REQUEST to the + credit-control server in order to perform credit re-authorization for + Service 3 (13). This message contains two instances of the + Multiple-Services-Credit-Control AVP to report the units used by + Services 3 and 4. The server deducts the last $5 from the user's + account (pool 2) and returns the answer with Result-Code 4011 in the + Multiple-Services-Credit-Control AVP to indicate that Service 3 can + continue without credit-control (14). + + The end user logs off from the network (15). To debit the used units + from the end user's account and to stop the credit-control session, + the service element sends a Diameter Credit-Control-Request with CC- + Request-Type set to TERMINATION_REQUEST to the credit-control server + (16). This message contains the units consumed by each of the used + services in multiple instances of the Multiple-Services-Credit- + Control AVP. The used units are associated with the relevant + Service-Identifier and Rating-Group. The Diameter credit-control + + + + + +Hakala, et al. Standards Track [Page 111] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + server debits the used units to the user's account (Pool 1) and + acknowledges the session termination by sending a Diameter Credit- + Control-Answer to the service element (17). + +Authors' Addresses + + Harri Hakala + Oy L M Ericsson Ab + Joukahaisenkatu 1 + 20520 Turku + Finland + + Phone: +358 2 265 3722 + EMail: [email protected] + + + Leena Mattila + Oy L M Ericsson Ab + Joukahaisenkatu 1 + 20520 Turku + Finland + + Phone: +358 2 265 3731 + EMail: [email protected] + + + Juha-Pekka Koskinen + Nokia Networks + Hatanpaanvaltatie 30 + 33100 Tampere + Finland + + Phone: +358 7180 74027 + EMail: [email protected] + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 112] + +RFC 4006 Diameter Credit-Control Application August 2005 + + + Marco Stura + Nokia Networks + Hiomotie 32 + 00380 Helsinki + Finland + + Phone: +358 7180 64308 + EMail: [email protected] + + + John Loughney + Nokia Research Center + Itamerenkatu 11-13 + 00180 Helsinki + Finland + + Phone: +358 50 483 642 + EMail: [email protected] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Hakala, et al. Standards Track [Page 113] + +RFC 4006 Diameter Credit-Control Application August 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Hakala, et al. Standards Track [Page 114] + diff --git a/lib/diameter/doc/standard/rfc4072.txt b/lib/diameter/doc/standard/rfc4072.txt new file mode 100644 index 0000000000..dd0b3a18ac --- /dev/null +++ b/lib/diameter/doc/standard/rfc4072.txt @@ -0,0 +1,1851 @@ + + + + + + +Network Working Group P. Eronen, Ed. +Request for Comments: 4072 Nokia +Category: Standards Track T. Hiller + Lucent Technologies + G. Zorn + Cisco Systems + August 2005 + + + Diameter Extensible Authentication Protocol (EAP) Application + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The Internet Society (2005). + +Abstract + + The Extensible Authentication Protocol (EAP) provides a standard + mechanism for support of various authentication methods. This + document defines the Command-Codes and AVPs necessary to carry EAP + packets between a Network Access Server (NAS) and a back-end + authentication server. + +Table of Contents + + 1. Introduction ...................................................2 + 1.1. Conventions Used in This Document ........................3 + 2. Extensible Authentication Protocol Support in Diameter .........3 + 2.1. Advertising Application Support ..........................3 + 2.2. Protocol Overview ........................................4 + 2.3. Sessions and NASREQ Interaction ..........................6 + 2.3.1. Scenario 1: Direct Connection .....................7 + 2.3.2. Scenario 2: Direct Connection with Redirects ......8 + 2.3.3. Scenario 3: Direct EAP, Authorization via Agents ..9 + 2.3.4. Scenario 4: Proxy Agents .........................10 + 2.4. Invalid Packets .........................................10 + 2.5. Retransmission ..........................................11 + 2.6. Fragmentation ...........................................12 + 2.7. Accounting ..............................................12 + 2.8. Usage Guidelines ........................................13 + + + +Eronen, et al. Standards Track [Page 1] + +RFC 4072 Diameter EAP Application August 2005 + + + 2.8.1. User-Name AVP ....................................13 + 2.8.2. Conflicting AVPs .................................13 + 2.8.3. Displayable Messages .............................14 + 2.8.4. Role Reversal ....................................14 + 2.8.5. Identifier Space .................................14 + 3. Command-Codes .................................................14 + 3.1. Diameter-EAP-Request (DER) Command ......................15 + 3.2. Diameter-EAP-Answer (DEA) Command .......................16 + 4. Attribute-Value Pairs .........................................18 + 4.1. New AVPs ................................................18 + 4.1.1. EAP-Payload AVP ..................................18 + 4.1.2. EAP-Reissued-Payload AVP .........................18 + 4.1.3. EAP-Master-Session-Key AVP .......................19 + 4.1.4. EAP-Key-Name AVP .................................19 + 4.1.5. Accounting-EAP-Auth-Method AVP ...................19 + 5. AVP Occurrence Tables .........................................19 + 5.1. EAP Command AVP Table ...................................20 + 5.2. Accounting AVP Table ....................................21 + 6. RADIUS/Diameter Interactions ..................................22 + 6.1. RADIUS Request Forwarded as Diameter Request ............22 + 6.2. Diameter Request Forwarded as RADIUS Request ............23 + 6.3. Accounting Requests .....................................24 + 7. IANA Considerations ...........................................24 + 8. Security Considerations .......................................24 + 8.1. Overview ................................................24 + 8.2. AVP Editing .............................................26 + 8.3. Negotiation Attacks .....................................27 + 8.4. Session Key Distribution ................................28 + 8.5. Privacy Issues ..........................................28 + 8.6. Note about EAP and Impersonation ........................29 + 9. Acknowledgements ..............................................29 + 10. References ....................................................30 + 10.1. Normative References ....................................30 + 10.2. Informative References ..................................30 + +1. Introduction + + The Extensible Authentication Protocol (EAP), defined in [EAP], is an + authentication framework which supports multiple authentication + mechanisms. EAP may be used on dedicated links, switched circuits, + and wired as well as wireless links. + + To date, EAP has been implemented with hosts and routers that connect + via switched circuits or dial-up lines using PPP [RFC1661], IEEE 802 + wired switches [IEEE-802.1X], and IEEE 802.11 wireless access points + [IEEE-802.11i]. EAP has also been adopted for IPsec remote access in + IKEv2 [IKEv2]. + + + + +Eronen, et al. Standards Track [Page 2] + +RFC 4072 Diameter EAP Application August 2005 + + + This document specifies the Diameter EAP application that carries EAP + packets between a Network Access Server (NAS) working as an EAP + Authenticator and a back-end authentication server. The Diameter EAP + application is based on the Diameter Network Access Server + Application [NASREQ] and is intended for environments similar to + NASREQ. + + In the Diameter EAP application, authentication occurs between the + EAP client and its home Diameter server. This end-to-end + authentication reduces the possibility for fraudulent authentication, + such as replay and man-in-the-middle attacks. End-to-end + authentication also provides a possibility for mutual authentication, + which is not possible with PAP and CHAP in a roaming PPP environment. + + The Diameter EAP application relies heavily on [NASREQ], and in + earlier versions was part of the Diameter NASREQ application. It can + also be used in conjunction with NASREQ, selecting the application + based on the user authentication mechanism (EAP or PAP/CHAP). The + Diameter EAP application defines new Command-Codes and Attribute- + Value Pairs (AVPs), and can work together with RADIUS EAP support + [RFC3579]. + +1.1. Conventions Used in This Document + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in [RFC2119]. + +2. Extensible Authentication Protocol Support in Diameter + +2.1. Advertising Application Support + + Diameter nodes conforming to this specification MUST advertise + support by including the Diameter EAP Application ID value of 5 in + the Auth-Application-Id AVP of the Capabilities-Exchange-Request and + Capabilities-Exchange-Answer command [BASE]. + + If the NAS receives a response with the Result-Code set to + DIAMETER_APPLICATION_UNSUPPORTED [BASE], it indicates that the + Diameter server in the home realm does not support EAP. If possible, + the access device MAY attempt to negotiate another authentication + protocol, such as PAP or CHAP. An access device SHOULD be cautious + when determining whether a less secure authentication protocol will + be used, since this could result from a downgrade attack (see + Section 8.3). + + + + + + +Eronen, et al. Standards Track [Page 3] + +RFC 4072 Diameter EAP Application August 2005 + + +2.2. Protocol Overview + + The EAP conversation between the authenticating peer and the access + device begins with the initiation of EAP within a link layer, such as + PPP [RFC1661] or IEEE 802.11i [IEEE-802.11i]. Once EAP has been + initiated, the access device will typically send a Diameter-EAP- + Request message with an empty EAP-Payload AVP to the Diameter server, + signifying an EAP-Start. + + If the Diameter home server is willing to do EAP authentication, it + responds with a Diameter-EAP-Answer message containing an EAP-Payload + AVP that includes an encapsulated EAP packet. The Result-Code AVP in + the message will be set to DIAMETER_MULTI_ROUND_AUTH, signifying that + a subsequent request is expected. The EAP payload is forwarded by + the access device to the EAP client. This is illustrated in the + diagram below. + + User NAS Server + | | | + | (initiate EAP) | | + |<------------------------------>| | + | | Diameter-EAP-Request | + | | EAP-Payload(EAP Start) | + | |------------------------------->| + | | | + | | Diameter-EAP-Answer | + | Result-Code=DIAMETER_MULTI_ROUND_AUTH | + | | EAP-Payload(EAP Request #1) | + | |<-------------------------------| + | EAP Request #1 | | + |<-------------------------------| | + : : : + : ...continues... : + + The initial Diameter-EAP-Answer in a multi-round exchange normally + includes an EAP-Request/Identity, requesting the EAP client to + identify itself. Upon receipt of the EAP client's EAP-Response, the + access device will then issue a second Diameter-EAP-Request message, + with the client's EAP payload encapsulated within the EAP-Payload + AVP. + + A preferred approach is for the access device to issue the + EAP-Request/Identity message to the EAP client, and forward the + EAP-Response/Identity packet, encapsulated within the EAP-Payload + AVP, as a Diameter-EAP-Request to the Diameter server (see the + diagram below). This alternative reduces the number of Diameter + message round trips. When the EAP-Request/Identity message is issued + by the access device, it SHOULD interpret the EAP-Response/Identity + + + +Eronen, et al. Standards Track [Page 4] + +RFC 4072 Diameter EAP Application August 2005 + + + packet returned by the authenticating peer, and copy its value to a + User-Name AVP in Diameter-EAP-Request. This is useful in roaming + environments, since the Destination-Realm is needed for routing + purposes. Note that this alternative cannot be universally employed, + as there are circumstances in which a user's identity is not needed + (such as when authorization occurs based on a calling or called phone + number). + + User NAS Server + | | | + | (initiate EAP) | | + |<------------------------------>| | + | | | + | EAP Request(Identity) | | + |<-------------------------------| | + | | | + | EAP Response(Identity) | | + |------------------------------->| | + | | Diameter-EAP-Request | + | | EAP-Payload(EAP Response) | + | |------------------------------->| + : : : + : ...continues... : + + The conversation continues until the Diameter server sends a + Diameter-EAP-Answer with a Result-Code AVP indicating success or + failure, and an optional EAP-Payload. The Result-Code AVP is used by + the access device to determine whether service is to be provided to + the EAP client. The access device MUST NOT rely on the contents of + the optional EAP-Payload to determine whether service is to be + provided. + + + + + + + + + + + + + + + + + + + + +Eronen, et al. Standards Track [Page 5] + +RFC 4072 Diameter EAP Application August 2005 + + + : ...continued... : + : : : + | EAP Response #N | | + |------------------------------->| | + | | Diameter-EAP-Request | + | | EAP-Payload(EAP Response #N) | + | |------------------------------->| + | | | + | | Diameter-EAP-Answer | + | | Result-Code=DIAMETER_SUCCESS | + | | EAP-Payload(EAP Success) | + | | [EAP-Master-Session-Key] | + | | (authorization AVPs) | + | |<-------------------------------| + | | | + | EAP Success | | + |<-------------------------------| | + + If authorization was requested, a Diameter-EAP-Answer with + Result-Code set to DIAMETER_SUCCESS SHOULD also include the + appropriate authorization AVPs required for the service requested + (see Section 5 and [NASREQ]). In some cases, the home server may not + be able to provide all necessary authorization AVPs; in this case, a + separate authorization step MAY be used as described in + Section 2.3.3. Diameter-EAP-Answer messages whose Result-Code AVP is + set to DIAMETER_MULTI_ROUND_AUTH MAY include authorization AVPs. + + A Diameter-EAP-Answer with successful Result-Code MAY also include an + EAP-Master-Session-Key AVP that contains keying material for + protecting the communication 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. + + A home Diameter server MAY request EAP re-authentication by issuing + the Re-Auth-Request [BASE] message to the Diameter client. + + Should an EAP authentication session be interrupted due to a home + server failure, the session MAY be directed to an alternate server, + but the authentication session will have to be restarted from the + beginning. + +2.3. Sessions and NASREQ Interaction + + The previous section introduced the basic protocol between the NAS + and the home server. Since the Diameter-EAP-Answer message may + include a Master Session Key (MSK) for protecting the communication + between the user and the NAS, one must ensure that this key does not + fall into wrong hands. + + + +Eronen, et al. Standards Track [Page 6] + +RFC 4072 Diameter EAP Application August 2005 + + + Basic Diameter security mechanisms (IPsec and TLS) protect Diameter + messages hop-by-hop. Since there are currently no end-to-end + (NAS-to-home server) security mechanisms defined for Diameter, this + section describes possible scenarios on how the messages could be + transport protected using these hop-by-hop mechanisms. + + This list of scenarios is not intended to be exhaustive, and it is + possible to combine them. For instance, the first proxy agent after + the NAS could use redirects as in Scenario 2 to bypass any additional + proxy agents. + +2.3.1. Scenario 1: Direct Connection + + The simplest case is when the NAS contacts the home server directly. + All authorization AVPs and EAP keying material are delivered by the + home server. + + NAS home server + | | + | Diameter-EAP-Request | + | Auth-Request-Type=AUTHORIZE_AUTHENTICATE | + | EAP-Payload(EAP Start) | + |---------------------------------------------------------------->| + | | + | Diameter-EAP-Answer | + | Result-Code=DIAMETER_MULTI_ROUND_AUTH | + | EAP-Payload(EAP Request) | + |<----------------------------------------------------------------| + | | + : ...more EAP Request/Response pairs... : + | | + | Diameter-EAP-Request | + | EAP-Payload(EAP Response) | + |---------------------------------------------------------------->| + | | + | Diameter-EAP-Answer | + | Result-Code=DIAMETER_SUCCESS | + | EAP-Payload(EAP Success) | + | EAP-Master-Session-Key | + | (authorization AVPs) | + |<----------------------------------------------------------------| + + This scenario is the most likely to be used in small networks, or in + cases where Diameter agents are not needed to provide routing or + additional authorization AVPs. + + + + + + +Eronen, et al. Standards Track [Page 7] + +RFC 4072 Diameter EAP Application August 2005 + + +2.3.2. Scenario 2: Direct Connection with Redirects + + In this scenario the NAS uses a redirect agent to locate the home + server. The rest of the session proceeds as before. + + NAS Local redirect agent Home server + | | | + | Diameter-EAP-Request | | + | Auth-Request-Type=AUTHORIZE_AUTHENTICATE | + | EAP-Payload(EAP Start) | | + |------------------------------->| | + | | | + | Diameter-EAP-Answer | + | Redirect-Host=homeserver.example.com | + | Redirect-Host-Usage=REALM_AND_APPLICATION | + |<-------------------------------| | + | : | + | Diameter-EAP-Request : | + | Auth-Request-Type=AUTHORIZE_AUTHENTICATE | + | EAP-Payload(EAP Start) : | + |---------------------------------------------------------------->| + | : | + : ...rest of the session continues as in first case... : + : : : + + The advantage of this scenario is that knowledge of realms and home + servers is centralized to a redirect agent, and it is not necessary + to modify the NAS configuration when, for example, a new roaming + agreement is made. + + + + + + + + + + + + + + + + + + + + + + +Eronen, et al. Standards Track [Page 8] + +RFC 4072 Diameter EAP Application August 2005 + + +2.3.3. Scenario 3: Direct EAP, Authorization via Agents + + In this scenario the EAP authentication is done directly with the + home server (with Auth-Request-Type set to AUTHENTICATE_ONLY), and + authorization AVPs are retrieved from local proxy agents. This + scenario is intended for environments in which the home server cannot + provide all the necessary authorization AVPs to the NAS. + + NAS Local proxy agent Home server + | : | + | Diameter-EAP-Request : | + | Auth-Request-Type=AUTHENTICATE_ONLY | + | EAP-Payload(EAP Start) : | + |---------------------------------------------------------------->| + | : | + | : Diameter-EAP-Answer | + | Result-Code=DIAMETER_MULTI_ROUND_AUTH | + | : EAP-Payload(EAP Request) | + |<----------------------------------------------------------------| + | : | + : ...more EAP Request/Response pairs... : + | : | + | Diameter-EAP-Request : | + | EAP-Payload(EAP Response) : | + |---------------------------------------------------------------->| + | : | + | : Diameter-EAP-Answer | + | : Result-Code=DIAMETER_SUCCESS | + | : EAP-Payload(EAP Success) | + | : EAP-Master-Session-Key | + | : (authorization AVPs) | + |<----------------------------------------------------------------| + | | | + | AA-Request | | + | Auth-Request-Type=AUTHORIZE_ONLY | + | (some AVPs from first session) | | + |------------------------------->| | + | | | + | AA-Answer | | + | Result-Code=DIAMETER_SUCCESS | | + | (authorization AVPs) | | + |<-------------------------------| | + + The NASREQ application is used here for authorization because the + realm-specific routing table supports routing based on application, + not on Diameter commands. + + + + + +Eronen, et al. Standards Track [Page 9] + +RFC 4072 Diameter EAP Application August 2005 + + +2.3.4. Scenario 4: Proxy Agents + + This scenario is the same as Scenario 1, but the NAS contacts the + home server through proxies. Note that the proxies can see the EAP + session keys, thus it is not suitable for environments where proxies + cannot be trusted. + + NAS Local proxy/relay agent Home server + | | | + | Diameter-EAP-Request | | + | Auth-Request-Type=AUTHORIZE_AUTHENTICATE | + | EAP-Payload(EAP Start) | | + |------------------------------->|------------------------------->| + | | | + | | Diameter-EAP-Answer | + | Result-Code=DIAMETER_MULTI_ROUND_AUTH | + | | EAP-Payload(EAP Request) | + |<-------------------------------|<-------------------------------| + | : | + : ...more EAP Request/Response pairs... : + | : | + | Diameter-EAP-Request | | + | EAP-Payload(EAP Response) | | + |------------------------------->|------------------------------->| + | | | + | | Diameter-EAP-Answer | + | | Result-Code=DIAMETER_SUCCESS | + | | EAP-Payload(EAP Success) | + | | EAP-Master-Session-Key | + | | (authorization AVPs) | + |<-------------------------------|<-------------------------------| + +2.4. Invalid Packets + + While acting as a pass-through, the NAS MUST validate the EAP header + fields (Code, Identifier, Length) prior to forwarding an EAP packet + to or from the Diameter server. On receiving an EAP packet from the + peer, the NAS checks the Code (Code 2=Response) and Length fields, + and matches the Identifier value against the current Identifier, + supplied by the Diameter server in the most recently validated EAP + Request. On receiving an EAP packet from the Diameter server + (encapsulated within a Diameter-EAP-Answer), the NAS checks the Code + (Code 1=Request) and Length fields, then updates the current + Identifier value. Pending EAP Responses that do not match the + current Identifier value are silently discarded by the NAS. + + + + + + +Eronen, et al. Standards Track [Page 10] + +RFC 4072 Diameter EAP Application August 2005 + + + Since EAP method fields (Type, Type-Data) are typically not validated + by a NAS operating as a pass-through, despite these checks it is + possible for a NAS to forward an invalid EAP packet to or from the + Diameter server. + + A Diameter server receiving an EAP-Payload AVP that it does not + understand SHOULD determine whether the error is fatal or non-fatal + based on the EAP Type. A Diameter server determining that a fatal + error has occurred MUST send a Diameter-EAP-Answer with a failure + Result-Code and an EAP-Payload AVP encapsulating an EAP Failure + packet. A Diameter server determining that a non-fatal error has + occurred MUST send a Diameter-EAP-Answer with + DIAMETER_MULTI_ROUND_AUTH Result-Code, but no EAP-Payload AVP. To + simplify RADIUS translation, this message MUST also include an + EAP-Reissued-Payload AVP encapsulating the previous EAP Request sent + by the server. + + When receiving a Diameter-EAP-Answer without an EAP-Payload AVP (and + DIAMETER_MULTI_ROUND_AUTH Result-Code), the NAS SHOULD discard the + EAP-Response packet most recently transmitted to the Diameter server + and check whether additional EAP Response packets that match the + current Identifier value have been received. If so, a new EAP + Response packet, if available, MUST be sent to the Diameter server + within an Diameter-EAP-Request. If no EAP Response packet is + available, then the previous EAP Request is resent to the peer, and + the retransmission timer is reset. + + In order to provide protection against Denial of Service (DoS) + attacks, it is advisable for the NAS to allocate a finite buffer for + EAP packets received from the peer, and to discard packets according + to an appropriate policy once that buffer has been exceeded. Also, + the Diameter server is advised to permit only a modest number of + invalid EAP packets within a single session, prior to terminating the + session with DIAMETER_AUTHENTICATION_REJECTED Result-Code. By + default, a value of 5 invalid EAP packets is recommended. + +2.5. Retransmission + + As noted in [EAP], if an EAP packet is lost in transit between the + authenticating peer and the NAS (or vice versa), the NAS will + retransmit. + + It may be necessary to adjust retransmission strategies and + authentication time-outs in certain cases. For example, when a token + card is used, additional time may be required to allow the user to + find the card and enter the token. Since the NAS will typically not + have knowledge of the required parameters, these need to be provided + by the Diameter server. + + + +Eronen, et al. Standards Track [Page 11] + +RFC 4072 Diameter EAP Application August 2005 + + + If a Multi-Round-Time-Out AVP [BASE] is present in a Diameter-EAP- + Answer message that also contains an EAP-Payload AVP, that value is + used to set the EAP retransmission timer for that EAP Request and + that Request alone. + +2.6. Fragmentation + + Using the EAP-Payload AVP, it is possible for the Diameter server to + encapsulate an EAP packet that is larger than the MTU on the link + between the NAS and the peer. Since it is not possible for the + Diameter server to use MTU discovery to ascertain the link MTU, a + Framed-MTU AVP may be included in a Diameter-EAP-Request message in + order to provide the Diameter server with this information. + + A Diameter server having received a Framed-MTU AVP in a + Diameter-EAP-Request message MUST NOT send any subsequent packet in + this EAP conversation containing EAP-Payload AVP whose length exceeds + that specified by the Framed-MTU value, taking the link type + (specified by the NAS-Port-Type AVP) into account. For example, as + noted in [RFC3580] Section 3.10, for a NAS-Port-Type value of IEEE + 802.11, the RADIUS server may send an EAP packet as large as + Framed-MTU minus four (4) octets, taking into account the additional + overhead for the IEEE 802.1X Version (1 octet), Type (1 octet) and + Body Length (2 octets) fields. + +2.7. Accounting + + When a user is authenticated using EAP, the NAS MAY include an + Accounting-Auth-Method AVP [NASREQ] with value 5 (EAP) in + Accounting-Request messages. This document specifies one additional + AVP for accounting messages. One or more Accounting-EAP-Auth-Method + AVPs (see Section 4.1.5) MAY be included in Accounting-Request + messages to indicate the EAP method(s) used to authenticate the user. + + If the NAS has authenticated the user with a locally implemented EAP + method, it knows the method used and SHOULD include it in an + Accounting-EAP-Auth-Method AVP. + + If the authentication was done using Diameter-EAP-Request/Answer + messages, the Diameter server SHOULD include one or more + Accounting-EAP-Auth-Method AVPs in Diameter-EAP-Answer packets with a + successful result code. In this case, the NAS SHOULD include these + AVPs in Accounting-Request messages. + + + + + + + + +Eronen, et al. Standards Track [Page 12] + +RFC 4072 Diameter EAP Application August 2005 + + +2.8. Usage Guidelines + +2.8.1. User-Name AVP + + Unless the access device interprets the EAP-Response/Identity packet + returned by the authenticating peer, it will not have access to the + user's identity. Furthermore, some EAP methods support identity + protection where the user's real identity is not included in + EAP-Response/Identity. Therefore, the Diameter Server SHOULD return + the user's identity by inserting a User-Name AVP to + Diameter-EAP-Answer messages that have a Result-Code of + DIAMETER_SUCCESS. A separate billing identifier or pseudonym MAY be + used for privacy reasons (see Section 8.5). If the user's identity + is not available to the NAS, the Session-Id AVP MAY be used for + accounting and billing; however operationally this could be very + difficult to manage. + +2.8.2. Conflicting AVPs + + A Diameter-EAP-Answer message containing an EAP-Payload of type + EAP-Success or EAP-Failure MUST NOT have the Result-Code AVP set to + DIAMETER_MULTI_ROUND_AUTH. + + Some lower layers assume that the authorization decision is made by + the EAP server, and thus the peer considers EAP Success as an + indication that access was granted. In this case, the Result-Code + SHOULD match the contained EAP packet: a successful Result-Code for + EAP-Success, and a failure Result-Code for EAP-Failure. If the + encapsulated EAP packet does not match the result implied by the + Result-Code AVP, the combination is likely to cause confusion, + because the NAS and peer will conclude the outcome of the + authentication differently. For example, if the NAS receives a + failure Result-Code with an encapsulated EAP Success, it will not + grant access to the peer. However, on receiving the EAP Success, the + peer will be led to believe that access was granted. + + This situation can be difficult to avoid when Diameter proxy agents + make authorization decisions (that is, proxies can change the + Result-Code AVP sent by the home server). Because it is the + responsibility of the Diameter server to avoid conflicts, the NAS + MUST NOT "manufacture" EAP result packets in order to correct the + contradictory messages that it receives. This behavior, originally + mandated within [IEEE-802.1X], is now deprecated. + + + + + + + + +Eronen, et al. Standards Track [Page 13] + +RFC 4072 Diameter EAP Application August 2005 + + +2.8.3. Displayable Messages + + The Reply-Message AVP [NASREQ] MUST NOT be included in any Diameter + message containing an EAP-Payload AVP. + +2.8.4. Role Reversal + + Some environments in which EAP is used, such as PPP, support + peer-to-peer operation. Both parties act as authenticators and + authenticatees at the same time, in two simultaneous and independent + EAP conversations. + + This specification is intended for communication between EAP + (passthrough) authenticator and backend authentication server. A + Diameter client MUST NOT send a Diameter-EAP-Request encapsulating an + EAP Request packet, and a Diameter server receiving such a packet + MUST respond with a failure Result-Code. + +2.8.5. Identifier Space + + In EAP, each session has its own unique Identifier space. Diameter + server implementations MUST be able to distinguish between EAP + packets with the same Identifier existing within distinct EAP + sessions and originating on the same NAS. This is done by using the + Session-Id AVP. + + If a Diameter NAS is in the middle of a multi-round authentication + exchange, and it detects that the EAP session between the client and + the NAS has been terminated, it MUST select a new Diameter Session-Id + for any subsequent EAP sessions. This is necessary in order to + distinguish a restarted EAP authentication process from the + continuation of an ongoing process (by the same user on the same NAS + and port). + + In RADIUS, the same functionality can be achieved through the + inclusion or omission of the State attribute. Translation rules in + [NASREQ] ensure that an Access-Request without the State attribute + maps to a new Diameter Session-Id AVP value. Furthermore, a + translation agent will always include a State attribute in + Access-Challenge messages, making sure that the State attribute is + available for a RADIUS NAS. + +3. Command-Codes + + This section defines new Command-Code values that MUST be supported + by all Diameter implementations conforming to this specification. + The following commands are defined in this section: + + + + +Eronen, et al. Standards Track [Page 14] + +RFC 4072 Diameter EAP Application August 2005 + + + Command-Name Abbrev. Code Reference + -------------------------------------------------------- + Diameter-EAP-Request DER 268 3.1 + Diameter-EAP-Answer DEA 268 3.2 + + When the NASREQ AA-Request (AAR) or AA-Answer (AAA) commands are used + for AUTHORIZE_ONLY messages in conjunction with EAP (see + Section 2.3.3), an Application Identifier value of 1 (NASREQ) is + used, and the commands follow the rules and ABNF defined in [NASREQ]. + + When the Re-Auth-Request (RAR), Re-Auth-Answer (RAA), + Session-Termination-Request (STR), Session-Termination-Answer (STA), + Abort-Session-Request (ASR), Abort-Session-Answer (ASA), + Accounting-Request (ACR), and Accounting-Answer (ACA) commands are + used together with the Diameter EAP application, they follow the + rules in [NASREQ] and [BASE]. The accounting commands use + Application Identifier value of 3 (Diameter Base Accounting); the + others use 0 (Diameter Common Messages). + +3.1. 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-EAP-Request> ::= < Diameter Header: 268, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Request-Type } + [ Destination-Host ] + + + +Eronen, et al. Standards Track [Page 15] + +RFC 4072 Diameter EAP Application August 2005 + + + [ 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 ] + +3.2. 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. + + + + + + +Eronen, et al. Standards Track [Page 16] + +RFC 4072 Diameter EAP Application August 2005 + + + 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-EAP-Answer> ::= < 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 ] + + + +Eronen, et al. Standards Track [Page 17] + +RFC 4072 Diameter EAP Application August 2005 + + + [ 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 ] + +4. Attribute-Value Pairs + + This section both defines new AVPs, unique to the EAP Diameter + application and describes the usage of AVPs defined elsewhere (if + that usage in the EAP application is noteworthy). + +4.1. New AVPs + +4.1.1. EAP-Payload AVP + + 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. + +4.1.2. EAP-Reissued-Payload AVP + + The EAP-Reissued-Payload AVP (AVP Code 463) is of type OctetString. + The use of this AVP is described in Section 2.4. + + + + + +Eronen, et al. Standards Track [Page 18] + +RFC 4072 Diameter EAP Application August 2005 + + +4.1.3. EAP-Master-Session-Key AVP + + 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. + +4.1.4. EAP-Key-Name AVP + + 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. + +4.1.5. Accounting-EAP-Auth-Method AVP + + 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). + + The use of this AVP is described in Section 2.7. + +5. AVP Occurrence Tables + + The following tables use these symbols: + + 0 The AVP MUST NOT be present in the message + 0+ Zero or more instances of the AVP MAY be present in the message + 0-1 Zero or one instance of the AVP MAY be present in the message + 1 One instance of the AVP MUST be present in the message + + Note that AVPs that can only be present within a Grouped AVP are not + represented in these tables. + + + + + + +Eronen, et al. Standards Track [Page 19] + +RFC 4072 Diameter EAP Application August 2005 + + +5.1. EAP Command AVP Table + + The following table lists the AVPs that may be present in the DER and + DEA Commands, as defined in this document; the AVPs listed are + defined both here and in [NASREQ]. + + +---------------+ + | Command-Code | + |-------+-------+ + Attribute Name | DER | DEA | + ------------------------------------|-------+-------| + Accounting-EAP-Auth-Method | 0 | 0+ | + Acct-Interim-Interval [BASE] | 0 | 0-1 | + Auth-Application-Id [BASE] | 1 | 1 | + Auth-Grace-Period [BASE] | 0-1 | 0-1 | + Auth-Request-Type [BASE] | 1 | 1 | + Auth-Session-State [BASE] | 0-1 | 0-1 | + Authorization-Lifetime [BASE] | 0-1 | 0-1 | + Callback-Id [NASREQ] | 0 | 0-1 | + Callback-Number [NASREQ] | 0-1 | 0-1 | + Called-Station-Id [NASREQ] | 0-1 | 0 | + Calling-Station-Id [NASREQ] | 0-1 | 0 | + Class [BASE] | 0 | 0+ | + Configuration-Token [NASREQ] | 0 | 0+ | + Connect-Info [NASREQ] | 0-1 | 0 | + Destination-Host [BASE] | 0-1 | 0 | + Destination-Realm [BASE] | 1 | 0 | + EAP-Master-Session-Key | 0 | 0-1 | + EAP-Key-Name | 0-1 | 0-1 | + EAP-Payload | 1 | 0-1 | + EAP-Reissued-Payload | 0 | 0-1 | + Error-Message [BASE] | 0 | 0-1 | + Error-Reporting-Host [BASE] | 0 | 0-1 | + Failed-AVP [BASE] | 0 | 0+ | + Filter-Id [NASREQ] | 0 | 0+ | + Framed-Appletalk-Link [NASREQ] | 0 | 0-1 | + Framed-Appletalk-Network [NASREQ] | 0 | 0+ | + Framed-Appletalk-Zone [NASREQ] | 0 | 0-1 | + Framed-Compression [NASREQ] | 0+ | 0+ | + Framed-Interface-Id [NASREQ] | 0-1 | 0-1 | + Framed-IP-Address [NASREQ] | 0-1 | 0-1 | + Framed-IP-Netmask [NASREQ] | 0-1 | 0-1 | + Framed-IPv6-Prefix [NASREQ] | 0+ | 0+ | + Framed-IPv6-Pool [NASREQ] | 0 | 0-1 | + Framed-IPv6-Route [NASREQ] | 0 | 0+ | + Framed-IPX-Network [NASREQ] | 0 | 0-1 | + Framed-MTU [NASREQ] | 0-1 | 0-1 | + Framed-Pool [NASREQ] | 0 | 0-1 | + + + +Eronen, et al. Standards Track [Page 20] + +RFC 4072 Diameter EAP Application August 2005 + + + Framed-Protocol [NASREQ] | 0-1 | 0-1 | + Framed-Route [NASREQ] | 0 | 0+ | + Framed-Routing [NASREQ] | 0 | 0-1 | + Idle-Timeout [NASREQ] | 0 | 0-1 | + Multi-Round-Time-Out [BASE] | 0 | 0-1 | + NAS-Filter-Rule [NASREQ] | 0 | 0+ | + NAS-Identifier [NASREQ] | 0-1 | 0 | + NAS-IP-Address [NASREQ] | 0-1 | 0 | + NAS-IPv6-Address [NASREQ] | 0-1 | 0 | + NAS-Port [NASREQ] | 0-1 | 0 | + NAS-Port-Id [NASREQ] | 0-1 | 0 | + NAS-Port-Type [NASREQ] | 0-1 | 0 | + Originating-Line-Info [NASREQ] | 0-1 | 0 | + Origin-Host [BASE] | 1 | 1 | + Origin-Realm [BASE] | 1 | 1 | + Origin-State-Id [BASE] | 0-1 | 0-1 | + Port-Limit [NASREQ] | 0-1 | 0-1 | + Proxy-Info [BASE] | 0+ | 0+ | + QoS-Filter-Rule [NASREQ] | 0 | 0+ | + Re-Auth-Request-Type [BASE] | 0 | 0-1 | + Redirect-Host [BASE] | 0 | 0+ | + Redirect-Host-Usage [BASE] | 0 | 0-1 | + Redirect-Max-Cache-Time [BASE] | 0 | 0-1 | + Reply-Message [NASREQ] | 0 | 0+ | + Result-Code [BASE] | 0 | 1 | + Route-Record [BASE] | 0+ | 0+ | + Service-Type [NASREQ] | 0-1 | 0-1 | + Session-Id [BASE] | 1 | 1 | + Session-Timeout [BASE] | 0 | 0-1 | + State [NASREQ] | 0-1 | 0-1 | + Tunneling [NASREQ] | 0+ | 0+ | + User-Name [BASE] | 0-1 | 0-1 | + +5.2. Accounting AVP Table + + The table in this section is used to represent which AVPs defined in + this document are to be present in the Accounting messages, as + defined in [BASE]. + + +-----------+ + | Command | + | Code | + |-----+-----+ + Attribute Name | ACR | ACA | + ---------------------------------------|-----+-----+ + Accounting-EAP-Auth-Method | 0+ | 0 | + + + + + +Eronen, et al. Standards Track [Page 21] + +RFC 4072 Diameter EAP Application August 2005 + + +6. RADIUS/Diameter Interactions + + Section 9 of [NASREQ] describes basic guidelines for translation + agents that translate between RADIUS and Diameter protocols. These + guidelines SHOULD be followed for Diameter EAP application as well, + with some additional guidelines given in this section. Note that + this document does not restrict implementations from creating + additional methods, as long as the translation function does not + violate the RADIUS or the Diameter protocols. + +6.1. RADIUS Request Forwarded as Diameter Request + + RADIUS Access-Request to Diameter-EAP-Request: + + o RADIUS EAP-Message attribute(s) are translated to a Diameter + EAP-Payload AVP. If multiple RADIUS EAP-Message attributes are + present, they are concatenated and translated to a single Diameter + EAP-Payload AVP. + + o An empty RADIUS EAP-Message attribute (with length 2) signifies + EAP-Start, and it is translated to an empty EAP-Payload AVP. + + Diameter-EAP-Answer to RADIUS Access-Accept/Reject/Challenge: + + o Diameter EAP-Payload AVP is translated to RADIUS EAP-Message + attribute(s). If necessary, the value is split into multiple + RADIUS EAP-Message attributes. + + o Diameter EAP-Reissued-Payload AVP is translated to a message that + contains RADIUS EAP-Message attribute(s), and a RADIUS Error-Cause + attribute [RFC3576] with value 202 (decimal), "Invalid EAP Packet + (Ignored)" [RFC3579]. + + o As described in [NASREQ], if the Result-Code AVP set to + DIAMETER_MULTI_ROUND_AUTH and the Multi-Round-Time-Out AVP is + present, it is translated to the RADIUS Session-Timeout attribute. + + o Diameter EAP-Master-Session-Key AVP can be translated to the + vendor-specific RADIUS MS-MPPE-Recv-Key and MS-MPPE-Send-Key + attributes [RFC2548]. The first up to 32 octets of the key is + stored into MS-MPPE-Recv-Key, and the next up to 32 octets (if + present) are stored into MS-MPPE-Send-Key. The encryption of this + attribute is described in [RFC2548]. + + o Diameter Accounting-EAP-Auth-Method AVPs, if present, are + discarded. + + + + + +Eronen, et al. Standards Track [Page 22] + +RFC 4072 Diameter EAP Application August 2005 + + +6.2. Diameter Request Forwarded as RADIUS Request + + Diameter-EAP-Request to RADIUS Access-Request: + + o The Diameter EAP-Payload AVP is translated to RADIUS EAP-Message + attribute(s). + + o An empty Diameter EAP-Payload AVP signifies EAP-Start, and is + translated to an empty RADIUS EAP-Message attribute. + + o The type (or expanded type) field from the EAP-Payload AVP can be + saved either in a local state table, or encoded in a RADIUS + Proxy-State attribute. This information is needed to construct an + Accounting-EAP-Auth-Method AVP for the answer message (see below). + + RADIUS Access-Accept/Reject/Challenge to Diameter-EAP-Answer: + + o If the RADIUS Access-Challenge message does not contain an + Error-Cause attribute [RFC3576] with value 202 (decimal), "Invalid + EAP Packet (Ignored)" [RFC3579], any RADIUS EAP-Message attributes + are translated to a Diameter EAP-Payload AVP, concatenating them + if multiple attributes are present. + + o If the Error-Cause attribute with value 202 is present, any RADIUS + EAP-Message attributes are translated to a Diameter + EAP-Reissued-Payload AVP, concatenating them if multiple + attributes are present. + + o As described in [NASREQ], if the Session-Timeout attribute is + present in a RADIUS Access-Challenge message, it is translated to + the Diameter Multi-Round-Time-Out AVP. + + o If the vendor-specific RADIUS MS-MPPE-Recv-Key and/or + MS-MPPE-Send-Key attributes [RFC2548] are present, they can be + translated to a Diameter EAP-Master-Session-Key AVP. The + attributes have to be decrypted before conversion, and the Salt, + Key-Length and Padding sub-fields are discarded. The Key + sub-fields are concatenated (MS-MPPE-Recv-Key first, + MS-MPPE-Send-Key next), and the concatenated value is stored into + a Diameter EAP-Master-Session-Key AVP. + + o If the Diameter-EAP-Answer will have a successful result code, the + saved state (see above) can be used to construct an + Accounting-EAP-Auth-Method AVP. + + + + + + + +Eronen, et al. Standards Track [Page 23] + +RFC 4072 Diameter EAP Application August 2005 + + +6.3. Accounting Requests + + In Accounting-Requests, the vendor-specific RADIUS MS-Acct-EAP-Type + attribute [RFC2548] can be translated to a Diameter + Accounting-EAP-Auth-Method AVP, and vice versa. + + When translating from Diameter to RADIUS, note that the + MS-Acct-EAP-Type attribute does not support expanded EAP types. Type + values greater than 255 should be translated to type 254. + +7. IANA Considerations + + This document does not create any new namespaces to be maintained by + IANA, but it requires new values in namespaces that have been defined + in the Diameter Base protocol and RADIUS specifications. + + o This document defines one new Diameter command (in Section 3) + whose Command Code is allocated from the Command Code namespace + defined in [BASE]. The Command Code for DER / DEA is 268. + + o This document defines four new AVPs whose AVP Codes are allocated + from the AVP Code namespace defined in [BASE] as follows: + + 462 for EAP-Payload (defined in Section 4.1.1), + 463 for EAP-Reissued-Payload (defined in Section 4.1.2), + 464 for EAP-Master-Session-Key (defined in Section 4.1.3), and + 465 for Accounting-EAP-Auth-Method (defined in Section 4.1.5). + + o This document defines one new AVP (attribute) whose AVP Code + (Attribute Type) is to be allocated from the Attribute Type + namespace defined in [RFC2865] and [RFC3575]. The Radius + Attribute Type for EAP-Key-Name (defined in Section 4.1.4) is 102. + + o This document defines one new Diameter application (in + Section 2.1) whose Application ID is to be allocated from the + Application Identifier namespace defined in [BASE]. The + Application ID for Diameter EAP is 5. + +8. Security Considerations + +8.1. Overview + + Diameter peer-to-peer connections can be protected with IPsec or TLS. + These mechanisms are believed to provide sufficient protection under + the normal Internet threat model, that is, assuming the authorized + nodes engaging in the protocol have not been compromised, but the + attacker has complete control over the communication channels between + them. This includes eavesdropping, message modification, insertion, + + + +Eronen, et al. Standards Track [Page 24] + +RFC 4072 Diameter EAP Application August 2005 + + + man-in-the-middle and replay attacks. The details and related + security considerations are discussed in [BASE]. + + In addition to authentication provided by IPsec or TLS, authorization + is also required. Here, authorization means determining if a + Diameter message received from an authenticated Diameter peer should + be accepted (and not authorization of users requesting network access + from a NAS). In other words, when a Diameter server receives a + Diameter-EAP-Request, it has to decide if the client is authorized to + act as a NAS for the specific user, service type, and so on. + Correspondingly, when a NAS contacts a server to send a + Diameter-EAP-Request, it has to determine whether the server is + authorized to act as home server for the realm in question. + + Authorization can involve local Access Control Lists (ACLs), + information contained in certificates, or some other means. See + [BASE] for more discussion and related security considerations. Note + that authorization issues are particularly relevant when Diameter + redirects are used. While redirection reduces the number of nodes + which have access to the contents of Diameter messages, a compromised + Diameter agent may not supply the right home server's address. If + the Diameter client is unable to tell whether this particular server + is authorized to act as the home server for this particular user, the + security of the communications rests on the redirect agent. + + The hop-by-hop security mechanisms (IPsec and TLS) combined with + proper authorization provide good protection against "outside" + attackers, except for denial-of-service attacks. The remaining part + of this section deals with attacks by nodes that have been properly + authorized (to function as a NAS, Diameter agent, or Diameter + server), but abuse their authorization or have been compromised. In + general, it is not possible to completely protect against attacks by + compromised nodes, but this section offers advice on limiting the + extent of the damage. + + Attacks involving eavesdropping or modification of EAP messages are + beyond the scope of these document. See [EAP] for discussion of + these security considerations (including method negotiation, + dictionary attacks, and privacy issues). While these attacks can be + carried out by an attacker between the client and the NAS, + compromised NASes and Diameter agents are naturally also in a good + position to modify and eavesdrop on the EAP messages. + + Similarly, attacks involving the link layer protocol used between the + client and the NAS, such as PPP or IEEE 802.11, are beyond the scope + of this document. + + + + + +Eronen, et al. Standards Track [Page 25] + +RFC 4072 Diameter EAP Application August 2005 + + +8.2. AVP Editing + + Diameter agents can modify, insert, and delete AVPs. Diameter agents + are usually meant to modify AVPs, and the protocol cannot distinguish + well-intentioned and malicious modifications (see [RFC2607] for more + discussion). Similarly, a compromised NAS or server can naturally + include a different set of AVPs than expected. + + Therefore, the question is what an attacker who compromises an + authorized NAS, agent, or server can do using Diameter EAP messages. + Some of the consequences are rather obvious. For instance, a + Diameter agent can give access to unauthorized users by changing the + Result-Code to DIAMETER_SUCCESS. Other consequences are less obvious + and are discussed below and authentication method negotiation attacks + are discussed in the next section. + + By including suitable AVPs in an AA-Answer/Diameter-EAP-Answer + messages, an attacker may be able (depending on implementation and + configuration details) to: + + o Give unauthorized users access, or deny access to authorized users + (Result-Code). + + o Give an attacker a login session to a host otherwise protected by + firewalls, or redirect an authorized user's login session to a + host controlled by the attacker (Login-Host). + + o Route an authorized user's traffic through a host controlled by + the attacker (various tunneling AVPs). + + o Redirect an authorized user's DNS requests to a malicious DNS + server (various vendor-specific AVPs). + + o Modify routing tables at the NAS and thus redirect packets + destined for someone else (Framed-Route, Framed-Routing). + + o Remove packet filters and other restrictions for user (Filter, + Callback, various vendor-specific AVPs). + + o Cause the NAS to call some number, possibly an expensive toll + number controlled by the attacker (callback AVPs). + + o Execute Command Line Interface (CLI) commands on the NAS (various + vendor-specific attributes). + + + + + + + +Eronen, et al. Standards Track [Page 26] + +RFC 4072 Diameter EAP Application August 2005 + + + By modifying an AA-Request/Diameter-EAP-Request, an attacker may be + able to: + + o Change NAS-Identifier/NAS-Port/Origin-Host (or another attribute) + so that a valid user appears to be accessing the network from a + different NAS than in reality. + + o Modify Calling-Station-ID (either to hide the true value, gain + access, or frame someone else). + + o Modify password change messages (some vendor-specific attributes). + + o Modify usage information in accounting messages. + + o Modify contents of Class and State AVPs. + + Some of these attacks can be prevented if the NAS or server is + configured to not accept some particular AVPs, or accepts them only + from some nodes. + +8.3. Negotiation Attacks + + This section deals with attacks where the NAS, any Diameter agents, + or Diameter server attempt to cause the authenticating user to choose + some authentication method other than EAP, such as PAP or CHAP + (negotiation attacks within EAP are discussed in [EAP], Section 7.8). + + The vulnerability can be mitigated via implementation of a per- + connection policy by the authenticating peer, and a per-user policy + by the Diameter server. For the authenticating peer, the + authentication policy should be set on a per-connection basis. + + With a per-connection policy, an authenticating peer will only + attempt to negotiate EAP for a session in which EAP support is + expected. As a result, it is presumed that an authenticating peer + selecting EAP requires that level of security. If it cannot be + provided, there is likely a misconfiguration, or the authenticating + peer may be contacting the wrong server. In this case, the + authenticating peer simply disconnects. + + Similarly, with a per-user policy, the home server will not accept + authentication methods other than EAP for users for which EAP support + is expected. + + For a NAS, it may not be possible to determine whether a peer is + required to authenticate with EAP until the peer's identity is known. + For example, for shared-uses NASes one reseller may implement EAP + while another does not. Alternatively, some peer might be + + + +Eronen, et al. Standards Track [Page 27] + +RFC 4072 Diameter EAP Application August 2005 + + + authenticated locally by the NAS while other peers are authenticated + via Diameter. In such cases, if any peers of the NAS MUST do EAP, + then the NAS MUST attempt to negotiate EAP for every session. This + avoids forcing a peer to support more than one authentication type, + which could weaken security. + +8.4. Session Key Distribution + + Since there are currently no end-to-end (NAS-to-home server) security + mechanisms specified for Diameter, any agents that process + Diameter-EAP-Answer messages can see the contents of the + EAP-Master-Session-Key AVP. For this reason, this specification + strongly recommends avoiding Diameter agents when they cannot be + trusted to keep the keys secret. + + In environments where agents are present, several factors should be + considered when deciding whether the agents that are authorized (and + considered "trustworthy enough") to grant access to users and specify + various authorization and tunneling AVPs are also "trustworthy + enough" to handle the session keys. These factors include (but are + not limited to) the type of access provided (e.g., public Internet or + corporate internet), security level of the agents, and the + possibilities for attacking user's traffic after it has been + decrypted by the NAS. + + Note that the keys communicated in Diameter messages are usually + short-term session keys (or short-term master keys that are used to + derive session keys). To actually cause any damage, those session + keys must end up with some malicious party that must be able to + eavesdrop, modify, or insert traffic between the user and the NAS + during the lifetime of those keys (for example, in 802.11i the + attacker must also eavesdrop the "four-way handshake"). + +8.5. Privacy Issues + + Diameter messages can contain AVPs that can be used to identify the + user (e.g., User-Name) and approximate location of the user (e.g., + Origin-Host for WLAN access points, Calling-Station-Id for fixed + phone lines). Thus, any Diameter nodes that process the messages may + be able to determine the geographic location of users. + + Note that in many cases, the user identity is also sent in clear + inside EAP-Payload AVPs, and it may be possible to eavesdrop this + between the user and the NAS. + + This can be mitigated somewhat by using EAP methods that provide + identity protection (see [EAP], Section 7.3), and using Session-Id or + pseudonyms for accounting. + + + +Eronen, et al. Standards Track [Page 28] + +RFC 4072 Diameter EAP Application August 2005 + + +8.6. Note about EAP and Impersonation + + If the EAP method used does not provide mutual authentication, + obviously anyone can impersonate the network to the user. Even when + EAP mutual authentication is used, it occurs between the user and the + Diameter home server. See [EAPKey] for an extensive discussion about + the details and their implications. + + One issue is worth pointing out here. As described in [EAPKey], the + current EAP architecture does not allow the home server to restrict + what service parameters or identities (such as SSID or BSSID in + 802.11 wireless LANs) are advertised by the NAS to the client. That + is, a compromised NAS can change its BSSID or SSID, and thus appear + to offer a different service than intended. Even if these parameters + are included in Diameter-EAP-Answer messages, the NAS can tell + different values to the client. + + Therefore, the NAS's possession of the session keys proves that the + user is talking to an authorized NAS, but a compromised NAS can lie + about its exact identity. See [EAPKey] for discussion on how + individual EAP methods can provide authentication of NAS service + parameters and identities. + + Note that the usefulness of this authentication may be rather limited + in many environments. For instance, in wireless LANs the user does + not usually securely know the identity (such as BSSID) of the "right" + access point; it is simply picked from a beacon message that has the + correct SSID and good signal strength (something that is easy to + spoof). Thus, simply authenticating the identity may not allow the + user to distinguish the "right" access point from all others. + +9. Acknowledgements + + This Diameter application relies heavily on earlier work on Diameter + NASREQ application [NASREQ] and RADIUS EAP support [RFC3579]. Much + of the material in this specification has been copied from these + documents. + + The authors would also like to acknowledge the following people for + their contributions to this document: Bernard Aboba, Jari Arkko, + Julien Bournelle, Pat Calhoun, Henry Haverinen, John Loughney, + Yoshihiro Ohba, and Joseph Salowey. + + + + + + + + + +Eronen, et al. Standards Track [Page 29] + +RFC 4072 Diameter EAP Application August 2005 + + +10. References + +10.1. Normative References + + [BASE] Calhoun, P., Loughney, J., Guttman, E., Zorn, G., and + J. Arkko, "Diameter Base Protocol", RFC 3588, + September 2003. + + [EAP] Aboba, B., Blunk, L., Vollbrecht, J., Carlson, J., and + H. Levkowetz, "Extensible Authentication Protocol + (EAP)", RFC 3748, June 2004. + + [NASREQ] Calhoun, P., Zorn, G., Spence, D., and D. Mitton, + "Diameter Network Access Server Application", RFC + 4005, August 2005. + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + +10.2. Informative References + + [EAPKey] Aboba, B., Simon, D., Arkko, J., Eronen, P., and H. + Levkowetz, "Extensible Authentication Protocol (EAP) + Key Management Framework", Work in Progress, July + 2004. + + [IEEE-802.1X] Institute of Electrical and Electronics Engineers, + "Local and Metropolitan Area Networks: Port-Based + Network Access Control", IEEE Standard 802.1X, + September 2001. + + [IEEE-802.11i] Institute of Electrical and Electronics Engineers, + "IEEE Standard for Information technology - + Telecommunications and information exchange between + systems - Local and metropolitan area networks - + Specific requirements - Part 11: Wireless Medium + Access Control (MAC) and Physical Layer (PHY) + Specifications: Amendment 6: Medium Access Control + (MAC) Security Enhancements", IEEE Standard + 802.11i-2004, July 2004. + + [IKEv2] Kaufman, C., Ed., "Internet Key Exchange (IKEv2) + Protocol", Work in Progress, June 2004. + + [RFC1661] Simpson, W., "The Point-to-Point Protocol (PPP)", + STD 51, RFC 1661, July 1994. + + + + + +Eronen, et al. Standards Track [Page 30] + +RFC 4072 Diameter EAP Application August 2005 + + + [RFC2548] Zorn, G., "Microsoft Vendor-specific RADIUS + Attributes", RFC 2548, March 1999. + + [RFC2607] Aboba, B. and J. Vollbrecht, "Proxy Chaining and + Policy Implementation in Roaming", RFC 2607, + June 1999. + + [RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson, + "Remote Authentication Dial In User Service (RADIUS)", + RFC 2865, June 2000. + + [RFC3575] Aboba, B., "IANA Considerations for RADIUS (Remote + Authentication Dial In User Service)", RFC 3575, + July 2003. + + [RFC3576] Chiba, M., Dommety, G., Eklund, M., Mitton, D., and B. + Aboba, "Dynamic Authorization Extensions to Remote + Authentication Dial In User Service (RADIUS)", + RFC 3576, July 2003. + + [RFC3579] Aboba, B. and P. Calhoun, "RADIUS (Remote + Authentication Dial In User Service) Support For + Extensible Authentication Protocol (EAP)", RFC 3579, + September 2003. + + [RFC3580] Congdon, P., Aboba, B., Smith, A., Zorn, G., and J. + Roese, "IEEE 802.1X Remote Authentication Dial In User + Service (RADIUS) Usage Guidelines", RFC 3580, + September 2003. + + + + + + + + + + + + + + + + + + + + + + +Eronen, et al. Standards Track [Page 31] + +RFC 4072 Diameter EAP Application August 2005 + + +Authors' Addresses + + Pasi Eronen (editor) + Nokia Research Center + P.O. Box 407 + FIN-00045 Nokia Group + Finland + + EMail: [email protected] + + + Tom Hiller + Lucent Technologies + 1960 Lucent Lane + Naperville, IL 60566 + USA + + Phone: +1 630 979 7673 + EMail: [email protected] + + + Glen Zorn + Cisco Systems + 500 108th Avenue N.E., Suite 500 + Bellevue, WA 98004 + USA + + Phone: +1 425 344 8113 + EMail: [email protected] + + + + + + + + + + + + + + + + + + + + + + +Eronen, et al. Standards Track [Page 32] + +RFC 4072 Diameter EAP Application August 2005 + + +Full Copyright Statement + + Copyright (C) The Internet Society (2005). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET + ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE + INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED + WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at ietf- + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + + +Eronen, et al. Standards Track [Page 33] + diff --git a/lib/diameter/doc/standard/rfc4740.txt b/lib/diameter/doc/standard/rfc4740.txt new file mode 100644 index 0000000000..2154334b66 --- /dev/null +++ b/lib/diameter/doc/standard/rfc4740.txt @@ -0,0 +1,4035 @@ + + + + + + +Network Working Group M. Garcia-Martin, Ed. +Request for Comments: 4740 Nokia +Category: Standards Track M. Belinchon + M. Pallares-Lopez + C. Canales-Valenzuela + Ericsson + K. Tammi + Nokia + November 2006 + + + Diameter Session Initiation Protocol (SIP) Application + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (C) The IETF Trust (2006). + +Abstract + + This document specifies the Diameter Session Initiation Protocol + (SIP) application. This is a Diameter application that allows a + Diameter client to request authentication and authorization + information. This application is designed to be used in conjunction + with SIP and provides a Diameter client co-located with a SIP server, + with the ability to request the authentication of users and + authorization of SIP resources usage from a Diameter server. + + + + + + + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 1] + +RFC 4740 Diameter SIP Application November 2006 + + +Table of Contents + + 1. Introduction ....................................................4 + 2. Terminology .....................................................5 + 3. Definitions .....................................................5 + 4. Acronyms ........................................................6 + 5. Applicability Statement .........................................6 + 6. Overview of Operation ...........................................7 + 6.1. General Architecture .......................................7 + 6.2. Diameter Server Authenticates the User .....................9 + 6.3. Delegating Final Authentication Check to the SIP Server ...12 + 6.4. SIP Server Requests Authentication and Authorization ......15 + 6.5. Locating the Recipient of the SIP Request .................16 + 6.6. Update of the User Profile ................................17 + 6.7. SIP Soft State Termination ................................18 + 6.8. Diameter Server Discovery .................................19 + 7. Advertising Application Support ................................21 + 8. Diameter SIP Application Command Codes .........................22 + 8.1. User-Authorization-Request (UAR) Command ..................22 + 8.2. User-Authorization-Answer (UAA) Command ...................23 + 8.3. Server-Assignment-Request (SAR) Command ...................27 + 8.4. Server-Assignment-Answer (SAA) Command ....................29 + 8.5. Location-Info-Request (LIR) Command .......................33 + 8.6. Location-Info-Answer (LIA) Command ........................33 + 8.7. Multimedia-Auth-Request (MAR) Command .....................35 + 8.8. Multimedia-Auth-Answer (MAA) Command ......................36 + 8.9. Registration-Termination-Request (RTR) Command ............39 + 8.10. Registration-Termination-Answer (RTA) Command ............39 + 8.11. Push-Profile-Request (PPR) Command .......................41 + 8.12. Push-Profile-Answer (PPA) Command ........................42 + 9. Diameter SIP Application AVPs ..................................44 + 9.1. SIP-Accounting-Information AVP ............................46 + 9.1.1. SIP-Accounting-Server-URI AVP ......................47 + 9.1.2. SIP-Credit-Control-Server-URI AVP ..................47 + 9.2. SIP-Server-URI AVP ........................................47 + 9.3. SIP-Server-Capabilities AVP ...............................47 + 9.3.1. SIP-Mandatory-Capability AVP .......................48 + 9.3.2. SIP-Optional-Capability AVP ........................48 + 9.4. SIP-Server-Assignment-Type AVP ............................48 + 9.5. SIP-Auth-Data-Item AVP ....................................50 + 9.5.1. SIP-Authentication-Scheme AVP ......................50 + 9.5.2. SIP-Item-Number AVP ................................51 + 9.5.3. SIP-Authenticate AVP ...............................51 + 9.5.4. SIP-Authorization AVP ..............................52 + 9.5.5. SIP-Authentication-Info AVP ........................52 + 9.5.6. Digest AVPs ........................................53 + 9.6. SIP-Number-Auth-Items AVP .................................55 + + + + +Garcia-Martin, et al. Standards Track [Page 2] + +RFC 4740 Diameter SIP Application November 2006 + + + 9.7. SIP-Deregistration-Reason AVP .............................55 + 9.7.1. SIP-Reason-Code AVP ................................55 + 9.7.2. SIP-Reason-Info AVP ................................56 + 9.8. SIP-AOR AVP ...............................................56 + 9.9. SIP-Visited-Network-Id AVP ................................56 + 9.10. SIP-User-Authorization-Type AVP ..........................56 + 9.11. SIP-Supported-User-Data-Type AVP .........................57 + 9.12. SIP-User-Data AVP ........................................57 + 9.12.1. SIP-User-Data-Type AVP ............................58 + 9.12.2. SIP-User-Data-Contents AVP ........................58 + 9.13. SIP-User-Data-Already-Available AVP ......................58 + 9.14. SIP-Method AVP ...........................................59 + 10. New Values for Existing AVPs ..................................59 + 10.1. Extension to the Result-Code AVP Values ..................59 + 10.1.1. Success Result-Code AVP Values ....................59 + 10.1.2. Transient Failures Result-Code AVP Values .........60 + 10.1.3. Permanent Failures Result-Code AVP Values .........60 + 11. Authentication Details ........................................61 + 12. Migration from RADIUS .........................................63 + 12.1. Gateway from RADIUS Client to Diameter Server ............63 + 12.2. Gateway from Diameter Client to RADIUS Server ............63 + 12.3. Known Limitations ........................................64 + 13. IANA Considerations ...........................................64 + 13.1. Application Identifier ...................................64 + 13.2. Command Codes ............................................65 + 13.3. AVP Codes ................................................65 + 13.4. Additional Values for the Result-Code AVP Value ..........65 + 13.5. Creation of the SIP-Server-Assignment-Type + Section in the AAA .......................................66 + 13.6. Creation of the SIP-Authentication-Scheme Section + in the AAA ...............................................66 + 13.7. Creation of the SIP-Reason-Code Section in the + AAA Registry .............................................66 + 13.8. Creation of the SIP-User-Authorization-Type + Section in the AAA .......................................66 + 13.9. Creation of the SIP-User-Data-Already-Available + Section in the ...........................................66 + 14. Security Considerations .......................................67 + 14.1. Final Authentication Check in the Diameter + Client/SIP Server ........................................67 + 15. Contributors ..................................................68 + 16. Acknowledgements ..............................................68 + 17. References ....................................................68 + 17.1. Normative References .....................................68 + 17.2. Informative References ...................................69 + + + + + + +Garcia-Martin, et al. Standards Track [Page 3] + +RFC 4740 Diameter SIP Application November 2006 + + +1. Introduction + + This document specifies the Diameter Session Initiation Protocol + (SIP) application. This is a Diameter application that allows a + Diameter client to request authentication and authorization + information to a Diameter server for SIP-based IP multimedia services + (see [RFC3261] about SIP). Furthermore, this Diameter SIP + application provides the Diameter client with functions that go + beyond the typical authorization and authentication, such as the + ability to download or receive updated user profiles, or rudimentary + routing functions that can assist a SIP server in finding another SIP + server allocated to the user. + + We assume that the SIP server (such as SIP proxy server, registrar, + redirect server, or alike) and the Diameter client are co-located in + the same node, so that the SIP server is able to receive and process + SIP requests and responses. In turn, the SIP server relies on the + Authentication, Authorization, and Accounting (AAA) infrastructure + for authenticating the SIP request and authorizing the usage of + particular SIP services. + + This document provides Diameter procedures to implement certain + required functionality when SIP is the protocol chosen to initiate + and tear down multimedia sessions or when SIP is used for other + non-session-related applications. However, this document does not + mandate any particular mapping of SIP procedures to Diameter SIP + application procedures, nor does it mandate any particular sequence + of events between SIP and Diameter. This document provides useful + examples to show the interaction between SIP and the Diameter SIP + application in order to achieve the desired functionality. + + This application does not require and is not related to other + authentication services provided by the Diameter Mobile IPv4 + [RFC4004] or the Diameter Network Access Server [RFC4005] + applications. + + This Diameter SIP application is loosely related to the Diameter + credit-control application [RFC4006]. Although both applications are + independent, the Diameter SIP application is able to supply the + addresses of credit-control servers that will be implementing the + Diameter credit-control application [RFC4006]. + + Section 5 discusses assumptions and configurations assumed by this + document. + + Section 6 provides the reader with informative descriptions of the + Diameter SIP application commands and responses and with some + guidance about their linkage with SIP procedures. + + + +Garcia-Martin, et al. Standards Track [Page 4] + +RFC 4740 Diameter SIP Application November 2006 + + + Advertisement of this application is specified in Section 7. + + Section 8 provides a normative description of all the new Diameter + commands defined by this specification. + + This application extends the Result-Code Attribute-Value-Pair (AVP) + with some new values. Further information is described in + Section 10. + + This application defines some new AVPs. All these AVPs are described + in Section 9. + + Some extra information about authentication is provided in + Section 11. + +2. Terminology + + In this document, the key words "MUST", "MUST NOT", "REQUIRED", + "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT + RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as + described in BCP 14, RFC 2119 [RFC2119] and indicate requirement + levels for compliant implementations. + +3. Definitions + + For the purpose of this document, the following terms and definitions + apply: + + Node: an addressable device attached to a computer network that + implements SIP functionality, Diameter functionality, or a + combination of both. + + For the purpose of this document, the following terms and definitions + given in RFC 3261 [RFC3261] Section 6, apply: + + o Address-of-Record (AOR) + o Outbound proxy + o Proxy + o Registrar + o Server (SIP server) + o User Agent (UA) + o User Agent Client (UAC) + o User Agent Server (UAS) + + For the purpose of this document, the following terms and definitions + given in RFC 3588 [RFC3588] Section 1.3, apply: + + + + + +Garcia-Martin, et al. Standards Track [Page 5] + +RFC 4740 Diameter SIP Application November 2006 + + + o Authorization + o Authentication + o Attribute-Value Pair (AVP) + o Diameter Client + o Diameter Server + o Home Realm + o Redirect Agent + o User + +4. Acronyms + + AKA: Authentication and Key Agreement + LIR: Location-Info-Request + LIA: Location-Info-Answer + MAR: Multimedia-Auth-Request + MAA: Multimedia-Auth-Answer + PPR: Push-Profile-Request + PPA: Push-Profile-Answer + RTR: Registration-Termination-Request + RTA: Registration-Termination-Answer + SAR: Server-Assignment-Request + SAA: Server-Assignment-Answer + SL: Subscriber Locator + UAR: User-Authorization-Request + UAA: User-Authorization-Answer + +5. Applicability Statement + + This document assumes a general architecture where a Home Realm is + composed of one or more nodes implementing Diameter or SIP functions. + Users are issuing SIP requests to access SIP resources. For each + particular user, the Home Realm needs to authenticate and authorize + the usage of those resources and/or the route to the appropriate + node. We assume that the database containing the user-related data + is located outside the SIP node that requires authorization. Data + belonging to different users may be stored in different nodes in the + Home Realm, but we assume that all the data related to a particular + user is stored in a single node. + + Note: Central to the architecture is the fact that the user data + is stored in a single point in the network. This restriction does + not mandate a particular implementation, e.g., it is possible to + implement clusters of databases operating in mirror mode to + provide redundancy. The property required by this specification + is that the user data the Diameter server has access to is stored + safely in what is seen, from the external point of view, as a + single user database. + + + + +Garcia-Martin, et al. Standards Track [Page 6] + +RFC 4740 Diameter SIP Application November 2006 + + + This document allows several configurations of the Home Realm. In + one configuration, a SIP server (proxy, registrar, etc.) is allocated + to a user for the purpose of triggering and executing services. The + allocation of the SIP server may be done dynamically, e.g., at the + time the user registers in the network. This configuration requires + a SIP server, typically located at the edge of the network, that is + able to allocate another SIP server for the user and that also + supports routing of SIP requests and responses towards that allocated + SIP server. Both SIP server nodes implement a Diameter client. + + In another configuration, the address of a SIP outbound proxy is + configured (by means outside the scope of this specification) into + the SIP User Agent. The outbound Diameter client in the SIP outbound + proxy node authenticates the user, requests authorization for SIP + requests, and performs accounting activities. + +6. Overview of Operation + + This section provides an informative description of how the Diameter + SIP application can be used together with SIP. This section is not + intended to mandate any specific usage of the Diameter SIP + application nor does it mandate a specific mapping between SIP and + Diameter messages. We provide a collection of examples that show how + the required AAA functionality can be achieved in conjunction with + SIP. + +6.1. General Architecture + + The Diameter SIP application can be used in a SIP environment where + an interface to a AAA infrastructure is required to authenticate and + authorize the usage of SIP resources. This application provides + support for SIP User Agents and proxies that implement and use HTTP + Digest authentication [RFC2617], which is the authentication + mechanism mandated by SIP [RFC3261]. The application is extensible + and, if need arises, it can be extended to provide support for other + authentication mechanisms or extensions to HTTP Digest authentication + when they occur. + + This application provides limited support for accounting services as + follows: the Diameter server is able to provide the addresses of + accounting severs to the Diameter client. Figure 1, below, shows a + general overview of the integration of the SIP architecture with the + AAA architecture. + + According to Figure 1, there are one or more SIP User Agents (UAs) + that initiate or terminate SIP traffic through one or more SIP + servers. Both SIP servers implement a Diameter client that supports + the Diameter application described in this specification. + + + +Garcia-Martin, et al. Standards Track [Page 7] + +RFC 4740 Diameter SIP Application November 2006 + + + +--------+ + UAR/UAA +--->|Diameter|<----+ PPR/PPA + LIR/LIA | | server | | MAR/MAA + | +--------+ | SAR/SAA + | | RTR/RTA + | | + v v + +------+ SIP +--------+ SIP +--------+ SIP +------+ + | SIP |<--------->| SIP |<-------->| SIP |<--------->| SIP | + | UA | |server 1| |server 2| | UA | + +------+ +--------+ +--------+ +------+ + ^ ^ + UAR/UAA | | + LIR/LIA | | MAR/MAA + | +--------+ | SAR/SAA + +--->|Diameter|<----+ + | SL | + +--------+ + + Figure 1: Architecture of the Diameter application for SIP + + In Figure 1, it can be seen that SIP server 1 sends different + Diameter commands and receives different responses than those sent + and received by SIP server 2. This is because SIP server 1 in + Figure 1 is located at the edge of a network, and its main task is to + locate SIP server 2. SIP server 2 is requesting and receiving + authentication and authorization data from the Diameter server and is + not located at the edge of the network. + + This Diameter application assumes that all the data pertaining to a + given user is stored in a single Diameter server. For redundancy + purposes, several Diameter servers can be configured in a redundancy + fashion, in which case all of them keep the data synchronized and + operate externally as a single Diameter server. + + With respect to SIP server 1 in Figure 1, the Diameter SIP + application provides support for the existence of a farm of these + servers, typically configured through one or more DNS records that + point to several hosts (this is a typical configuration in common SIP + deployments). There is no requirement for these types of servers to + keep state related to the Diameter SIP application. + + The Diameter SIP application provides support for a feature that + allows an administrative domain to provide a collection of SIP + servers 2 (as per Figure 1). Once the user registers for the first + time, one of these SIP servers is selected and all the SIP requests + related to the user are processed by the same SIP server. + + + + +Garcia-Martin, et al. Standards Track [Page 8] + +RFC 4740 Diameter SIP Application November 2006 + + + The Diameter Subscriber Locator (SL) serves the purpose of locating + the Diameter server that contains the user-related data. Its + functionality is based on the Diameter redirect mechanism and is + further described in Section 6.8. + + It should be noted that this document does not mandate any particular + SIP/AAA architecture. However, the Diameter SIP application provides + the functionality needed to accommodate all the different + architectures where SIP and Diameter are used. + + The following subsections provide an informative overview of the + Diameter SIP application, its commands, and a possible interaction + with SIP signaling. + +6.2. Diameter Server Authenticates the User + + This is the generic mechanism to authenticate users. In this + approach, we show an example of an administrative network where the + Diameter server is authenticating SIP user requests. This could be + the case of a medium-size network where the Diameter server is + keeping user records and authenticating SIP requests to perform a + certain transaction. We have chosen to show a SIP REGISTER request + in the example, but the SIP server could request authentication of + any other SIP request. + + + + + + + + + + + + + + + + + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 9] + +RFC 4740 Diameter SIP Application November 2006 + + + +--------+ +--------+ +--------+ + | SIP | |Diameter| | SIP | + |server 1| | server | |server 2| + +--------+ +--------+ +--------+ + | | | + 1. SIP REGISTER | | | + -------------------->| 2. UAR | | + |------------------>| | + | 3. UAA | | + |<------------------| | + | 4. SIP REGISTER | + |-------------------------------------->| + | | 5. MAR | + | |<------------------| + | | 6. MAA | + | |------------------>| + | 7. SIP 401 (Unauthorized) | + 8. SIP 401 (Unauth.) |<--------------------------------------| + <--------------------| | | + 9. SIP REGISTER | | | + -------------------->| 10. UAR | | + |------------------>| | + | 11. UAA | | + |<------------------| | + | 12. SIP REGISTER | + |-------------------------------------->| + | | 13. MAR | + | |<------------------| + | | 14. MAA | + | |------------------>| + | 15. SIP 200 (OK) | + 16. SIP 200 (OK) |<--------------------------------------| + <--------------------| | | + | | 17. SAR | + | |<------------------| + | | 18. SAA | + | |------------------>| + | | | + + Figure 2: Authentication performed in the Diameter server + + According to Figure 2, a SIP User Agent Client (UAC) sends a SIP + REGISTER request (step 1) to SIP server 1, which receives the SIP + request. In Figure 2, we assume that this SIP server is located at + the edge of the administrative home domain. The Diameter client in + SIP server 1 contacts its Diameter server by sending a Diameter + User-Authorization-Request (UAR) message (step 2) to determine if + this user is allowed to receive service, and if so, request the + + + +Garcia-Martin, et al. Standards Track [Page 10] + +RFC 4740 Diameter SIP Application November 2006 + + + address of a local SIP server capable of handling this user. The + Diameter server answers with a Diameter User-Authorization-Answer + (UAA) message (step 3), which indicates a list of capabilities that + SIP server 1 may use to select an appropriate SIP server (SIP server + 2) and/or a SIP or SIPS URI pointing to SIP server 2. + + SIP server 1 forwards the SIP REGISTER request (step 4) to an + appropriate SIP server (SIP server 2). Then the Diameter client in + SIP server 2 requests user authentication from the Diameter server by + sending a Diameter Multimedia-Auth-Request (MAR) message (step 5). + This request also serves to make the Diameter server aware of the SIP + or SIPS URI of SIP server 2, so as to return subsequent requests for + the same user to the same SIP server 2. The Diameter server responds + with a Diameter Multimedia-Auth-Answer (MAA) message (step 6) with + Result-Code AVP set to the value DIAMETER_MULTI_ROUND_AUTH. The + Diameter server also generates a nonce and includes a challenge in + the MAA message. SIP server 2 uses that challenge to map into the + WWW-Authenticate header in the SIP 401 (Unauthorized) response (step + 7), which is sent back to SIP server 1 and then to the SIP UAC (step + 8). + + SIP server 1 receives a next SIP REGISTER request containing the user + credentials (step 9). Note that SIP server 1 does not need to keep a + state, and even more, there is no guarantee that the SIP request + arrives at the same SIP server 1; there could be a farm of SIP + servers 1 operating in redundant configuration. The Diameter client + in SIP server 1 contacts the Diameter server by sending a Diameter + UAR message (step 10) to determine the SIP server allocated to the + user. The Diameter server sends the SIP or SIPS URI of SIP server 2 + in a Diameter UAA message (step 11). + + Then SIP server 1 forwards the SIP REGISTER request to SIP server 2 + (step 12). SIP server 2 extracts the credentials from the SIP + REGISTER request. The Diameter client in SIP server 2 sends those + credentials in a Diameter MAR message (step 13) to the Diameter + server. At this point, the Diameter server is able to authenticate + the user, and upon success, returns a Diameter MAA message (step 14) + with the AVP Result-Code set to the value DIAMETER_SUCCESS. + + Then SIP server 2 generates a SIP 200 (OK) response (step 15), which + is forwarded to SIP server 1 and eventually to the SIP UAC (step 16). + + If the Diameter client in SIP server 2 is interested in downloading + the user profile information or is required to store the address of + the SIP server in the Diameter server, then the Diameter client sends + a Diameter SAR message (step 17) to the Diameter server. The + Diameter server replies with a Diameter SAA message (step 18) that + contains the requested user profile information and the + + + +Garcia-Martin, et al. Standards Track [Page 11] + +RFC 4740 Diameter SIP Application November 2006 + + + acknowledgement of the SIP server address storage. These actions are + needed when the SIP server has to retrieve a user profile used to + provide services to the served user, or when the SIP server keeps a + state for the user, so the Diameter server needs to store the SIP + server's address. + +6.3. Delegating Final Authentication Check to the SIP Server + + An operator with a large base of installed SIP servers may wish to + minimize the number of round-trips between the Diameter client and + the Diameter server. We provide support for a mechanism where the + Diameter server delegates the final authentication check to the SIP + server, thereby saving a round-trip. Section 14.1 discusses the + security considerations of this scenario. + + It must noted that this scenario is not applicable when the Diameter + server is configured to use a session MD5 (MD5-sess) algorithm, + because the Diameter server requires the client nonce to compute the + H(A1) before sending it to the Diameter client. However, the client + nonce might not be available at that time. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 12] + +RFC 4740 Diameter SIP Application November 2006 + + + +--------+ +--------+ +--------+ + | SIP | |Diameter| | SIP | + |server 1| | server | |server 2| + +--------+ +--------+ +--------+ + | | | + 1. SIP REGISTER | | | + -------------------->| 2. UAR | | + |------------------>| | + | 3. UAA | | + |<------------------| | + | 4. SIP REGISTER | + |-------------------------------------->| + | | 5. MAR | + | |<------------------| + | | 6. MAA | + | |------------------>| + | 7. SIP 401 (Unauthorized) | + 8. SIP 401 (Unauth.) |<--------------------------------------| + <--------------------| | | + 9. SIP REGISTER | | | + -------------------->| 10. UAR | | + |------------------>| | + | 11. UAA | | + |<------------------| | + | 12. SIP REGISTER | + |-------------------------------------->| + | | 13. SAR | + | |<------------------| + | | 14. SAA | + | |------------------>| + | 15. SIP 200 (OK) | + 16. SIP 200 (OK) |<--------------------------------------| + <--------------------| | | + | | | + + Figure 3: Delegation of authentication to the SIP server + + Figure 3 shows an example where a SIP server is dynamically allocated + to serve a SIP User Agent with the support of the Diameter server. + This may be the case of certain architectures, such as that of the + 3rd Generation Partnership Project (3GPP) IP Multimedia Core Network + Subsystem. + + A first SIP server receives a SIP REGISTER request (step 1) whose + target is the home network domain. In Figure 3, we assume that this + SIP server is located at the edge of the administrative home domain. + The Diameter client in this SIP server requests authorization from + the Diameter server to proceed with the registration, by sending a + + + +Garcia-Martin, et al. Standards Track [Page 13] + +RFC 4740 Diameter SIP Application November 2006 + + + Diameter User-Authorization-Request (UAR) message (step 2). The + message includes, among other Attribute-Value-Pairs (AVPs), the SIP + Address-Of-Record (AOR) that is included in the SIP REGISTER request. + The Diameter server verifies the SIP AOR and, if it is a valid + defined user in the home network, authorizes the registration to + proceed. The Diameter server responds with a Diameter + User-Authorization-Answer (UAA) message (step 3), which informs the + Diameter client/SIP server about the result of the user + authorization. In case of a successful authorization, the Diameter + UAA message indicates the address of a local SIP server (SIP server 2 + in Figure 3) and/or a list of capabilities that SIP server 1 may use + to select an appropriate SIP server 2. + + When the authorization is successful, SIP server 1 forwards the SIP + REGISTER request (step 4) to the appropriate SIP server (SIP server + 2). The Diameter client in SIP server 2 requests authentication + parameters by sending a Diameter Multimedia-Auth-Request (MAR) + message (step 5) to the Diameter server. This request also makes the + Diameter server aware of the SIP or SIPS URI of SIP server 2, so as + to return subsequent requests of the same user to the same SIP server + 2. The Diameter server responds with a Diameter + Multimedia-Auth-Answer (MAA) message (step 6), which includes a nonce + and all the rest of the parameters necessary for the designated + authentication algorithm associated with the user. Among others, the + MAA message includes a Digest-HA1 AVP that contains H(A1) (as defined + in RFC 2617 [RFC2617]), and that allows the Diameter client to + calculate the expected response. Then the Diameter client can + compare this expected response with the response to the challenge + sent from the SIP UA. The absence of the Digest-HA1 AVP in MAA + indicates that authentication and authorization take place in the + Diameter server, as per the scenario described in Section 6.2. + + SIP server 2 creates a SIP 401 (Unauthorized) SIP response (step 7) + based on the challenge included in the MAA message, including the + authentication material needed by the SIP User Agent Client (UAC) to + include the appropriate credentials. SIP server 1 forwards the SIP + response to the SIP UAC (step 8). + + The SIP server 1 receives the next SIP REGISTER request containing + the user credentials (step 9). Because SIP server 1 does not need to + keep a state (and there is no guarantee that the SIP request arrives + to the same SIP server 1), the Diameter client in SIP server 1 + contacts the Diameter server again by sending a Diameter UAR message + (step 10) to determine the SIP server allocated to the user. The + Diameter server sends the SIP or SIPS URI of SIP server 2 in a + Diameter UAA message (step 11). + + + + + +Garcia-Martin, et al. Standards Track [Page 14] + +RFC 4740 Diameter SIP Application November 2006 + + + SIP server 1 forwards the SIP REGISTER request to SIP server 2 (step + 12). SIP server 2 validates the credentials by comparing the + response supplied by the SIP UA with the expected response calculated + by the SIP server 2 (based on the H(A1) received from the Diameter + server). + + If the credentials are valid, SIP server 2 sends a Diameter + Server-Assignment-Request (SAR) message (step 13) requesting the + Diameter server to confirm the completion of the authentication + procedure and to confirm the SIP or SIPS URI of the SIP server that + is currently serving the user. The Diameter SAR message also serves + the purpose of requesting that the Diameter server send the user + profile to the SIP server. The Diameter server responds with a + Diameter Server-Assignment-Answer (SAA) message (step 14). If the + Result-Code AVP value does not inform SIP Server 2 of an error, the + SAA message can include zero or more SIP-User-Data AVPs containing + the information that SIP server 2 needs in order to provide a service + to the user. + + SIP server 2 generates a SIP 200 (OK) response (step 15), which is + forwarded to SIP server 1 and eventually to the SIP UAC (step 16). + +6.4. SIP Server Requests Authentication and Authorization + + Figure 4 depicts a typical scenario where a stateless SIP proxy + requests authentication information and authorization to a Diameter + server, for the purpose of providing SIP routing services to a SIP + User Agent. The SIP proxy server may be configured as an outbound + SIP proxy, so that all the requests initiated by the SIP UA traverse + the SIP proxy. + + According to Figure 4, a SIP User Agent sends a SIP request to its + outbound SIP proxy server. In this case, the message is a SIP INVITE + request (see step 1), but it could be any other SIP request. We + assume that this SIP request does not contain any credentials at this + time. The outbound SIP proxy server needs to authenticate and + authorize the proxy services offered to the user. The Diameter + client in the SIP server sends a Multimedia-Auth-Request (MAR) + message (step 2). The Diameter server generates a nonce and sends a + Multimedia-Auth-Answer (MAA) message (step 3) that includes the nonce + and the rest of the data necessary for the SIP server to challenge + the user, typically with HTTP Digest Authentication indicated in the + MAA message. This data enables the SIP server to create a SIP 407 + (Proxy Authentication Required) response (step 4) that contains a + challenge. The SIP UA creates a new INVITE request (step 5) that + contains the credentials. The Diameter client in the SIP server + sends the credentials to the Diameter server in a new Diameter MAR + message (step 6). The Diameter server validates the credentials and + + + +Garcia-Martin, et al. Standards Track [Page 15] + +RFC 4740 Diameter SIP Application November 2006 + + + authorize the SIP transaction in a Diameter MAA message (step 7). + The SIP server forwards the SIP INVITE request to its destination + (step 8) as per regular SIP procedures. Eventually, the session + setup is confirmed with a SIP 200 (OK) response (step 9) that is + forwarded to the SIP UA (step 10). The session setup is complete. + + +--------+ +--------+ + |Diameter| | SIP | + | server | | server | + +--------+ +--------+ + | | + | | + 1. SIP INVITE | + ----------------------------------->| + | 2. MAR | + |<------------------| + | 3. MAA | + |------------------>| + | | + 4. SIP 407 (Proxy | + Authentication Required) | + <-----------------------------------| + | | + 5. SIP INVITE | + ----------------------------------->| + | 6. MAR | + |<------------------| + | 7. MAA | + |------------------>| 8. SIP INVITE + | |----------------> + | | 9. SIP 200 (OK) + 10. SIP 200 (OK) |<---------------- + <-----------------------------------| + | | + + Figure 4: SIP server requests authorization + +6.5. Locating the Recipient of the SIP Request + + Figure 5 shows the scenario where SIP server 1 may be configured as a + SIP edge proxy server, processing SIP traffic at the edge of a + network. SIP server 1 receives a SIP INVITE request (step 1). SIP + server 1 needs to find the address of SIP server 2, which is serving + the recipient of the SIP request. The Diameter client in SIP server + 1 sends a Diameter Location-Info-Request (LIR) message (step 2) to + the Diameter server. The Diameter server responds with a Diameter + Location-Info-Answer (LIA) message (step 3) that contains the SIP or + + + + +Garcia-Martin, et al. Standards Track [Page 16] + +RFC 4740 Diameter SIP Application November 2006 + + + SIPS URI of SIP server 2. SIP server 1 then forwards the SIP INVITE + to SIP server 2 (step 4). SIP server 2 eventually forwards the SIP + INVITE to the appropriate UAS (step 5). + + +--------+ +--------+ +--------+ + | SIP | |Diameter| | SIP | + |server 1| | server | |server 2| + +--------+ +--------+ +--------+ + | | | + 1. SIP INVITE | | | + -------------->| 2. LIR | | + |---------------->| | + | 3. LIA | | + |<----------------| | + | 4. SIP INVITE | + |--------------------------------->| + | | | 5. SIP INVITE + | | |--------------> + | | | + | | | + + Figure 5: Locating the SIP server of the recipient + + Although the example shows the connection between a SIP INVITE + request and the Diameter LIR message, any SIP request other than + REGISTER (such as SUBSCRIBE, OPTIONS, etc.) would trigger the same + Diameter message. (A SIP REGISTER request will trigger a Diameter + UAR message, as indicated in Figure 2 and Figure 3.) + + The scenario described in this section is also applicable in case an + outbound SIP server is not interested in authenticating the user, but + is required to locate a further SIP server to route the outbound SIP + requests. In this case, the outbound SIP server is mapped to SIP + server 1 as shown in Figure 5. + +6.6. Update of the User Profile + + The Diameter SIP application provides a mechanism for a Diameter + server to asynchronously download a user profile to a SIP server + whenever there is an update of such user profile. It must be noted + that the Diameter server also attaches the user profile to the + Diameter Server-Assignment-Answer (SAA) message. This is valid for + most of the daily situations; however, the administrator may decide + to update or modify the user profile for a particular user, due to, + e.g., new services made available to the user. This may involve + mechanisms outside the scope of this specification, such as human + + + + + +Garcia-Martin, et al. Standards Track [Page 17] + +RFC 4740 Diameter SIP Application November 2006 + + + intervention, in the Diameter server. In this situation, the + Diameter server is able to push the new user profile into the SIP + server allocated to the user. + + The scenario is illustrated in Figure 6. When the user profile + changes, the Diameter server sends a Diameter Push-Profile-Request + (PPR) message (step 1) to the Diameter client in the SIP server + allocated to that user (SIP server 2 in the examples). The Diameter + PPR message contains one or more SIP-User-Data AVPs, a User-Name AVP + and zero or more SIP-AOR AVPs. The Diameter client in SIP server 2 + acknowledges the Diameter PPR message by sending a Diameter + Push-Profile-Answer (PPA) message (step 2) to the Diameter server. + + +--------+ +--------+ + |Diameter| | SIP | + | server | |server 2| + +--------+ +--------+ + | | + | 1. PPR | + |------------------>| + | | + | 2. PPA | + |<------------------| + | | + + Figure 6: Diameter server pushes an update of the user profile + +6.7. SIP Soft State Termination + + SIP can create soft states in SIP nodes based on events such as SIP + registrations or SIP event subscriptions. These states are + periodically refreshed, and cease to exist if they are not refreshed. + Additionally, an administrative action can be taken to terminate a + SIP soft state, or the SIP UA can explicitly terminate a SIP soft + state. + + The Diameter base protocol offers a mechanism to create and delete + states in Diameter nodes. These states are called Diameter user + sessions. The Diameter server decides whether to use a Diameter user + session as a mechanism to map to a SIP soft state. If the Diameter + server decides to use Diameter user sessions, the termination of a + Diameter user session implies the termination of the corresponding + SIP soft state (e.g., registration, event subscription), and vice + versa. If the Diameter server does not use Diameter user sessions, + this Diameter SIP application offers specific commands to manage the + SIP soft states. Implementations compliant with this specification + MUST support both mechanisms of session management. + + + + +Garcia-Martin, et al. Standards Track [Page 18] + +RFC 4740 Diameter SIP Application November 2006 + + + We provide support for both Diameter client- and Diameter + server-initiated session termination. Depending on whether Diameter + sessions are used, termination of a SIP soft state can be achieved by + one of the following methods: + + o When the Diameter client (SIP proxy) wants to terminate the SIP + soft state and Diameter user sessions are not maintained (i.e., + the Auth-Session-State AVP has been previously set to + NO_STATE_MAINTAINED), the Diameter client MUST send a + Server-Assignment-Request (SAR) message with the + SIP-Server-Assignment-Type AVP (Section 9.4) set to any of the + deregistration values: TIMEOUT_DEREGISTRATION, + USER_DEREGISTRATION, TIMEOUT_DEREGISTRATION_STORE_SERVER_NAME, + USER_DEREGISTRATION_STORE_SERVER_NAME, + ADMINISTRATIVE_DEREGISTRATION, DEREGISTRATION_TOO_MUCH_DATA. + + o When the Diameter client (SIP proxy) wants to terminate the SIP + soft state and Diameter user sessions are maintained (i.e., the + Auth-Session-State AVP has been previously set to + STATE_MAINTAINED), the Diameter client MUST send a Session- + Termination-Request (STR) message as per regular procedures + according to RFC 3588 [RFC3588]. + + o When the Diameter server wants to terminate the SIP soft state and + Diameter user sessions are not maintained (i.e., the + Auth-Session-State AVP has been previously set to + NO_STATE_MAINTAINED), the Diameter server MUST send a + Registration-Termination-Request (RTR) message (see Section 8.9). + + o When the Diameter server wants to terminate the SIP soft state and + Diameter user sessions are maintained (i.e., the + Auth-Session-State AVP has been previously set to + STATE_MAINTAINED), the Diameter server MUST send an + Abort-Session-Request (ASR) message as per regular procedures + according to RFC 3588 [RFC3588]. + +6.8. Diameter Server Discovery + + The basic architecture assumption of this document is that all the + data related to a user is stored in a unique Diameter server. + Contrary to general opinion, this does not create a single point of + failure. It is assumed that Diameter servers are configured in a + redundant fashion in an attempt to mitigate the + single-point-of-failure problem. + + In large networks, where the number of users may be significantly + high, there might be a need to scale the number of Diameter servers. + All the data associated with a user is still stored in one Diameter + + + +Garcia-Martin, et al. Standards Track [Page 19] + +RFC 4740 Diameter SIP Application November 2006 + + + server (typically, operating in a redundant configuration), but the + data associated with different users may reside in different Diameter + servers. + + Although this configuration scales well, it introduces a new problem, + namely: given the user's SIP AOR as an input, how to determine which + of various Diameter servers is storing the data for that particular + SIP AOR. We solve this problem with inspiration from the Diameter + redirection mechanism specified in RFC 3588 [RFC3588]. We include in + the architecture a new Diameter node that, for the purpose of this + document, is known as Diameter Subscriber Locator (SL). The Diameter + SL contains a database or routing tables that map SIP AORs to + Diameter server URIs. A particular Diameter server URI points to the + actual Diameter server that stores all the data related to a + particular SIP AOR, and in consequence, to the user who owns the SIP + AOR. The Diameter SL acts in a similar way to a Diameter Redirect + Agent, dispatching Diameter requests (e.g., providing the redirection + URI in the answer). The Diameter SL can redirect all the request + pertaining to a user by setting the Redirect-Host-Usage AVP with a + value ALL_USER, as specified in RFC 3588 [RFC3588]. + + The Diameter SL can be replicated in different nodes along the + network, for the purpose of building scalability and redundancy. The + database or routing tables have to be consistent across all these + different Diameter SLs, so that equal Diameter requests will produce + equal Diameter answers, no matter which Diameter SL processes the + request. + + +--------+ +--------+ +--------+ +--------+ + | SIP | |Diameter| |Diameter| | SIP | + |server 1| |SL red. | |server 1| |server 2| + +--------+ +--------+ +--------+ +--------+ + | | | | + 1. SIP INVITE| | | | + ------------>| 2. LIR | | | + |---------->| | | + | 3. LIA | | | + |<----------| | | + | 4. LIR | | + |---------------------->| | + | 5. LIA | | + |<----------------------| | + | 6. SIP INVITE | | + |----------------------------------->| 7. SIP INVITE + | | | | -------------> + | | | | + + Figure 7: Locating a Diameter server. SL redirecting requests + + + +Garcia-Martin, et al. Standards Track [Page 20] + +RFC 4740 Diameter SIP Application November 2006 + + + Figure 7 shows an example of operation of a Diameter SL acting in + redirect mode. SIP server 1 receives an INVITE request (step 1) + addressed (in the SIP Request-URI) to a user for which the Diameter + client in SIP server 1 does not possess routing information. In + other words, the Diameter client in SIP server 1 does not know the + URI of the Diameter server 1. The Diameter client sends a Diameter + LIR message (step 2) to any of the Diameter SLs configured in the + network. The address of those SLs is assumed to be pre-provisioned + in the Diameter client. The Diameter SL, based on the contents of + the SIP-AOR AVP and its own routing tables, determines the Diameter + server that stores the information allocated to such user. Then it + builds a Diameter LIA message (step 3) that includes a Result-Code + AVP set to DIAMETER_REDIRECT_INDICATION and one Redirect-Host AVP, + whose value is set to the URI of the Diameter server that stores the + information related to such user. Then the Diameter client in SIP + server 1 builds a new LIR message (step 4) addressed to the Diameter + server received in the Redirect-Host AVP. The rest of the procedure + is completed as described in previous sections. + +7. Advertising Application Support + + Diameter implementations conforming to this specification MUST + advertise its support by including an Auth-Application-Id AVP in the + Capabilities-Exchange-Request (CER) and Capabilities-Exchange-Answer + (CEA) commands, according to the Diameter base protocol, RFC 3588 + [RFC3588]. This Auth-Application-Id AVP MUST be set to the value of + this Diameter SIP application (Section 13.1 indicates the actual + value allocated by IANA). + + + + + + + + + + + + + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 21] + +RFC 4740 Diameter SIP Application November 2006 + + +8. Diameter SIP Application Command Codes + + All the Diameter implementations conforming to this specification + MUST implement and support the list of Diameter commands listed in + Table 1. + + +-------------------------------------+-------+------+--------------+ + | Command Name | Abbr. | Code | Reference | + +-------------------------------------+-------+------+--------------+ + | User-Authorization-Request | UAR | 283 | Section 8.1 | + | User-Authorization-Answer | UAA | 283 | Section 8.2 | + | Server-Assignment-Request | SAR | 284 | Section 8.3 | + | Server-Assignment-Answer | SAA | 284 | Section 8.4 | + | Location-Info-Request | LIR | 285 | Section 8.5 | + | Location-Info-Answer | LIA | 285 | Section 8.6 | + | Multimedia-Auth-Request | MAR | 286 | Section 8.7 | + | Multimedia-Auth-Answer | MAA | 286 | Section 8.8 | + | Registration-Termination-Request | RTR | 287 | Section 8.9 | + | Registration-Termination-Answer | RTA | 287 | Section 8.10 | + | Push-Profile-Request | PPR | 288 | Section 8.11 | + | Push-Profile-Answer | PPA | 288 | Section 8.12 | + +-------------------------------------+-------+------+--------------+ + + Table 1: Defined command codes + + Sections defining commands contain the Message Format for that + particular command. The Message Formats included in this document + are defined as per Section 3.2 of RFC 3588 [RFC3588]. + +8.1. User-Authorization-Request (UAR) Command + + The User-Authorization-Request (UAR) is indicated by the Command-Code + set to 283 and the Command Flags' 'R' bit set. The Diameter client + in a SIP server sends this command to the Diameter server to request + authorization for the SIP User Agent to route a SIP REGISTER request. + Because the SIP REGISTER request implicitly carries a permission to + bind an AOR to a contact address, the Diameter client uses the + Diameter UAR as a first authorization request towards the Diameter + server to authorize the registration. For instance, the Diameter + server can verify that the AOR is a legitimate user of the realm. + + The Diameter client in the SIP server requests authorization for one + of the possible values defined in the SIP-User-Authorization-Type AVP + (Section 9.10). + + The user name used for authentication of the user is conveyed in a + User-Name AVP (defined in the Diameter base protocol, RFC 3588 + [RFC3588]). The location of the authentication user name in the SIP + + + +Garcia-Martin, et al. Standards Track [Page 22] + +RFC 4740 Diameter SIP Application November 2006 + + + REGISTER request varies depending on the authentication mechanism. + When the authentication mechanism is HTTP Digest as defined in RFC + 2617 [RFC2617], the authentication user name is found in the + "username" directive of the SIP Authorization header field value. + This Diameter SIP application only provides support for HTTP Digest + authentication in SIP; other authentication mechanisms are not + currently supported. + + The SIP or SIPS URI to be registered is conveyed in the SIP-AOR AVP + (Section 9.8). Typically this SIP or SIPS URI is found in the To + header field value of the SIP REGISTER request that triggered the + Diameter UAR message. + + The SIP-Visited-Network-Id AVP indicates the network that is + providing SIP services (e.g., SIP proxy functionality or any other + kind of services) to the SIP User Agent. + + The Message Format of the UAR command is as follows: + + <UAR> ::= < Diameter Header: 283, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + [ Destination-Host ] + [ User-Name ] + [ SIP-Visited-Network-Id ] + [ SIP-User-Authorization-Type ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.2. User-Authorization-Answer (UAA) Command + + The User-Authorization-Answer (UAA) is indicated by the Command-Code + set to 283 and the Command Flags' 'R' bit cleared. The Diameter + server sends this command in response to a previously received + Diameter User-Authorization-Request (UAR) command. The Diameter + server indicates the result of the requested registration + authorization. Additionally, the Diameter server may indicate a + collection of SIP capabilities that assists the Diameter client to + select a SIP proxy to the AOR under registration. + + + + + + +Garcia-Martin, et al. Standards Track [Page 23] + +RFC 4740 Diameter SIP Application November 2006 + + + In addition to the values already defined in RFC 3588 [RFC3588], the + Result-Code AVP may contain one of the values defined in + Section 10.1. + + Whenever the Diameter server fails to process the Diameter UAR + message, it MUST stop processing and return the relevant error in the + Diameter UAA message. When there is success in the process, the + Diameter server MUST set the code to DIAMETER_SUCCESS in the Diameter + UAA message. + + If the Diameter server requires a User-Name AVP value to process the + Diameter UAR request, but the Diameter UAR message did not contain a + User-Name AVP value, the Diameter server MUST set the Result-Code AVP + value to DIAMETER_USER_NAME_REQUIRED (see Section 10.1.2) and return + it in a Diameter UAA message. Upon reception of this Diameter UAA + message with the Result-Code AVP value set to + DIAMETER_USER_NAME_REQUIRED, the SIP server typically requests + authentication by sending a SIP 401 (Unauthorized) or SIP 407 (Proxy + Authentication Required) response back to the originator. + + When the authorization procedure succeeds, the Diameter server + constructs a User-Authorization-Answer (UAA) message that MUST + include (1) the address of the SIP server already assigned to the + user name, (2) the capabilities needed by the SIP server (Diameter + client) to select another SIP server for the user, or (3) a + combination of the previous two options. + + If the Diameter server is already aware of a SIP server allocated to + the user, the Diameter UAA message contains the address of that SIP + server. + + The Diameter UAA message contains the capabilities required by a SIP + server to trigger and execute services. It is required that these + capabilities are present in the Diameter UAA message due to the + possibility that the Diameter client (in the SIP server) allocates a + different SIP server to trigger and execute services for that + particular user. + + If a User-Name AVP is present in the Diameter UAR message, then the + Diameter server MUST verify the existence of the user in the realm, + i.e., the User-Name AVP value is a valid user within that realm. If + the Diameter server does not recognize the user name received in the + User-Name AVP, the Diameter server MUST build a Diameter User- + Authorization-Answer (UAA) message and MUST set the Result-Code AVP + to DIAMETER_ERROR_USER_UNKNOWN. + + + + + + +Garcia-Martin, et al. Standards Track [Page 24] + +RFC 4740 Diameter SIP Application November 2006 + + + If a User-Name AVP is present in the Diameter UAR message, then the + Diameter server MUST authorize that User-Name AVP value is able to + register the SIP or SIPS URI included in the SIP-AOR AVP. If this + authorization fails, the Diameter server must set the Result-Code AVP + to DIAMETER_ERROR_IDENTITIES_DONT_MATCH and send it in a Diameter + User-Authorization-Answer (UAA) message. + + Note: Correlation between User-Name and SIP-AOR AVP values is + required in order to avoid registration of a SIP-AOR allocated to + another user. + + If there is a SIP-Visited-Network-Id AVP in the Diameter UAR message, + and the SIP-User-Authorization-Type AVP value received in the + Diameter UAR message is set to REGISTRATION or REGISTRATION& + CAPABILITIES, then the Diameter server SHOULD verify whether the user + is allowed to roam into the network specified in the + SIP-Visited-Network-Id AVP in the Diameter UAR message. If the user + is not allowed to roam into that network, the Diameter AAA server + MUST set the Result-Code AVP value in the Diameter UAA message to + DIAMETER_ERROR_ROAMING_NOT_ALLOWED. + + If the SIP-User-Authorization-Type AVP value received in the Diameter + UAR message is set to REGISTRATION or REGISTRATION&CAPABILITIES, then + the Diameter server SHOULD verify whether the SIP-AOR AVP value is + authorized to register in the Home Realm. Where the SIP AOR is not + authorized to register in the Home Realm, the Diameter server MUST + set the Result-Code AVP to DIAMETER_AUTHORIZATION_REJECTED and send + it in a Diameter UAA message. + + When the SIP-User-Authorization-Type AVP is not present in the + Diameter UAR message, or when it is present and its value is set to + REGISTRATION, then: + + o If the Diameter server is not aware of any previous registration + of the user name (including registrations of other SIP AORs + allocated to the same user name), then the Diameter server does + not know of any SIP server allocated to the user. In this case, + the Diameter server MUST set the Result-Code AVP value to + DIAMETER_FIRST_REGISTRATION in the Diameter UAA message, and the + Diameter server SHOULD include the required SIP server + capabilities in the SIP-Server-Capabilities AVP value in the + Diameter UAA message. The SIP-Server-Capabilities AVP assists the + Diameter client (SIP server) to select an appropriate SIP server + for the user, according to the required capabilities. + + o In some cases, the Diameter server is aware of a previously + assigned SIP server for the same or different SIP AORs allocated + to the same user name. In these cases, re-assignment of a new SIP + + + +Garcia-Martin, et al. Standards Track [Page 25] + +RFC 4740 Diameter SIP Application November 2006 + + + server may or may not be needed, depending on the capabilities of + the SIP server. The Diameter server MUST always include the + allocated SIP server URI in the SIP-Server-URI AVP of the UAA + message. If the Diameter server does not return the SIP + capabilities, the Diameter server MUST set the Result-Code AVP in + the Diameter UAA message to DIAMETER_SUBSEQUENT_REGISTRATION. + Otherwise (i.e., if the Diameter server includes a + SIP-Server-Capabilities AVP), then the Diameter server MUST set + the Result-Code AVP in the Diameter UAA message to + DIAMETER_SERVER_SELECTION. Then the Diameter client determines, + based on the received information, whether it needs to select a + new SIP server. + + When the SIP-User-Authorization-Type AVP value received in the + Diameter UAR message is set to REGISTRATION&CAPABILITIES, then + Diameter Server MUST return the list of capabilities in the + SIP-Server-Capabilities AVP value of the Diameter UAA message, it + MUST set the Result-Code to DIAMETER_SUCCESS, and it MUST NOT return + a SIP-Server-URI AVP. The SIP-Server-Capabilities AVP enables the + SIP server (Diameter client) to select another appropriate SIP server + for invoking and executing services for the user, depending on the + required capabilities. The Diameter server MAY leave the list of + capabilities empty to indicate that any SIP server can be selected. + + When the SIP-User-Authorization-Type AVP value received in the + Diameter UAR message is set to DEREGISTRATION, then: + + o If the Diameter server is aware of a SIP server assigned to the + SIP AOR under deregistration, the Diameter server MUST set the + Result-Code AVP to DIAMETER_SUCCESS and MUST set the + SIP-Server-URI AVP value to the known SIP server, and return them + in the Diameter UAA message. + + o If the Diameter server is not aware of a SIP server assigned to + the SIP AOR under deregistration, then the Diameter server MUST + set the Result-Code AVP in the Diameter UAA message to + DIAMETER_ERROR_IDENTITY_NOT_REGISTERED. + + The Message Format of the UAA command is as follows: + + <UAA> ::= < Diameter Header: 283, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ SIP-Server-URI ] + + + +Garcia-Martin, et al. Standards Track [Page 26] + +RFC 4740 Diameter SIP Application November 2006 + + + [ SIP-Server-Capabilities ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.3. Server-Assignment-Request (SAR) Command + + The Server-Assignment-Request (SAR) command is indicated by the + Command-Code set to 284 and the Command Flags' 'R' bit set. The + Diameter client in a SIP server sends this command to the Diameter + server to indicate the completion of the authentication process and + to request that the Diameter server store the URI of the SIP server + that is currently serving the user. The main functions of the + Diameter SAR command are to inform the Diameter server of the URI of + the SIP server allocated to the user, and to store or clear it from + the Diameter server. Additionally, the Diameter client can request + to download the user profile or part of it. + + During the registration procedure, a SIP server becomes assigned to + the user. The Diameter client in the assigned SIP server MUST + include its own URI in the SIP-Server-URI AVP of the + Server-Assignment-Request (SAR) Diameter message and send it to the + Diameter server. The Diameter server then becomes aware of the + allocation of the SIP server to the user name and the server's URI. + + The Diameter client in the SIP server MAY send a Diameter SAR message + because of other reasons. These reasons are identified in the + SIP-Server-Assignment-Type AVP (Section 9.4) value. For instance, a + Diameter client in a SIP server may contact the Diameter server to + request deregistration of a user, to inform the Diameter server of an + authentication failure, or just to download the user profile. For a + complete description of all the SIP-Server-Assignment-Type AVP + values, see Section 9.4. + + Typically the reception of a SIP REGISTER request in a SIP server + will trigger the Diameter client in the SIP server to send the + Diameter SAR message. However, if a SIP server is receiving other + SIP request, such as INVITE, and the SIP server does not have the + user profile, the Diameter client in the SIP server may send the + Diameter SAR message to the Diameter server in order to download the + user profile and make the Diameter server aware of the SIP server + assigned to the user. + + + + +Garcia-Martin, et al. Standards Track [Page 27] + +RFC 4740 Diameter SIP Application November 2006 + + + The user profile is an important piece of information that dictates + the behavior of the SIP server when triggering or providing services + for the user. Typically the user profile is divided into: + + o Services to be rendered to the user when the user is registered + and initiates a SIP request. + + o Services to be rendered to the user when the user is registered + and a SIP request destined to that user arrives to the SIP proxy. + + o Services to be rendered to the user when the user is not + registered and a SIP request destined to that user arrives to the + SIP proxy. + + The SIP-Server-Assignment-Type AVP indicates the reason why the + Diameter client (SIP server) contacted the Diameter server. If the + Diameter client sets the SIP-Server-Assignment-Type AVP value to + REGISTRATION, RE_REGISTRATION, UNREGISTERED_USER, NO_ASSIGNMENT, + AUTHENTICATION_FAILURE or AUTHENTICATION_TIMEOUT, the Diameter client + MUST include exactly one SIP-AOR AVP in the Diameter SAR message. + + The SAR message MAY contain zero or more SIP-Supported-User-Data-Type + AVPs. Each of them contains a type of user data understood by the + SIP server. This allows the Diameter client to provide an indication + to the Diameter server of the different format of user data + understood by the SIP server. The Diameter server uses this + information to select one or more SIP-User-Data AVPs that will be + included in the SAA message. + + The Message Format of the SAR command is as follows: + + <SAR> ::= < Diameter Header: 284, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-Server-Assignment-Type } + { SIP-User-Data-Already-Available } + [ Destination-Host ] + [ User-Name ] + [ SIP-Server-URI ] + * [ SIP-Supported-User-Data-Type ] + * [ SIP-AOR ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + + +Garcia-Martin, et al. Standards Track [Page 28] + +RFC 4740 Diameter SIP Application November 2006 + + +8.4. Server-Assignment-Answer (SAA) Command + + The Server-Assignment-Answer (SAA) is indicated by the Command-Code + set to 284 and the Command Flags' 'R' bit cleared. The Diameter + server sends this command in response to a previously received + Diameter Server-Assignment-Request (SAR) command. The response may + include the user profile or part of it, if requested. + + In addition to the values already defined in RFC 3588 [RFC3588], the + Result-Code AVP may contain one of the values defined in + Section 10.1. + + The Result-Code AVP value in the Diameter SAA message may indicate a + success or an error in the execution of the Diameter SAR command. If + Result-Code AVP value in the Diameter SAA message does not contain an + error code, the SAA message MAY include one or more SIP-User-Data + AVPs that typically contain the profile of the user, indicating + services that the SIP server can provide to that user. + + The Diameter server MAY include one or more + SIP-Supported-User-Data-Type AVPs, each one identifying a type of + user data format supported in the Diameter server. If there is not a + common supported user data type between the Diameter client and the + Diameter server, the Diameter server SHOULD declare its list of + supported user data types by including one or more + SIP-Supported-User-Data-Type AVPs in a Diameter SAA message. This + indication is merely for debugging reasons, since there is not a + fallback mechanism that allows the Diameter client to retrieve the + profile in a supported format. + + If the Diameter server requires a User-Name AVP value to process the + Diameter SAR request, but the Diameter SAR message did not contain a + User-Name AVP value, the Diameter server MUST set the Result-Code AVP + value to DIAMETER_USER_NAME_REQUIRED (see Section 10.1.2) and return + it in a Diameter SAA message. Upon reception of this Diameter SAA + message with the Result-Code AVP value set to + DIAMETER_USER_NAME_REQUIRED, the SIP server typically requests + authentication by generating a SIP 401 (Unauthorized) or SIP 407 + (Proxy Authentication Required) response back to the originator. + + If the User-Name AVP is included in the Diameter SAR message, upon + reception of the Diameter SAR message, the Diameter server MUST + verify the existence of the user in the realm, i.e., the User-Name + AVP value is a valid user within that realm. If the Diameter server + does not recognize the user name received in the User-Name AVP, the + Diameter server MUST build a Diameter Server-Assignment-Answer (SAA) + message and MUST set the Result-Code AVP to + DIAMETER_ERROR_USER_UNKNOWN. + + + +Garcia-Martin, et al. Standards Track [Page 29] + +RFC 4740 Diameter SIP Application November 2006 + + + Then the Diameter server MUST authorize that User-Name AVP value is a + valid authentication name for the SIP or SIPS URI included in the + SIP-AOR AVP of the Diameter SAR message. If this authorization + fails, the Diameter server must set the Result-Code AVP to + DIAMETER_ERROR_IDENTITIES_DONT_MATCH and send it in a Diameter + Server-Assignment-Answer (SAA) message. + + After successful execution of the Diameter SAR command, the Diameter + server MUST clear the "authentication pending" flag and SHOULD move + the temporarily stored SIP server URI to permanent storage. + + The actions of the Diameter server upon reception of the Diameter SAR + message depend on the value of the SIP-Server-Assignment-Type: + + o If the SIP-Server-Assignment-Type AVP value in the Diameter SAR + message is set to REGISTRATION or RE_REGISTRATION, the Diameter + server SHOULD verify that there is only one SIP-AOR AVP. + Otherwise, the Diameter server MUST answer with a Diameter SAA + message with the Result-Code AVP value set to + DIAMETER_AVP_OCCURS_TOO_MANY_TIMES and MUST NOT include any + SIP-User-Data AVP. If there is only one SIP-AOR AVP and if the + SIP-User-Data-Already-Available AVP value is set to + USER_DATA_NOT_AVAILABLE, then the Diameter server SHOULD include + one or more user profile data with the SIP or SIPS URI (SIP-AOR + AVP) and all other SIP identities associated with that AVP in the + SIP-User-Data AVP value of the Diameter SAA message. On selecting + the type of user data, the Diameter server SHOULD take into + account the supported formats at the SIP server + (SIP-Supported-User-Data-Type AVP in the SAR message) and the + local policy. Additionally, the Diameter server MUST set the + Result-Code AVP value to DIAMETER_SUCCESS in the Diameter SAA + message. The Diameter server considers the SIP AOR authenticated + and registered. + + o If the SIP-Server-Assignment-Type AVP value in the Diameter SAR + message is set to UNREGISTERED_USER, then the Diameter server MUST + store the SIP server address included in the SIP-Server-URI AVP + value. The Diameter server will return the SIP server address in + Diameter Location-Info-Answer (LIA) messages. If the + SIP-User-Data-Already-Available AVP value is set to + USER_DATA_NOT_AVAILABLE, then the Diameter server SHOULD include + one or more user profile data associated with the SIP or SIPS URI + (SIP-AOR AVP) and associated identities in the SIP-User-Data AVP + value of the Diameter SAA message. On selecting the type of user + data, the Diameter server SHOULD take into account the supported + formats at the SIP server (SIP-Supported-User-Data-Type AVP in the + SAR message) and the local policy. The Diameter server MUST set + the Result-Code AVP value to DIAMETER_SUCCESS. The Diameter + + + +Garcia-Martin, et al. Standards Track [Page 30] + +RFC 4740 Diameter SIP Application November 2006 + + + server considers the SIP AOR UNREGISTERED, but with a SIP server + allocated to trigger and provide services for unregistered users. + Note that in case of UNREGISTERED_USER (SIP-Server-Assignment-Type + AVP), the Diameter server MUST verify that there is only one + SIP-AOR AVP. Otherwise, the Diameter server MUST answer the + Diameter SAR message with a Diameter SAA message, and it MUST set + the Result-Code AVP value to DIAMETER_AVP_OCCURS_TOO_MANY_TIMES + and MUST NOT include any SIP-User-Data AVP. + If the User-Name AVP was not present in the Diameter SAR message + and the SIP-AOR is not known for the Diameter server, the Diameter + server MUST NOT include a User-Name AVP in the Diameter SAA + message and MUST set the Result-Code AVP value to + DIAMETER_ERROR_USER_UNKNOWN. + + o If the SIP-Server-Assignment-Type AVP value in the Diameter SAR + message is set to TIMEOUT_DEREGISTRATION, USER_DEREGISTRATION, + DEREGISTRATION_TOO_MUCH_DATA, or ADMINISTRATIVE_DEREGISTRATION, + the Diameter server MUST clear the SIP server address associated + with all SIP AORs indicated in each of the SIP-AOR AVP values + included in the Diameter SAR message. The Diameter server + considers all of these SIP AORs as not registered. The Diameter + server MUST set the Result-Code AVP value to DIAMETER_SUCCESS in + the Diameter SAA message. + + o If the SIP-Server-Assignment-Type AVP value in the Diameter SAR + message is set to TIMEOUT_DEREGISTRATION_STORE_SERVER_NAME or + USER_DEREGISTRATION_STORE_SERVER_NAME, the Diameter server MAY + keep the SIP server address associated with the SIP AORs included + in the SIP-AOR AVP values of the Diameter SAR message, even though + the SIP AORs become unregistered. This feature allows a SIP + server to request that the Diameter server remain an assigned SIP + server for those SIP AORs (SIP-AOR AVP values) allocated to the + same user name, and avoid SIP server assignment. The Diameter + server MUST consider all these SIP AORs as not registered. If the + Diameter server honors the request of the Diameter client (SIP + server) to remain as an allocated SIP server, then the Diameter + server MUST keep the SIP server assigned to those SIP AORs + allocated to the username and MUST set the Result-Code AVP value + to DIAMETER_SUCCESS in the Diameter SAA message. Otherwise, when + the Diameter server does not honor the request of the Diameter + client (SIP server) to remain as an allocated SIP server, the + Diameter server MUST clear the SIP server name assigned to those + SIP AORs and it MUST set the Result-Code AVP value to + DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED in the Diameter SAA + message. + + + + + + +Garcia-Martin, et al. Standards Track [Page 31] + +RFC 4740 Diameter SIP Application November 2006 + + + o If the SIP-Server-Assignment-Type AVP value in the Diameter SAR + message is set to NO_ASSIGNMENT, the Diameter server SHOULD first + verify that the SIP-Server-URI AVP value in the Diameter SAR + message is the same URI as the one assigned to the SIP-AOR AVP + value. If they differ, then the Diameter server MUST set the + Result-Code AVP value to DIAMETER_UNABLE_TO_COMPLY in the Diameter + SAA message. Otherwise, if the SIP-User-Data-Already-Available + AVP value is set to USER_DATA_NOT_AVAILABLE, then the Diameter + server SHOULD include the user profile data with the SIP or SIPS + URI (SIP-AOR AVP) and all other SIP identities associated with + that AVP in the SIP-User-Data AVP value of the Diameter SAA + message. On selecting the type of user data, the Diameter server + SHOULD take into account the supported formats at the SIP server + (SIP-Supported-User-Data-Type AVP in the SAR message) and the + local policy. + + o If the SIP-Server-Assignment-Type AVP value in the Diameter SAR + message is set to AUTHENTICATION_FAILURE or + AUTHENTICATION_TIMEOUT, the Diameter server MUST verify that there + is exactly one SIP-AOR AVP in the Diameter SAR message. If the + number of occurrences of the SIP-AOR AVP is not exactly one, the + Diameter server MUST set the Result-Code AVP value to + DIAMETER_AVP_OCCURS_TOO_MANY_TIMES in the Diameter SAA message, + and SHOULD not take further actions. If there is exactly one + SIP-AOR AVP in the Diameter SAR message, the Diameter server MUST + clear the address of the SIP server assigned to the SIP AOR + allocated to the user name, and the Diameter server MUST set the + Result-Code AVP value to DIAMETER_SUCCESS in the Diameter SAA + message. The Diameter server MUST consider the SIP AOR as not + registered. + + The Message Format of the SAA command is as follows: + + <SAA> ::= < Diameter Header: 284, PXY > + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + * [ SIP-User-Data ] + [ SIP-Accounting-Information ] + * [ SIP-Supported-User-Data-Type ] + [ User-Name ] + [ Auth-Grace-Period ] + [ Authorization-Lifetime ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + + + +Garcia-Martin, et al. Standards Track [Page 32] + +RFC 4740 Diameter SIP Application November 2006 + + + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.5. Location-Info-Request (LIR) Command + + The Location-Info-Request (LIR) is indicated by the Command-Code set + to 285 and the Command Flags' 'R' bit set. The Diameter client in a + SIP server sends this command to the Diameter server to request + routing information, e.g., the URI of the SIP server assigned to the + SIP-AOR AVP value allocated to the users. + + The Message Format of the LIR command is as follows: + + <LIR> ::= < Diameter Header: 285, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + [ Destination-Host ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.6. Location-Info-Answer (LIA) Command + + The Location-Info-Answer (LIA) is indicated by the Command-Code set + to 285 and the Command Flags' 'R' bit cleared. The Diameter server + sends this command in response to a previously received Diameter + Location-Info-Request (LIR) command. + + In addition to the values already defined in RFC 3588 [RFC3588], the + Result-Code AVP may contain one of the values defined in + Section 10.1. When the Diameter server finds an error in processing + the Diameter LIR message, the Diameter server MUST stop the process + of the message and answer with a Diameter LIA message that includes + the appropriate error code in the Result-Code AVP value. When there + is no error, the Diameter server MUST set the Result-Code AVP value + to DIAMETER_SUCCESS in the Diameter LIA message. + + One of the errors that the Diameter server may find is that the + SIP-AOR AVP value is not a valid user in the realm. In such cases, + the Diameter server MUST set the Result-Code AVP value to + DIAMETER_ERROR_USER_UNKNOWN and return it in a Diameter LIA message. + + + +Garcia-Martin, et al. Standards Track [Page 33] + +RFC 4740 Diameter SIP Application November 2006 + + + If the Diameter server cannot process the Diameter LIR command, e.g., + due to a database error, the Diameter server MUST set the Result-Code + AVP value to DIAMETER_UNABLE_TO_COMPLY and return it in a Diameter + LIA message. The Diameter server MUST NOT include any SIP-Server-URI + or SIP-Server-Capabilities AVP in the Diameter LIA message. + + The Diameter server may or may not be aware of a SIP server assigned + to the SIP-AOR AVP value included in the Diameter LIR message. If + the Diameter server is aware of a SIP server allocated to that + particular user, the Diameter server MUST include the URI of such SIP + server in the SIP-Server-URI AVP and return it in a Diameter LIA + message. This is typically the situation when the user is either + registered, or unregistered but a SIP server is still assigned to the + user. + + When the Diameter server is not aware of a SIP server allocated to + the user (typically the case when the user unregistered), the + Result-Code AVP value in the Diameter LIA message depends on whether + the Diameter server is aware that the user has services defined for + unregistered users: + + o Those users who have services defined for unregistered users may + require the allocation of a SIP server to trigger and perhaps + execute those services. Therefore, when the Diameter server is + not aware of an assigned SIP server, but the user has services + defined for unregistered users, the Diameter server MUST set the + Result-Code AVP value to DIAMETER_UNREGISTERED_SERVICE and return + it in a Diameter LIA message. The Diameter server MAY also + include a SIP-Server-Capabilities AVP to facilitate the SIP server + (Diameter client) with the selection of an appropriate SIP server + with the required capabilities. Absence of the SIP-Server- + Capabilities AVP indicates to the SIP server (Diameter client) + that any SIP server is suitable to be allocated for the user. + + o Those users who do not have service defined for unregistered users + do not require further processing. The Diameter server MUST set + the Result-Code AVP value to + DIAMETER_ERROR_IDENTITY_NOT_REGISTERED and return it to the + Diameter client in a Diameter LIA message. The SIP server + (Diameter client) may return the appropriate SIP response (e.g., + 480 (Temporarily unavailable)) to the original SIP request. + + The Message Format of the LIA command is as follows: + + <LIA> ::= < Diameter Header: 285, PXY > + < Session-Id > + { Auth-Application-Id } + { Result-Code } + + + +Garcia-Martin, et al. Standards Track [Page 34] + +RFC 4740 Diameter SIP Application November 2006 + + + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ SIP-Server-URI ] + [ SIP-Server-Capabilities ] + [ Auth-Grace-Period ] + [ Authorization-Lifetime ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.7. Multimedia-Auth-Request (MAR) Command + + The Multimedia-Auth-Request (MAR) command is indicated by the + Command-Code set to 286 and the Command Flags' 'R' bit set. The + Diameter client in a SIP server sends this command to the Diameter + server to request that the Diameter server authenticate and authorize + a user attempt to use some SIP service (in this context, SIP service + can be something as simple as a SIP subscription or using the proxy + services for a SIP request). + + The MAR command may also register the SIP server's own URI to the + Diameter server, so that future LIR/LIA messages can return this URI. + If the SIP server is acting as a SIP registrar (see examples in + Sections 6.2 and 6.3), its Diameter client MUST include a SIP- + Server-URI AVP in the MAR command. In any other cases (see example + in Section 6.4), its Diameter client MUST NOT include a SIP-Server- + URI AVP in the MAR command. + + The SIP-Method AVP MUST include the SIP method name of the SIP + request that triggered this Diameter MAR message. The Diameter + server can use this AVP to authorize some SIP requests depending on + the method. + + The Diameter MAR message MUST include a SIP-AOR AVP. The SIP-AOR AVP + indicates the target of the SIP request. The value of the AVP is + extracted from different places in SIP request, depending on the + semantics of the SIP request. For SIP REGISTER messages the SIP-AOR + AVP value indicates the intended public user identity under + registration, and it is the SIP or SIPS URI populated in the To + header field value (addr-spec as per RFC 3261 [RFC3261]) of the SIP + REGISTER request. For other types of SIP requests, such as INVITE, + SUBSCRIBE, MESSAGE, etc., the SIP-AOR AVP value indicates the + intended destination of the request. This is typically populated in + the Request-URI of the SIP request. Extracting the SIP-AOR AVP value + + + +Garcia-Martin, et al. Standards Track [Page 35] + +RFC 4740 Diameter SIP Application November 2006 + + + from the proper SIP header field is the Diameter client's + responsibility. Extensions to SIP (new SIP methods or new semantics) + may require the SIP-AOR to be extracted from other parts of the + request. + + If the SIP request includes some sort of authentication information, + the Diameter client MUST include the user name, extracted from the + authentication information of the SIP request, in the User-Name AVP + value. + + The Message Format of the MAR command is as follows: + + <MAR> ::= < Diameter Header: 286, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { SIP-AOR } + { SIP-Method } + [ Destination-Host ] + [ User-Name ] + [ SIP-Server-URI ] + [ SIP-Number-Auth-Items ] + [ SIP-Auth-Data-Item ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.8. Multimedia-Auth-Answer (MAA) Command + + The Multimedia-Auth-Answer (MAA) is indicated by the Command-Code set + to 286 and the Command Flags' 'R' bit cleared. The Diameter server + sends this command in response to a previously received Diameter + Multimedia-Auth-Request (MAR) command. + + In addition to the values already defined in RFC 3588 [RFC3588], the + Result-Code AVP may contain one of the values defined in + Section 10.1. + + If the Diameter server requires a User-Name AVP value to process the + Diameter MAR request, but the Diameter MAR message did not contain a + User-Name AVP value, the Diameter server MUST set the Result-Code AVP + value to DIAMETER_USER_NAME_REQUIRED (see Section 10.1.2) and return + it in a Diameter MAA message. The Diameter server MAY include a + SIP-Number-Auth-Items AVP and one or more SIP-Auth-Data-Item AVPs + with authentication information (e.g., a challenge). Upon reception + + + +Garcia-Martin, et al. Standards Track [Page 36] + +RFC 4740 Diameter SIP Application November 2006 + + + of this Diameter MAA message with the Result-Code AVP value set to + DIAMETER_USER_NAME_REQUIRED, the SIP server typically requests + authentication by generating a SIP 401 (Unauthorized) or SIP 407 + (Proxy Authentication Required) response back to the originator. + + If the User-Name AVP is present in the Diameter MAR message, the + Diameter server MUST verify the existence of the user in the realm, + i.e., the User-Name AVP value is a valid user within that realm. If + the Diameter server does not recognize the user name received in the + User-Name AVP, the Diameter server MUST build a Diameter + Multimedia-Auth-Answer (MAA) message and MUST set the Result-Code AVP + to DIAMETER_ERROR_USER_UNKNOWN. + + If the SIP-Methods AVP value of the Diameter MAR message is set to + REGISTER and a User-Name AVP is present, then the Diameter server + MUST authorize that User-Name AVP value is able to use the URI + included in the SIP-AOR AVP. If this authorization fails, the + Diameter server must set the Result-Code AVP to + DIAMETER_ERROR_IDENTITIES_DONT_MATCH and send it in a Diameter + Multimedia-Auth-Answer (MAA) message. + + Note: Correlation between User-Name and SIP-AOR AVP values is only + required for SIP REGISTER request, to prevent a user from + registering a SIP-AOR allocated to another user. In other types + of SIP requests (e.g., INVITE), the SIP-AOR indicates the intended + destination of the request, rather than the originator of it. + + The Diameter server MUST verify whether the authentication scheme + (SIP-Authentication-Scheme AVP value) indicated in the grouped + SIP-Auth-Data-Item AVP is supported or not. If that authentication + scheme is not supported, then the Diameter server MUST set the + Result-Code AVP to DIAMETER_ERROR_AUTH_SCHEME_NOT_SUPPORTED and send + it in a Diameter Multimedia-Auth-Answer (MAA) message. + + If the SIP-Number-Auth-Items AVP is present in the Diameter MAR + message, it indicates the number of authentication data items that + the Diameter client is requesting. It is RECOMMENDED that the + Diameter server, when building the Diameter MAA message, includes a + number of SIP-Auth-Data-Item AVPs that are a subset of the + authentication data items requested by the Diameter client in the + SIP-Number-Auth-Items AVP value of the Diameter MAR message. + + If the SIP-Server-URI AVP is present in the Diameter MAR message, + then the Diameter server MUST compare the stored SIP server (assigned + to the user) with the SIP-Server-URI AVP value (received in the + Diameter MAR message). If they don't match, the Diameter server MUST + temporarily save the newly received SIP server assigned to the user, + and MUST set an "authentication pending" flag for the user. If they + + + +Garcia-Martin, et al. Standards Track [Page 37] + +RFC 4740 Diameter SIP Application November 2006 + + + match, the Diameter server shall clear the "authentication pending" + flag for the user. + + In any other situation, if there is a success in processing the + Diameter MAR command and the Diameter server stored the + SIP-Server-URI, the Diameter server MUST set the Result-Code AVP + value to DIAMETER_SUCCESS and return it in a Diameter MAA message. + + If there is a success in processing the Diameter MAR command, but the + Diameter server does not store the SIP-Server-URI because the AVP was + not present in the Diameter MAR command, then the Diameter server + MUST set the Result-Code AVP value to either: + + 1. DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED, if the Diameter + server is sending authentication credentials to create a + challenge. + + 2. DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED, if the Diameter server + successfully authenticated the user and authorized the SIP server + to proceed with the SIP request. + + Otherwise, the Diameter server MUST set the Result-Code AVP value to + DIAMETER_UNABLE_TO_COMPLY, and it MUST NOT include any + SIP-Auth-Data-Item AVP. + + The Message Format of the MAA command is as follows: + + <MAA> ::= < Diameter Header: 286, PXY > + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ SIP-AOR ] + [ SIP-Number-Auth-Items ] + * [ SIP-Auth-Data-Item ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + + + + +Garcia-Martin, et al. Standards Track [Page 38] + +RFC 4740 Diameter SIP Application November 2006 + + +8.9. Registration-Termination-Request (RTR) Command + + The Registration-Termination-Request (RTR) command is indicated by + the Command-Code set to 287 and the Command Flags' 'R' bit set. The + Diameter server sends this command to the Diameter client in a SIP + server to indicate to the SIP server that one or more SIP AORs have + to be deregistered. The command allows an operator to + administratively cancel the registration of a user from a centralized + Diameter server. + + The Diameter server has the capability to initiate the deregistration + of a user and inform the SIP server by means of the Diameter RTR + command. The Diameter server can decide whether only one SIP AOR is + going to be deregistered, a list of SIP AORs, or all the SIP AORs + allocated to the user. + + The absence of a SIP-AOR AVP in the Diameter RTR message indicates + that all the SIP AORs allocated to the user identified by the + User-Name AVP are being deregistered. + + The Diameter server MUST include a SIP-Deregistration-Reason AVP + value to indicate the reason for the deregistration. + + The Message Format of the RTR command is as follows: + + <RTR> ::= < Diameter Header: 287, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Host } + { SIP-Deregistration-Reason } + [ Destination-Realm ] + [ User-Name ] + * [ SIP-AOR ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.10. Registration-Termination-Answer (RTA) Command + + The Registration-Termination-Answer (RTA) is indicated by the + Command-Code set to 287 and the Command Flags' 'R' bit cleared. The + Diameter client sends this command in response to a previously + received Diameter Registration-Termination-Request (RTR) command. + + + + + +Garcia-Martin, et al. Standards Track [Page 39] + +RFC 4740 Diameter SIP Application November 2006 + + + In addition to the values already defined in RFC 3588 [RFC3588], the + Result-Code AVP may contain one of the values defined in + Section 10.1. + + If the SIP server (Diameter client) requires a User-Name AVP value to + process the Diameter RTR request, but the Diameter RTR message did + not contain a User-Name AVP value, the Diameter client MUST set the + Result-Code AVP value to DIAMETER_USER_NAME_REQUIRED (see Section + 10.1.2) and return it in a Diameter RTA message. + + The SIP server (Diameter client) applies the administrative + deregistration to each of the URIs included in each of the SIP-AOR + AVP values, or, if there is no SIP-AOR AVP present in the Diameter + RTR request, to all the URIs allocated to the User-Name AVP value. + + The value of the SIP-Deregistration-Reason AVP in the Diameter RTR + command has an effect on the actions performed at the SIP server + (Diameter client): + + o If the value is set to PERMANENT_TERMINATION, then the user has + terminated his/her registration to the realm. If informing the + interested parties (e.g., subscribers to the "reg" event + [RFC3680]) about the administrative deregistration is supported + through SIP procedures, the SIP server (Diameter client) will do + so. The Diameter Client in the SIP Server SHOULD NOT request a + new user registration. The SIP server clears the registration + state of the deregistered AORs. + + o If the value is set to NEW_SIP_SERVER_ASSIGNED, the Diameter + server informs the SIP server (Diameter client) that a new SIP + server has been allocated to the user, due to some reason. The + SIP server, if supported through SIP procedures, will inform the + interested parties (e.g., subscribers to the "reg" event + [RFC3680]) about the administrative deregistration at this SIP + server. The Diameter client in the SIP server SHOULD NOT request + a new user registration. The SIP server clears the registration + state of the deregistered SIP AORs. + + o If the value is set to SIP_SERVER_CHANGE, the Diameter server + informs the SIP server (Diameter client) that a new SIP server has + to be allocated to the user, e.g., due to user's capabilities + requiring a new SIP server, or not enough resources in the current + SIP server. If informing the interested parties about the + administrative deregistration is supported through SIP procedures + (e.g., subscriptions to the "reg" event [RFC3680]), the SIP server + will do so. The Diameter client in the SIP Server SHOULD NOT + request a new user registration. The SIP server clears the + registration state of the deregistered SIP AORs. + + + +Garcia-Martin, et al. Standards Track [Page 40] + +RFC 4740 Diameter SIP Application November 2006 + + + o If the value is set to REMOVE_SIP_SERVER, the Diameter server + informs the SIP server (Diameter client) that the SIP server will + no longer be bound in the Diameter server with that user. The SIP + server can delete all data related to the user. + + The Message Format of the RTA command is as follows: + + <RTA> ::= < Diameter Header: 287, PXY > + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.11. Push-Profile-Request (PPR) Command + + The Push-Profile-Request (PPR) command is indicated by the + Command-Code set to 288 and the Command Flags' 'R' bit set. The + Diameter server sends this command to the Diameter client in a SIP + server to update either the user profile of an already registered + user in that SIP server or the SIP accounting information. This + allows an operator to modify the data of a user profile or the + accounting information and push it to the SIP server where the user + is registered. + + Each user has a user profile associated with him/her and other + accounting information. The profile or the accounting information + may change with time, e.g., due to addition of new services to the + user. When the user profile or the accounting information changes, + the Diameter server sends a Diameter Push-Profile-Request (PPR) + command to the Diameter client in a SIP server, in order to start + applying those new services. + + A PPR command MAY contain a SIP-Accounting-Information AVP that + updates the addresses of the accounting servers. Changes in the + addresses of the accounting servers take effect immediately. The + Diameter client SHOULD close any existing accounting session with the + existing server and start providing accounting information to the + newly acquired accounting server. + + + +Garcia-Martin, et al. Standards Track [Page 41] + +RFC 4740 Diameter SIP Application November 2006 + + + A PPR command MAY contain zero or more SIP-User-Data AVP values + containing the new user profile. On selecting the type of user data, + the Diameter server SHOULD take into account the supported formats at + the SIP server (SIP-Supported-User-Data-Type AVP sent in a previous + SAR message) and the local policy. + + The User-Name AVP indicates the user to whom the profile is + applicable. + + The Message Format of the PPR command is as follows: + + <PPR> ::= < Diameter Header: 288, REQ, PXY > + < Session-Id > + { Auth-Application-Id } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { User-Name } + * [ SIP-User-Data ] + [ SIP-Accounting-Information ] + [ Destination-Host ] + [ Authorization-Lifetime ] + [ Auth-Grace-Period ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + +8.12. Push-Profile-Answer (PPA) Command + + The Push-Profile-Answer (PPA) is indicated by the Command-Code set to + 288 and the Command Flags' 'R' bit cleared. The Diameter client + sends this command in response to a previously received Diameter + Push-Profile-Request (PPR) command. + + In addition to the values already defined in RFC 3588 [RFC3588], the + Result-Code AVP may contain one of the values defined in + Section 10.1. + + If there is no error when processing the received Diameter PPR + message, the SIP server (Diameter client) MUST download the received + user profile from the SIP-User-Data AVP values in the Diameter PPR + message and store it associated with the user specified in the + User-Name AVP value. + + If the SIP server does not recognize or does not support some of the + data transferred in the SIP-User-Data AVP values, the Diameter client + in the SIP server MUST return a Diameter PPA message that includes a + + + +Garcia-Martin, et al. Standards Track [Page 42] + +RFC 4740 Diameter SIP Application November 2006 + + + Result-Code AVP set to the value + DIAMETER_ERROR_NOT_SUPPORTED_USER_DATA. + + If the SIP server (Diameter client) receives a Diameter PPR message + with a User-Name AVP that is unknown, the Diameter client MUST set + the Result-Code AVP value to DIAMETER_ERROR_USER_UNKNOWN and MUST + return it to the Diameter server in a Diameter PPA message. + + If the SIP server (Diameter client) receives in the + SIP-User-Data-Content AVP value (of the grouped SIP-User-Data AVP) + more data than it can accept, it MUST set the Result-Code AVP value + to DIAMETER_ERROR_TOO_MUCH_DATA and MUST return it to the Diameter + server in a Diameter PPA message. The SIP server MUST NOT override + the existing user profile with the one received in the PPR message. + + If the Diameter server receives the Result-Code AVP value set to + DIAMETER_ERROR_TOO_MUCH_DATA in a Diameter PPA message, it SHOULD + force a new re-registration of the user by sending to the Diameter + client a Diameter Registration-Termination-Request (RTR) with the + SIP-Deregistration-Reason AVP value set to SIP_SERVER_CHANGE. This + will force a re-registration of the user and will trigger a selection + of a new SIP server. + + If the Diameter client is not able to honor the command, for any + other reason, it MUST set the Result-Code AVP value to + DIAMETER_UNABLE_TO_COMPLY and it MUST return it in a Diameter PPA + message. + + The Message Format of the PPA command is as follows: + + <PPA> ::= < Diameter Header: 288, PXY > + < Session-Id > + { Auth-Application-Id } + { Result-Code } + { Auth-Session-State } + { Origin-Host } + { Origin-Realm } + [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 43] + +RFC 4740 Diameter SIP Application November 2006 + + +9. Diameter SIP Application AVPs + + This section defines new AVPs used in this Diameter SIP application. + Applications compliant with this specification MUST implement these + AVPs. + + Table 2 lists the new AVPs defined in this Diameter SIP application. + The following abbreviations are used in the Data-Type column: + + o DURI: DiameterURI + o E: Enumerated + o G: Grouped + o OS: OctetString + o UTF8S: UTF8String + o U32: Unsigned32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 44] + +RFC 4740 Diameter SIP Application November 2006 + + + +-----------------------------------+------+----------------+-------+ + | Attribute Name | AVP | Reference | Data- | + | | Code | | Type | + +-----------------------------------+------+----------------+-------+ + | SIP-Accounting-Information | 368 | Section 9.1 | G | + | SIP-Accounting-Server-URI | 369 | Section 9.1.1 | DURI | + | SIP-Credit-Control-Server-URI | 370 | Section 9.1.2 | DURI | + | SIP-Server-URI | 371 | Section 9.2 | UTF8S | + | SIP-Server-Capabilities | 372 | Section 9.3 | G | + | SIP-Mandatory-Capability | 373 | Section 9.3.1 | U32 | + | SIP-Optional-Capability | 374 | Section 9.3.2 | U32 | + | SIP-Server-Assignment-Type | 375 | Section 9.4 | E | + | SIP-Auth-Data-Item | 376 | Section 9.5 | G | + | SIP-Authentication-Scheme | 377 | Section 9.5.1 | E | + | SIP-Item-Number | 378 | Section 9.5.2 | U32 | + | SIP-Authenticate | 379 | Section 9.5.3 | G | + | SIP-Authorization | 380 | Section 9.5.4 | G | + | SIP-Authentication-Info | 381 | Section 9.5.5 | G | + | SIP-Number-Auth-Items | 382 | Section 9.6 | U32 | + | SIP-Deregistration-Reason | 383 | Section 9.7 | G | + | SIP-Reason-Code | 384 | Section 9.7.1 | E | + | SIP-Reason-Info | 385 | Section 9.7.2 | UTF8S | + | SIP-Visited-Network-Id | 386 | Section 9.9 | UTF8S | + | SIP-User-Authorization-Type | 387 | Section 9.10 | E | + | SIP-Supported-User-Data-Type | 388 | Section 9.11 | UTF8S | + | SIP-User-Data | 389 | Section 9.12 | G | + | SIP-User-Data-Type | 390 | Section 9.12.1 | UTF8S | + | SIP-User-Data-Contents | 391 | Section 9.12.2 | OS | + | SIP-User-Data-Already-Available | 392 | Section 9.13 | E | + | SIP-Method | 393 | Section 9.14 | UTF8S | + +-----------------------------------+------+----------------+-------+ + + Table 2: Defined AVPs + + Table 3 expands the table of AVPs included in Section 4.5 of RFC 3588 + [RFC3588]. The table indicates the Diameter AVPs defined in this + Diameter SIP Application, their possible flag values, and whether the + AVP may be encrypted. The acronyms 'M', 'P', and 'V' refer to AVP + flags whose semantics are described in RFC 3588 [RFC3588]. The value + of the 'Encr' column is also described in RFC 3588 [RFC3588]. + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 45] + +RFC 4740 Diameter SIP Application November 2006 + + + +----------------------------------+------+-----+-----+------+------+ + | Attribute Name | MUST | MAY | SHD | MUST | Encr | + | | | | NOT | NOT | | + +----------------------------------+------+-----+-----+------+------+ + | SIP-Accounting-Information | M | P | | V | N | + | SIP-Accounting-Server-URI | M | P | | V | N | + | SIP-Credit-Control-Server-URI | M | P | | V | N | + | SIP-Server-URI | M | P | | V | N | + | SIP-Server-Capabilities | M | P | | V | N | + | SIP-Mandatory-Capability | M | P | | V | N | + | SIP-Optional-Capability | M | P | | V | N | + | SIP-Server-Assignment-Type | M | P | | V | N | + | SIP-Auth-Data-Item | M | P | | V | N | + | SIP-Authentication-Scheme | M | P | | V | N | + | SIP-Item-Number | M | P | | V | N | + | SIP-Authenticate | M | P | | V | N | + | SIP-Authorization | M | P | | V | N | + | SIP-Authentication-Info | M | P | | V | N | + | SIP-Number-Auth-Items | M | P | | V | N | + | SIP-Deregistration-Reason | M | P | | V | N | + | SIP-Reason-Code | M | P | | V | N | + | SIP-Reason-Info | M | P | | V | N | + | SIP-Visited-Network-Id | M | P | | V | N | + | SIP-User-Authorization-Type | M | P | | V | N | + | SIP-Supported-User-Data-Type | M | P | | V | N | + | SIP-User-Data | M | P | | V | N | + | SIP-User-Data-Type | M | P | | V | N | + | SIP-User-Data-Contents | M | P | | V | N | + | SIP-User-Data-Already-Available | M | P | | V | N | + | SIP-Method | M | P | | V | N | + +----------------------------------+------+-----+-----+------+------+ + + Table 3: Summary of the new AVPs flags + +9.1. SIP-Accounting-Information AVP + + The SIP-Accounting-Information (AVP Code 368) is of type Grouped, and + contains the Diameter addresses of those nodes that are able to + collect accounting information. + + The SIP-Accounting-Information AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [RFC3588]): + + SIP-Accounting-Information ::= < AVP Header: 368 > + * [ SIP-Accounting-Server-URI ] + * [ SIP-Credit-Control-Server-URI ] + * [ AVP] + + + + +Garcia-Martin, et al. Standards Track [Page 46] + +RFC 4740 Diameter SIP Application November 2006 + + +9.1.1. SIP-Accounting-Server-URI AVP + + The SIP-Accounting-Server-URI AVP (AVP Code 369) is of type + DiameterURI. This AVP contains the address of a Diameter server that + is able to receive SIP-session-related accounting information. + +9.1.2. SIP-Credit-Control-Server-URI AVP + + The SIP-Credit-Control-Server-URI AVP (AVP Code 370) is of type + DiameterURI. This AVP contains the address of a Diameter server that + is able to authorize real-time credit control usage. The Diameter + Credit-Control Application [RFC4006] may be used for this purpose. + +9.2. SIP-Server-URI AVP + + The SIP-Server-URI AVP (AVP Code 371) is of type UTF8String. This + AVP contains a SIP or SIPS URI (as defined in RFC 3261 [RFC3261]) + that identifies a SIP server. + +9.3. SIP-Server-Capabilities AVP + + The SIP-Server-Capabilities AVP (AVP Code 372) is of type Grouped. + The Diameter indicates in this AVP the requirements for a particular + SIP capability, so that the Diameter client (SIP server) is able to + select another appropriate SIP server to serve the user. + + The SIP-Server-Capabilities AVP allows a Diameter client (SIP server) + to select another SIP server for triggering or executing services to + the user. A user may have enabled some services that require the + implementation of certain capabilities in the SIP server that + triggers or executes those services. For example, the SIP server + that triggers or executes services to this user may need to implement + SIP servlets [JSR-000116], Call Processing Language (CPL) [RFC3880], + or any other kind of capability. Or perhaps that user belongs to a + premium users group that has a certain stringent quality-of-service + agreement that requires a fast SIP server. The capabilities required + or recommended to a given user are conveyed in the + SIP-Server-Capabilities AVP. When it receives them, the Diameter + client (SIP server) that does the SIP server selection needs to have + the means to find out available SIP servers that meet the required or + optional capabilities. Such means are outside the scope of this + specification. + + Note that the SIP-Server-Capabilities AVP assists the Diameter client + (SIP server) to produce a subset of all the available SIP servers to + be allocated to the user in the Home Realm; this is the subset that + conforms the requirements of capabilities on a per-user basis. + Typically this subset will be formed of more than a single SIP + + + +Garcia-Martin, et al. Standards Track [Page 47] + +RFC 4740 Diameter SIP Application November 2006 + + + server, so once the subset of those SIP servers is identified, it is + possible that several instances of these SIP servers exist, in which + case the Diameter client (SIP server) should choose one particular + SIP server to execute and trigger services to this user. It is + expected that at this point the SIP server (Diameter client) will + follow the procedures of RFC 3263 [RFC3263] to allocate one SIP + server to the user. + + The SIP-Server-Capabilities AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [RFC3588]): + + SIP-Server-Capabilities ::= < AVP Header: 372 > + * [ SIP-Mandatory-Capability ] + * [ SIP-Optional-Capability ] + * [ SIP-Server-URI ] + * [ AVP ] + +9.3.1. SIP-Mandatory-Capability AVP + + The SIP-Mandatory-Capability AVP (AVP Code 373) is of type + Unsigned32. The value represents a certain capability (or set of + capabilities) that have to be fulfilled by the SIP server allocated + to the user. + + The semantics of the different values are not standardized, as it is + a matter of the administrative network to allocate its own semantics + within its own network. Each value has to represent a single + capability within the administrative network. + +9.3.2. SIP-Optional-Capability AVP + + The SIP-Optional-Capability AVP (AVP Code 374) is of type Unsigned32. + The value represents a certain capability (or set of capabilities) + that, optionally, may be fulfilled by the SIP server allocated to the + user. + + The semantics of the different values are not standardized, as it is + a matter of the administrative network to allocate its own semantics + within its own network. Each value has to represent a single + capability within the administrative network. + +9.4. SIP-Server-Assignment-Type AVP + + The SIP-Server-Assignment-Type AVP (AVP Code 375) is of type + Enumerated and indicates the type of server update being performed in + a Diameter Server-Assignment-Request (SAR) operation. The following + values are defined: + + + + +Garcia-Martin, et al. Standards Track [Page 48] + +RFC 4740 Diameter SIP Application November 2006 + + + o NO_ASSIGNMENT (0) + The Diameter client uses this value to request the user profile of + a SIP AOR, without affecting the registration state of that + identity. + + o REGISTRATION (1) + First SIP registration of a SIP AOR. + + o RE_REGISTRATION (2) + Subsequent SIP registration of a SIP AOR. + + o UNREGISTERED_USER (3) + The SIP server has received a SIP request (e.g., SIP INVITE) + addressed for a SIP AOR that is not registered. + + o TIMEOUT_DEREGISTRATION (4) + The SIP registration timer of an identity has expired. + + o USER_DEREGISTRATION (5) + The SIP server has received a request to deregister a SIP AOR. + + o TIMEOUT_DEREGISTRATION_STORE_SERVER_NAME (6) + The SIP registration timer of an identity has expired. The SIP + server keeps the user data stored and requests the Diameter server + to store the SIP server address. + + o USER_DEREGISTRATION_STORE_SERVER_NAME (7) + The SIP server has received a user-initiated deregistration + request. The SIP server keeps the user data stored and requests + the Diameter server to store the SIP server address. + + o ADMINISTRATIVE_DEREGISTRATION (8) + The SIP server, due to administrative reasons, has deregistered a + SIP AOR. + + o AUTHENTICATION_FAILURE (9) + The authentication of a user has failed. + + o AUTHENTICATION_TIMEOUT (10) + The authentication timer has expired. + + o DEREGISTRATION_TOO_MUCH_DATA (11) + The SIP server has requested user profile information from the + Diameter server and has received a volume of data higher than it + can accept. + + + + + + +Garcia-Martin, et al. Standards Track [Page 49] + +RFC 4740 Diameter SIP Application November 2006 + + +9.5. SIP-Auth-Data-Item AVP + + The SIP-Auth-Data-Item (AVP Code 376) is of type Grouped and contains + the authentication and/or authorization information pertaining to a + user. + + When the Diameter server uses the grouped SIP-Auth-Data-Item AVP to + include a SIP-Authenticate AVP, the Diameter server MUST send a + maximum of one authentication data item (e.g., in case the SIP + request contained several credentials). Section 11 contains a + detailed discussion and normative text of the case when a SIP request + contains several credentials. + + The SIP-Auth-Data-Item AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [RFC3588]): + + SIP-Auth-Data-Item ::= < AVP Header: 376 > + { SIP-Authentication-Scheme } + [ SIP-Item-Number ] + [ SIP-Authenticate ] + [ SIP-Authorization ] + [ SIP-Authentication-Info ] + * [ AVP ] + +9.5.1. SIP-Authentication-Scheme AVP + + The SIP-Authentication-Scheme AVP (AVP Code 377) is of type + Enumerated and indicates the authentication scheme used in the + authentication of SIP services. RFC 2617 identifies this value as an + "auth-scheme" (see Section 1.2 of RFC 2617 [RFC2617]). The only + currently defined value is: + + o DIGEST (0) to indicate HTTP Digest authentication as specified in + RFC 2617 [RFC2617] Section 3.2.1. Derivative work is also + considered Digest authentication scheme, as long as the + "auth-scheme" is identified as Digest in the SIP headers carrying + the HTTP authentication. This includes, e.g., the HTTP Digest + authentication using AKA [RFC3310]. + + Each HTTP Digest directive (parameter) is transported in a + corresponding AVP, whose name follows the pattern Digest-*. The + Digest-* AVPs are RADIUS attributes imported from the RADIUS + Extension for Digest Authentication [RFC4590] namespace, allowing a + smooth transition between RADIUS and Diameter applications supporting + SIP. The Diameter SIP application goes a step further by grouping + the Digest-* AVPs into the SIP-Authenticate, SIP-Authorization, and + + + + + +Garcia-Martin, et al. Standards Track [Page 50] + +RFC 4740 Diameter SIP Application November 2006 + + + SIP-Authentication-Info grouped AVPs that correspond to the SIP WWW- + Authenticate/Proxy-Authentication, Authorization/Proxy-Authorization, + and Authentication-Info headers fields, respectively. + + Note: Due to the fact that HTTP Digest authentication [RFC2617] is + the only mandatory authentication mechanism in SIP, this memo only + provides support for HTTP Digest authentication and derivative + work such as HTTP Digest authentication using AKA [RFC3310]. + Extensions to this memo can register new values and new AVPs to + provide support for other authentication schemes or extensions to + HTTP Digest authentication. + + Note: Although RFC 2617 [RFC2617] defines the Basic and Digest + schemes for authenticating HTTP requests, RFC 3261 [RFC3261] only + imports HTTP Digest as a mechanism to provide authentication in + SIP. + + Due to syntactic requirements, HTTP Digest authentication has to + escape quote characters in contents of HTTP Digest directives. When + translating directives into Digest-* AVPs, the Diameter client or + server removes the surrounding quotes where present, as required by + the syntax of the Digest-* attributes defined in the "RADIUS + Extension for Digest Authentication" [RFC4590]. + +9.5.2. SIP-Item-Number AVP + + The SIP-Item-Number (AVP Code 378) is of type Unsigned32 and is + included in a SIP-Auth-Data-Item grouped AVP in circumstances where + there are multiple occurrences of SIP-Auth-Data-Item AVPs and the + order of processing is relevant. The AVP indicates the order in + which the Grouped SIP-Auth-Data-Item should be processed. Lower + values of the SIP-Item-Number AVP indicate that the whole + SIP-Auth-Data-Item SHOULD be processed before other + SIP-Auth-Data-Item AVPs that contain higher values in the + SIP-Item-Number AVP. + +9.5.3. SIP-Authenticate AVP + + The SIP-Authenticate AVP (AVP Code 379) is of type Grouped and + contains a reconstruction of either the SIP WWW-Authenticate or + Proxy-Authentication header fields specified in RFC 2617 [RFC2617] + for the HTTP Digest authentication scheme. Additionally, the AVP may + include a Digest-HA1 AVP that contains H(A1) (as defined in RFC 2617 + [RFC2617]). H(A1) allows the Diameter client to create an expected + response and compare it with the Digest response received from the + SIP UA. + + + + + +Garcia-Martin, et al. Standards Track [Page 51] + +RFC 4740 Diameter SIP Application November 2006 + + + The SIP-Authenticate AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [RFC3588]): + + SIP-Authenticate ::= < AVP Header: 379 > + { Digest-Realm } + { Digest-Nonce } + [ Digest-Domain ] + [ Digest-Opaque ] + [ Digest-Stale ] + [ Digest-Algorithm ] + [ Digest-QoP ] + [ Digest-HA1] + * [ Digest-Auth-Param ] + * [ AVP ] + +9.5.4. SIP-Authorization AVP + + The SIP-Authorization AVP (AVP Code 380) is of type Grouped and + contains a reconstruction of either the SIP Authorization or + Proxy-Authorization header fields specified in RFC 2617 [RFC2617] for + the HTTP Digest authentication scheme. + + The SIP-Authorization AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [RFC3588]): + + SIP-Authorization ::= < AVP Header: 380 > + { Digest-Username } + { Digest-Realm } + { Digest-Nonce } + { Digest-URI } + { Digest-Response } + [ Digest-Algorithm ] + [ Digest-CNonce ] + [ Digest-Opaque ] + [ Digest-QoP ] + [ Digest-Nonce-Count ] + [ Digest-Method] + [ Digest-Entity-Body-Hash ] + * [ Digest-Auth-Param ] + * [ AVP ] + +9.5.5. SIP-Authentication-Info AVP + + The SIP-Authentication-Info AVP (AVP Code 381) is of type Grouped and + contains a reconstruction of the SIP Authentication-Info header + specified in RFC 2617 [RFC2617] for the HTTP Digest authentication + scheme. + + + + +Garcia-Martin, et al. Standards Track [Page 52] + +RFC 4740 Diameter SIP Application November 2006 + + + The SIP-Authentication-Info AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [RFC3588]): + + SIP-Authentication-Info ::= < AVP Header: 381 > + [ Digest-Nextnonce ] + [ Digest-QoP ] + [ Digest-Response-Auth ] + [ Digest-CNonce ] + [ Digest-Nonce-Count ] + * [ AVP ] + + Note that, in some cases, the Digest-Response-Auth AVP cannot be + calculated at the Diameter server, but has to be calculated at the + Diameter client (SIP server). For example, if the value of the + quality of protection (qop) parameter in Digest is set to "auth-int", + then the response-digest (rspauth parameter value in Digest) is + calculated with the hash of the body of the SIP response, which is + not available at the Diameter server. In this case, the Diameter + client (SIP server) must calculate the response-digest once the body + of the SIP response is calculated. + + Therefore, a value of "auth-int" in the Digest-QoP AVP of the + SIP-Authentication-Info AVP indicates that the Diameter client (SIP + server) MUST compute the Digest "rspauth" parameter value at the + Diameter client (SIP server). + +9.5.6. Digest AVPs + + The following AVPs are RADIUS attributes defined in the RADIUS + Extension for Digest Authentication [RFC4590] and imported by this + specification: Digest-AKA-Auts, Digest-Algorithm, Digest-Auth-Param, + Digest-CNonce, Digest-Domain, Digest-Entity-Body-Hash, Digest-HA1, + Digest-Method, Digest-Nextnonce, Digest-Nonce, Digest-Nonce-Count, + Digest-Opaque, Digest-QoP, Digest-Realm, Digest-Response, + Digest-Response-Auth, Digest-URI, Digest-Username, and Digest-Stale. + +9.5.6.1. Considerations about Digest-HA1 AVP + + The Digest-HA1 AVP contains the value, pre-calculated at the Diameter + server, of H(A1) as defined in RFC 2617 [RFC2617]. The Diameter + client can use H(A1) to calculate the expected Digest response, + according to this challenge. If the SIP UA is in possession of the + credentials, the calculated expected response and the response sent + from the SIP UA will match. The Diameter server MAY include this AVP + to enable and assist the SIP server in authenticating the SIP UA. + + This scenario is not applicable when the Diameter server is + configured to use a session MD5 (MD5-sess) algorithm, because the + + + +Garcia-Martin, et al. Standards Track [Page 53] + +RFC 4740 Diameter SIP Application November 2006 + + + Diameter server requires the client nonce to compute the H(A1) before + sending it to the Diameter client, and the client nonce might not be + available when the computation of H(A1) is done. Therefore, if the + final authentication is delegated to the Diameter client, it is + RECOMMENDED to configure the Diameter server to use algorithms + different than MD5-sess in HTTP Digest. + + It is up to the Diameter server to include a Digest-HA1 AVP. The + Diameter server calculates the Digest H(A1) with the username, + password, and realm (and nonce and cnonce, if applicable) as inputs, + and places the result in the Digest-HA1 AVP value. For more details + of the A1 computation, see RFC 2617 [RFC2617] Section 3.2.2.2. The + Diameter client can calculate the Digest expected response with H(A1) + as input, as described in RFC 2617 [RFC2617] Section 3.2.2. + + Section 11 provides further normative details about the usage of the + Digest-HA1 AVP. + +9.5.6.2. Considerations about Digest-Entity-Body-Hash AVP + + The Digest-Entity-Body-Hash AVP contains a hash of the entity body + contained in the SIP message. This hash is required by HTTP Digest + with quality of protection set to "auth-int". Diameter clients MUST + use this AVP to transport the hash of the entity body when HTTP + Digest is the authentication mechanism and the Diameter server + requires verification of the integrity of the entity body (e.g., qop + parameter set to "auth-int"). + + The clarifications described in Section 22.4 of RFC 3261 [RFC3261] + about the hash of empty entity bodies apply to the + Digest-Entity-Body-Hash AVP. + +9.5.6.3. Considerations about Digest-Auth-Param AVP + + The Digest-Auth-Param AVP is the mechanism whereby the Diameter + client and Diameter server can exchange possible extension parameters + contained in Digest headers that are either not understood by the + Diameter client or for which there are no corresponding stand-alone + AVPs. Unlike the previously listed Digest-* AVPs, the + Digest-Auth-Param contains not only the value, but also the parameter + name, since it is unknown to the Diameter client. The Diameter node + MUST insert one Digest parameter/value combination per AVP value. If + the Digest header contains several unknown parameters, then the + Diameter implementation MUST repeat this AVP and each instance MUST + contain one different unknown Digest parameter/value combination. + This AVP corresponds to the "auth-param" parameter defined in Section + 3.2.1 of RFC 2617 [RFC2617]. + + + + +Garcia-Martin, et al. Standards Track [Page 54] + +RFC 4740 Diameter SIP Application November 2006 + + + Example: Assume that the Diameter server wants the SIP server to send + a "foo" parameter with the value set to "bar", so that the SIP server + sends that combination in a SIP WWW-Authenticate header field. The + Diameter server builds a grouped SIP-Authenticate AVP that contains a + Digest-Auth-Param whose value is set to foo="bar". Then the SIP + server creates the WWW-Authenticate header field with all the digest + parameters (received in Digest-* AVPs) and adds the foo="bar" + parameter to that header field. + +9.6. SIP-Number-Auth-Items AVP + + The SIP-Number-Auth-Items AVP (AVP Code 382) is of type Unsigned32 + and indicates the number of authentication and/or authorization + credentials that the Diameter server included in a Diameter message. + + When the AVP is present in a request, it indicates the number of + SIP-Auth-Data-Items the Diameter client is requesting. This can be + used, for instance, when the SIP server is requesting several + pre-calculated authentication credentials. In the answer message, + the SIP-Number-Auth-Items AVP indicates the actual number of items + that the Diameter server included. + +9.7. SIP-Deregistration-Reason AVP + + The SIP-Deregistration-Reason AVP (AVP Code 383) is of type Grouped + and indicates the reason for a deregistration operation. + + The SIP-Deregistration-Reason AVP is defined as follows (per the + grouped-avp-def of RFC 3588 [RFC3588]): + + SIP-Deregistration-Reason ::= < AVP Header: 383 > + { SIP-Reason-Code } + [ SIP-Reason-Info ] + * [ AVP ] + +9.7.1. SIP-Reason-Code AVP + + The SIP-Reason-Code AVP (AVP Code 384) is of type Enumerated and + defines the reason for the network initiated deregistration. The + following values are defined: + + o PERMANENT_TERMINATION (0) + o NEW_SIP_SERVER_ASSIGNED (1) + o SIP_SERVER_CHANGE (2) + o REMOVE_SIP_SERVER (3) + + + + + + +Garcia-Martin, et al. Standards Track [Page 55] + +RFC 4740 Diameter SIP Application November 2006 + + +9.7.2. SIP-Reason-Info AVP + + The SIP-Reason-Info AVP (AVP Code 385) is of type UTF8String and + contains textual information that can be rendered to the user, about + the reason for a deregistration. + +9.8. SIP-AOR AVP + + The SIP-AOR AVP is a RADIUS attribute imported from the RADIUS + Extension for Digest Authentication [RFC4590] namespace, allowing a + smooth transition between RADIUS and Diameter applications supporting + SIP. The SIP-AOR AVP carries the URI of the intended user related to + the SIP request (whose location in SIP may vary depending on the + actual SIP request and whether the SIP server is acting on Diameter + due to a SIP-originated or terminating requests). + + The Diameter client (SIP server) uses the value found in a SIP + Request-URI or a header field value of the SIP request to construct + the SIP-AOR AVP. The selection of a Request-URI or a particular + header field to create the value of the SIP-AOR AVP depends on the + semantics of the SIP message and whether the SIP server is acting for + originating or terminating requests. For instance, when the SIP + server receives an INVITE request addressed to the served user (e.g., + the SIP server is receiving a terminating SIP request), it maps the + SIP Request-URI of the SIP request to this AVP. However, when the + SIP server receives an INVITE request originated by the served user, + it can map either the P-Asserted-Identity or the From header field + values to this AVP. If the SIP server is acting as a SIP registrar, + then it maps the To header field of the REGISTER request to the + SIP-AOR AVP. + +9.9. SIP-Visited-Network-Id AVP + + The SIP-Visited-Network-Id AVP (AVP Code 386) is of type UTF8String. + This AVP contains an identifier that helps the home network identify + the visited network (e.g., the visited network domain name), in order + to authorize roaming to that visited network. + +9.10. SIP-User-Authorization-Type AVP + + The SIP-User-Authorization-Type AVP (AVP Code 387) is of type + Enumerated and indicates the type of user authorization being + performed in a User Authorization operation, i.e., the Diameter + User-Authorization-Request (UAR) command. The following values are + defined: + + + + + + +Garcia-Martin, et al. Standards Track [Page 56] + +RFC 4740 Diameter SIP Application November 2006 + + + o REGISTRATION (0) + This value is used for initial registration or re-registration. + This is the default value. + + o DEREGISTRATION (1) + This value is used for deregistration. + + o REGISTRATION_AND_CAPABILITIES (2) + This value is used for initial registration or re-registration + when the SIP server explicitly requests the Diameter server to get + capability information. This capability information helps the SIP + server to allocate another SIP server to serve the user. + +9.11. SIP-Supported-User-Data-Type AVP + + The SIP-Supported-User-Data-Type AVP (AVP Code 388) is of type + UTF8String and contains a string that identifies the type of + supported user data (user profile, see SIP-User-Data AVP + (Section 9.12)) supported in the node. The AVP can be repeated, if + the SIP server supports several user data types. In case of + repetition, the Diameter client should order the different instances + of this AVP according to its preferences. + + When the Diameter client inserts this AVP in a SAR message, it allows + the Diameter client to provide an indication to the Diameter server + of the types of user data supported by the SIP server. The Diameter + server, upon inspection of these AVPs, will return a suitable + SIP-User-Data AVP (Section 9.12) of the type indicated in the + SIP-User-Data-Type AVP (Section 9.12.1). + +9.12. SIP-User-Data AVP + + The SIP-User-Data AVP (AVP Code 389) is of type Grouped. This AVP + allows the Diameter server to transport user-specific data, such as a + user profile, to the SIP server (in the Diameter client). The + Diameter server selects a type of user data that is understood by the + SIP server in the Diameter client, and has been indicated in a + SIP-Supported-User-Data-Type AVP. In case the Diameter client + indicated support for several types of user data, the Diameter server + SHOULD choose the first type supported by the client. + + The SIP-User-Data grouped AVP contains a SIP-User-Data-Type AVP that + indicates the type of user data included in the + SIP-User-Data-Contents-AVP. + + The SIP-User-Data AVP is defined as follows (per the grouped-avp-def + of RFC 3588 [RFC3588]): + + + + +Garcia-Martin, et al. Standards Track [Page 57] + +RFC 4740 Diameter SIP Application November 2006 + + + SIP-User-Data ::= < AVP Header: 389 > + { SIP-User-Data-Type } + { SIP-User-Data-Contents } + * [ AVP ] + +9.12.1. SIP-User-Data-Type AVP + + The SIP-User-Data AVP (AVP Code 390) is of type UTF8String and + contains a string that identifies the type of user data included in + the SIP-User-Data AVP (Section 9.12). + + This document does not specify a convention to characterize the type + of user data contained in the SIP-User-Data AVP (Section 9.12). It + is believed that in most cases this feature will be used in + environments controlled by a network administrator who can configure + both the client and server to assign the same value type at the + client and server. It is also RECOMMENDED that organizations + developing their own profile of SIP-User-Data AVP (Section 9.12) + allocate a type based on their canonical DNS name. For instance, + organization "example.com" can define several types of SIP-User-Data + and allocate the types "type1.dsa.example.com", + "type2.dsa.example.com", and so on. This convention will avoid a + clash in the allocation of types of SIP-User-Data AVP (Section 9.12). + +9.12.2. SIP-User-Data-Contents AVP + + The SIP-User-Data-Contents AVP (AVP Code 391) is of type OctetString. + The Diameter peers do not need to understand the value of this AVP. + + The AVP contains the user profile data required for a SIP server to + give service to the user. + +9.13. SIP-User-Data-Already-Available AVP + + The SIP-User-Data-Already-Available AVP (AVP Code 392) is of type + Enumerated and gives an indication to the Diameter server about + whether the Diameter client (SIP server) already received the portion + of the user profile needed in order to serve the user. The following + values are defined: + + o USER_DATA_NOT_AVAILABLE (0) + The Diameter client (SIP server) does not have the data that it + needs to serve the user. + + o USER_DATA_ALREADY_AVAILABLE (1) + The Diameter client (SIP server) already has received the data + that it needs to serve the user. + + + + +Garcia-Martin, et al. Standards Track [Page 58] + +RFC 4740 Diameter SIP Application November 2006 + + +9.14. SIP-Method AVP + + The SIP-Method-AVP (AVP Code 393) is of type UTF8String and contains + the method of the SIP request that triggered the Diameter message. + The Diameter server MUST use this AVP solely for authorization of SIP + requests, and MUST NOT use it to compute the Digest authentication. + To compute the Digest authentication, the Diameter server MUST use + the Digest-Method AVP instead. + +10. New Values for Existing AVPs + + This section defines new values that the Diameter SIP application + extends to already existing AVPs. + +10.1. Extension to the Result-Code AVP Values + + The Result-Code AVP is already defined in RFC 3588 [RFC3588]. In + addition to the values already defined in RFC 3588 [RFC3588], the + Diameter SIP application defines the following new Result-Code AVP + values: + +10.1.1. Success Result-Code AVP Values + + A Diameter peer uses Result-Code AVP values that fall into the + success category to inform the remote peer that a request has been + successfully completed. + + o DIAMETER_FIRST_REGISTRATION 2003 + The user was not previously registered. The Diameter server has + now authorized the registration. + + o DIAMETER_SUBSEQUENT_REGISTRATION 2004 + The user is already registered. The Diameter server has now + authorized the re-registration. + + o DIAMETER_UNREGISTERED_SERVICE 2005 + The user is not currently registered, but the requested service + can still be granted to the user. + + o DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED 2006 + The request operation was successfully processed. The Diameter + server does not keep a record of the SIP server address assigned + to the user. + + o DIAMETER_SERVER_SELECTION 2007 + The Diameter server has authorized the registration. The user has + already been assigned a SIP server, but it may be necessary to + select a new SIP server for the user. + + + +Garcia-Martin, et al. Standards Track [Page 59] + +RFC 4740 Diameter SIP Application November 2006 + + + o DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED 2008 + The requested operation was successfully executed. The Diameter + server is sending a number of authentication credentials in the + answer message. The Diameter server does not keep a record of the + SIP server. + +10.1.2. Transient Failures Result-Code AVP Values + + A Diameter peer uses a Result-Code AVP value that falls in the + transient failures category to inform the remote peer that a request + could not be satisfied at the time it was received, but it MAY be + satisfied by the Diameter peer in the future. + + o DIAMETER_USER_NAME_REQUIRED 4013 + The Diameter request did not contain a User-Name AVP, which is + required to complete the transaction. The Diameter peer MAY + include a User-Name AVP and attempt the request again. + +10.1.3. Permanent Failures Result-Code AVP Values + + A Diameter peer uses a Result-Code AVP value that falls into the + permanent failure category to inform the remote peer that the request + failed and should not be attempted again. + + o DIAMETER_ERROR_USER_UNKNOWN 5032 + The SIP-AOR AVP value does not belong to a known user in this + realm. + + o DIAMETER_ERROR_IDENTITIES_DONT_MATCH 5033 + The value in one of the SIP-AOR AVPs is not allocated to the user + specified in the User-Name AVP. + + o DIAMETER_ERROR_IDENTITY_NOT_REGISTERED 5034 + A query for location information is received for a SIP AOR that + has not been registered before. The user to which this identity + belongs cannot be given service in this situation. + + o DIAMETER_ERROR_ROAMING_NOT_ALLOWED 5035 + The user is not allowed to roam to the visited network. + + o DIAMETER_ERROR_IDENTITY_ALREADY_REGISTERED 5036 + The identity being registered has already been assigned a server + and the registration status does not allow that it is overwritten. + + o DIAMETER_ERROR_AUTH_SCHEME_NOT_SUPPORTED 5037 + The authentication scheme indicated in an authentication request + is not supported. + + + + +Garcia-Martin, et al. Standards Track [Page 60] + +RFC 4740 Diameter SIP Application November 2006 + + + o DIAMETER_ERROR_IN_ASSIGNMENT_TYPE 5038 + The SIP server address sent in the SIP-Server-URI AVP value of the + Diameter Server-Assignment-Request (SAR) command is the same SIP + server address that is currently assigned to the user name, but + the SIP-Server-Assignment-Type AVP is not allowed. For example, + the user is registered and the Server-Assignment-Request indicates + the assignment for an unregistered user. + + o DIAMETER_ERROR_TOO_MUCH_DATA 5039 + The Diameter peer in the SIP server receives more data than it can + accept. The SIP server cannot overwrite the already stored data. + + o DIAMETER_ERROR_NOT SUPPORTED_USER_DATA 5040 + The SIP server informs the Diameter server that the received + subscription data contained information that was not recognized or + supported. + +11. Authentication Details + + Authenticating a user can occur through various mechanisms. + Currently HTTP Digest authentication is supported. The actual + authentication is performed in either the SIP server or the Diameter + server. + + If the Diameter server wants to assure that authentication will take + place in the Diameter server (as opposed to a delegated + authentication taking place in the SIP server), it MUST NOT include a + Digest-HA1 AVP (part of the grouped SIP-Authenticate AVP, which in + turn is part of the SIP-Auth-Data-Item AVP) in a MAA message. The + Diameter server MAY include a pre-calculated Digest-HA1 AVP in the + MAA message if it wants to delegate authentication of the user to the + SIP server. + + Note that on systems where the SIP User Agent is using HTTP Digest + authentication [RFC2617] inside of Transport Layer Security (TLS) + [RFC4346], where only the SIP proxy server has a certificate, + delegating authentication to the SIP server (by making Digest-HA1 + available to the SIP server) might reduce the load on the Diameter + server. + + When requesting authentication, the Diameter client indicates in the + SIP-Number-Auth-Items AVP value of a Diameter MAR message how many + authentication credentials are being requested. In the Diameter MAA + message, the Diameter server MAY include more than one + SIP-Auth-Data-Item AVP, but it is only useful for the Diameter client + if the Digest-QoP AVP was set to 'auth-int' (in the MAR message), and + if future authentications will have the same realm. When including + more than one SIP-Auth-Data-Item AVP, the Diameter server SHOULD + + + +Garcia-Martin, et al. Standards Track [Page 61] + +RFC 4740 Diameter SIP Application November 2006 + + + indicate how many instances of SIP-Auth-Data-Item AVPs are present + with the SIP-Number-Auth-Items AVP. This number may be different + from the one requested in the Diameter MAR message. If multiple + SIP-Auth-Data-Item AVPs are present, and their ordering is + significant, the Diameter server MUST include a SIP-Item-Number AVP + in each grouping to indicate the order. The + SIP-Authentication-Scheme AVP indicates "Digest" and the + SIP-Authenticate AVP contains data (typically a challenge of some + kind) that the user can use for her authentication. The grouped + SIP-Authorization AVP contains the AVPs that conform to the response + expected from the user. + + If the Diameter server performs the authentication of the user, the + Diameter MAR message that the Diameter client sends to the Diameter + server MUST include all the authentication credentials supplied by + the SIP UA (there might be more than one credential, e.g., different + realms, authentication of proxies, etc.). Each credential is + inserted in a grouped SIP-Authorization AVP (part of the grouped + SIP-Auth-Data-Item AVP). The Diameter client MUST insert a + SIP-Number-Auth-Items AVP with the value set to the number of + credentials enclosed. If necessary, the Digest-Entity-Body-Hash AVP + will contain a hash of the body, needed to perform the + authentication. If the authentication is successful, the Diameter + MAA message will contain a Result-Code AVP indicating success, and if + necessary, the Diameter server MAY include one or more + SIP-Auth-Data-Item AVPs to provide further authentication credentials + to the SIP server. If the authentication is unsuccessful due to + missing credentials, the Diameter MAA message will include a + SIP-Auth-Data-Item AVP with the SIP-Authentication-Scheme and + SIP-Authenticate AVPs containing data (typically a challenge of some + kind) that the user can use to authenticate itself. + + There are situations where a SIP request traverses several proxies, + and each of the proxies requests to authenticate the SIP UA. In this + situation, it is a valid scenario that a SIP request received at a + SIP server contains several sets of credentials. The 'realm' + directive in HTTP is the key that the Diameter client can use to + determine which credential is applicable. Also, none of the realms + may be of interest to the Diameter client, in which case the Diameter + client MUST consider that no credentials (of interest) were sent. In + any case, a Diameter client MUST send zero or exactly one credential + to the Diameter server. The Diameter client MUST choose the + credential based on the 'realm' directive in the + Authorization/Proxy-Authorization header field, and it MUST match the + realm of the Diameter client. + + It must be noted that nonces are always generated in the Diameter + server. + + + +Garcia-Martin, et al. Standards Track [Page 62] + +RFC 4740 Diameter SIP Application November 2006 + + +12. Migration from RADIUS + + RADIUS offers support for HTTP Digest authentication in the RADIUS + Extension for Digest Authentication [RFC4590]. A number of AVPs (the + Digest-* AVPs) of this Diameter SIP application are imported from the + RADIUS attributes namespace, thus making the migration from RADIUS to + Diameter smooth. + + Note that the RADIUS Extension for Digest Authentication [RFC4590] + provides a more limited scope than this Diameter SIP application. + Specifically, the RADIUS extension for Digest Authentication merely + provides support for HTTP Digest authentication, whereas the Diameter + SIP application provides support for user location, profile + downloading and update, etc. + + The following sections discuss several configurations in which a + gateway translates RADIUS to Diameter and vice versa. + +12.1. Gateway from RADIUS Client to Diameter Server + + The gateway maps Access-Request messages to MAR request. If a RADIUS + Access-Request message contains at least one Digest-* attribute, the + gateway maps all Digest-* attributes to the AVPs of a Diameter + SIP-Authorization AVP, constructs a MAR message, and sends it to the + Diameter server. If the RADIUS Access-Request message does not + contain any Digest-* attribute, then the RADIUS client does not want + to apply HTTP Digest authentication, in which case, actions at the + gateway are outside the scope of this document. + + The Diameter server responds with a MAA message. If the MAA message + contains a Result-Code AVP set to the value DIAMETER_MULTI_ROUND_AUTH + and contains challenge parameters in a SIP-Authenticate AVP, then the + gateway translates the AVPs of SIP-Authenticate AVP and puts the + resulting RADIUS attributes into an Access-Challenge message. It + sends the Access-Challenge message to the RADIUS client. + + If the MAA message contains a SIP-Authentication-Info and a + Digest-Response AVP, the gateway converts these AVPs to the + corresponding RADIUS attributes and constructs a RADIUS message. If + the Result-Code AVP is DIAMETER_SUCCESS, an Access-Accept is sent. + In all other cases, an Access-Reject is sent. + +12.2. Gateway from Diameter Client to RADIUS Server + + The Diameter client sends a Diameter MAR message to the gateway. If + the MAR message does not contain SIP-Auth-Data-Item AVPs, the gateway + constructs an Access-Request message and maps the SIP-AOR and + SIP-Method AVPs to RADIUS attributes. The gateway sends the + + + +Garcia-Martin, et al. Standards Track [Page 63] + +RFC 4740 Diameter SIP Application November 2006 + + + Access-Request message to the RADIUS server, which will respond with + an Access-Challenge. The gateway creates a MAA message with a + Result-Code AVP set to DIAMETER_MULTI_ROUND_AUTH and maps the + Digest-* attributes to Diameter AVPs in a SIP-Authenticate AVP. The + gateway sends the resulting MAA to the Diameter client, which will + respond with a new MAR. + + The gateway checks the SIP-Auth-Data-Item AVPs of this MAR for an AVP + where the Digest-Realm AVP matches the locally configured realm + value. It takes the AVPs from this SIP-Auth-Data-Item AVP, converts + them into the corresponding RADIUS attributes and constructs a RADIUS + Access-Request message. The gateway sends the Access-Request message + to the RADIUS server. If the RADIUS server responds with an + Access-Accept message, the gateway converts the RADIUS attributes to + Diameter AVPs, constructs a MAA message with a Result-Code AVP set to + DIAMETER_SUCCESS and sends this message to the Diameter client. If + the RADIUS server responds with an Access-Reject message, the gateway + converts the RADIUS attributes to Diameter AVPs, constructs a MAA + message with a Result-Code AVP set to + DIAMETER_ERROR_IDENTITIES_DONT_MATCH, and sends this message to the + Diameter client. + +12.3. Known Limitations + + As mentioned earlier, there is not a 100% match between the Diameter + SIP application and the RADIUS Extension for Digest Authentication + [RFC4590]. In particular, the RADIUS Extension for Digest + Authentication [RFC4590] does not offer equivalent functionality to + the Diameter UAR/UAA, SAR/SAA, LIR/LIA, RTR/RTA, and PPR/PPA messages + defined by this specification. + +13. IANA Considerations + + This document serves as IANA registration request for a number of + items that should be registered in the AAA parameters registry. + +13.1. Application Identifier + + This document defines a standards-track Application-ID that falls + into the Application Identifier standards-track address space defined + by RFC 3588 [RFC3588] Section 11.3. This Application-ID has been + registered in the Application IDs sub-registry of the AAA parameters + registry with the following data: + + ID values Name Reference + ----------- ------------------------ --------- + 6 Diameter Session Initiation RFC 4740 + Protocol (SIP) Application + + + +Garcia-Martin, et al. Standards Track [Page 64] + +RFC 4740 Diameter SIP Application November 2006 + + +13.2. Command Codes + + This document defines new standard commands whose Command Codes are + to be allocated within the standard permanent Command Codes address + space defined in RFC 3588 [RFC3588] Section 11.2.1. These command + codes should be registered in the Command Codes sub-registry of the + AAA parameters registry. + + Table 1 in Section 8 contains the detailed list of Command Code names + and values that are part of this Diameter application. + +13.3. AVP Codes + + This document defines new standard AVPs, whose AVP Codes are to be + allocated within the AVP Codes address space defined in RFC 3588 + [RFC3588] Section 11.4. These AVP codes have been registered in the + AVP Codes sub-registry of the AAA parameters registry. + + Table 2 in Section 9 contains the detailed list of AVP names and AVP + codes that are part of this Diameter application. + +13.4. Additional Values for the Result-Code AVP Value + + This document defines new standard Result-Code AVP values to be + allocated within the Result-Code AVP address space defined in RFC + 3588 [RFC3588] Section 14.4.1. These values are listed in the + Result-Code AVP values section of the AVP Specific Values + sub-registry of the AAA parameters registry. + + Section 10.1.1 lists the new Result-Code AVP values that fall into + the success category, according to RFC 3588 [RFC3588] Section 7.1.2. + + Section 10.1.2 lists the new Result-Code AVP values that fall into + the transient failures category, according to RFC 3588 [RFC3588] + Section 7.1.4. + + Section 10.1.3 lists the new Result-Code AVP values that fall into + the permanent failures category, according to RFC 3588 [RFC3588] + Section 7.1.5. + + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 65] + +RFC 4740 Diameter SIP Application November 2006 + + +13.5. Creation of the SIP-Server-Assignment-Type Section in the AAA + Registry + + This document defines a new SIP-Server-Assignment-Type AVP (see + Section 9.4). This AVP is of type Enumerated. We define an initial + set of values that should be registered by IANA. IANA should create + a new "SIP-Sever-Assignment-Type AVP values" section under the AVP + Specific Values sub-registry of the AAA parameters registry. The + initial list of values is listed in Section 9.4. + +13.6. Creation of the SIP-Authentication-Scheme Section in the AAA + Registry + + This document defines a new SIP-Authentication-Scheme AVP (see + Section 9.5.1). This AVP is of type Enumerated. We currently define + a single value that should be registered by IANA. IANA should create + a new "SIP-Authentication-Scheme AVP values" section under the AVP + Specific Values sub-registry of the AAA parameters registry. The + initial list of values is included in Section 9.5.1. + +13.7. Creation of the SIP-Reason-Code Section in the AAA Registry + + This document defines a new SIP-Reason-Code AVP (see Section 9.7.1). + This AVP is of type Enumerated. We define an initial set of values + that should be registered by IANA. IANA should create a new + "SIP-Reason-Code AVP values" section under the AVP Specific Values + sub-registry of the AAA parameters registry. The initial list of + values is listed in Section 9.7.1. + +13.8. Creation of the SIP-User-Authorization-Type Section in the AAA + Registry + + This document defines a new SIP-User-Authorization-Type AVP (see + Section 9.10). This AVP is of type Enumerated. We define an initial + set of values that should be registered by IANA. IANA should create + a new "SIP-User-Authorization-Type AVP values" section under the AVP + Specific Values sub-registry of the AAA parameters registry. The + initial list of values is listed in Section 9.10. + +13.9. Creation of the SIP-User-Data-Already-Available Section in the + AAA Registry + + This document defines a new SIP-User-Data-Already-Available AVP (see + Section 9.13). This AVP is of type Enumerated. We define an initial + set of values which should be registered by IANA. IANA should create + a new "SIP-User-Data-Already-Available AVP values" section under the + AVP Specific Values sub-registry of the AAA parameters registry. The + initial list of values is listed in Section 9.13. + + + +Garcia-Martin, et al. Standards Track [Page 66] + +RFC 4740 Diameter SIP Application November 2006 + + +14. Security Considerations + + This memo does not describe a stand-alone protocol, but a particular + application for the Diameter protocol [RFC3588]. Consequently, all + the security considerations applicable to Diameter automatically + apply to this memo. In particular, Section 13 of RFC 3588 applies to + this memo. + + This Diameter SIP application allows a Diameter client to use the + properties of HTTP Digest authentication [RFC2617] by evaluating or + sending to the Diameter server the credentials supplied by a user. + The discussion of HTTP Digest authentication in Section 4 of RFC 2617 + [RFC2617] is also applicable to this memo. + + This Diameter SIP application also allows a Diameter client to use + the properties of HTTP Digest authentication using AKA [RFC3310] by + evaluating or sending to the Diameter server the credentials supplied + by a user. Section 5 of RFC 3310 [RFC3310] is also applicable to + this memo. + +14.1. Final Authentication Check in the Diameter Client/SIP Server + + The Diameter SIP application can be configured to operate in a + scenario where the final authentication check is performed in the + Diameter client (SIP server). There are a number of security + considerations associated to it; all of them are consequences of the + requirement to transfer H(A1) from the Diameter server to the + Diameter client: + + o Both Diameter client and server must trust each other, such as + when both client and server belong to the same administrative + domain. + + o To avoid eavesdroppers, the transport protocol between the + Diameter client and server MUST be secured. RFC 3588 [RFC3588] + specifies TLS [RFC4346] and IPsec as possible transport protection + mechanisms for Diameter. + + Due to these security considerations, it is RECOMMENDED to configure + the Diameter SIP application to operate in the mode where the final + authentication check is performed in the Diameter server. + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 67] + +RFC 4740 Diameter SIP Application November 2006 + + +15. Contributors + + The authors would like to thank the following contributors who made + substantial contributions to this work: + + Pete McCann Lucent + + Jaakko Rajaniemi Nokia + + Wolfgang Beck (Deutsche Telekom AG) provided the text in Section 12, + "Migration from RADIUS". + +16. Acknowledgements + + The authors would like to thank Tony Johansson and Kevin Purser for + their invaluable contribution to the start-up of this application and + the continuous progress. The authors would like to thank Daniel + Warren, Jayshree Bharatia, Kuntal Chowdhury, Jari Arkko, Avi Lior, + Wolfgang Beck, Ulrich Wiehe, Cullen Jennings, Anu Leinonen, Glen + Zorn, German Blanco, Mikko Aittola, Bert Wijnen, and Sam Hartman for + their reviews and valuable comments. + + The Diameter SIP application is based on the Diameter application for + the Cx interface of the 3GPP IP Multimedia Subsystem [3GPP.29.229]. + The authors would like to thank 3GPP Working Group CN4 for this work. + +17. References + +17.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, + S., Leach, P., Luotonen, A., and L. Stewart, "HTTP + Authentication: Basic and Digest Access + Authentication", RFC 2617, June 1999. + + [RFC3261] Rosenberg, J., Schulzrinne, H., Camarillo, G., + Johnston, A., Peterson, J., Sparks, R., Handley, M., + and E. Schooler, "SIP: Session Initiation Protocol", + RFC 3261, June 2002. + + [RFC3310] Niemi, A., Arkko, J., and V. Torvinen, "Hypertext + Transfer Protocol (HTTP) Digest Authentication Using + Authentication and Key Agreement (AKA)", RFC 3310, + September 2002. + + + + +Garcia-Martin, et al. Standards Track [Page 68] + +RFC 4740 Diameter SIP Application November 2006 + + + [RFC3588] Calhoun, P., Loughney, J., Guttman, E., Zorn, G., and + J. Arkko, "Diameter Base Protocol", RFC 3588, + September 2003. + + [RFC4590] Sterman, B., Sadolevsky, D., Schwartz, D., Williams, + D., and W. Beck, "RADIUS Extension for Digest + Authentication", RFC 4590, July 2006. + +17.2. Informative References + + [RFC4346] Dierks, T. and E. Rescorla, "The Transport Layer + Security (TLS) Protocol Version 1.1", RFC 4346, April + 2006. + + [RFC3263] Rosenberg, J. and H. Schulzrinne, "Session Initiation + Protocol (SIP): Locating SIP Servers", RFC 3263, + June 2002. + + [RFC3680] Rosenberg, J., "A Session Initiation Protocol (SIP) + Event Package for Registrations", RFC 3680, + March 2004. + + [RFC3880] Lennox, J., Wu, X., and H. Schulzrinne, "Call + Processing Language (CPL): A Language for User Control + of Internet Telephony Services", RFC 3880, + October 2004. + + [RFC4004] Calhoun, P., Johansson, T., Perkins, C., Hiller, T., + and P. McCann, "Diameter Mobile IPv4 Application", + RFC 4004, August 2005. + + [RFC4005] Calhoun, P., Zorn, G., Spence, D., and D. Mitton, + "Diameter Network Access Server Application", + RFC 4005, August 2005. + + [RFC4006] Hakala, H., Mattila, L., Koskinen, J-P., Stura, M., + and J. Loughney, "Diameter Credit-Control + Application", RFC 4006, August 2005. + + [3GPP.29.229] 3GPP, "Cx and Dx interfaces based on the Diameter + protocol; Protocol details", 3GPP TS 29.229 5.12.0, + June 2006. + + [JSR-000116] Java Community Process, "SIP Servlet API Specification + 1.0 Final Release", JSR 000116, March 2003. + + + + + + +Garcia-Martin, et al. Standards Track [Page 69] + +RFC 4740 Diameter SIP Application November 2006 + + +Authors' Addresses + + Miguel A. Garcia-Martin (Editor) + Nokia + P.O. Box 407 + NOKIA GROUP, FIN 00045 + Finland + + Phone: +358 50 480 4586 + EMail: [email protected] + + + Maria-Carmen Belinchon + Ericsson + Via de los Poblados 13 + Madrid 28033 + Spain + + Phone: +34 91 339 3535 + EMail: [email protected] + + + Miguel A. Pallares-Lopez + Ericsson + Via de los Poblados 13 + Madrid 28033 + Spain + + Phone: +34 91 339 4222 + EMail: [email protected] + + + Carolina Canales-Valenzuela + Ericsson + Via de los Poblados 13 + Madrid 28033 + Spain + + Phone: +34 91 339 2680 + EMail: [email protected] + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 70] + +RFC 4740 Diameter SIP Application November 2006 + + + Kalle Tammi + Nokia + P.O.Box 785 + Tampere 33101 + Finland + + Phone: +358 40 505 8670 + EMail: [email protected] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Garcia-Martin, et al. Standards Track [Page 71] + +RFC 4740 Diameter SIP Application November 2006 + + +Full Copyright Statement + + Copyright (C) The IETF Trust (2006). + + This document is subject to the rights, licenses and restrictions + contained in BCP 78, and except as set forth therein, the authors + retain all their rights. + + This document and the information contained herein are provided on an + "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS + OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY, THE IETF TRUST, + AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT + THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY + IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR + PURPOSE. + +Intellectual Property + + The IETF takes no position regarding the validity or scope of any + Intellectual Property Rights or other rights that might be claimed to + pertain to the implementation or use of the technology described in + this document or the extent to which any license under such rights + might or might not be available; nor does it represent that it has + made any independent effort to identify any such rights. Information + on the procedures with respect to rights in RFC documents can be + found in BCP 78 and BCP 79. + + Copies of IPR disclosures made to the IETF Secretariat and any + assurances of licenses to be made available, or the result of an + attempt made to obtain a general license or permission for the use of + such proprietary rights by implementers or users of this + specification can be obtained from the IETF on-line IPR repository at + http://www.ietf.org/ipr. + + The IETF invites any interested party to bring to its attention any + copyrights, patents or patent applications, or other proprietary + rights that may cover technology that may be required to implement + this standard. Please address the information to the IETF at + +Acknowledgement + + Funding for the RFC Editor function is currently provided by the + Internet Society. + + + + + + +Garcia-Martin, et al. Standards Track [Page 72] + diff --git a/lib/diameter/doc/standard/rfc5447.txt b/lib/diameter/doc/standard/rfc5447.txt new file mode 100644 index 0000000000..ec556ccc9f --- /dev/null +++ b/lib/diameter/doc/standard/rfc5447.txt @@ -0,0 +1,955 @@ + + + + + + +Network Working Group J. Korhonen, Ed. +Request for Comments: 5447 Nokia Siemens Networks +Category: Standards Track J. Bournelle + Orange Labs + H. Tschofenig + Nokia Siemens Networks + C. Perkins + WiChorus + K. Chowdhury + Starent Networks + February 2009 + + + Diameter Mobile IPv6: + Support for Network Access Server to Diameter Server Interaction + +Status of This Memo + + This document specifies an Internet standards track protocol for the + Internet community, and requests discussion and suggestions for + improvements. Please refer to the current edition of the "Internet + Official Protocol Standards" (STD 1) for the standardization state + and status of this protocol. Distribution of this memo is unlimited. + +Copyright Notice + + Copyright (c) 2009 IETF Trust and the persons identified as the + document authors. All rights reserved. + + This document is subject to BCP 78 and the IETF Trust's Legal + Provisions Relating to IETF Documents (http://trustee.ietf.org/ + license-info) in effect on the date of publication of this document. + Please review these documents carefully, as they describe your rights + and restrictions with respect to this document. + +Abstract + + A Mobile IPv6 node requires a home agent address, a home address, and + a security association with its home agent before it can start + utilizing Mobile IPv6. RFC 3775 requires that some or all of these + parameters be statically configured. Mobile IPv6 bootstrapping work + aims to make this information dynamically available to the mobile + node. An important aspect of the Mobile IPv6 bootstrapping solution + is to support interworking with existing Authentication, + Authorization, and Accounting (AAA) infrastructures. This document + describes MIPv6 bootstrapping using the Diameter Network Access + Server to home AAA server interface. + + + + +Korhonen, et al. Standards Track [Page 1] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + +Table of Contents + + 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 3 + 2. Terminology and Abbreviations . . . . . . . . . . . . . . . . 3 + 3. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 + 4. Commands, Attribute-Value Pairs, and Advertising + Application Support . . . . . . . . . . . . . . . . . . . . . 6 + 4.1. Advertising Application Support . . . . . . . . . . . . . 6 + 4.2. Attribute-Value Pair Definitions . . . . . . . . . . . . . 6 + 4.2.1. MIP6-Agent-Info AVP . . . . . . . . . . . . . . . . . 6 + 4.2.2. MIP-Home-Agent-Address AVP . . . . . . . . . . . . . . 7 + 4.2.3. MIP-Home-Agent-Host AVP . . . . . . . . . . . . . . . 7 + 4.2.4. MIP6-Home-Link-Prefix AVP . . . . . . . . . . . . . . 8 + 4.2.5. MIP6-Feature-Vector AVP . . . . . . . . . . . . . . . 8 + 5. Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 + 5.1. Home Agent Assignment by the NAS . . . . . . . . . . . . . 10 + 5.2. Home Agent Assignment by the Diameter Server . . . . . . . 11 + 5.3. Home Agent Assignment by the NAS or Diameter Server . . . 11 + 6. Attribute-Value Pair Occurrence Tables . . . . . . . . . . . . 12 + 7. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 13 + 7.1. Registration of New AVPs . . . . . . . . . . . . . . . . . 13 + 7.2. New Registry: Mobility Capability . . . . . . . . . . . . 13 + 8. Security Considerations . . . . . . . . . . . . . . . . . . . 14 + 9. Acknowledgments . . . . . . . . . . . . . . . . . . . . . . . 14 + 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 15 + 10.1. Normative References . . . . . . . . . . . . . . . . . . . 15 + 10.2. Informative References . . . . . . . . . . . . . . . . . . 15 + + + + + + + + + + + + + + + + + + + + + + + + +Korhonen, et al. Standards Track [Page 2] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + +1. Introduction + + The Mobile IPv6 (MIPv6) specification [RFC3775] requires a mobile + node (MN) to perform registration with a home agent (HA) with + information about its current point of attachment (care-of address). + The HA creates and maintains the binding between the MN's home + address and the MN's care-of address. + + In order to register with an HA, the MN needs to know some + information, such as the home link prefix, the HA address, the home + address(es), the home link prefix length, and security-association- + related information. + + The aforementioned information may be statically configured. + However, static provisioning becomes an administrative burden for an + operator. Moreover, it does not address load balancing, failover, + opportunistic home link assignment, or assignment of local HAs in + close proximity to the MN. Also, the ability to react to sudden + environmental or topological changes is minimal. Static provisioning + may not be desirable, in light of these limitations. + + Dynamic assignment of MIPv6 home registration information is a + desirable feature for ease of deployment and network maintenance. + For this purpose, the AAA infrastructure, which is used for access + authentication, can be leveraged to assign some or all of the + necessary parameters. The Diameter server in the Access Service + Provider's (ASP's) or Mobility Service Provider's (MSP's) network may + return these parameters to the AAA client. Regarding the + bootstrapping procedures, the AAA client might either be the Network + Access Server, in case of the integrated scenario, or the HA, in case + of the split scenario [RFC5026]. The terms "integrated" and "split" + are described in the following terminology section and were + introduced in [RFC4640] and [AAA]. + +2. Terminology and Abbreviations + + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", + "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this + document are to be interpreted as described in RFC 2119 [RFC2119]. + + General mobility terminology can be found in [RFC3753]. The + following additional terms are either borrowed from [RFC4640] or + [RFC5026] or are introduced in this document: + + Access Service Authorizer (ASA): + + A network operator that authenticates an MN and establishes the + MN's authorization to receive Internet service. + + + +Korhonen, et al. Standards Track [Page 3] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + + Access Service Provider (ASP): + + A network operator that provides direct IP packet-forwarding to + and from the MN. + + Mobility Service Authorizer (MSA): + + A service provider that authorizes MIPv6 service. + + Mobility Service Provider (MSP): + + A service provider that provides MIPv6 service. In order to + obtain such service, the MN must be authenticated and authorized + to do so. + + Split Scenario: + + A scenario where the mobility service and the network access + service are authorized by different entities. + + Integrated Scenario: + + A scenario where the mobility service and the network access + service are authorized by the same entity. + + Network Access Server (NAS): + + A device that provides an access service for a user to a network. + + Home AAA (HAAA): + + An Authentication, Authorization, and Accounting server located in + the user's home network, i.e., in the home realm. + + Local AAA (LAAA): + + An Authentication, Authorization, and Accounting proxy located in + the local (ASP) network. + + Visited AAA (VAAA): + + An Authentication, Authorization, and Accounting proxy located in + a visited network, i.e., in the visited realm. In a roaming case, + the local Diameter proxy has the VAAA role (see Figure 1). + + + + + + + +Korhonen, et al. Standards Track [Page 4] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + +3. Overview + + This document addresses the Authentication, Authorization, and + Accounting (AAA) functionality required for the MIPv6 bootstrapping + solutions outlined in [RFC4640], and focuses on the Diameter-based + AAA functionality for the NAS-to-HAAA (home AAA) server + communication. + + In the integrated scenario, MIPv6 bootstrapping is provided as part + of the network access authentication procedure. Figure 1 shows the + participating entities. + + +---------------------------+ +-----------------+ + |Access Service Provider | |ASA/MSA/(MSP) | + |(Mobility Service Provider)| | | + | | | | + | +--------+ | | +--------+ | + | |Local | Diameter | | |Home | | + | |Diameter|<---------------------->|Diameter| | + | |Proxy | (*) | | |Server | | + | +--------+ | | +--------+ | + | ^ ^ | | ^ | + | | | | | |(+) | + | | | | | | | + | Diameter | | v | + | | |(+) +-------+ | | +-------+ | + | | | |Home | | | |Home | | + | | +-------->|Agent | | | |Agent | | + | (*)| |in ASP | | | |in MSP | | + | v +-------+ | | +-------+ | + +-------+ IEEE | +-----------+ +-------+ | +-----------------+ + |Mobile | 802.1X | |NAS/Relay | |DHCPv6 | | + |Node |------------|Diameter |---|Server | | + | | PANA, | |Client |(+)| | | + +-------+ IKEv2, | +-----------+ +-------+ | + DHCP,... +---------------------------+ + (+) + + Legend: + (*): Functionality in scope of this specification. + (+): Extensions described in other documents. + + Figure 1: Mobile IPv6 Bootstrapping in the Integrated Scenario + + In a typical MIPv6 access scenario, an MN is attached to an ASP's + network. During the network attachment procedure, the MN interacts + with the NAS/Diameter client. Subsequently, the NAS/Diameter client + interacts with the Diameter server over the NAS-to-HAAA interface. + + + +Korhonen, et al. Standards Track [Page 5] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + + When the Diameter server performs the authentication and + authorization for network access, it also determines whether the user + is authorized for the MIPv6 service. Based on the MIPv6 service + authorization and the user's policy profile, the Diameter server may + return several MIPv6 bootstrapping-related parameters to the NAS. + The NAS-to-HAAA interface described in this document is not tied to + the Dynamic Host Configuration Protocol for IPv6 (DHCPv6) as the only + mechanism to convey MIPv6-related configuration parameters from the + NAS/Diameter client to the mobile node. + + While this specification addresses the bootstrapping of MIPv6 HA + information and possibly the assignment of the home link prefix, it + does not address how the Security Association (SA) between the MN and + the HA for MIPv6 purposes is created. The creation or the use of the + SA between the MN and the HA takes places after the procedures + described in this specification, and therefore are out of scope. + +4. Commands, Attribute-Value Pairs, and Advertising Application Support + +4.1. Advertising Application Support + + This document does not define a new application. On the other hand, + it defines a number of attribute-value pairs (AVPs) used in the + interface between NAS to HAAA for the integrated scenario of MIPv6 + bootstrapping. These AVPs can be used with any present and future + Diameter applications, where permitted by the command ABNF. The + examples using existing applications and their commands in the + following sections are for informational purposes only. The examples + in this document reuse the Extensible Authentication Protocol (EAP) + [RFC4072] application and its respective commands. + +4.2. Attribute-Value Pair Definitions + +4.2.1. MIP6-Agent-Info AVP + + The MIP6-Agent-Info AVP (AVP code 486) is of type Grouped and + contains necessary information to assign an HA to the MN. When the + MIP6-Agent-Info AVP is present in a message, it MUST contain either + the MIP-Home-Agent-Address AVP, the MIP-Home-Agent-Host AVP, or both + AVPs. The grouped AVP has the following modified ABNF (as defined in + [RFC3588]): + + MIP6-Agent-Info ::= < AVP-Header: 486 > + *2[ MIP-Home-Agent-Address ] + [ MIP-Home-Agent-Host ] + [ MIP6-Home-Link-Prefix ] + * [ AVP ] + + + + +Korhonen, et al. Standards Track [Page 6] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + + If both the MIP-Home-Agent-Address and MIP-Home-Agent-Host APVs are + present in the MIP6-Agent-Info, the MIP-Home-Agent-Address SHOULD + have a precedence over the MIP-Home-Agent-Host. The reason for this + recommendation is that the MIP-Home-Agent-Address points to a + specific home agent, whereas the MIP-Home-Agent-Host may point to a + group of HAs located within the same realm. A Diameter client or + agent may use the MIP-Home-Agent-Host AVP, for instance, to find out + in which realm the HA is located. + + The ABNF allows returning up to two MIPv6 HA addresses. This is a + useful feature for deployments where the HA has both IPv6 and IPv4 + addresses, and particularly addresses Dual Stack Mobile IPv6 + (DSMIPv6) deployment scenarios [DSMIPv6]. + + The MIP6-Agent-Info AVP MAY also be attached by the NAS or by the + intermediating Diameter proxies in a request message when sent to the + Diameter server as a hint of a locally assigned HA. This AVP MAY + also be attached by the intermediating Diameter proxies in a reply + message from the Diameter server, if locally assigned HAs are + authorized by the Diameter server. There MAY be multiple instances + of the MIP6-Agent-Info AVP in Diameter messages, for example, in + cases where the NAS receives HA information from an MN's home network + and locally allocated HA information from the visited network. See + Section 4.2.5 for further discussion on possible scenarios. + +4.2.2. MIP-Home-Agent-Address AVP + + The MIP-Home-Agent-Address AVP (AVP Code 334 [RFC4004]) is of type + Address and contains the IPv6 or IPv4 address of the MIPv6 HA. The + Diameter server MAY decide to assign an HA to the MN that is in close + proximity to the point of attachment (e.g., determined by the NAS- + Identifier AVP). There may be other reasons for dynamically + assigning HAs to the MN, for example, to share the traffic load. + +4.2.3. MIP-Home-Agent-Host AVP + + The MIP-Home-Agent-Host AVP (AVP Code 348 [RFC4004]) is of type + Grouped and contains the identity of the assigned MIPv6 HA. Both the + Destination-Realm and the Destination-Host AVPs of the HA are + included in the grouped AVP. The usage of the MIP-Home-Agent-Host + AVP is equivalent to the MIP-Home-Agent-Address AVP but offers an + additional level of indirection by using the DNS infrastructure. The + Destination-Host AVP is used to identify an HA, and the Destination- + Realm AVP is used to identify the realm where the HA is located. + + Depending on the actual deployment and DNS configuration, the + Destination-Host AVP MAY represent one or more home agents. It is + RECOMMENDED that the Destination-Host AVP identifies exactly one HA. + + + +Korhonen, et al. Standards Track [Page 7] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + + It is RECOMMENDED that the MIP-Home-Agent-Host AVP is always included + in the MIP6-Agent-Info AVP. In this way, the HA can be associated + with the corresponding realm of the Diameter entity that added the + MIP6-Agent-Info AVP using the Destination-Realm AVP, which is + included in the MIP-Home-Agent-Host AVP. + +4.2.4. MIP6-Home-Link-Prefix AVP + + The MIP6-Home-Link-Prefix AVP (AVP Code 125) is of type OctetString + and contains the Mobile IPv6 home network prefix information in a + network byte order. The home network prefix MUST be encoded as the + 8-bit prefix length information (one octet) followed by the 128-bit + field (16 octets) for the available home network prefix. The + trailing bits of the IPv6 prefix after the prefix length bits MUST be + set to zero (e.g., if the prefix length is 60, then the remaining 68 + bits MUST be set to zero). + + The HAAA MAY act as a central entity managing prefixes for MNs. In + this case, the HAAA returns to the NAS the prefix allocated to the + MN. The NAS/ASP then delivers the home link prefix to the MN using, + e.g., mechanisms described in [INTEGRATED]. The NAS/ASP MAY propose + to the HAAA a specific prefix to allocate to the MN by including the + MIP6-Home-Link-Prefix AVP in the request message. However, the HAAA + MAY override the prefix allocation hint proposed by the NAS/ASP and + return a different prefix in the response message. + +4.2.5. MIP6-Feature-Vector AVP + + The MIP6-Feature-Vector AVP (AVP Code 124) is of type Unsigned64 and + contains a 64-bit flags field of supported capabilities of the NAS/ + ASP. Sending and receiving the MIP6-Feature-Vector AVP with value 0 + MUST be supported, although that does not provide much guidance about + specific needs of bootstrapping. + + The NAS MAY include this AVP to indicate capabilities of the NAS/ASP + to the Diameter server. For example, the NAS may indicate that a + local HA can be provided. Similarly, the Diameter server MAY include + this AVP to inform the NAS/ASP about which of the NAS/ASP indicated + capabilities are supported or authorized by the ASA/MSA(/MSP). + + The following capabilities are defined in this document: + + + + + + + + + + +Korhonen, et al. Standards Track [Page 8] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + + MIP6_INTEGRATED (0x0000000000000001) + + When this flag is set by the NAS, it means that the Mobile IPv6 + integrated scenario bootstrapping functionality is supported by + the NAS. When this flag is set by the Diameter server, then the + Mobile IPv6 integrated scenario bootstrapping is supported by the + Diameter server. + + LOCAL_HOME_AGENT_ASSIGNMENT (0x0000000000000002) + + When this flag is set in the request message, a local home agent + outside the home realm is requested and may be assigned to the MN. + When this flag is set by the Diameter server in the answer + message, then the assignment of local HAs is authorized by the + Diameter server. + + A local HA may be assigned by the NAS, LAAA, or VAAA depending on + the network architecture and the deployment. + + The following examples show how the LOCAL_HOME_AGENT_ASSIGNMENT + (referred to as LOCAL-bit in the examples) capability and the MIP- + Agent-Info AVP (referred to as HA-Info in the examples) are used to + assign HAs -- either a local HA (L-HA) or a home network HA (H-HA). + Below are examples of request message combinations as seen by the + HAAA: + + LOCAL-bit HA-Info Meaning + + 0 - ASP or [LV]AAA is not able to assign an L-HA. + 0 L-HA Same as above. HA-Info must be ignored. + 1 - ASP or [LV]AAA can/wishes to assign an L-HA. + 1 L-HA Same as above but the ASP or [LV]AAA also + provides a hint of the assigned L-HA. + + The same as above but for answer message combinations as seen by the + NAS: + + LOCAL-bit HA-Info Meaning + + 0 - No HA assignment allowed for HAAA or [LV]AAA. + 0 H-HA L-HA is not allowed. HAAA assigns an H-HA. + 1 - L-HA is allowed. No HAAA- or [LV]AAA-assigned HA. + 1 L-HA L-HA is allowed. [LV]AAA also assigns an L-HA. + 1 H-HA L-HA is allowed. HAAA also assigns an HA. + 1 H-HA L-HA is allowed. HAAA assigns an H-HA and + + L-HA [LV]AAA also assigns an L-HA. + + An NAS should expect to receive multiple MIP6-Agent-Info AVPs. + + + +Korhonen, et al. Standards Track [Page 9] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + +5. Examples + +5.1. Home Agent Assignment by the NAS + + In this scenario, we consider the case where the NAS wishes to + allocate a local HA to the MN. The NAS will also inform the Diameter + server about the HA address it has assigned to the visiting MN (e.g., + 2001:db8:1:c020::1). The Diameter-EAP-Request message, therefore, + has the MIP6-Feature-Vector with the LOCAL_HOME_AGENT_ASSIGNMENT and + the MIP6_INTEGRATED set. The MIP6-Agent-Info AVP contains the MIP- + Home-Agent-Address AVP with the address of the proposed HA. + + Diameter + NAS/VAAA Server + | | + | Diameter-EAP-Request | + | MIP6-Feature-Vector=(LOCAL_HOME_AGENT_ASSIGNMENT | + | | MIP6_INTEGRATED) | + | MIP6-Agent-Info{ | + | MIP-Home-Agent-Address(2001:db8:1:c020::1)} | + | } | + | Auth-Request-Type=AUTHORIZE_AUTHENTICATE | + | EAP-Payload(EAP Start) | + |---------------------------------------------------------------->| + | | + | | + : ...more EAP Request/Response pairs... : + | | + | | + | Diameter-EAP-Answer | + | MIP6-Feature-Vector=(LOCAL_HOME_AGENT_ASSIGNMENT | + | | MIP6_INTEGRATED) | + | Result-Code=DIAMETER_SUCCESS | + | EAP-Payload(EAP Success) | + | EAP-Master-Session-Key | + | (authorization AVPs) | + | ... | + |<----------------------------------------------------------------| + | | + + Figure 2: Home Agent Assignment by the NAS + + Depending on the Diameter server's configuration and the user's + subscription profile, the Diameter server either accepts or rejects + the local HA allocated by the NAS. In our example, the Diameter + server accepts the proposal, and the MIP6-Feature-Vector AVP with + LOCAL_HOME_AGENT_ASSIGNMENT flag (together with the MIP6_INTEGRATED + flag) is set and returned to the NAS. + + + +Korhonen, et al. Standards Track [Page 10] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + +5.2. Home Agent Assignment by the Diameter Server + + In this scenario, we consider the case where the NAS supports the + Diameter MIPv6 integrated scenario as defined in this document, but + does not offer local HA assignment. Hence, the MIP6-Feature-Vector + AVP only has the MIP6_INTEGRATED flag set. The Diameter server + allocates an HA to the mobile node and conveys the address in the + MIP-Home-Agent-Address AVP that is encapsulated in the MIP6-Agent- + Info AVP. Additionally, the MIP6-Feature-Vector AVP has the + MIP6_INTEGRATED flag set. + + Diameter + NAS Server + | | + | Diameter-EAP-Request | + | MIP6-Feature-Vector=(MIP6_INTEGRATED) | + | Auth-Request-Type=AUTHORIZE_AUTHENTICATE | + | EAP-Payload(EAP Start) | + |---------------------------------------------------------------->| + | | + | | + : ...more EAP Request/Response pairs... : + | | + | | + | Diameter-EAP-Answer | + | MIP6-Agent-Info{ | + | MIP-Home-Agent-Address(2001:db8:6000:302::1) | + | } | + | MIP6-Feature-Vector=(MIP6_INTEGRATED) | + | Result-Code=DIAMETER_SUCCESS | + | EAP-Payload(EAP Success) | + | EAP-Master-Session-Key | + | (authorization AVPs) | + | ... | + |<----------------------------------------------------------------| + | | + + Figure 3: Home Agent Assignment by the Diameter Server + +5.3. Home Agent Assignment by the NAS or Diameter Server + + This section shows another message flow for the MIPv6 integrated + scenario bootstrapping where the NAS informs the Diameter server that + it is able to locally assign an HA to the MN. The Diameter server is + able to provide an HA to the MN but also authorizes the assignment of + the local HA. The Diameter server then replies to the NAS with + HA-related bootstrapping information. + + + + +Korhonen, et al. Standards Track [Page 11] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + + Whether the NAS/ASP then offers a locally assigned HA or the + Diameter-server-assigned HA to the MN is, in this example, based on + the local ASP policy. + + Diameter + NAS/VAAA Server + | | + | Diameter-EAP-Request | + | MIP6-Feature-Vector=(LOCAL_HOME_AGENT_ASSIGNMENT | + | | MIP6_INTEGRATED) | + | MIP6-Agent-Info{ | + | MIP-Home-Agent-Address(2001:db8:1:c020::1)} | + | } | + | Auth-Request-Type=AUTHORIZE_AUTHENTICATE | + | EAP-Payload(EAP Start) | + |---------------------------------------------------------------->| + | | + | | + : ...more EAP Request/Response pairs... : + | | + | | + | Diameter-EAP-Answer | + | MIP6-Agent-Info{ | + | MIP-Home-Agent-Address(2001:db8:6000:302::1)} | + | MIP6-Feature-Vector=(LOCAL_HOME_AGENT_ASSIGNMENT | + | | MIP6_INTEGRATED) | + | Result-Code=DIAMETER_SUCCESS | + | EAP-Payload(EAP Success) | + | EAP-Master-Session-Key | + | (authorization AVPs) | + | ... | + |<----------------------------------------------------------------| + | | + + Figure 4: Home Agent Assignment by the NAS or Diameter Server + + If the Diameter server does not allow the MN to use a locally + assigned HA, the Diameter server returns to the MN the MIP6-Feature- + Vector AVP with the LOCAL_HOME_AGENT_ASSIGNMENT bit unset and the HA + address it allocated. + +6. Attribute-Value Pair Occurrence Tables + + Figure 5 lists the MIPv6 bootstrapping NAS-to-HAAA interface AVPs + along with a specification determining how many of each new AVP may + be included in a Diameter command. They may be present in any + Diameter application request and answer commands, where permitted by + the command ABNF. + + + +Korhonen, et al. Standards Track [Page 12] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + + +-----------+ + | Command | + |-----+-----+ + Attribute Name | Req | Ans | + -------------------------------|-----+-----| + MIP6-Agent-Info | 0+ | 0+ | + MIP6-Feature-Vector | 0-1 | 0-1 | + +-----+-----+ + + Figure 5: Generic Request and Answer Commands AVP Table + +7. IANA Considerations + +7.1. Registration of New AVPs + + This specification defines the following AVPs that have been + allocated from a normal Diameter AVP Code space (values >= 256): + + MIP6-Agent-Info is set to 486 + + The following new AVPs are to be allocated from RADIUS Attribute Type + space [RFC2865] so that they are RADIUS backward-compatible (AVP Code + values between 0-255): + + MIP6-Feature-Vector is set to 124 + MIP6-Home-Link-Prefix is set to 125 + +7.2. New Registry: Mobility Capability + + IANA has created a new registry for the Mobility Capability as + described in Section 4.2.5. + + Token | Value | Description + ----------------------------------+---------------------+------------ + MIP6_INTEGRATED | 0x0000000000000001 | [RFC5447] + LOCAL_HOME_AGENT_ASSIGNMENT | 0x0000000000000002 | [RFC5447] + Available for Assignment via IANA | 2^x | + + Allocation rule: Only numeric values that are 2^x (power of two, + where x >= 2) are allowed, based on the allocation policy described + below. + + Following the example policies described in [RFC5226], new values for + the Mobility Capability Registry will be assigned based on the + "Specification Required" policy. No mechanism to mark entries as + "deprecated" is envisioned. + + + + + +Korhonen, et al. Standards Track [Page 13] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + +8. Security Considerations + + The security considerations for the Diameter interaction required to + accomplish the integrated scenario are described in [INTEGRATED]. + Additionally, the security considerations for the Diameter base + protocol [RFC3588], the Diameter NASREQ application [RFC4005], and + the Diameter EAP application (with respect to network access + authentication and the transport of keying material) [RFC4072] are + applicable to this document. Developers should insure that special + attention is paid to configuring the security associations protecting + the messages that enable the global positioning and allocation of + home agents, for instance, as outlined in Section 5. + + Furthermore, the Diameter messages may be transported between the NAS + and the Diameter server via one or more AAA brokers or Diameter + agents (such as proxies). In this case, the AAA communication from + the NAS to the Diameter server relies on the security properties of + the intermediate AAA brokers and Diameter agents. + +9. Acknowledgments + + This document is heavily based on the ongoing work for RADIUS MIPv6 + interaction. Hence, credits go to respective authors for their work + with "RADIUS Mobile IPv6 Support" (November 2008). Furthermore, the + authors of this document would like to thank the authors of "Diameter + Mobile IPv6 Application" (November 2004) -- Franck Le, Basavaraj + Patil, Charles E. Perkins, and Stefano Faccin -- for their work in + the context of MIPv6 Diameter interworking. Their work influenced + this document. Jouni Korhonen would like to thank the Academy of + Finland and TEKES MERCoNe Project for providing funding to work on + this document while he was with TeliaSonera. Julien Bournelle would + like to thank GET/INT since he began to work on this document while + he was in their employ. Authors would also like to acknowledge + Raymond Hsu for his valuable feedback on local HA assignment and + Wolfgang Fritsche for his thorough review. Additionally, we would + like to Domagoj Premec for his review comments. + + Finally, we would like to thank Alper Yegin, Robert Marks, and David + Frascone for their comments at the second WG Last Call. + + + + + + + + + + + + +Korhonen, et al. Standards Track [Page 14] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + +10. References + +10.1. Normative References + + [RFC2119] Bradner, S., "Key words for use in RFCs to Indicate + Requirement Levels", BCP 14, RFC 2119, March 1997. + + [RFC2865] Rigney, C., Willens, S., Rubens, A., and W. Simpson, + "Remote Authentication Dial In User Service (RADIUS)", + RFC 2865, June 2000. + + [RFC3588] Calhoun, P., Loughney, J., Guttman, E., Zorn, G., and + J. Arkko, "Diameter Base Protocol", RFC 3588, + September 2003. + + [RFC3775] Johnson, D., Perkins, C., and J. Arkko, "Mobility + Support in IPv6", RFC 3775, June 2004. + + [RFC4004] Calhoun, P., Johansson, T., Perkins, C., Hiller, T., + and P. McCann, "Diameter Mobile IPv4 Application", + RFC 4004, August 2005. + + [RFC4005] Calhoun, P., Zorn, G., Spence, D., and D. Mitton, + "Diameter Network Access Server Application", RFC 4005, + August 2005. + + [RFC4072] Eronen, P., Hiller, T., and G. Zorn, "Diameter + Extensible Authentication Protocol (EAP) Application", + RFC 4072, August 2005. + +10.2. Informative References + + [AAA] Giaretta, G., Guardini, I., Demaria, E., Bournelle, J., + and R. Lopez, "AAA Goals for Mobile IPv6", Work + in Progress, May 2008. + + [DSMIPv6] Solimand, H., "Mobile IPv6 Support for Dual Stack Hosts + and Routers (DSMIPv6)", Work in Progress, + December 2008. + + [INTEGRATED] Chowdhury, K. and A. Yegin, "MIP6-bootstrapping for the + Integrated Scenario", Work in Progress, April 2008. + + [RFC3753] Manner, J. and M. Kojo, "Mobility Related Terminology", + RFC 3753, June 2004. + + + + + + +Korhonen, et al. Standards Track [Page 15] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + + [RFC4640] Patel, A. and G. Giaretta, "Problem Statement for + bootstrapping Mobile IPv6 (MIPv6)", RFC 4640, + September 2006. + + [RFC5026] Giaretta, G., Kempf, J., and V. Devarapalli, "Mobile + IPv6 Bootstrapping in Split Scenario", RFC 5026, + October 2007. + + [RFC5226] Narten, T. and H. Alvestrand, "Guidelines for Writing + an IANA Considerations Section in RFCs", BCP 26, + RFC 5226, May 2008. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +Korhonen, et al. Standards Track [Page 16] + +RFC 5447 Diameter MIPv6 NAS-to-HAAA Interaction February 2009 + + +Authors' Addresses + + Jouni Korhonen (editor) + Nokia Siemens Networks + Linnoitustie 6 + Espoo FIN-02600 + Finland + + EMail: [email protected] + + + Julien Bournelle + Orange Labs + 38-4O rue du general Leclerc + Issy-Les-Moulineaux 92794 + France + + EMail: [email protected] + + + Hannes Tschofenig + Nokia Siemens Networks + Linnoitustie 6 + Espoo 02600 + Finland + + EMail: [email protected] + URI: http://www.tschofenig.priv.at + + + Charles E. Perkins + WiChorus Inc. + 3590 North First St., Suite 300 + San Jose, CA 95134 + US + + EMail: [email protected] + + + Kuntal Chowdhury + Starent Networks + 30 International Place + Tewksbury, MA 01876 + US + + EMail: [email protected] + + + + + +Korhonen, et al. Standards Track [Page 17] + diff --git a/lib/diameter/ebin/.gitignore b/lib/diameter/ebin/.gitignore new file mode 100644 index 0000000000..185bb606e3 --- /dev/null +++ b/lib/diameter/ebin/.gitignore @@ -0,0 +1,5 @@ + +*.app +*.appup +*.beam + diff --git a/lib/diameter/examples/.gitignore b/lib/diameter/examples/.gitignore new file mode 100644 index 0000000000..d7995d4e6b --- /dev/null +++ b/lib/diameter/examples/.gitignore @@ -0,0 +1,3 @@ + +*.beam + diff --git a/lib/diameter/examples/GNUmakefile b/lib/diameter/examples/GNUmakefile new file mode 100644 index 0000000000..4c3f87939b --- /dev/null +++ b/lib/diameter/examples/GNUmakefile @@ -0,0 +1,35 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +EXAMPLES = client server relay # redirect proxy + +CALLBACKS = $(EXAMPLES:%=%_cb) +MODULES = peer $(EXAMPLES) $(EXAMPLES:%=%_cb) + +BEAM = $(MODULES:%=%.beam) + +%.beam: %.erl + erlc -W $< + +all: $(BEAM) + +clean: + rm -f $(BEAM) + +.PHONY: all clean diff --git a/lib/diameter/examples/client.erl b/lib/diameter/examples/client.erl new file mode 100644 index 0000000000..36a77dd524 --- /dev/null +++ b/lib/diameter/examples/client.erl @@ -0,0 +1,125 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% An example Diameter client that can sends base protocol RAR +%% requests to a connected peer. +%% +%% The simplest usage is as follows this to connect to a server +%% listening on the default port on the local host, assuming diameter +%% is already started (eg. diameter:start()). +%% +%% client:start(). +%% client:connect(tcp). +%% client:call(). +%% +%% The first call starts the a service with the default name of +%% ?MODULE, the second defines a connecting transport that results in +%% a connection to the peer (if it's listening), the third sends it a +%% RAR and returns the answer. +%% + +-module(client). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/1, %% start a service + connect/2, %% add a connecting transport + call/1, %% send using the record encoding + cast/1, %% send using the list encoding and detached + stop/1]). %% stop a service +%% A real application would typically choose an encoding and whether +%% they want the call to return the answer or not. Sending with +%% both the record and list encoding here, one detached and one not, +%% is just for demonstration purposes. + +%% Convenience functions using the default service name, ?SVC_NAME. +-export([start/0, + connect/1, + stop/0, + call/0, + cast/0]). + +-define(SVC_NAME, ?MODULE). +-define(APP_ALIAS, ?MODULE). +-define(CALLBACK_MOD, client_cb). + +-define(L, atom_to_list). + +%% The service configuration. As in the server example, a client +%% supporting multiple Diameter applications may or may not want to +%% configure a common callback module on all applications. +-define(SERVICE(Name), [{'Origin-Host', ?L(Name) ++ ".example.com"}, + {'Origin-Realm', "example.com"}, + {'Vendor-Id', 0}, + {'Product-Name', "Client"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, ?DIAMETER_DICT_COMMON}, + {module, ?CALLBACK_MOD}]}]). + +%% start/1 + +start(Name) + when is_atom(Name) -> + peer:start(Name, ?SERVICE(Name)). + +start() -> + start(?SVC_NAME). + +%% connect/2 + +connect(Name, T) -> + peer:connect(Name, T). + +connect(T) -> + connect(?SVC_NAME, T). + +%% call/1 + +call(Name) -> + SId = diameter:session_id(?L(Name)), + RAR = #diameter_base_RAR{'Session-Id' = SId, + 'Auth-Application-Id' = 0, + 'Re-Auth-Request-Type' = 0}, + diameter:call(Name, ?APP_ALIAS, RAR, []). + +call() -> + call(?SVC_NAME). + +%% cast/1 + +cast(Name) -> + SId = diameter:session_id(?L(Name)), + RAR = ['RAR', {'Session-Id', SId}, + {'Auth-Application-Id', 0}, + {'Re-Auth-Request-Type', 1}], + diameter:call(Name, ?APP_ALIAS, RAR, [detach]). + +cast() -> + cast(?SVC_NAME). + +%% stop/1 + +stop(Name) -> + peer:stop(Name). + +stop() -> + stop(?SVC_NAME). diff --git a/lib/diameter/examples/client_cb.erl b/lib/diameter/examples/client_cb.erl new file mode 100644 index 0000000000..524a8f94a1 --- /dev/null +++ b/lib/diameter/examples/client_cb.erl @@ -0,0 +1,103 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(client_cb). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +%% peer_up/3 + +peer_up(_SvcName, _Peer, State) -> + State. + +%% peer_down/3 + +peer_down(_SvcName, _Peer, State) -> + State. + +%% pick_peer/4 + +pick_peer([Peer | _], _, _SvcName, _State) -> + {ok, Peer}. + +%% prepare_request/3 + +prepare_request(#diameter_packet{msg = ['RAR' = T | Avps]}, _, {_, Caps}) -> + #diameter_caps{origin_host = {OH, DH}, + origin_realm = {OR, DR}} + = Caps, + + {send, [T, {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Destination-Host', DH}, + {'Destination-Realm', DR} + | Avps]}; + +prepare_request(#diameter_packet{msg = Rec}, _, {_, Caps}) -> + #diameter_caps{origin_host = {OH, DH}, + origin_realm = {OR, DR}} + = Caps, + + {send, Rec#diameter_base_RAR{'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Destination-Host' = DH, + 'Destination-Realm' = DR}}. + +%% prepare_retransmit/3 + +prepare_retransmit(Packet, SvcName, Peer) -> + prepare_request(Packet, SvcName, Peer). + +%% handle_answer/4 + +%% Since client.erl has detached the call when using the list +%% encoding and not otherwise, output to the terminal in the +%% the former case, return in the latter. + +handle_answer(#diameter_packet{msg = Msg}, Request, _SvcName, _Peer) + when is_list(Request) -> + io:format("answer: ~p~n", [Msg]); + +handle_answer(#diameter_packet{msg = Msg}, _Request, _SvcName, _Peer) -> + {ok, Msg}. + +%% handle_error/4 + +handle_error(Reason, Request, _SvcName, _Peer) + when is_list(Request) -> + io:format("error: ~p~n", [Reason]); + +handle_error(Reason, _Request, _SvcName, _Peer) -> + {error, Reason}. + +%% handle_request/3 + +handle_request(_Packet, _SvcName, _Peer) -> + erlang:error({unexpected, ?MODULE, ?LINE}). diff --git a/lib/diameter/examples/peer.erl b/lib/diameter/examples/peer.erl new file mode 100644 index 0000000000..89203e15c3 --- /dev/null +++ b/lib/diameter/examples/peer.erl @@ -0,0 +1,139 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% A library module that factors out commonality in the example +%% Diameter peers. +%% + +-module(peer). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/2, + listen/2, + connect/2, + stop/1]). + +-type service_name() + :: term(). + +-type protocol() + :: tcp | sctp. + +-type ip_address() + :: default + | inet:ip_address(). + +-type server_config() + :: protocol() + | {protocol(), ip_address(), non_neg_integer()}. + +-type client_config() + :: protocol() + | {protocol(), ip_address(), non_neg_integer()} + | {protocol(), ip_address(), ip_address(), non_neg_integer()}. + +-define(DEFAULT_ADDR, {127,0,0,1}). +-define(DEFAULT_PORT, 3868). + +%% --------------------------------------------------------------------------- +%% Interface functions +%% --------------------------------------------------------------------------- + +%% start/2 + +-spec start(service_name(), list()) + -> ok + | {error, term()}. + +start(Name, Opts) + when is_atom(Name), is_list(Opts) -> + diameter:start_service(Name, Opts). + +%% connect/2 + +-spec connect(service_name(), client_config()) + -> {ok, reference()} + | {error, term()}. + +connect(Name, T) -> + diameter:add_transport(Name, {connect, [{reconnect_timer, 5000} + | client(T)]}). + +%% listen/2 + +-spec listen(service_name(), server_config()) + -> {ok, reference()} + | {error, term()}. + +listen(Name, T) -> + diameter:add_transport(Name, {listen, server(T)}). + +%% stop/1 + +-spec stop(service_name()) + -> ok + | {error, term()}. + +stop(Name) -> + diameter:stop_service(Name). + +%% --------------------------------------------------------------------------- +%% Internal functions +%% --------------------------------------------------------------------------- + +%% server/1 +%% +%% Return config for a listening transport. + +server({T, Addr, Port}) -> + [{transport_module, tmod(T)}, + {transport_config, [{reuseaddr, true}, + {ip, addr(Addr)}, + {port, Port}]}]; + +server(T) -> + server({T, ?DEFAULT_ADDR, ?DEFAULT_PORT}). + +%% client/1 +%% +%% Return config for a connecting transport. + +client({T, LA, RA, RP}) -> + [{transport_module, tmod(T)}, + {transport_config, [{ip, addr(LA)}, + {raddr, addr(RA)}, + {rport, RP}, + {reuseaddr, true}]}]; + +client({T, LA, RP}) -> + client({T, LA, LA, RP}); + +client(T) -> + client({T, ?DEFAULT_ADDR, ?DEFAULT_ADDR, ?DEFAULT_PORT}). + +tmod(tcp) -> diameter_tcp; +tmod(sctp) -> diameter_sctp. + +addr(default) -> + ?DEFAULT_ADDR; +addr(A) -> + A. diff --git a/lib/diameter/examples/redirect.erl b/lib/diameter/examples/redirect.erl new file mode 100644 index 0000000000..b54701243f --- /dev/null +++ b/lib/diameter/examples/redirect.erl @@ -0,0 +1,70 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(redirect). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/1, + listen/2, + stop/1]). + +-export([start/0, + listen/1, + stop/0]). + +-define(APP_ALIAS, ?MODULE). +-define(SVC_NAME, ?MODULE). +-define(CALLBACK_MOD, redirect_mod). + +%% The service configuration. +-define(SERVICE(Name), [{'Origin-Host', atom_to_list(Name) ++ ".example.com"}, + {'Origin-Realm', "example.com"}, + {'Vendor-Id', 193}, + {'Product-Name', "RedirectAgent"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_RELAY]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, ?DIAMETER_DICT_RELAY}, + {module, ?CALLBACK_MOD}]}]). + +%% start/1 + +start(Name) + when is_atom(Name) -> + peer:start(Name, ?SERVICE(Name)). + +start() -> + start(?SVC_NAME). + +%% listen/2 + +listen(Name, T) -> + peer:listen(Name, T). + +listen(T) -> + listen(?SVC_NAME, T). + +%% stop/1 + +stop(Name) -> + peer:stop(Name). + +stop() -> + stop(?SVC_NAME). diff --git a/lib/diameter/examples/redirect_cb.erl b/lib/diameter/examples/redirect_cb.erl new file mode 100644 index 0000000000..ea7ad38749 --- /dev/null +++ b/lib/diameter/examples/redirect_cb.erl @@ -0,0 +1,63 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(redirect_cb). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +-define(UNEXPECTED, erlang:error({unexpected, ?MODULE, ?LINE})). + +peer_up(_SvcName, {PeerRef, _}, State) -> + io:format("up: ~p~n", [PeerRef]), + State. + +peer_down(_SvcName, {PeerRef, _}, State) -> + io:format("down: ~p~n", [PeerRef]), + State. + +pick_peer(_, _, _SvcName, _State) -> + ?UNEXPECTED. + +prepare_request(_, _SvcName, _Peer) -> + ?UNEXPECTED. + +prepare_retransmit(_Packet, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_answer(_Packet, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_error(_Reason, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_request(#diameter_packet{msg = _, errors = []}, _SvcName, {_, Caps}) -> + #diameter_caps{} + = Caps, + discard. %% TODO diff --git a/lib/diameter/examples/relay.erl b/lib/diameter/examples/relay.erl new file mode 100644 index 0000000000..deecb1cfc0 --- /dev/null +++ b/lib/diameter/examples/relay.erl @@ -0,0 +1,92 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% An example Diameter relay agent. +%% +%% Usage to connect to a server listening on the default port over TCP +%% and to listen on the default port over SCTP is as follows, assuming +%% diameter is already started (eg. diameter:start()). +%% +%% Eg. relay:start(). +%% relay:connect(tcp). +%% relay:listen(sctp). +%% + +-module(relay). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/1, + listen/2, + connect/2, + stop/1]). + +-export([start/0, + listen/1, + connect/1, + stop/0]). + +-define(APP_ALIAS, ?MODULE). +-define(SVC_NAME, ?MODULE). +-define(CALLBACK_MOD, relay_cb). + +%% The service configuration. +-define(SERVICE(Name), [{'Origin-Host', atom_to_list(Name) ++ ".example.com"}, + {'Origin-Realm', "example.com"}, + {'Vendor-Id', 193}, + {'Product-Name', "RelayAgent"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_RELAY]}, + {application, [{alias, ?MODULE}, + {dictionary, ?DIAMETER_DICT_RELAY}, + {module, ?CALLBACK_MOD}]}]). + +%% start/1 + +start(Name) + when is_atom(Name) -> + peer:start(Name, ?SERVICE(Name)). + +start() -> + start(?SVC_NAME). + +%% listen/2 + +listen(Name, T) -> + peer:listen(Name, T). + +listen(T) -> + listen(?SVC_NAME, T). + +%% connect/2 + +connect(Name, T) -> + peer:connect(Name, T). + +connect(T) -> + connect(?SVC_NAME, T). + +%% stop/1 + +stop(Name) -> + peer:stop(Name). + +stop() -> + stop(?SVC_NAME). diff --git a/lib/diameter/examples/relay_cb.erl b/lib/diameter/examples/relay_cb.erl new file mode 100644 index 0000000000..9ed6517d5c --- /dev/null +++ b/lib/diameter/examples/relay_cb.erl @@ -0,0 +1,69 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(relay_cb). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/5, + prepare_request/4, + prepare_retransmit/4, + handle_answer/5, + handle_error/5, + handle_request/3]). + +peer_up(_SvcName, {PeerRef, _}, State) -> + io:format("up: ~p~n", [PeerRef]), + State. + +peer_down(_SvcName, {PeerRef, _}, State) -> + io:format("down: ~p~n", [PeerRef]), + State. + +%% Returning 'relay' from handle_request causes diameter to resend the +%% incoming request, which leads to pick_peer and prepare_request +%% callbacks as if sending explicitly. The 'extra' argument is +%% appended to the argument list for callbacks following from +%% resending of the request. + +handle_request(_Pkt, _SvcName, _Peer) -> + {relay, [{timeout, 1000}, {extra, [relayed]}]}. + +%% diameter will filter the sender in the Peers list. +pick_peer([Peer | _], _, _SvcName, _State, relayed) -> + {ok, Peer}. + +prepare_request(Pkt, _SvcName, _Peer, relayed) -> + {send, Pkt}. + +prepare_retransmit(Pkt, _SvcName, _Peer, relayed) -> + {send, Pkt}. + +%% diameter expects handle_answer to return the diameter_packet record +%% containing the answer when called for a relayed request. + +handle_answer(Pkt, _Request, _SvcName, _Peer, relayed) -> + Pkt. + +handle_error(Reason, _Request, _SvcName, _Peer, relayed) -> + {error, Reason}. diff --git a/lib/diameter/examples/sctp.erl b/lib/diameter/examples/sctp.erl new file mode 100644 index 0000000000..2e0e9d8b0b --- /dev/null +++ b/lib/diameter/examples/sctp.erl @@ -0,0 +1,113 @@ + +-module(sctp). + +%% +%% A small example demonstrating the establishment of an SCTP +%% association with gen_sctp. +%% + +-export([assoc/0, + dbg/0]). + +-include_lib("kernel/include/inet_sctp.hrl"). + +-define(ADDR, {127,0,0,1}). +-define(SERVER_PORT, 3868). +-define(CONNECT_TIMEOUT, 2000). +-define(REQUEST, <<0:64>>). +-define(REPLY, <<1:64>>). + +-record(server, {client, + socket, + assoc}). + +-record(client, {socket, + assoc}). + +%% assoc/0 +%% +%% Return on a successfully established association, raise an +%% exception otherwise. + +assoc() -> + {_, MRef} = spawn_monitor(fun server/0), + receive {'DOWN', MRef, process, _, Info} -> Info end. + +%% dbg/0 + +dbg() -> + dbg:tracer(), + dbg:p(all,c), + dbg:tpl(?MODULE, [{'_',[],[{exception_trace}]}]), + dbg:tp(gen_sctp, [{'_',[],[{exception_trace}]}]), + ok. + +%% server/0 + +server() -> + {ok, Sock} = gen_sctp:open([binary, + {reuseaddr, true}, + {active, true}, + {ip, ?ADDR}, + {port, ?SERVER_PORT}]), + ok = gen_sctp:listen(Sock, true), + {_Pid, MRef} = spawn_monitor(fun client/0), + s(#server{client = MRef, socket = Sock}), + gen_sctp:close(Sock). + +%% s/1 + +s(#server{} = S) -> + s(s(receive T -> T end, S)); +s(T) -> + T. + +%% s/2 + +s({sctp, Sock, _RA, _RP, {[], #sctp_assoc_change{state = comm_up, + assoc_id = Id}}}, + #server{socket = Sock, assoc = undefined} + = S) -> + S#server{assoc = Id}; + +s({sctp, Sock, _RA, _RP, {[#sctp_sndrcvinfo{assoc_id = AId, + stream = SId}], + ?REQUEST}}, + #server{socket = Sock, assoc = AId} + = S) -> + ok = gen_sctp:send(Sock, AId, SId, ?REPLY), + S; + +s({'DOWN', MRef, process, _, normal} = T, #server{client = MRef}) -> + T. + +%% client/0 + +client() -> + {ok, Sock} = gen_sctp:open([binary, + {reuseaddr, true}, + {active, true}, + {ip, ?ADDR}, + {port, 0}]), + ok = gen_sctp:connect_init(Sock, ?ADDR, ?SERVER_PORT, []), + c(#client{socket = Sock}), + gen_sctp:close(Sock). + + +%% c/1 + +c(#client{} = S) -> + c(c(receive T -> T end, S)); +c(T) -> + T. + +c({sctp, Sock, _RA, _RP, {[], #sctp_assoc_change{state = comm_up, + assoc_id = Id}}}, + #client{socket = Sock, assoc = undefined} + = S) -> + ok = gen_sctp:send(Sock, Id, 0, ?REQUEST), + S#client{assoc = Id}; + +c({sctp, Sock, _RA, _RP, {[#sctp_sndrcvinfo{assoc_id = AId}], ?REPLY}}, + #client{socket = Sock, assoc = AId}) -> + ok. diff --git a/lib/diameter/examples/server.erl b/lib/diameter/examples/server.erl new file mode 100644 index 0000000000..ebb408e501 --- /dev/null +++ b/lib/diameter/examples/server.erl @@ -0,0 +1,88 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% An example Diameter server that can respond to the base protocol +%% RAR sent by the client example. +%% +%% The simplest example to start a server listening on the loopback +%% address (which will serve the example usage given in client.erl) is +%% like this assuming diameter is already started (eg. diameter:start()): +%% +%% server:start(). +%% server:listen(tcp). +%% +%% The first call starts a service, the second adds a transport listening +%% on the default port. +%% + +-module(server). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +-export([start/1, %% start a service + listen/2, %% add a listening transport + stop/1]). %% stop a service + +%% Convenience functions using the default service name, ?SVC_NAME. +-export([start/0, + listen/1, + stop/0]). + +-define(SVC_NAME, ?MODULE). +-define(APP_ALIAS, ?MODULE). +-define(CALLBACK_MOD, server_cb). + +%% The service configuration. In a server supporting multiple Diameter +%% applications each application may have its own, although they could all +%% be configured with a common callback module. +-define(SERVICE(Name), [{'Origin-Host', atom_to_list(Name) ++ ".example.com"}, + {'Origin-Realm', "example.com"}, + {'Vendor-Id', 193}, + {'Product-Name', "Server"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, + {application, [{alias, ?APP_ALIAS}, + {dictionary, ?DIAMETER_DICT_COMMON}, + {module, ?CALLBACK_MOD}]}]). + +%% start/1 + +start(Name) + when is_atom(Name) -> + peer:start(Name, ?SERVICE(Name)). + +start() -> + start(?SVC_NAME). + +%% listen/2 + +listen(Name, T) -> + peer:listen(Name, T). + +listen(T) -> + listen(?SVC_NAME, T). + +%% stop/1 + +stop(Name) -> + peer:stop(Name). + +stop() -> + stop(?SVC_NAME). diff --git a/lib/diameter/examples/server_cb.erl b/lib/diameter/examples/server_cb.erl new file mode 100644 index 0000000000..43b8e24b5c --- /dev/null +++ b/lib/diameter/examples/server_cb.erl @@ -0,0 +1,115 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% The diameter application callback module configured by server.erl. +%% + +-module(server_cb). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter/src/app/diameter_gen_base_rfc3588.hrl"). + +%% diameter callbacks +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_answer/4, + handle_error/4, + handle_request/3]). + +-define(UNEXPECTED, erlang:error({unexpected, ?MODULE, ?LINE})). + +peer_up(_SvcName, {PeerRef, _}, State) -> + io:format("up: ~p~n", [PeerRef]), + State. + +peer_down(_SvcName, {PeerRef, _}, State) -> + io:format("down: ~p~n", [PeerRef]), + State. + +pick_peer(_, _, _SvcName, _State) -> + ?UNEXPECTED. + +prepare_request(_, _SvcName, _Peer) -> + ?UNEXPECTED. + +prepare_retransmit(_Packet, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_answer(_Packet, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +handle_error(_Reason, _Request, _SvcName, _Peer) -> + ?UNEXPECTED. + +%% A request whose decode was successful ... +handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) + when is_record(Req, diameter_base_RAR) -> + #diameter_caps{origin_host = {OH,_}, + origin_realm = {OR,_}} + = Caps, + #diameter_base_RAR{'Session-Id' = Id, + 'Re-Auth-Request-Type' = RT} + = Req, + + {reply, answer(RT, Id, OH, OR)}; + +%% ... or one that wasn't. 3xxx errors are answered by diameter itself +%% but these are 5xxx errors for which we must contruct a reply. +%% diameter will set Result-Code and Failed-AVP's. +handle_request(#diameter_packet{msg = Req} = Pkt, _SvcName, {_, Caps}) + when is_record(Req, diameter_base_RAR) -> + #diameter_caps{origin_host = {OH,_}, + origin_realm = {OR,_}} + = Caps, + #diameter_base_RAR{'Session-Id' = Id} + = Req, + + Ans = #diameter_base_RAA{'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Session-Id' = Id}, + + {reply, Ans}; + +%% Should really reply to other base messages that we don't support +%% but simply discard them instead. +handle_request(#diameter_packet{}, _SvcName, {_,_}) -> + discard. + +%% --------------------------------------------------------------------------- + +%% Answer using the record or list encoding depending on +%% Re-Auth-Request-Type. This is just as an example. You would +%% typically just choose one, and this has nothing to do with the how +%% client.erl sends. + +answer(0, Id, OH, OR) -> + #diameter_base_RAA{'Result-Code' = 2001, %% DIAMETER_SUCCESS + 'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Session-Id' = Id}; + +answer(_, Id, OH, OR) -> + ['RAA', {'Result-Code', 5012}, %% DIAMETER_UNABLE_TO_COMPLY + {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Session-Id', Id}]. diff --git a/lib/diameter/include/diameter.hrl b/lib/diameter/include/diameter.hrl new file mode 100644 index 0000000000..0fa7fd406f --- /dev/null +++ b/lib/diameter/include/diameter.hrl @@ -0,0 +1,130 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-ifndef(diameter_hrl). +-define(diameter_hrl, true). + +%% RFC 3588, 2.4: +-define(DIAMETER_APP_ID_COMMON, 0). +-define(DIAMETER_APP_ID_ACCOUNTING, 3). +-define(DIAMETER_APP_ID_RELAY, 16#FFFFFFFF). + +%% Corresponding dictionaries: +-define(DIAMETER_DICT_COMMON, diameter_gen_base_rfc3588). +-define(DIAMETER_DICT_ACCOUNTING, diameter_gen_base_accounting). +-define(DIAMETER_DICT_RELAY, diameter_gen_relay). + +%% Events sent to processes that have subscribed with +%% diameter:subscribe/1. +%% +-record(diameter_event, + {service, %% name + info}). %% tuple() + +%% diameter_packet records are passed through the encode/decode +%% interface supplied by a dictionary module configured on a Diameter +%% application. For an incoming message the bin field contains the +%% received binary and the header, avps, msg and errors fields the +%% result of decoding. + +-record(diameter_packet, + {header, %% #diameter_header{} + avps, %% deep list() of #diameter_avp{} + msg, %% fully decoded message + bin, %% binary received/sent over the wire + errors = [],%% list() of Result-Code | {Result-Code, #diameter_avp{}} + transport_data}). + +-record(diameter_header, + {version, %% 8-bit unsigned + length, %% 24-bit unsigned + cmd_code, %% 8-bit unsigned + application_id, %% 24-bit unsigned + hop_by_hop_id, %% 32-bit unsigned + end_to_end_id, %% 32-bit unsigned + is_request, %% boolean() R flag + is_proxiable, %% boolean() P flag + is_error, %% boolean() E flag + is_retransmitted}). %% boolean() T flag + +-record(diameter_avp, + {code, %% 32-bit unsigned + vendor_id, %% 32-bit unsigned + is_mandatory = false, %% boolean() M flag + need_encryption = false, %% boolean() P flag + data, %% encoded binary() + name, %% atom() AVP name + value, %% decoded term() decoded | undefined + type, %% atom() type name, + index}). %% non_neg_integer() | undefined + +%% A diameter_caps record corresponds to capabilities configuration on +%% diameter:start_service/2. In application callbacks is identifies +%% the peer connection for which the callback is taking place, and in +%% this case each field is a 2-tuple specifying the host (ie. local) +%% and peer (ie. remote) values, host values having been configured +%% and peer values having been received at capabilities exchange. + +-record(diameter_caps, + {origin_host, %% 'DiameterIdentity'() + origin_realm, %% 'DiameterIdentity'() + host_ip_address = [], %% ['Address'()] + vendor_id, %% 'Unsigned32'() + product_name, %% 'OctetString'() + origin_state_id = [], %% ['Unsigned32'()] + supported_vendor_id = [], %% ['Unsigned32'()] + auth_application_id = [], %% ['Unsigned32'()] + inband_security_id = [], %% ['Unsigned32'()] + acct_application_id = [], %% ['Unsigned32'()] + vendor_specific_application_id = [], %% ['Grouped'()] + firmware_revision = [], %% ['Unsigned32()] + avp = []}). + +%% AVP's of type DiameterURI are encoded as a diameter_uri record. +%% Note that AVP's of type IPFilterRule and QoSFilterRule are currently +%% encoded simply as OctetString's. + +-record(diameter_uri, + {type, %% aaa | aaas + fqdn, %% string() + port = 3868, %% non_neg_integer(), + transport = sctp, %% | tcp, + protocol = diameter}). %% | radius | 'tacacs+' + +%% The diameter service and diameter_apps records are only passed +%% through the transport interface when starting a transport process, +%% although typically a transport implementation will (and probably +%% should) only be interested host_ip_address. + +-record(diameter_service, + {pid, + capabilities, %% #diameter_caps{} + applications = []}). %% [#diameter_app{}] + +-record(diameter_app, + {alias, %% option 'alias' + dictionary, %% option 'dictionary', module() + module, %% [Mod | Args] callback module() and extra args + init_state, %% option 'state', initial callback state + id, %% 32-bit unsigned application identifier = Dict:id() + mutable = false, %% boolean(), do traffic callbacks modify state? + answer_errors = report}). %% | callback | discard + %% how to handle containing errors? + +-endif. %% -ifdef(diameter_hrl). diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl new file mode 100644 index 0000000000..4c91954a21 --- /dev/null +++ b/lib/diameter/include/diameter_gen.hrl @@ -0,0 +1,431 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This file contains code that's included by encode/decode modules +%% generated by diameter_codegen.erl. This code does most of the work, the +%% generated code being kept simple. +%% + +-define(THROW(T), throw({?MODULE, T})). + +%%% --------------------------------------------------------------------------- +%%% # encode_avps/3 +%%% +%%% Returns: binary() +%%% --------------------------------------------------------------------------- + +encode_avps(Name, Vals) + when is_list(Vals) -> + encode_avps(Name, '#set-'(Vals, newrec(Name))); + +encode_avps(Name, Rec) -> + try + list_to_binary(encode(Name, Rec)) + catch + throw: {?MODULE, Reason} -> + diameter_dbg:log({encode, error}, + ?MODULE, + ?LINE, + {Reason, Name, Rec}), + erlang:error(list_to_tuple(Reason ++ [Name, Rec, ?MODULE])); + error: Reason -> + Stack = erlang:get_stacktrace(), + diameter_dbg:log({encode, failure}, + ?MODULE, + ?LINE, + {Reason, Name, Rec, Stack}), + erlang:error({encode_failure, Reason, Name, Rec, ?MODULE, Stack}) + end. + +%% encode/2 + +encode(Name, Rec) -> + lists:flatmap(fun(A) -> encode(Name, A, '#get-'(A, Rec)) end, + '#info-'(element(1, Rec), fields)). + +%% encode/3 + +encode(Name, AvpName, Values) -> + e(Name, AvpName, avp_arity(Name, AvpName), Values). + +%% e/4 + +e(_, AvpName, 1, undefined) -> + ?THROW([mandatory_avp_missing, AvpName]); + +e(Name, AvpName, 1, Value) -> + e(Name, AvpName, [Value]); + +e(_, _, {0,_}, []) -> + []; + +e(_, AvpName, _, T) + when not is_list(T) -> + ?THROW([repeated_avp_as_non_list, AvpName, T]); + +e(_, AvpName, {Min, _}, L) + when length(L) < Min -> + ?THROW([repeated_avp_insufficient_arity, AvpName, Min, L]); + +e(_, AvpName, {_, Max}, L) + when Max < length(L) -> + ?THROW([repeated_avp_excessive_arity, AvpName, Max, L]); + +e(Name, AvpName, _, Values) -> + e(Name, AvpName, Values). + +%% e/3 + +e(Name, 'AVP', Values) -> + [pack_AVP(Name, A) || A <- Values]; + +e(_, AvpName, Values) -> + e(AvpName, Values). + +%% e/2 + +e(AvpName, Values) -> + H = avp_header(AvpName), + [diameter_codec:pack_avp(H, avp(encode, V, AvpName)) || V <- Values]. + +%% pack_AVP/2 + +%% No value: assume AVP data is already encoded. The normal case will +%% be when this is passed back from #diameter_packet.errors as a +%% consequence of a failed decode. Any AVP can be encoded this way +%% however, which side-steps any arity checks for known AVP's and +%% could potentially encode something unfortunate. +pack_AVP(_, #diameter_avp{value = undefined} = A) -> + diameter_codec:pack_avp(A); + +%% Missing name for value encode. +pack_AVP(_, #diameter_avp{name = N, value = V}) + when N == undefined; + N == 'AVP' -> + ?THROW([value_with_nameless_avp, N, V]); + +%% Or not. Ensure that 'AVP' is the appropriate field. Note that if we +%% don't know this AVP at all then the encode will fail. +pack_AVP(Name, #diameter_avp{name = AvpName, + value = Data}) -> + 0 == avp_arity(Name, AvpName) + orelse ?THROW([known_avp_as_AVP, Name, AvpName, Data]), + e(AvpName, [Data]). + +%%% --------------------------------------------------------------------------- +%%% # decode_avps/2 +%%% +%%% Returns: {Rec, Avps, Failed} +%%% +%%% Rec = decoded message record +%%% Avps = list of Avp +%%% Failed = list of {ResultCode, #diameter_avp{}} +%%% +%%% Avp = #diameter_avp{} if type is not Grouped +%%% | list of Avp where first element has type Grouped +%%% and following elements are its component +%%% AVP's. +%%% --------------------------------------------------------------------------- + +decode_avps(Name, Recs) -> + d_rc(Name, lists:foldl(fun(T,A) -> decode(Name, T, A) end, + {[], {newrec(Name), []}}, + Recs)). + +newrec(Name) -> + '#new-'(name2rec(Name)). + +%% No errors so far: keep looking. +d_rc(Name, {Avps, {Rec, [] = Failed}}) -> + try + true = have_required_avps(Rec, Name), + {Rec, Avps, Failed} + catch + throw: {?MODULE, {AvpName, Reason}} -> + diameter_dbg:log({decode, error}, + ?MODULE, + ?LINE, + {AvpName, Reason, Rec}), + {Rec, Avps, [{5005, empty_avp(AvpName)}]} + end; +%% 3588: +%% +%% DIAMETER_MISSING_AVP 5005 +%% The request did not contain an AVP that is required by the Command +%% Code definition. If this value is sent in the Result-Code AVP, a +%% Failed-AVP AVP SHOULD be included in the message. The Failed-AVP +%% AVP MUST contain an example of the missing AVP complete with the +%% Vendor-Id if applicable. The value field of the missing AVP +%% should be of correct minimum length and contain zeroes. + +%% Or not. Only need to report the first error so look no further. +d_rc(_, {Avps, {Rec, Failed}}) -> + {Rec, Avps, lists:reverse(Failed)}. + +%% empty_avp/1 + +empty_avp(Name) -> + {Code, Flags, VId} = avp_header(Name), + {Name, Type} = avp_name(Code, VId), + #diameter_avp{name = Name, + code = Code, + vendor_id = VId, + is_mandatory = 0 /= (Flags band 2#01000000), + need_encryption = 0 /= (Flags band 2#00100000), + data = empty_value(Name), + type = Type}. + +%% have_required_avps/2 + +have_required_avps(Rec, Name) -> + lists:foreach(fun(F) -> hra(Name, F, Rec) end, + '#info-'(element(1, Rec), fields)), + true. + +hra(Name, AvpName, Rec) -> + Arity = avp_arity(Name, AvpName), + hra(Arity, '#get-'(AvpName, Rec)) + orelse ?THROW({AvpName, {insufficient_arity, Arity}}). + +%% Maximum arities have already been checked in building the record. + +hra({Min, _}, L) -> + Min =< length(L); +hra(N, V) -> + N /= 1 orelse V /= undefined. + +%% 3588, ch 7: +%% +%% The Result-Code AVP describes the error that the Diameter node +%% encountered in its processing. In case there are multiple errors, +%% the Diameter node MUST report only the first error it encountered +%% (detected possibly in some implementation dependent order). The +%% specific errors that can be described by this AVP are described in +%% the following section. + +%% decode/3 + +decode(Name, #diameter_avp{code = Code, vendor_id = Vid} = Avp, Acc) -> + decode(Name, avp_name(Code, Vid), Avp, Acc). + +%% decode/4 + +%% Don't know this AVP: see if it can be packed in an 'AVP' field +%% undecoded, unless it's mandatory. Need to give Failed-AVP special +%% treatment since it'll contain any unrecognized mandatory AVP's. +decode(Name, 'AVP', #diameter_avp{is_mandatory = M} = Avp, {Avps, Acc}) -> + {[Avp | Avps], if M, Name /= 'Failed-AVP' -> + unknown(Avp, Acc); + true -> + pack_AVP(Name, Avp, Acc) + end}; +%% Note that the type field is 'undefined' in this case. + +%% Or try to decode. +decode(Name, {AvpName, Type}, Avp, Acc) -> + d(Name, Avp#diameter_avp{name = AvpName, type = Type}, Acc). + +%% d/3 + +d(Name, Avp, {Avps, Acc}) -> + #diameter_avp{name = AvpName, + data = Data} + = Avp, + + try avp(decode, Data, AvpName) of + V -> + {H, A} = ungroup(V, Avp), + {[H | Avps], pack_avp(Name, A, Acc)} + catch + error: Reason -> + %% Failures here won't be visible since they're a "normal" + %% occurrence if the peer sends a faulty AVP that we need to + %% respond sensibly to. Log the occurence for traceability, + %% but the peer will also receive info in the resulting + %% answer-message. + diameter_dbg:log({decode, failure}, + ?MODULE, + ?LINE, + {Reason, Avp, erlang:get_stacktrace()}), + {Rec, Failed} = Acc, + {[Avp|Avps], {Rec, [{rc(Reason), Avp} | Failed]}} + end. + +%% rc/1 + +%% diameter_types will raise an error of this form to communicate +%% DIAMETER_INVALID_AVP_LENGTH (5014). A module specified to a +%% @custom_types tag in a spec file can also raise an error of this +%% form. +rc({'DIAMETER', RC, _}) -> + RC; + +%% 3588: +%% +%% DIAMETER_INVALID_AVP_VALUE 5004 +%% The request contained an AVP with an invalid value in its data +%% portion. A Diameter message indicating this error MUST include +%% the offending AVPs within a Failed-AVP AVP. +rc(_) -> + 5004. + +%% ungroup/2 +%% +%% Returns: {Avp, Dec} +%% +%% Avp = #diameter_avp{} if type is not Grouped +%% | list of Avp where first element has type Grouped +%% and following elements are its component +%% AVP's. +%% = as for decode_avps/2 +%% +%% Dec = #diameter_avp{}, either Avp or its head in the list case. + +%% The decoded value in the Grouped case is as returned by grouped_avp/3: +%% a record and a list of component AVP's. +ungroup(V, #diameter_avp{type = 'Grouped'} = Avp) -> + {Rec, As} = V, + A = Avp#diameter_avp{value = Rec}, + {[A|As], A}; + +%% Otherwise it's just a plain value. +ungroup(V, #diameter_avp{} = Avp) -> + A = Avp#diameter_avp{value = V}, + {A, A}. + +%% pack_avp/3 + +pack_avp(Name, #diameter_avp{name = AvpName} = Avp, Acc) -> + pack_avp(Name, avp_arity(Name, AvpName), Avp, Acc). + +%% pack_avp/4 + +pack_avp(Name, 0, Avp, Acc) -> + pack_AVP(Name, Avp, Acc); + +pack_avp(_, Arity, Avp, Acc) -> + pack(Arity, Avp#diameter_avp.name, Avp, Acc). + +%% pack_AVP/3 + +pack_AVP(Name, Avp, Acc) -> + case avp_arity(Name, 'AVP') of + 0 -> + unknown(Avp, Acc); + Arity -> + pack(Arity, 'AVP', Avp, Acc) + end. + +%% 3588: +%% +%% DIAMETER_AVP_UNSUPPORTED 5001 +%% The peer received a message that contained an AVP that is not +%% recognized or supported and was marked with the Mandatory bit. A +%% Diameter message with this error MUST contain one or more Failed- +%% AVP AVP containing the AVPs that caused the failure. +%% +%% DIAMETER_AVP_NOT_ALLOWED 5008 +%% A message was received with an AVP that MUST NOT be present. The +%% Failed-AVP AVP MUST be included and contain a copy of the +%% offending AVP. +%% +unknown(#diameter_avp{is_mandatory = B} = Avp, {Rec, Failed}) -> + {Rec, [{if B -> 5001; true -> 5008 end, Avp} | Failed]}. + +%% pack/4 + +pack(Arity, FieldName, Avp, {Rec, _} = Acc) -> + pack('#get-'(FieldName, Rec), Arity, FieldName, Avp, Acc). + +%% pack/5 + +pack(undefined, 1, FieldName, Avp, Acc) -> + p(FieldName, fun(V) -> V end, Avp, Acc); + +%% 3588: +%% +%% DIAMETER_AVP_OCCURS_TOO_MANY_TIMES 5009 +%% A message was received that included an AVP that appeared more +%% often than permitted in the message definition. The Failed-AVP +%% AVP MUST be included and contain a copy of the first instance of +%% the offending AVP that exceeded the maximum number of occurrences +%% +pack(_, 1, _, Avp, {Rec, Failed}) -> + {Rec, [{5009, Avp} | Failed]}; +pack(L, {_, Max}, _, Avp, {Rec, Failed}) + when length(L) == Max -> + {Rec, [{5009, Avp} | Failed]}; + +pack(L, _, FieldName, Avp, Acc) -> + p(FieldName, fun(V) -> [V|L] end, Avp, Acc). + +%% p/4 + +p(F, Fun, Avp, {Rec, Failed}) -> + {'#set-'({F, Fun(value(F, Avp))}, Rec), Failed}. + +value('AVP', Avp) -> + Avp; +value(_, Avp) -> + Avp#diameter_avp.value. + +%%% --------------------------------------------------------------------------- +%%% # grouped_avp/3 +%%% --------------------------------------------------------------------------- + +grouped_avp(decode, Name, Data) -> + {Rec, Avps, []} = decode_avps(Name, diameter_codec:collect_avps(Data)), + {Rec, Avps}; +%% Note that a failed match here will result in 5004. Note that this is +%% the only AVP type that doesn't just return the decoded value, also +%% returning the list of component #diameter_avp{}'s. + +grouped_avp(encode, Name, Data) -> + encode_avps(Name, Data). + +%%% --------------------------------------------------------------------------- +%%% # empty_group/1 +%%% --------------------------------------------------------------------------- + +empty_group(Name) -> + list_to_binary(empty_body(Name)). + +empty_body(Name) -> + [z(F, avp_arity(Name, F)) || F <- '#info-'(name2rec(Name), fields)]. + +z(Name, 1) -> + z(Name); +z(_, {0,_}) -> + []; +z(Name, {Min, _}) -> + lists:duplicate(Min, z(Name)). + +z('AVP') -> + <<0:64/integer>>; %% minimal header +z(Name) -> + Bin = diameter_codec:pack_avp(avp_header(Name), empty_value(Name)), + << <<0>> || <<_>> <= Bin >>. + +%%% --------------------------------------------------------------------------- +%%% # empty/1 +%%% --------------------------------------------------------------------------- + +empty(AvpName) -> + avp(encode, zero, AvpName). diff --git a/lib/diameter/info b/lib/diameter/info new file mode 100644 index 0000000000..67ef726781 --- /dev/null +++ b/lib/diameter/info @@ -0,0 +1,3 @@ +group: comm +short: Diameter + diff --git a/lib/diameter/make/release_targets.mk b/lib/diameter/make/release_targets.mk new file mode 100644 index 0000000000..5a3b585cbc --- /dev/null +++ b/lib/diameter/make/release_targets.mk @@ -0,0 +1,92 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +ifeq ($(TOPDOC),) +$(HTMLDIR)/index.html: $(XML_FILES) + date=`date +"%B %e %Y"`; \ + $(XSLTPROC) --noout --stringparam outdir $(HTMLDIR) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \ + --stringparam pdfdir "$(PDFDIR)" \ + --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \ + -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml +endif + +$(HTMLDIR)/users_guide.html: $(XML_FILES) + date=`date +"%B %e %Y"`; \ + $(XSLTPROC) --noout --stringparam outdir $(HTMLDIR) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \ + --stringparam pdfdir "$(PDFDIR)" \ + --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \ + -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml + + +%.fo: $(XML_FILES) + date=`date +"%B %e %Y"`; \ + $(XSLTPROC) --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" \ + --stringparam appver "$(VSN)" --xinclude \ + -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_pdf.xsl book.xml > $@ + + + +# ------------------------------------------------------------------------ +# The following targets just exist in the documentation directory +# ------------------------------------------------------------------------ +ifneq ($(XML_FILES),) + +# ---------------------------------------------------- +# Generation of application index data +# ---------------------------------------------------- +$(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES) + date=`date +"%B %e %Y"`; \ + $(XSLTPROC) --stringparam docgen "$(DOCGEN)" \ + --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \ + -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_eix.xsl book.xml > $@ + +docs: +#docs: $(HTMLDIR)/$(APPLICATION).eix + +# ---------------------------------------------------- +# Local documentation target for testing +# ---------------------------------------------------- +local_docs: TOPDOCDIR=. +local_docs: local_copy_of_topdefs docs + +local_html: TOPDOCDIR=. +local_html: local_copy_of_topdefs html + +local_copy_of_topdefs: + $(INSTALL) $(DOCGEN)/priv/css/otp_doc.css $(HTMLDIR) + $(INSTALL) $(DOCGEN)/priv/images/erlang-logo.png $(HTMLDIR) + $(INSTALL) $(DOCGEN)/priv/images/erlang-logo.gif $(HTMLDIR) + $(INSTALL_DIR) $(HTMLDIR)/js/flipmenu + $(INSTALL) $(DOCGEN)/priv/js/flipmenu/flip_closed.gif \ + $(DOCGEN)/priv/js/flipmenu/flip_open.gif \ + $(DOCGEN)/priv/js/flipmenu/flip_static.gif \ + $(DOCGEN)/priv/js/flipmenu/flipmenu.js $(HTMLDIR)/js/flipmenu + +endif + +# ---------------------------------------------------- +# Standard release target +# ---------------------------------------------------- + +ifneq ($(PREFIX),) + +release release_docs release_tests release_html: + $(MAKE) $(MFLAGS) RELEASE_PATH=$(PREFIX) $(TARGET_MAKEFILE) $@_spec + +endif diff --git a/lib/diameter/make/rules.mk.in b/lib/diameter/make/rules.mk.in new file mode 100644 index 0000000000..4a1a55b8d3 --- /dev/null +++ b/lib/diameter/make/rules.mk.in @@ -0,0 +1,195 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode +# ---------------------------------------------------- +# %CopyrightBegin% +# +# Copyright Ericsson AB 2009-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +.SUFFIXES: .erl .beam .yrl .hrl .xml .xmlsrc .html \ + .3 .1 .pdf .fo .el .elc + +# ---------------------------------------------------- +# Common macros +# ---------------------------------------------------- +DEFAULT_TARGETS = opt debug release release_docs clean docs + + +# Slash separated list of return values from $(origin VAR) +# that are untrusted - set default in this file instead. +# The list is not space separated since some return values +# contain space, and we want to use $(findstring ...) to +# search the list. +DUBIOUS_ORIGINS = /undefined/environment/ + + +# # ---------------------------------------------------- +# # TARGET definition +# # ---------------------------------------------------- +# # TARGET = @TARGET@ +# ifneq ($(OVERRIDE_TARGET),) +# ifneq ($(TARGET), $(OVERRIDE_TARGET)) +# $(warning overriding $$(TARGET) = \ +# "$(TARGET)" \ +# with \ +# $$(OVERRIDE_TARGET) = \ +# "$(OVERRIDE_TARGET)") +# override TARGET := $(OVERRIDE_TARGET) +# endif +# endif +# + +# ---------------------------------------------------- +# Command macros +# ---------------------------------------------------- +PREFIX = @prefix@ +INSTALL = @INSTALL@ +INSTALL_DIR = @INSTALL_DIR@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_DATA = @INSTALL_DATA@ + + +# ---------------------------------------------------- +# Erlang language section +# ---------------------------------------------------- +ERL_ROOT_DIR = @ERLANG_ROOT_DIR@ +ERL_LIB_DIR = @ERLANG_LIB_DIR@ +DOCGEN_DIR = @ERLANG_LIB_DIR_erl_docgen@ +TEST_SERVER_DIR = @ERLANG_LIB_VER_test_server@ +EMULATOR = beam +ERL_COMPILE_FLAGS += +debug_info +ERLC_WFLAGS = -W +ERLC = $(ERL_ROOT_DIR)/bin/erlc $(ERLC_WFLAGS) $(ERLC_FLAGS) +ERL = $(ERL_ROOT_DIR)/bin/erl -boot start_clean +#ERLC = @ERLC@ $(ERLC_WFLAGS) $(ERLC_FLAGS) +#ERL = @ERL@ -boot start_clean + +ifneq (,$(findstring $(origin EBIN),$(DUBIOUS_ORIGINS))) +EBIN = ../../ebin +endif + +# Generated (non ebin) files... +ifneq (,$(findstring $(origin EGEN),$(DUBIOUS_ORIGINS))) +EGEN = . +endif + +ifneq (,$(findstring $(origin ESRC),$(DUBIOUS_ORIGINS))) +ESRC = . +endif + +$(EBIN)/%.beam: $(EGEN)/%.erl + $(ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $< + +$(EBIN)/%.beam: $(ESRC)/%.erl + $(ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $< + +.erl.beam: + $(ERLC) $(ERL_COMPILE_FLAGS) -o$(dir $@) $< + + +# +# When .erl files are automatically created GNU make removes them if +# they were the result of a chain of implicit rules. To prevent this +# we say that all .erl files are "precious". +# +.PRECIOUS: %.erl %.fo + + +# ---------------------------------------------------- +# Documentation section +# ---------------------------------------------------- +# export VSN + +# DOCSUPPORT = 1 + +# TOPDOCDIR=../../../../doc + +DOCDIR = .. + +PDFDIR=$(DOCDIR)/pdf + +HTMLDIR = $(DOCDIR)/html + +MAN1DIR = $(DOCDIR)/man1 +MAN2DIR = $(DOCDIR)/man2 +MAN3DIR = $(DOCDIR)/man3 +MAN4DIR = $(DOCDIR)/man4 +MAN6DIR = $(DOCDIR)/man6 +MAN9DIR = $(DOCDIR)/man9 + +# HTML & GIF files that always are generated and must be delivered +XML_COLL_FILES = $(XML_APPLICATION_FILES) $(XML_PART_FILES) +DEFAULT_HTML_FILES = \ + $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_frame.html) \ + $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_first.html) \ + $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_term.html) \ + $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_cite.html) \ + $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%_index.html) \ + $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.kwc) \ + $(HTMLDIR)/index.html + +DEFAULT_GIF_FILES = $(HTMLDIR)/min_head.gif + +# +# Flags & Commands +# +XSLTPROC = @XSLTPROC@ +FOP = @FOP@ + +DOCGEN=$(DOCGEN_DIR) + +$(MAN1DIR)/%.1:: %.xml + date=`date +"%B %e %Y"`; \ + xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + + +$(MAN2DIR)/%.2:: %.xml + date=`date +"%B %e %Y"`; \ + xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + + +$(MAN3DIR)/%.3:: %.xml + date=`date +"%B %e %Y"`; \ + xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + +# left for compatability +$(MAN4DIR)/%.4:: %.xml + date=`date +"%B %e %Y"`; \ + xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + +$(MAN4DIR)/%.5:: %.xml + date=`date +"%B %e %Y"`; \ + xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + +# left for compatability +$(MAN6DIR)/%.6:: %_app.xml + date=`date +"%B %e %Y"`; \ + xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + +$(MAN6DIR)/%.7:: %_app.xml + date=`date +"%B %e %Y"`; \ + xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + +$(MAN9DIR)/%.9:: %.xml + date=`date +"%B %e %Y"`; \ + xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< + + +.xmlsrc.xml: + escript $(DOCGEN)/priv/bin/codeline_preprocessing.escript $< $@ + +.fo.pdf: + $(FOP) -fo $< -pdf $@ + diff --git a/lib/diameter/make/subdir.mk b/lib/diameter/make/subdir.mk new file mode 100644 index 0000000000..24b08080ae --- /dev/null +++ b/lib/diameter/make/subdir.mk @@ -0,0 +1,53 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# Make include file for otp + +.PHONY: debug opt release docs release_docs tests release_tests \ + clean depend valgrind + +# +# Targets that don't affect documentation directories +# +opt debug release docs release_docs tests release_tests clean depend valgrind: + @set -e ; \ + app_pwd=`pwd` ; \ + if test -f vsn.mk; then \ + echo "=== Entering application" `basename $$app_pwd` ; \ + fi ; \ + case "$(MAKE)" in *clearmake*) tflag="-T";; *) tflag="";; esac; \ + for d in $(SUB_DIRS); do \ + if test -f $$d/SKIP ; then \ + echo "=== Skipping subdir $$d, reason:" ; \ + cat $$d/SKIP ; \ + echo "===" ; \ + else \ + if test ! -d $$d ; then \ + echo "=== Skipping subdir $$d, it is missing" ; \ + else \ + xflag="" ; \ + if test -f $$d/ignore_config_record.inf; then \ + xflag=$$tflag ; \ + fi ; \ + (cd $$d && $(MAKE) $$xflag $@) || exit $$? ; \ + fi ; \ + fi ; \ + done ; \ + if test -f vsn.mk; then \ + echo "=== Leaving application" `basename $$app_pwd` ; \ + fi diff --git a/lib/diameter/make/target.mk b/lib/diameter/make/target.mk new file mode 100644 index 0000000000..4ae470b9e2 --- /dev/null +++ b/lib/diameter/make/target.mk @@ -0,0 +1,33 @@ +ifeq ($(OVERRIDE_TARGET),) + +ifeq ($(TARGET),) + +TARGET := $(shell $(DIAMETER_TOP)/autoconf/config.guess) + +else + +endif + +else + +ifneq ($(TARGET),) + +ifneq ($(TARGET), $(OVERRIDE_TARGET)) +$(warning overriding $$(TARGET) = \ + "$(TARGET)" \ + with \ + $$(OVERRIDE_TARGET) = \ + "$(OVERRIDE_TARGET)") +else +endif + +override TARGET := $(OVERRIDE_TARGET) + +else + +TARGET := $(OVERRIDE_TARGET) + +endif + +endif + diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile new file mode 100644 index 0000000000..6935eb053e --- /dev/null +++ b/lib/diameter/src/Makefile @@ -0,0 +1,43 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk +else +include $(DIAMETER_TOP)/make/target.mk +include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk +endif + +# ---------------------------------------------------- +# Common Macros +# ---------------------------------------------------- + +include subdirs.mk + +SPECIAL_TARGETS = + +# ---------------------------------------------------- +# Default Subdir Targets +# ---------------------------------------------------- +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/otp_subdir.mk +else +include $(DIAMETER_TOP)/make/subdir.mk +endif +#include ../make/subdir.mk diff --git a/lib/diameter/src/app/.gitignore b/lib/diameter/src/app/.gitignore new file mode 100644 index 0000000000..d388e61877 --- /dev/null +++ b/lib/diameter/src/app/.gitignore @@ -0,0 +1,6 @@ + +/diameter_gen_*.erl +/diameter_gen_*.hrl +/depend.mk +/diameter.mk + diff --git a/lib/diameter/src/app/Makefile b/lib/diameter/src/app/Makefile new file mode 100644 index 0000000000..6de220d282 --- /dev/null +++ b/lib/diameter/src/app/Makefile @@ -0,0 +1,199 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/target.mk +EBIN = ../../ebin +include $(ERL_TOP)/make/$(TARGET)/otp.mk +else +include $(DIAMETER_TOP)/make/target.mk +EBIN = ../../ebin +include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk +endif + + + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- + +include ../../vsn.mk + +VSN=$(DIAMETER_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- + +RELSYSDIR = $(RELEASE_PATH)/lib/diameter-$(VSN) + +INCDIR = ../../include + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +include modules.mk + +SPEC_ERL_FILES = \ + $(SPEC_FILES:%.dia=%.erl) + +SPEC_HRL_FILES = \ + $(SPEC_FILES:%.dia=%.hrl) + +APP_MODULES = \ + $(MODULES) \ + $(SPEC_FILES:%.dia=%) + +TARGET_FILES = \ + $(APP_MODULES:%=$(EBIN)/%.$(EMULATOR)) \ + $(APP_TARGET) \ + $(APPUP_TARGET) + +ESCRIPT_FILES = \ + ../../bin/diameterc + +APP_FILE = diameter.app +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +APPUP_FILE = diameter.appup +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug +endif + +include diameter.mk + +ERL_COMPILE_FLAGS += \ + $(DIAMETER_ERL_COMPILE_FLAGS) \ + -I$(INCDIR) + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug: + @$(MAKE) TYPE=debug opt + +opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) $(SPEC_ERL_FILES) $(SPEC_HRL_FILES) + rm -f $(APP_TARGET) $(APPUP_TARGET) + rm -f errs core *~ diameter_gen_*.forms diameter_gen_*.spec + rm -f depend.mk + +docs: + +info: + @echo "" + @echo "SPEC_FILES = $(FILES)" + @echo "MODULES = $(MODULES)" + @echo "" + @echo "EXTERNAL_HRL_FILES = $(EXTERNAL_HRL_FILES)" + @echo "INTERNAL_HRL_FILES = $(INTERNAL_HRL_FILES)" + @echo "" + @echo "EXAMPLE_FILES = $(EXAMPLE_FILES)" + @echo "" + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +# Generate the app file and then modules into in. This shouldn't know +# about ../{compiler,transport} but good enough for now. +$(APP_TARGET): $(APP_SRC) \ + ../../vsn.mk \ + modules.mk \ + ../compiler/modules.mk \ + ../transport/modules.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + M=`echo $(APP_MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \ + echo "/%APP_MODULES%/s//$$M/;w;q" | tr ';' '\n' \ + | ed -s $@ + $(MAKE) -C ../compiler $(APP_TARGET) APP_TARGET=$(APP_TARGET) + $(MAKE) -C ../transport $(APP_TARGET) APP_TARGET=$(APP_TARGET) + +$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +compiler: + $(MAKE) -C ../$@ + +app: $(APP_TARGET) $(APPUP_TARGET) + +# erl/hrl from application spec +diameter_gen_%.erl diameter_gen_%.hrl: diameter_gen_%.dia + ../../bin/diameterc -i $(EBIN) -o $(@D) $< + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/otp_release_targets.mk +else +include $(DIAMETER_TOP)/make/release_targets.mk +endif + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/bin + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src/app + $(INSTALL_DIR) $(RELSYSDIR)/include + $(INSTALL_DIR) $(RELSYSDIR)/examples + $(INSTALL_SCRIPT) $(ESCRIPT_FILES) $(RELSYSDIR)/bin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(MODULES:%=%.erl) $(SPEC_ERL_FILES) $(RELSYSDIR)/src/app + $(INSTALL_DATA) $(SPEC_FILES) $(RELSYSDIR)/src/app + $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/app + $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(SPEC_HRL_FILES) $(RELSYSDIR)/include + $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples + +release_docs_spec: + +# ---------------------------------------------------- +# Dependencies +# ---------------------------------------------------- + +depend: depend.mk + +# Generate dependencies makefile. It's assumed that the compile target +# has already been made since it's currently not smart enough to not +# force a rebuild of those beams dependent on generated hrls, and this +# is a no-no at make release. +depend.mk: depend.sed $(MODULES:%=%.erl) Makefile + (for f in $(MODULES); do \ + sed -f $< $$f.erl | sed "s@/@/$$f@"; \ + done) \ + > $@ + +-include depend.mk + +.PRECIOUS: $(SPEC_ERL_FILES) $(SPEC_HRL_FILES) +.PHONY: app clean debug depend info opt compiler release_spec release_docs_spec diff --git a/lib/diameter/src/app/depend.sed b/lib/diameter/src/app/depend.sed new file mode 100644 index 0000000000..9df0133960 --- /dev/null +++ b/lib/diameter/src/app/depend.sed @@ -0,0 +1,31 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +# +# Extract include dependencies from .erl files. The output is massaged +# further in Makefile. +# + +/^-include/!d +/"diameter/!d + +s@^-include_lib("[^/]*@$(DIAMETER_TOP)@ +s@^-include("@@ +s@".*@@ +s@^@$(EBIN)/.$(EMULATOR): @ diff --git a/lib/diameter/src/app/diameter.app.src b/lib/diameter/src/app/diameter.app.src new file mode 100644 index 0000000000..119997953e --- /dev/null +++ b/lib/diameter/src/app/diameter.app.src @@ -0,0 +1,28 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +{application, diameter, + [{description, "Diameter protocol"}, + {vsn, "%VSN%"}, + {modules, [%APP_MODULES%,%COMPILER_MODULES%,%TRANSPORT_MODULES%]}, + {registered, []}, + {applications, [stdlib, kernel]}, + {env, []}, + {mod, {diameter_app, []}} + ]}. diff --git a/lib/diameter/src/app/diameter.appup.src b/lib/diameter/src/app/diameter.appup.src new file mode 100644 index 0000000000..2b96153575 --- /dev/null +++ b/lib/diameter/src/app/diameter.appup.src @@ -0,0 +1,27 @@ +%% This is an -*- erlang -*- file. +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +{"%VSN%", + [ + ], + [ + ] +}. + diff --git a/lib/diameter/src/app/diameter.erl b/lib/diameter/src/app/diameter.erl new file mode 100644 index 0000000000..2f721421d8 --- /dev/null +++ b/lib/diameter/src/app/diameter.erl @@ -0,0 +1,190 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter). + +%% Configuration. +-export([start_service/2, + stop_service/1, + add_transport/2, + remove_transport/2, + subscribe/1, + unsubscribe/1]). + +%% Traffic. +-export([session_id/1, + origin_state_id/0, + call/3, + call/4]). + +%% Information. +-export([services/0, + service_info/2]). + +%% Start/stop the application. In a "real" application this should +%% typically be a consequence of specifying diameter in a release file +%% rather than by calling start/stop explicitly. +-export([start/0, + stop/0]). + +-include("diameter_internal.hrl"). +-include("diameter_types.hrl"). + +%%% -------------------------------------------------------------------------- +%%% start/0 +%%% -------------------------------------------------------------------------- + +-spec start() + -> ok + | {error, term()}. + +start() -> + application:start(?APPLICATION). + +%%% -------------------------------------------------------------------------- +%%% stop/0 +%%% -------------------------------------------------------------------------- + +-spec stop() + -> ok + | {error, term()}. + +stop() -> + application:stop(?APPLICATION). + +%%% -------------------------------------------------------------------------- +%%% start_service/2 +%%% -------------------------------------------------------------------------- + +-spec start_service(service_name(), [service_opt()]) + -> ok + | {error, term()}. + +start_service(SvcName, Opts) + when is_list(Opts) -> + diameter_config:start_service(SvcName, Opts). + +%%% -------------------------------------------------------------------------- +%%% stop_service/1 +%%% -------------------------------------------------------------------------- + +-spec stop_service(service_name()) + -> ok + | {error, term()}. + +stop_service(SvcName) -> + diameter_config:stop_service(SvcName). + +%%% -------------------------------------------------------------------------- +%%% services/0 +%%% -------------------------------------------------------------------------- + +-spec services() + -> [service_name()]. + +services() -> + [Name || {Name, _} <- diameter_service:services()]. + +%%% -------------------------------------------------------------------------- +%%% service_info/2 +%%% -------------------------------------------------------------------------- + +-spec service_info(service_name(), atom() | [atom()]) + -> any(). + +service_info(SvcName, Option) -> + diameter_service:info(SvcName, Option). + +%%% -------------------------------------------------------------------------- +%%% add_transport/3 +%%% -------------------------------------------------------------------------- + +-spec add_transport(service_name(), {listen|connect, [transport_opt()]}) + -> {ok, transport_ref()} + | {error, term()}. + +add_transport(SvcName, {T, Opts} = Cfg) + when is_list(Opts), (T == connect orelse T == listen) -> + diameter_config:add_transport(SvcName, Cfg). + +%%% -------------------------------------------------------------------------- +%%% remove_transport/2 +%%% -------------------------------------------------------------------------- + +-spec remove_transport(service_name(), transport_pred()) + -> ok | {error, term()}. + +remove_transport(SvcName, Pred) -> + diameter_config:remove_transport(SvcName, Pred). + +%%% -------------------------------------------------------------------------- +%%% # subscribe(SvcName) +%%% +%%% Description: Subscribe to #diameter_event{} messages for the specified +%%% service. +%%% -------------------------------------------------------------------------- + +-spec subscribe(service_name()) + -> true. + +subscribe(SvcName) -> + diameter_service:subscribe(SvcName). + +%%% -------------------------------------------------------------------------- +%%% # unsubscribe(SvcName) +%%% -------------------------------------------------------------------------- + +-spec unsubscribe(service_name()) + -> true. + +unsubscribe(SvcName) -> + diameter_service:unsubscribe(SvcName). + +%%% ---------------------------------------------------------- +%%% # session_id/1 +%%% ---------------------------------------------------------- + +-spec session_id('DiameterIdentity'()) + -> 'OctetString'(). + +session_id(Ident) -> + diameter_session:session_id(Ident). + +%%% ---------------------------------------------------------- +%%% # origin_state_id/0 +%%% ---------------------------------------------------------- + +-spec origin_state_id() + -> 'Unsigned32'(). + +origin_state_id() -> + diameter_session:origin_state_id(). + +%%% -------------------------------------------------------------------------- +%%% # call/[34] +%%% -------------------------------------------------------------------------- + +-spec call(service_name(), app_alias(), any(), [call_opt()]) + -> any(). + +call(SvcName, App, Message, Options) -> + diameter_service:call(SvcName, {alias, App}, Message, Options). + +call(SvcName, App, Message) -> + call(SvcName, App, Message, []). diff --git a/lib/diameter/src/app/diameter.mk.in b/lib/diameter/src/app/diameter.mk.in new file mode 100644 index 0000000000..c161064303 --- /dev/null +++ b/lib/diameter/src/app/diameter.mk.in @@ -0,0 +1,47 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +DIAMETER_TOP = @DIAMETER_TOP@ + +# ifneq ($(PREFIX),) +# ifeq ($(TESTROOT),) +# TESTROOT = $(PREFIX) +# endif +# endif + +ifeq ($(USE_DIAMETER_TEST_CODE), true) +ERL_COMPILE_FLAGS += -DDIAMETER_TEST_CODE=mona_lisa_spelar_doom +endif + +ifeq ($(USE_DIAMETER_HIPE), true) +ERL_COMPILE_FLAGS += +native +endif + +ifeq ($(WARN_UNUSED_WARS), true) +ERL_COMPILE_FLAGS += +warn_unused_vars +endif + +DIAMETER_APP_VSN_COMPILE_FLAGS = \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,$(APP_VSN)}' + +DIAMETER_ERL_COMPILE_FLAGS += \ + -pa $(DIAMETER_TOP)/ebin \ + $(DIAMETER_APP_VSN_COMPILE_FLAGS) + diff --git a/lib/diameter/src/app/diameter_app.erl b/lib/diameter/src/app/diameter_app.erl new file mode 100644 index 0000000000..600f7ff04d --- /dev/null +++ b/lib/diameter/src/app/diameter_app.erl @@ -0,0 +1,36 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_app). + +-behaviour(application). + +%% application callbacks +-export([start/2, + stop/1]). + +%% start/2 + +start(_Type, _Args) -> + diameter_sup:start_link(). + +%% stop/1 + +stop(_) -> + ok. diff --git a/lib/diameter/src/app/diameter_callback.erl b/lib/diameter/src/app/diameter_callback.erl new file mode 100644 index 0000000000..fcf9a8fc1e --- /dev/null +++ b/lib/diameter/src/app/diameter_callback.erl @@ -0,0 +1,91 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% A minimal application callback module. +%% + +-module(diameter_callback). + +-export([peer_up/3, + peer_down/3, + pick_peer/4, + prepare_request/3, + prepare_retransmit/3, + handle_request/3, + handle_answer/4, + handle_error/4]). + +-include_lib("diameter/include/diameter.hrl"). + +%%% ---------------------------------------------------------- +%%% # peer_up/3 +%%% ---------------------------------------------------------- + +peer_up(_Svc, _Peer, State) -> + State. + +%%% ---------------------------------------------------------- +%%% # peer_down/3 +%%% ---------------------------------------------------------- + +peer_down(_SvcName, _Peer, State) -> + State. + +%%% ---------------------------------------------------------- +%%% # pick_peer/4 +%%% ---------------------------------------------------------- + +pick_peer([Peer|_], _, _SvcName, _State) -> + {ok, Peer}. + +%%% ---------------------------------------------------------- +%%% # prepare_request/3 +%%% ---------------------------------------------------------- + +prepare_request(Pkt, _SvcName, _Peer) -> + Pkt. + +%%% ---------------------------------------------------------- +%%% # prepare_retransmit/3 +%%% ---------------------------------------------------------- + +prepare_retransmit(Pkt, _SvcName, _Peer) -> + Pkt. + +%%% ---------------------------------------------------------- +%%% # handle_request/3 +%%% ---------------------------------------------------------- + +handle_request(_Pkt, _SvcName, _Peer) -> + discard. + +%%% ---------------------------------------------------------- +%%% # handle_answer/4 +%%% ---------------------------------------------------------- + +handle_answer(#diameter_packet{msg = Ans}, _Req, _SvcName, _Peer) -> + {ok, Ans}. + +%%% --------------------------------------------------------------------------- +%%% # handle_error/4 +%%% --------------------------------------------------------------------------- + +handle_error(Reason, _Req, _SvcName, _Peer) -> + {error, Reason}. diff --git a/lib/diameter/src/app/diameter_capx.erl b/lib/diameter/src/app/diameter_capx.erl new file mode 100644 index 0000000000..aa5318e79d --- /dev/null +++ b/lib/diameter/src/app/diameter_capx.erl @@ -0,0 +1,388 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This module builds CER and CEA records for use during capabilities +%% exchange. All of a CER/CEA is built from AVP values configured on +%% the service in question but values for Supported-Vendor-Id, +%% Vendor-Specific-Application-Id, Auth-Application-Id and +%% Acct-Application-id are also obtained using an older method that +%% remains only for backwards compatibility. With this method, each +%% dictionary module was required to export a cer/0 that returned a +%% diameter_base_CER record (or corresponding list, although the list +%% is also a later addition). Each returned CER contributes its member +%% values for the aforementioned four AVPs to the resulting CER, with +%% remaining AVP's either unspecified or identical to those configured +%% on the service. Auth-Application-Id and Acct-Application-id were +%% originally treated a little differently, each callback being +%% required to return either no value of the same value as the other +%% callbacks, but this coupled the callback modules unnecessarily. (A +%% union is backwards compatible to boot.) +%% +%% Values obtained from the service and callbacks are all included +%% when building a CER. Older code with only callback can continue to +%% use them, newer code should probably stick to service configuration +%% (since this is more explicit) or mix at their own peril. +%% +%% The cer/0 callback is now undocumented (despite never being fully +%% documented to begin with) and should be considered deprecated even +%% by those poor souls still using it. +%% + +-module(diameter_capx). + +-export([build_CER/1, + recv_CER/2, + recv_CEA/2, + make_caps/2]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). +-include("diameter_types.hrl"). +-include("diameter_gen_base_rfc3588.hrl"). + +-define(SUCCESS, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_SUCCESS'). +-define(NOAPP, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_NO_COMMON_APPLICATION'). +-define(NOSECURITY, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_NO_COMMON_SECURITY'). + +-define(NO_INBAND_SECURITY, 0). + +%% =========================================================================== + +-type tried(T) :: {ok, T} | {error, {term(), list()}}. + +-spec build_CER(#diameter_caps{}) + -> tried(#diameter_base_CER{}). + +build_CER(Caps) -> + try_it([fun bCER/1, Caps]). + +-spec recv_CER(#diameter_base_CER{}, #diameter_service{}) + -> tried({['Unsigned32'()], #diameter_caps{}, #diameter_base_CEA{}}). + +recv_CER(CER, Svc) -> + try_it([fun rCER/2, CER, Svc]). + +-spec recv_CEA(#diameter_base_CEA{}, #diameter_service{}) + -> tried({['Unsigned32'()], #diameter_caps{}}). + +recv_CEA(CEA, Svc) -> + try_it([fun rCEA/2, CEA, Svc]). + +make_caps(Caps, Opts) -> + try_it([fun mk_caps/2, Caps, Opts]). + +%% =========================================================================== +%% =========================================================================== + +try_it([Fun | Args]) -> + try apply(Fun, Args) of + T -> {ok, T} + catch + throw: ?FAILURE(Reason) -> {error, {Reason, Args}} + end. + +%% mk_caps/2 + +mk_caps(Caps0, Opts) -> + {Caps, _} = lists:foldl(fun set_cap/2, + {Caps0, #diameter_caps{_ = false}}, + Opts), + Caps. + +-define(SC(K,F), + set_cap({K, Val}, {Caps, #diameter_caps{F = false} = C}) -> + {Caps#diameter_caps{F = cap(K, Val)}, C#diameter_caps{F = true}}). + +?SC('Origin-Host', origin_host); +?SC('Origin-Realm', origin_realm); +?SC('Host-IP-Address', host_ip_address); +?SC('Vendor-Id', vendor_id); +?SC('Product-Name', product_name); +?SC('Origin-State-Id', origin_state_id); +?SC('Supported-Vendor-Id', supported_vendor_id); +?SC('Auth-Application-Id', auth_application_id); +?SC('Inband-Security-Id', inband_security_id); +?SC('Acct-Application-Id', acct_application_id); +?SC('Vendor-Specific-Application-Id', vendor_specific_application_id); +?SC('Firmware-Revision', firmware_revision); + +set_cap({Key, _}, _) -> + ?THROW({duplicate, Key}). + +cap(K, V) when K == 'Origin-Host'; + K == 'Origin-Realm'; + K == 'Vendor-Id'; + K == 'Product-Name' -> + V; + +cap('Host-IP-Address', Vs) + when is_list(Vs) -> + lists:map(fun ipaddr/1, Vs); + +cap('Firmware-Revision', V) -> + [V]; + +%% Not documented but accept it as long as it's what we support. +cap('Inband-Security-Id', [0] = Vs) -> %% NO_INBAND_SECURITY + Vs; + +cap(K, Vs) when K /= 'Inband-Security-Id', is_list(Vs) -> + Vs; + +cap(K, V) -> + ?THROW({invalid, K, V}). + +ipaddr(A) -> + try + diameter_lib:ipaddr(A) + catch + error: {invalid_address, _} = T -> + ?THROW(T) + end. + +%% bCER/1 +%% +%% Build a CER record to send to a remote peer. + +bCER(#diameter_caps{origin_host = Host, + origin_realm = Realm, + host_ip_address = Addrs, + vendor_id = Vid, + product_name = Name, + origin_state_id = OSI, + supported_vendor_id = SVid, + auth_application_id = AuId, + acct_application_id = AcId, + vendor_specific_application_id = VSA, + firmware_revision = Rev}) -> + #diameter_base_CER{'Origin-Host' = Host, + 'Origin-Realm' = Realm, + 'Host-IP-Address' = Addrs, + 'Vendor-Id' = Vid, + 'Product-Name' = Name, + 'Origin-State-Id' = OSI, + 'Supported-Vendor-Id' = SVid, + 'Auth-Application-Id' = AuId, + 'Acct-Application-Id' = AcId, + 'Vendor-Specific-Application-Id' = VSA, + 'Firmware-Revision' = Rev}. + +%% rCER/2 +%% +%% Build a CEA record to send to a remote peer in response to an +%% incoming CER. RFC 3588 gives no guidance on what should be sent +%% here: should we advertise applications that the peer hasn't sent in +%% its CER (aside from the relay application) or not? If we send +%% applications that the peer hasn't advertised then the peer may have +%% to be aware of the possibility. If we don't then we just look like +%% a server that supports a subset (possibly) of what the client +%% advertised, so this feels like the path of least incompatibility. +%% However, the current draft standard (draft-ietf-dime-rfc3588bis-26, +%% expires 24 July 2011) says this in section 5.3, Capabilities +%% Exchange: +%% +%% The receiver of the Capabilities-Exchange-Request (CER) MUST +%% determine common applications by computing the intersection of its +%% own set of supported Application Id against all of the application +%% identifier AVPs (Auth-Application-Id, Acct-Application-Id and Vendor- +%% Specific-Application-Id) present in the CER. The value of the +%% Vendor-Id AVP in the Vendor-Specific-Application-Id MUST NOT be used +%% during computation. The sender of the Capabilities-Exchange-Answer +%% (CEA) SHOULD include all of its supported applications as a hint to +%% the receiver regarding all of its application capabilities. +%% +%% Both RFC and the draft also say this: +%% +%% The receiver only issues commands to its peers that have advertised +%% support for the Diameter application that defines the command. A +%% Diameter node MUST cache the supported applications in order to +%% ensure that unrecognized commands and/or AVPs are not unnecessarily +%% sent to a peer. +%% +%% That is, each side sends all of its capabilities and is responsible for +%% not sending commands that the peer doesn't support. + +%% TODO: Make it an option to send only common applications in CEA to +%% allow backwards compatibility, and also because there are likely +%% servers that expect this. Or maybe a callback. + +%% 6.10. Inband-Security-Id AVP +%% +%% NO_INBAND_SECURITY 0 +%% This peer does not support TLS. This is the default value, if the +%% AVP is omitted. + +rCER(CER, #diameter_service{capabilities = LCaps} = Svc) -> + #diameter_base_CER{'Inband-Security-Id' = RIS} + = CER, + #diameter_base_CEA{} + = CEA + = cea_from_cer(bCER(LCaps)), + + RCaps = capx_to_caps(CER), + SApps = common_applications(LCaps, RCaps, Svc), + + {SApps, + RCaps, + build_CEA([] == SApps, + RIS, + lists:member(?NO_INBAND_SECURITY, RIS), + CEA#diameter_base_CEA{'Result-Code' = ?SUCCESS, + 'Inband-Security-Id' = []})}. + +%% TODO: 5.3 of RFC3588 says we MUST return DIAMETER_NO_COMMON_APPLICATION +%% in the CEA and SHOULD disconnect the transport. However, we have +%% no way to guarantee the send before disconnecting. + +build_CEA(true, _, _, CEA) -> + CEA#diameter_base_CEA{'Result-Code' = ?NOAPP}; +build_CEA(false, [_|_], false, CEA) -> + CEA#diameter_base_CEA{'Result-Code' = ?NOSECURITY}; +build_CEA(false, [_|_], true, CEA) -> + CEA#diameter_base_CEA{'Inband-Security-Id' = [?NO_INBAND_SECURITY]}; +build_CEA(false, [], false, CEA) -> + CEA. + +%% cea_from_cer/1 + +cea_from_cer(#diameter_base_CER{} = CER) -> + lists:foldl(fun(F,A) -> to_cea(CER, F, A) end, + #diameter_base_CEA{}, + record_info(fields, diameter_base_CER)). + +to_cea(CER, Field, CEA) -> + try ?BASE:'#info-'(diameter_base_CEA, {index, Field}) of + N -> + setelement(N, CEA, ?BASE:'#get-'(Field, CER)) + catch + error: _ -> + CEA + end. + +%% rCEA/2 + +rCEA(CEA, #diameter_service{capabilities = LCaps} = Svc) + when is_record(CEA, diameter_base_CEA) -> + #diameter_base_CEA{'Result-Code' = RC} + = CEA, + + RC == ?SUCCESS orelse ?THROW({'Result-Code', RC}), + + RCaps = capx_to_caps(CEA), + SApps = common_applications(LCaps, RCaps, Svc), + + [] == SApps andalso ?THROW({no_common_apps, LCaps, RCaps}), + + {SApps, RCaps}; + +rCEA(CEA, _Svc) -> + ?THROW({invalid, CEA}). + +%% capx_to_caps/1 + +capx_to_caps(#diameter_base_CEA{'Origin-Host' = OH, + 'Origin-Realm' = OR, + 'Host-IP-Address' = IP, + 'Vendor-Id' = VId, + 'Product-Name' = PN, + 'Origin-State-Id' = OSI, + 'Supported-Vendor-Id' = SV, + 'Auth-Application-Id' = Auth, + 'Inband-Security-Id' = IS, + 'Acct-Application-Id' = Acct, + 'Vendor-Specific-Application-Id' = VSA, + 'Firmware-Revision' = FR, + 'AVP' = X}) -> + #diameter_caps{origin_host = OH, + origin_realm = OR, + vendor_id = VId, + product_name = PN, + origin_state_id = OSI, + host_ip_address = IP, + supported_vendor_id = SV, + auth_application_id = Auth, + inband_security_id = IS, + acct_application_id = Acct, + vendor_specific_application_id = VSA, + firmware_revision = FR, + avp = X}; + +capx_to_caps(#diameter_base_CER{} = CER) -> + capx_to_caps(cea_from_cer(CER)). + +%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- + +%% common_applications/3 +%% +%% Identify the (local) applications to be supported on the connection +%% in question. + +common_applications(LCaps, RCaps, #diameter_service{applications = Apps}) -> + LA = app_union(LCaps), + RA = app_union(RCaps), + + lists:foldl(fun(I,A) -> ca(I, Apps, RA, A) end, [], LA). + +ca(Id, Apps, RA, Acc) -> + Relay = lists:member(?APP_ID_RELAY, RA), + #diameter_app{alias = Alias} = find_app(Id, Apps), + tcons(Relay %% peer is a relay + orelse ?APP_ID_RELAY == Id %% we're a relay + orelse lists:member(Id, RA), %% app is supported by the peer + Id, + Alias, + Acc). +%% 5.3 of the RFC states that a peer advertising itself as a relay must +%% be interpreted as having common applications. + +%% Extract the list of all application identifiers from Auth-Application-Id, +%% Acct-Application-Id and Vendor-Specific-Application-Id. +app_union(#diameter_caps{auth_application_id = U, + acct_application_id = C, + vendor_specific_application_id = V}) -> + set_list(U ++ C ++ lists:flatmap(fun vsa_apps/1, V)). + +vsa_apps(#'diameter_base_Vendor-Specific-Application-Id' + {'Auth-Application-Id' = U, + 'Acct-Application-Id' = C}) -> + U ++ C; +vsa_apps(L) -> + Rec = ?BASE:'#new-'('diameter_base_Vendor-Specific-Application-Id', L), + vsa_apps(Rec). + +%% It's a configuration error for a locally advertised application not +%% to be represented in Apps. Don't just match on lists:keyfind/3 in +%% order to generate a more helpful error. +find_app(Id, Apps) -> + case lists:keyfind(Id, #diameter_app.id, Apps) of + #diameter_app{} = A -> + A; + false -> + ?THROW({app_not_configured, Id}) + end. + +set_list(L) -> + sets:to_list(sets:from_list(L)). + +tcons(true, K, V, Acc) -> + [{K,V} | Acc]; +tcons(false, _, _, Acc) -> + Acc. diff --git a/lib/diameter/src/app/diameter_codec.erl b/lib/diameter/src/app/diameter_codec.erl new file mode 100644 index 0000000000..f6cbde5446 --- /dev/null +++ b/lib/diameter/src/app/diameter_codec.erl @@ -0,0 +1,569 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_codec). + +-export([encode/2, + decode/2, + decode/3, + collect_avps/1, + decode_header/1, + sequence_numbers/1, + hop_by_hop_id/2, + msg_name/1, + msg_id/1]). + +%% Towards generated encoders (from diameter_gen.hrl). +-export([pack_avp/1, + pack_avp/2]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). + +-define(MASK(N,I), ((I) band (1 bsl (N)))). + +%% 0 1 2 3 +%% 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | Version | Message Length | +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | command flags | Command-Code | +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | Application-ID | +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | Hop-by-Hop Identifier | +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | End-to-End Identifier | +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | AVPs ... +%% +-+-+-+-+-+-+-+-+-+-+-+-+- + +%%% --------------------------------------------------------------------------- +%%% # encode/[2-4] +%%% --------------------------------------------------------------------------- + +encode(Mod, #diameter_packet{} = Pkt) -> + try + e(Mod, Pkt) + catch + error: Reason -> + %% Be verbose rather than letting the emulator truncate the + %% error report. + X = {Reason, ?STACK}, + diameter_lib:error_report(X, {?MODULE, encode, [Mod, Pkt]}), + exit(X) + end; + +encode(Mod, Msg) -> + Seq = diameter_session:sequence(), + Hdr = #diameter_header{version = ?DIAMETER_VERSION, + end_to_end_id = Seq, + hop_by_hop_id = Seq}, + encode(Mod, #diameter_packet{header = Hdr, + msg = Msg}). + +e(_, #diameter_packet{msg = [#diameter_header{} = Hdr | As]} = Pkt) -> + Avps = encode_avps(As), + Length = size(Avps) + 20, + + #diameter_header{version = Vsn, + cmd_code = Code, + application_id = Aid, + hop_by_hop_id = Hid, + end_to_end_id = Eid} + = Hdr, + + Flags = make_flags(0, Hdr), + + Pkt#diameter_packet{bin = <<Vsn:8, Length:24, + Flags:8, Code:24, + Aid:32, + Hid:32, + Eid:32, + Avps/binary>>}; + +e(Mod0, #diameter_packet{header = Hdr, msg = Msg} = Pkt) -> + #diameter_header{version = Vsn, + hop_by_hop_id = Hid, + end_to_end_id = Eid} + = Hdr, + + {Mod, MsgName} = rec2msg(Mod0, Msg), + {Code, Flags0, Aid} = msg_header(Mod, MsgName, Hdr), + Flags = make_flags(Flags0, Hdr), + + Avps = encode_avps(Mod, MsgName, values(Msg)), + Length = size(Avps) + 20, + + Pkt#diameter_packet{header = Hdr#diameter_header + {length = Length, + cmd_code = Code, + application_id = Aid, + is_request = 0 /= ?MASK(7, Flags), + is_proxiable = 0 /= ?MASK(6, Flags), + is_error = 0 /= ?MASK(5, Flags), + is_retransmitted = 0 /= ?MASK(4, Flags)}, + bin = <<Vsn:8, Length:24, + Flags:8, Code:24, + Aid:32, + Hid:32, + Eid:32, + Avps/binary>>}. + +%% make_flags/2 + +make_flags(Flags0, #diameter_header{is_request = R, + is_proxiable = P, + is_error = E, + is_retransmitted = T}) -> + {Flags, 3} = lists:foldl(fun(B,{F,N}) -> {mf(B,F,N), N-1} end, + {Flags0, 7}, + [R,P,E,T]), + Flags. + +mf(undefined, F, _) -> + F; +mf(B, F, N) -> %% reset the affected bit + (F bxor (F band (1 bsl N))) bor (bit(B) bsl N). + +bit(true) -> 1; +bit(false) -> 0. + +%% values/1 + +values([H|T]) + when is_atom(H) -> + T; +values(Avps) -> + Avps. + +%% encode_avps/3 + +%% Specifying values as a #diameter_avp list bypasses arity and other +%% checks: the values are expected to be already encoded and the AVP's +%% presented are simply sent. This is needed for relay agents, since +%% these have to be able to resend whatever comes. + +%% Message as a list of #diameter_avp{} ... +encode_avps(_, _, [#diameter_avp{} | _] = Avps) -> + encode_avps(reorder(Avps, [], Avps)); + +%% ... or as a tuple list or record. +encode_avps(Mod, MsgName, Values) -> + Mod:encode_avps(MsgName, Values). + +%% reorder/1 + +reorder([#diameter_avp{index = 0} | _] = Avps, Acc, _) -> + Avps ++ Acc; + +reorder([#diameter_avp{index = N} = A | Avps], Acc, _) + when is_integer(N) -> + lists:reverse(Avps, [A | Acc]); + +reorder([H | T], Acc, Avps) -> + reorder(T, [H | Acc], Avps); + +reorder([], Acc, _) -> + Acc. + +%% encode_avps/1 + +encode_avps(Avps) -> + list_to_binary(lists:map(fun pack_avp/1, Avps)). + +%% msg_header/3 + +msg_header(Mod, MsgName, Header) -> + {Code, Flags, ApplId} = h(Mod, MsgName, Header), + {Code, p(Flags, Header), ApplId}. + +%% 6.2 of 3588 requires the same 'P' bit on an answer as on the +%% request. + +p(Flags, #diameter_header{is_request = true, + is_proxiable = P}) -> + Flags bor choose(P, 2#01000000, 0); +p(Flags, _) -> + Flags. + +%% The header below is that of the incoming request being answered, +%% not of the answer (which hasn't been encoded yet). + +h(Mod, 'answer-message' = MsgName, Header) -> + ?BASE = Mod, + #diameter_header{is_request = true, + cmd_code = Code} + = Header, + {_, Flags, ApplId} = ?BASE:msg_header(MsgName), + {Code, Flags, ApplId}; + +h(Mod, MsgName, #diameter_header{is_request = true, + cmd_code = Code}) -> + {Code, _, _} = Mod:msg_header(MsgName); %% ensure Code + +h(Mod, MsgName, _) -> + Mod:msg_header(MsgName). + +%% rec2msg/2 + +rec2msg(_, ['answer-message' = M | _]) -> + {?BASE, M}; + +rec2msg(Mod, [MsgName|_]) + when is_atom(MsgName) -> + {Mod, MsgName}; + +rec2msg(Mod, Rec) -> + R = element(1, Rec), + A = 'answer-message', + case ?BASE:msg2rec(A) of + R -> + {?BASE, A}; + _ -> + {Mod, Mod:rec2msg(R)} + end. + +%%% --------------------------------------------------------------------------- +%%% # decode/2 +%%% --------------------------------------------------------------------------- + +%% Unsuccessfully decoded AVPs will be placed in #diameter_packet.errors. + +decode(Mod, Pkt) -> + decode(Mod:id(), Mod, Pkt). + +%% If we're a relay application then just extract the avp's without +%% any decoding of their data since we don't know the application in +%% question. +decode(?APP_ID_RELAY, _, #diameter_packet{} = Pkt) -> + case collect_avps(Pkt) of + {Bs, As} -> + Pkt#diameter_packet{avps = As, + errors = [Bs]}; + As -> + Pkt#diameter_packet{avps = As} + end; + +%% Otherwise decode using the dictionary. +decode(_, Mod, #diameter_packet{header = Hdr} = Pkt) + when is_atom(Mod) -> + #diameter_header{cmd_code = CmdCode, + is_request = IsRequest, + is_error = IsError} + = Hdr, + + {M, MsgName} = if IsError andalso not IsRequest -> + {?BASE, 'answer-message'}; + true -> + {Mod, Mod:msg_name(CmdCode, IsRequest)} + end, + + decode_avps(MsgName, M, Pkt, collect_avps(Pkt)); + +decode(Id, Mod, Bin) + when is_bitstring(Bin) -> + decode(Id, Mod, #diameter_packet{header = decode_header(Bin), bin = Bin}). + +decode_avps(MsgName, Mod, Pkt, {Bs, Avps}) -> %% invalid avp bits ... + ?LOG(invalid, Pkt#diameter_packet.bin), + #diameter_packet{errors = Failed} + = P + = decode_avps(MsgName, Mod, Pkt, Avps), + P#diameter_packet{errors = [Bs | Failed]}; + +decode_avps('', Mod, Pkt, Avps) -> %% unknown message ... + ?LOG(unknown, {Mod, Pkt#diameter_packet.header}), + Pkt#diameter_packet{errors = lists:reverse(Avps)}; +%% msg = undefined identifies this case. + +decode_avps(MsgName, Mod, Pkt, Avps) -> %% ... or not + {Rec, As, Failed} = Mod:decode_avps(MsgName, Avps), + ?LOGC([] /= Failed, failed, {Mod, Failed}), + Pkt#diameter_packet{msg = Rec, + errors = Failed, + avps = As}. + +%%% --------------------------------------------------------------------------- +%%% # decode_header/1 +%%% --------------------------------------------------------------------------- + +decode_header(<<Version:8, + MsgLength:24, + CmdFlags:1/binary, + CmdCode:24, + ApplicationId:32, + HopByHopId:32, + EndToEndId:32, + _/bitstring>>) -> + <<R:1, P:1, E:1, T:1, _:4>> + = CmdFlags, + %% 3588 (ch 3) says that reserved bits MUST be set to 0 and ignored + %% by the receiver. + + %% The RFC is quite unclear about the order of the bits in this + %% case. It writes + %% + %% 0 1 2 3 4 5 6 7 + %% +-+-+-+-+-+-+-+-+ + %% |R P E T r r r r| + %% +-+-+-+-+-+-+-+-+ + %% + %% in defining these but the scale refers to the (big endian) + %% transmission order, first to last, not the bit order. That is, + %% R is the high order bit. It's odd that a standard reserves + %% low-order bit rather than high-order ones. + + #diameter_header{version = Version, + length = MsgLength, + cmd_code = CmdCode, + application_id = ApplicationId, + hop_by_hop_id = HopByHopId, + end_to_end_id = EndToEndId, + is_request = 1 == R, + is_proxiable = 1 == P, + is_error = 1 == E, + is_retransmitted = 1 == T}; + +decode_header(_) -> + false. + +%%% --------------------------------------------------------------------------- +%%% # sequence_numbers/1 +%%% --------------------------------------------------------------------------- + +%% The End-To-End identifier must be unique for at least 4 minutes. We +%% maintain a 24-bit wraparound counter, and add an 8-bit persistent +%% wraparound counter. The 8-bit counter is incremented each time the +%% system is restarted. + +sequence_numbers(#diameter_packet{bin = Bin}) + when is_binary(Bin) -> + sequence_numbers(Bin); + +sequence_numbers(#diameter_packet{header = #diameter_header{} = H}) -> + sequence_numbers(H); + +sequence_numbers(#diameter_header{hop_by_hop_id = H, + end_to_end_id = E}) -> + {H,E}; + +sequence_numbers(<<_:12/binary, H:32, E:32, _/binary>>) -> + {H,E}. + +%%% --------------------------------------------------------------------------- +%%% # hop_by_hop_id/2 +%%% --------------------------------------------------------------------------- + +hop_by_hop_id(Id, <<H:12/binary, _:32, T/binary>>) -> + <<H/binary, Id:32, T/binary>>. + +%%% --------------------------------------------------------------------------- +%%% # msg_name/1 +%%% --------------------------------------------------------------------------- + +msg_name(#diameter_header{application_id = ?APP_ID_COMMON, + cmd_code = C, + is_request = R}) -> + ?BASE:msg_name(C,R); + +msg_name(Hdr) -> + msg_id(Hdr). + +%% Note that messages in different applications could have the same +%% name. + +%%% --------------------------------------------------------------------------- +%%% # msg_id/1 +%%% --------------------------------------------------------------------------- + +msg_id(#diameter_packet{msg = [#diameter_header{} = Hdr | _]}) -> + msg_id(Hdr); + +msg_id(#diameter_packet{header = #diameter_header{} = Hdr}) -> + msg_id(Hdr); + +msg_id(#diameter_header{application_id = A, + cmd_code = C, + is_request = R}) -> + {A, C, if R -> 1; true -> 0 end}; + +msg_id(<<_:32, Rbit:1, _:7, CmdCode:24, ApplId:32, _/bitstring>>) -> + {ApplId, CmdCode, Rbit}. + +%%% --------------------------------------------------------------------------- +%%% # collect_avps/1 +%%% --------------------------------------------------------------------------- + +%% Note that the returned list of AVP's is reversed relative to their +%% order in the binary. Note also that grouped avp's aren't unraveled, +%% only those at the top level. + +collect_avps(#diameter_packet{bin = Bin}) -> + <<_:20/binary, Avps/bitstring>> = Bin, + collect_avps(Avps); + +collect_avps(Bin) -> + collect_avps(Bin, 0, []). + +collect_avps(<<>>, _, Acc) -> + Acc; +collect_avps(Bin, N, Acc) -> + try split_avp(Bin) of + {Rest, AVP} -> + collect_avps(Rest, N+1, [AVP#diameter_avp{index = N} | Acc]) + catch + ?FAILURE(_) -> + {Bin, Acc} + end. + +%% 0 1 2 3 +%% 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | AVP Code | +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% |V M P r r r r r| AVP Length | +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | Vendor-ID (opt) | +%% +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +%% | Data ... +%% +-+-+-+-+-+-+-+-+ + +%% split_avp/1 + +split_avp(Bin) -> + 8 =< size(Bin) orelse ?THROW(truncated_header), + + <<Code:32, Flags:1/binary, Length:24, Rest/bitstring>> + = Bin, + + DataSize = Length - 8, % size(Code+Flags+Length) = 8 octets + PadSize = (4 - (DataSize rem 4)) rem 4, + + DataSize + PadSize =< size(Rest) + orelse ?THROW(truncated_data), + + <<Data:DataSize/binary, _:PadSize/binary, R/bitstring>> + = Rest, + <<Vbit:1, Mbit:1, Pbit:1, _Reserved:5>> + = Flags, + + 0 == Vbit orelse 4 =< size(Data) + orelse ?THROW(truncated_vendor_id), + + {Vid, D} = vid(Vbit, Data), + {R, #diameter_avp{code = Code, + vendor_id = Vid, + is_mandatory = 1 == Mbit, + need_encryption = 1 == Pbit, + data = D}}. + +%% The RFC is a little misleading when stating that OctetString is +%% padded to a 32-bit boundary while other types align naturally. All +%% other types are already multiples of 32 bits so there's no need to +%% distinguish between types here. Any invalid lengths will result in +%% decode error in diameter_types. + +vid(1, <<Vid:32, Data/bitstring>>) -> + {Vid, Data}; +vid(0, Data) -> + {undefined, Data}. + +%%% --------------------------------------------------------------------------- +%%% # pack_avp/1 +%%% --------------------------------------------------------------------------- + +%% The normal case here is data as an #diameter_avp{} list or an +%% iolist, which are the cases that generated codec modules use. The +%% other case is as a convenience in the relay case in which the +%% dictionary doesn't know about specific AVP's. + +%% Grouped AVP whose components need packing ... +pack_avp(#diameter_avp{data = [#diameter_avp{} | _] = Avps} = A) -> + pack_avp(A#diameter_avp{data = encode_avps(Avps)}); + +%% ... data as a type/value tuple, possibly with header data, ... +pack_avp(#diameter_avp{data = {Type, Value}} = A) + when is_atom(Type) -> + pack_avp(A#diameter_avp{data = diameter_types:Type(encode, Value)}); +pack_avp(#diameter_avp{data = {{_,_,_} = T, {Type, Value}}}) -> + pack_avp(T, iolist_to_binary(diameter_types:Type(encode, Value))); +pack_avp(#diameter_avp{data = {{_,_,_} = T, Bin}}) + when is_binary(Bin) -> + pack_avp(T, Bin); +pack_avp(#diameter_avp{data = {Dict, Name, Value}} = A) -> + {Code, _Flags, Vid} = Hdr = Dict:avp_header(Name), + {Name, Type} = Dict:avp_name(Code, Vid), + pack_avp(A#diameter_avp{data = {Hdr, {Type, Value}}}); + +%% ... or as an iolist. +pack_avp(#diameter_avp{code = Code, + vendor_id = V, + is_mandatory = M, + need_encryption = P, + data = Data}) -> + Flags = lists:foldl(fun flag_avp/2, 0, [{V /= undefined, 2#10000000}, + {M, 2#01000000}, + {P, 2#00100000}]), + pack_avp({Code, Flags, V}, iolist_to_binary(Data)). + +flag_avp({true, B}, F) -> + F bor B; +flag_avp({false, _}, F) -> + F. + +%%% --------------------------------------------------------------------------- +%%% # pack_avp/2 +%%% --------------------------------------------------------------------------- + +pack_avp({Code, Flags, VendorId}, Bin) + when is_binary(Bin) -> + Sz = size(Bin), + pack_avp(Code, Flags, VendorId, Sz, pad(Sz rem 4, Bin)). + +pad(0, Bin) -> + Bin; +pad(N, Bin) -> + P = 8*(4-N), + <<Bin/binary, 0:P>>. +%% Note that padding is not included in the length field as mandated by +%% the RFC. + +%% pack_avp/5 +%% +%% Prepend the vendor id as required. + +pack_avp(Code, Flags, Vid, Sz, Bin) + when 0 == Flags band 2#10000000 -> + undefined = Vid, %% sanity check + pack_avp(Code, Flags, Sz, Bin); + +pack_avp(Code, Flags, Vid, Sz, Bin) -> + pack_avp(Code, Flags, Sz+4, <<Vid:32, Bin/binary>>). + +%% pack_avp/4 + +pack_avp(Code, Flags, Sz, Bin) -> + Length = Sz + 8, + <<Code:32, Flags:8, Length:24, Bin/binary>>. + +%% =========================================================================== + +choose(true, X, _) -> X; +choose(false, _, X) -> X. diff --git a/lib/diameter/src/app/diameter_config.erl b/lib/diameter/src/app/diameter_config.erl new file mode 100644 index 0000000000..42c70890b3 --- /dev/null +++ b/lib/diameter/src/app/diameter_config.erl @@ -0,0 +1,681 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This module writes service/transport configuration to the table +%% diameter_config, so that the config will survive service process +%% death, and then turns it into calls towards diameter_service. It +%% also restarts services upon their death. +%% +%% The table diameter_config is only written here while +%% diameter_service reads. This is all somewhat after the fact. Once +%% upon a time the config was only stored in the service process, +%% causing much grief if these processes died (which they did with +%% some regularity) and one was forced to reconfigure. This module was +%% then inserted into the service start in order to keep a more +%% permanent record of the config. That said, service processes are +%% now much more robust than they once were and crashing is a thing of +%% the past. +%% + +-module(diameter_config). +-compile({no_auto_import, [monitor/2]}). + +-behaviour(gen_server). + +-export([start_service/2, + stop_service/1, + add_transport/2, + remove_transport/2, + have_transport/2, + lookup/1]). + +%% child server start +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, + terminate/2, + handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3]). + +%% diameter_sync requests. +-export([sync/1]). + +%% debug +-export([state/0, + uptime/0]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). + +%% Server state. +-record(state, {id = now()}). + +%% Registered name of the server. +-define(SERVER, ?MODULE). + +%% Table config is written to. +-define(TABLE, ?MODULE). + +%% Workaround for dialyzer's lack of understanding of match specs. +-type match(T) + :: T | '_' | '$1' | '$2' | '$3' | '$4'. + +%% Configuration records in ?TABLE. + +-record(service, + {name, + rec :: match(#diameter_service{}), + options :: match(list())}). + +-record(transport, + {service, %% name + ref = make_ref() :: match(reference()), + type :: match(connect | listen), + options :: match(list())}). + +%% Monitor entry in ?TABLE. +-record(monitor, {mref = make_ref() :: reference(), + service}). %% name + +%% Time to lay low before restarting a dead service. +-define(RESTART_SLEEP, 2000). + +%% A minimal diameter_caps for checking for valid capabilities values. +-define(EXAMPLE_CAPS, + #diameter_caps{origin_host = "TheHost", + origin_realm = "TheRealm", + host_ip_address = [{127,0,0,1}], + vendor_id = 42, + product_name = "TheProduct"}). + +-define(VALUES(Rec), tl(tuple_to_list(Rec))). + +%%% The return values below assume the server diameter_config is started. +%%% The functions will exit if it isn't. + +%% -------------------------------------------------------------------------- +%% # start_service(SvcName, Opts) +%% +%% Output: ok | {error, Reason} +%% -------------------------------------------------------------------------- + +start_service(SvcName, Opts) + when is_list(Opts) -> + start_rc(sync(SvcName, {start_service, SvcName, Opts})). + +start_rc({ok = T, _Pid}) -> + T; +start_rc({error, _} = No) -> + No; +start_rc(timeout) -> + {error, application_not_started}. + +%% -------------------------------------------------------------------------- +%% # stop_service(SvcName) +%% +%% Output: ok +%% -------------------------------------------------------------------------- + +stop_service(SvcName) -> + sync(SvcName, {stop_service, SvcName}). + +%% -------------------------------------------------------------------------- +%% # add_transport(SvcName, {Type, Opts}) +%% +%% Input: Type = connect | listen +%% +%% Output: {ok, Ref} | {error, Reason} +%% -------------------------------------------------------------------------- + +add_transport(SvcName, {T, Opts}) + when is_list(Opts), (T == connect orelse T == listen) -> + sync(SvcName, {add, SvcName, T, Opts}). + +%% -------------------------------------------------------------------------- +%% # remove_transport(SvcName, Pred) +%% +%% Input: Pred = arity 3 fun on transport ref, connect|listen and Opts, +%% returning true if the transport is to be removed, false if +%% not +%% | arity 2 fun on Ref and Opts only +%% | arity 1 fun on Opts only +%% | Opts matching all transports that have all of the specified +%% options +%% | Ref matching only the transport with this reference. +%% | {M,F,A} applied to Ref, connect|listen and Opts +%% | boolean() +%% +%% Output: ok | {error, Reason} +%% -------------------------------------------------------------------------- + +remove_transport(SvcName, Pred) -> + try + sync(SvcName, {remove, SvcName, pred(Pred)}) + catch + ?FAILURE(Reason) -> + {error, Reason} + end. + +pred(Pred) + when is_function(Pred, 3) -> + Pred; +pred(Pred) + when is_function(Pred, 2) -> + fun(R,_,O) -> Pred(R,O) end; +pred(Pred) + when is_function(Pred, 1) -> + fun(_,_,O) -> Pred(O) end; +pred(Opts) + when is_list(Opts) -> + fun(_,_,O) -> [] == Opts -- O end; +pred(Ref) + when is_reference(Ref) -> + fun(R,_,_) -> R == Ref end; +pred({M,F,A}) + when is_atom(M), is_atom(F), is_list(A) -> + fun(R,T,O) -> apply(M,F,[R,T,O|A]) end; +pred({Type, Pred}) -> %% backwards compatibility + P = pred(Pred), + fun(R,T,O) -> T == Type andalso P(R,T,O) end; +pred(B) + when is_boolean(B) -> + fun(_,_,_) -> B end; +pred(_) -> + ?THROW(pred). + +%% -------------------------------------------------------------------------- +%% # have_transport/2 +%% +%% Output: true | false +%% -------------------------------------------------------------------------- + +have_transport(SvcName, Ref) -> + member([{#transport{service = '$1', + ref = '$2', + _ = '_'}, + [{'andalso', {'=:=', '$1', {const, SvcName}}, + {'=:=', '$2', {const, Ref}}}], + [true]}]). + +%% -------------------------------------------------------------------------- +%% # lookup/1 +%% -------------------------------------------------------------------------- + +lookup(SvcName) -> + select([{#service{name = '$1', rec = '$2', options = '$3'}, + [{'=:=', '$1', {const, SvcName}}], + [{{'$1', '$2', '$3'}}]}, + {#transport{service = '$1', + ref = '$2', + type = '$3', + options = '$4'}, + [{'=:=', '$1', {const, SvcName}}], + [{{'$2', '$3', '$4'}}]}]). + +%% --------------------------------------------------------- +%% EXPORTED INTERNAL FUNCTIONS +%% --------------------------------------------------------- + +start_link() -> + ServerName = {local, ?SERVER}, + Module = ?MODULE, + Args = [], + Options = [{spawn_opt, diameter_lib:spawn_opts(server, [])}], + gen_server:start_link(ServerName, Module, Args, Options). + +state() -> + call(state). + +uptime() -> + call(uptime). + +%%% ---------------------------------------------------------- +%%% # init/1 +%%% ---------------------------------------------------------- + +init([]) -> + {ok, #state{}}. + +%%% ---------------------------------------------------------- +%%% # handle_call/2 +%%% ---------------------------------------------------------- + +handle_call(state, _, State) -> + {reply, State, State}; + +handle_call(uptime, _, #state{id = Time} = State) -> + {reply, diameter_lib:now_diff(Time), State}; + +handle_call(Req, From, State) -> + warning_msg("received unexpected request from ~p:~n~w", [From, Req]), + Reply = {error, {bad_request, Req}}, + {reply, Reply, State}. + +%%% ---------------------------------------------------------- +%%% # handle_cast/2 +%%% ---------------------------------------------------------- + +handle_cast(Msg, State) -> + warning_msg("received unexpected message:~n~w", [Msg]), + {noreply, State}. + +%%% ---------------------------------------------------------- +%%% # handle_info/2 +%%% ---------------------------------------------------------- + +%% A service process has died. This is most likely a consequence of +%% stop_service, in which case the restart will find no config for the +%% service and do nothing. The entry keyed on the monitor ref is only +%% removed as a result of the 'DOWN' notification however. +handle_info({'DOWN', MRef, process, _, Reason}, State) -> + [#monitor{service = SvcName} = T] = select([{#monitor{mref = MRef, + _ = '_'}, + [], + ['$_']}]), + queue_restart(Reason, SvcName), + delete_object(T), + {noreply, State}; + +handle_info({monitor, SvcName, Pid}, State) -> + monitor(Pid, SvcName), + {noreply, State}; + +handle_info({restart, SvcName}, State) -> + restart(SvcName), + {noreply, State}; + +handle_info(restart, State) -> + restart(), + {noreply, State}; + +handle_info(Info, State) -> + warning_msg("received unknown info:~n~w", [Info]), + {noreply, State}. + +%%-------------------------------------------------------------------- +%% # terminate/2 +%%-------------------------------------------------------------------- + +terminate(_Reason, _State) -> + ok. + +%%% ---------------------------------------------------------- +%%% # code_change/3 +%%% ---------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%% --------------------------------------------------------- +%% INTERNAL FUNCTIONS +%% --------------------------------------------------------- + +insert(T) -> + ets:insert(?TABLE, T). + +%% ?TABLE is a bag: check only for a service entry. +have_service(SvcName) -> + member([{#service{name = '$1', _ = '_'}, + [{'=:=', '$1', {const, SvcName}}], + [true]}]). + +member(MatchSpec) -> + '$end_of_table' =/= ets:select(?TABLE, MatchSpec, 1). + +delete_object(T) -> + ets:delete_object(?TABLE, T). + +delete(Key) -> + ets:delete(?TABLE, Key). + +select(MatchSpec) -> + ets:select(?TABLE, MatchSpec). + +select_delete(MatchSpec) -> + ets:select_delete(?TABLE, MatchSpec). + +%% sync/2 +%% +%% Interface functions used to be implemented as calls to ?SERVER but +%% now serialize things per service instead since stopping a service +%% can take time if the server doesn't answer DPR. A caller who wants +%% to stop multiple services can then improve performance by spawning +%% processes to stop them concurrently. + +sync(SvcName, T) -> + diameter_sync:call({?MODULE, SvcName}, + {?MODULE, sync, [T]}, + infinity, + infinity). + +%% sync/1 + +sync({restart, SvcName}) -> + have_service(SvcName) andalso start(SvcName); + +sync({start_service, SvcName, Opts}) -> + try + start(have_service(SvcName), SvcName, Opts) + catch + ?FAILURE(Reason) -> {error, Reason} + end; + +sync({stop_service, SvcName}) -> + stop(SvcName); + +sync({add, SvcName, Type, Opts}) -> + try + add(SvcName, Type, Opts) + catch + ?FAILURE(Reason) -> {error, Reason} + end; + +sync({remove, SvcName, Pred}) -> + remove(select([{#transport{service = '$1', _ = '_'}, + [{'=:=', '$1', {const, SvcName}}], + ['$_']}]), + SvcName, + Pred). + +%% start/3 + +start(true, _, _) -> + {error, already_started}; +start(false, SvcName, Opts) -> + insert(make_config(SvcName, Opts)), + start(SvcName). + +%% start/1 + +start(SvcName) -> + RC = diameter_service:start(SvcName), + startmon(SvcName, RC), + RC. + +startmon(SvcName, {ok, Pid}) -> + ?SERVER ! {monitor, SvcName, Pid}; +startmon(_, {error, _}) -> + ok. + +monitor(Pid, SvcName) -> + MRef = erlang:monitor(process, Pid), + insert(#monitor{mref = MRef, service = SvcName}). + +%% queue_restart/2 + +%% Service has gone down on monitor death. Note that all service-related +%% config is deleted. +queue_restart({shutdown, {monitor, _}}, SvcName) -> + delete(SvcName); + +%% Application shutdown: ignore. +queue_restart(shutdown, _) -> + ok; + +%% Or not. +queue_restart(_, SvcName) -> + erlang:send_after(?RESTART_SLEEP, self(), {restart, SvcName}). + +%% restart/1 + +restart(SvcName) -> + sync(SvcName, {restart, SvcName}). + +%% restart/0 +%% +%% Start anything configured as required. Bang 'restart' to the server +%% to kick things into gear manually. (Not that it should be required +%% but it's been useful for test.) + +restart() -> + MatchSpec = [{#service{name = '$1', _ = '_'}, + [], + ['$1']}], + lists:foreach(fun restart/1, select(MatchSpec)). + +%% stop/1 + +stop(SvcName) -> + %% If the call to the service returns error for any reason other + %% than the process not being alive then deleting the config from + %% under it will surely bring it down. + diameter_service:stop(SvcName), + %% Delete only the service entry, not everything keyed on the name, + select_delete([{#service{name = '$1', _ = '_'}, + [{'=:=', '$1', {const, SvcName}}], + [true]}]), + ok. +%% Note that a transport has to be removed for its statistics to be +%% deleted. + +%% add/3 + +add(SvcName, Type, Opts) -> + %% Ensure usable capabilities. diameter_service:merge_service/2 + %% depends on this. + lists:foreach(fun(Os) -> + is_list(Os) orelse ?THROW({capabilities, Os}), + ok = encode_CER(Os) + end, + [Os || {capabilities, Os} <- Opts, is_list(Os)]), + + Ref = make_ref(), + T = {Ref, Type, Opts}, + %% The call to the service returns error if the service isn't + %% started yet, which is harmless. The transport will be started + %% when the service is in that case. + case start_transport(SvcName, T) of + ok -> + insert(#transport{service = SvcName, + ref = Ref, + type = Type, + options = Opts}), + {ok, Ref}; + {error, _} = No -> + No + end. + +start_transport(SvcName, T) -> + case diameter_service:start_transport(SvcName, T) of + {ok, _Pid} -> + ok; + {error, no_service} -> + ok; + {error, _} = No -> + No + end. + +%% remove/3 + +remove(L, SvcName, Pred) -> + rm(SvcName, lists:filter(fun(#transport{ref = R, type = T, options = O}) -> + Pred(R,T,O) + end, + L)). + +rm(_, []) -> + ok; +rm(SvcName, L) -> + Refs = lists:map(fun(#transport{ref = R}) -> R end, L), + case stop_transport(SvcName, Refs) of + ok -> + lists:foreach(fun delete_object/1, L); + {error, _} = No -> + No + end. + +stop_transport(SvcName, Refs) -> + case diameter_service:stop_transport(SvcName, Refs) of + ok -> + ok; + {error, no_service} -> + ok; + {error, _} = No -> + No + end. + +%% make_config/2 + +make_config(SvcName, Opts) -> + Apps = init_apps(Opts), + [] == Apps andalso ?THROW(no_apps), + + %% Use the fact that diameter_caps has the same field names as CER. + Fields = diameter_gen_base_rfc3588:'#info-'(diameter_base_CER) -- ['AVP'], + + COpts = [T || {K,_} = T <- Opts, lists:member(K, Fields)], + Caps = make_caps(#diameter_caps{}, COpts), + + ok = encode_CER(COpts), + + Os = split(Opts, [{[fun erlang:is_boolean/1], false, share_peers}, + {[fun erlang:is_boolean/1], false, use_shared_peers}, + {[fun erlang:is_pid/1, false], false, monitor}]), + %% share_peers and use_shared_peers are currently undocumented. + + #service{name = SvcName, + rec = #diameter_service{applications = Apps, + capabilities = Caps}, + options = Os}. + +make_caps(Caps, Opts) -> + case diameter_capx:make_caps(Caps, Opts) of + {ok, T} -> + T; + {error, {Reason, _}} -> + ?THROW(Reason) + end. + +%% Validate types by encoding a CER. +encode_CER(Opts) -> + {ok, CER} = diameter_capx:build_CER(make_caps(?EXAMPLE_CAPS, Opts)), + + Hdr = #diameter_header{version = ?DIAMETER_VERSION, + end_to_end_id = 0, + hop_by_hop_id = 0}, + + try + diameter_codec:encode(?BASE, #diameter_packet{header = Hdr, + msg = CER}), + ok + catch + exit: Reason -> + ?THROW(Reason) + end. + +init_apps(Opts) -> + lists:foldl(fun app_acc/2, [], lists:reverse(Opts)). + +app_acc({application, Opts}, Acc) -> + is_list(Opts) orelse ?THROW({application, Opts}), + + [Dict, Mod] = get_opt([dictionary, module], Opts), + Alias = get_opt(alias, Opts, Dict), + ModS = get_opt(state, Opts, Alias), + M = get_opt(call_mutates_state, Opts, false), + A = get_opt(answer_errors, Opts, report), + [#diameter_app{alias = Alias, + dictionary = Dict, + id = cb(Dict, id), + module = init_mod(Mod), + init_state = ModS, + mutable = init_mutable(M), + answer_errors = init_answers(A)} + | Acc]; +app_acc(_, Acc) -> + Acc. + +init_mod(M) + when is_atom(M) -> + [M]; +init_mod([M|_] = L) + when is_atom(M) -> + L; +init_mod(M) -> + ?THROW({module, M}). + +init_mutable(M) + when M == true; + M == false -> + M; +init_mutable(M) -> + ?THROW({call_mutates_state, M}). + +init_answers(A) + when callback == A; + report == A; + discard == A -> + A; +init_answers(A) -> + ?THROW({answer_errors, A}). + +%% Get a single value at the specified key. +get_opt(Keys, List) + when is_list(Keys) -> + [get_opt(K, List) || K <- Keys]; +get_opt(Key, List) -> + case [V || {K,V} <- List, K == Key] of + [V] -> V; + _ -> ?THROW({arity, Key}) + end. + +%% Get an optional value at the specified key. +get_opt(Key, List, Def) -> + case [V || {K,V} <- List, K == Key] of + [] -> Def; + [V] -> V; + _ -> ?THROW({arity, Key}) + end. + +split(Opts, Defs) -> + [{K, value(D, Opts)} || {_,_,K} = D <- Defs]. + +value({Preds, Def, Key}, Opts) -> + V = get_opt(Key, Opts, Def), + lists:any(fun(P) -> pred(P,V) end, Preds) + orelse ?THROW({value, Key}), + V. + +pred(F, V) + when is_function(F) -> + F(V); +pred(T, V) -> + T == V. + +cb(M,F) -> + try M:F() of + V -> V + catch + E: Reason -> + ?THROW({callback, E, Reason, ?STACK}) + end. + +%% call/1 + +call(Request) -> + gen_server:call(?SERVER, Request, infinity). + +%% warning_msg/2 + +warning_msg(F, A) -> + ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_dbg.erl b/lib/diameter/src/app/diameter_dbg.erl new file mode 100644 index 0000000000..b18f34e13d --- /dev/null +++ b/lib/diameter/src/app/diameter_dbg.erl @@ -0,0 +1,565 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_dbg). + +-export([table/1, + tables/0, + fields/1, + help/0, + modules/0, + versions/0, + version_info/0, + compiled/0, + procs/0, + latest/0, + nl/0, + log/4]). + +-export([diameter_config/0, + diameter_peer/0, + diameter_reg/0, + diameter_request/0, + diameter_sequence/0, + diameter_service/0, + diameter_stats/0]). + +-export([pp/1, + subscriptions/0, + children/0]). + +%% Trace help. +-export([tracer/0, tracer/1, + p/0, p/1, + stop/0, + tpl/1, + tp/1]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). + + +-define(INFO, diameter_info). +-define(SEP(), ?INFO:sep()). + +-define(LOCAL, [diameter_config, + diameter_peer, + diameter_reg, + diameter_request, + diameter_sequence, + diameter_service, + diameter_stats]). + +-define(VALUES(Rec), tl(tuple_to_list(Rec))). + +%%% ---------------------------------------------------------- +%%% # log/4 +%%% +%%% Called to have something to trace on for happenings of interest. +%%% ---------------------------------------------------------- + +log(_Slogan, _Mod, _Line, _Details) -> + ok. + +%%% ---------------------------------------------------------- +%%% # help() +%%% ---------------------------------------------------------- + +help() -> + ?INFO:usage(usage()). + +usage() -> + not_yet_implemented. + +%%% ---------------------------------------------------------- +%%% # table(TableName) +%%% +%%% Input: TableName = diameter table containing record entries. +%%% +%%% Output: Count | undefined +%%% ---------------------------------------------------------- + +table(T) + when (T == diameter_peer) orelse (T == diameter_reg) -> + ?INFO:format(collect(T), fields(T), fun ?INFO:split/2); + +table(diameter_service = T) -> + Fs = [name, started] ++ fields(T) ++ [peerT, + connT, + share_peers, + use_shared_peers, + shared_peers, + local_peers, + monitor], + ?INFO:format(T, + fun(R) -> + [I,N,S|Vs] = ?VALUES(R), + {Fs, [N,I] ++ ?VALUES(S) ++ Vs} + end, + fun ?INFO:split/2); + +table(Table) + when is_atom(Table) -> + case fields(Table) of + undefined = No -> + No; + Fields -> + ?INFO:format(Table, Fields, fun ?INFO:split/2) + end. + +%%% ---------------------------------------------------------- +%%% # TableName() +%%% ---------------------------------------------------------- + +-define(TABLE(Name), Name() -> table(Name)). + +?TABLE(diameter_config). +?TABLE(diameter_peer). +?TABLE(diameter_reg). +?TABLE(diameter_request). +?TABLE(diameter_sequence). +?TABLE(diameter_service). +?TABLE(diameter_stats). + +%%% ---------------------------------------------------------- +%%% # tables() +%%% +%%% Output: Number of records output. +%%% +%%% Description: Pretty-print records in diameter tables from all nodes. +%%% ---------------------------------------------------------- + +tables() -> + format_all(fun ?INFO:split/3). + +format_all(SplitFun) -> + ?INFO:format(field(?LOCAL), SplitFun, fun collect/1). + +field(Tables) -> + lists:map(fun(T) -> {T, fields(T)} end, lists:sort(Tables)). + +%%% ---------------------------------------------------------- +%%% # modules() +%%% ---------------------------------------------------------- + +modules() -> + Path = filename:join([appdir(), atom_to_list(?APPLICATION) ++ ".app"]), + {ok, [{application, ?APPLICATION, Attrs}]} = file:consult(Path), + {modules, Mods} = lists:keyfind(modules, 1, Attrs), + Mods. + +appdir() -> + [_|_] = code:lib_dir(?APPLICATION, ebin). + +%%% ---------------------------------------------------------- +%%% # versions() +%%% ---------------------------------------------------------- + +versions() -> + ?INFO:versions(modules()). + +%%% ---------------------------------------------------------- +%%% # versions() +%%% ---------------------------------------------------------- + +version_info() -> + ?INFO:version_info(modules()). + +%%% ---------------------------------------------------------- +%%% # compiled() +%%% ---------------------------------------------------------- + +compiled() -> + ?INFO:compiled(modules()). + +%%% ---------------------------------------------------------- +%%% procs() +%%% ---------------------------------------------------------- + +procs() -> + ?INFO:procs(?APPLICATION). + +%%% ---------------------------------------------------------- +%%% # latest() +%%% ---------------------------------------------------------- + +latest() -> + ?INFO:latest(modules()). + +%%% ---------------------------------------------------------- +%%% # nl() +%%% ---------------------------------------------------------- + +nl() -> + lists:foreach(fun(M) -> abcast = c:nl(M) end, modules()). + +%%% ---------------------------------------------------------- +%%% # pp(Bin) +%%% +%%% Description: Pretty-print a message binary. +%%% ---------------------------------------------------------- + +%% Network byte order = big endian. + +pp(<<Version:8, MsgLength:24, + Rbit:1, Pbit:1, Ebit:1, Tbit:1, Reserved:4, CmdCode:24, + ApplId:32, + HbHid:32, + E2Eid:32, + AVPs/binary>>) -> + ?SEP(), + ppp(["Version", + "Message length", + "[Actual length]", + "R(equest)", + "P(roxiable)", + "E(rror)", + "T(Potential retrans)", + "Reserved bits", + "Command code", + "Application id", + "Hop by hop id", + "End to end id"], + [Version, MsgLength, size(AVPs) + 20, + Rbit, Pbit, Ebit, Tbit, Reserved, + CmdCode, + ApplId, + HbHid, + E2Eid]), + N = avp_loop({AVPs, MsgLength - 20}, 0), + ?SEP(), + N; + +pp(<<_Version:8, MsgLength:24, _/binary>> = Bin) -> + {bad_message_length, MsgLength, size(Bin)}; + +pp(Bin) + when is_binary(Bin) -> + {truncated_binary, size(Bin)}; + +pp(_) -> + not_binary. + +%% avp_loop/2 + +avp_loop({Bin, Size}, N) -> + avp_loop(avp(Bin, Size), N+1); +avp_loop(ok, N) -> + N; +avp_loop([_E, _Rest] = L, N) -> + io:format("! ~s: ~p~n", L), + N; +avp_loop([E, Rest, Fmt | Values], N) + when is_binary(Rest) -> + io:format("! ~s (" ++ Fmt ++ "): ~p~n", [E|Values] ++ [Rest]), + N. + +%% avp/2 + +avp(<<>>, 0) -> + ok; +avp(<<Code:32, Flags:1/binary, Length:24, Rest/binary>>, + Size) -> + avp(Code, Flags, Length, Rest, Size); +avp(Bin, _) -> + ["truncated AVP header", Bin]. + +%% avp/5 + +avp(Code, Flags, Length, Rest, Size) -> + <<V:1, M:1, P:1, Res:5>> + = Flags, + b(), + ppp(["AVP Code", + "V(endor)", + "M(andatory)", + "P(Security)", + "R(eserved)", + "Length"], + [Code, V, M, P, Res, Length]), + avp(V, Rest, Length - 8, Size - 8). + +%% avp/4 + +avp(1, <<V:32, Data/binary>>, Length, Size) -> + ppp({"Vendor-ID", V}), + data(Data, Length - 4, Size - 4); +avp(1, Bin, _, _) -> + ["truncated Vendor-ID", Bin]; +avp(0, Data, Length, Size) -> + data(Data, Length, Size). + +data(Bin, Length, Size) + when size(Bin) >= Length -> + <<AVP:Length/binary, Rest/binary>> = Bin, + ppp({"Data", AVP}), + unpad(Rest, Size - Length, Length rem 4); + +data(Bin, _, _) -> + ["truncated AVP data", Bin]. + +%% Remove padding bytes up to the next word boundary. +unpad(Bin, Size, 0) -> + {Bin, Size}; +unpad(Bin, Size, N) -> + un(Bin, Size, 4 - N). + +un(Bin, Size, N) + when size(Bin) >= N -> + ppp({"Padding bytes", N}), + <<Pad:N/binary, Rest/binary>> = Bin, + Bits = N*8, + case Pad of + <<0:Bits>> -> + {Rest, Size - N}; + _ -> + ["non-zero padding", Bin, "~p", N] + end; + +un(Bin, _, _) -> + ["truncated padding", Bin]. + +b() -> + io:format("#~n"). + +ppp(Fields, Values) -> + lists:foreach(fun ppp/1, lists:zip(Fields, Values)). + +ppp({Field, Value}) -> + io:format(": ~-22s : ~p~n", [Field, Value]). + +%%% ---------------------------------------------------------- +%%% # subscriptions() +%%% +%%% Output: list of {SvcName, Pid} +%%% ---------------------------------------------------------- + +subscriptions() -> + diameter_service:subscriptions(). + +%%% ---------------------------------------------------------- +%%% # children() +%%% ---------------------------------------------------------- + +children() -> + diameter_sup:tree(). + +%%% ---------------------------------------------------------- + +%% tracer/[12] + +tracer(Port) + when is_integer(Port) -> + dbg:tracer(port, dbg:trace_port(ip, Port)); + +tracer(Path) + when is_list(Path) -> + dbg:tracer(port, dbg:trace_port(file, Path)). + +tracer() -> + dbg:tracer(process, {fun p/2, ok}). + +p(T,_) -> + io:format("+ ~p~n", [T]). + +%% p/[01] + +p() -> + p([c,timestamp]). + +p(T) -> + dbg:p(all,T). + +%% stop/0 + +stop() -> + dbg:ctp(), + dbg:stop_clear(). + +%% tpl/1 +%% tp/1 + +tpl(T) -> + dbg(tpl, dbg(T)). + +tp(T) -> + dbg(tp, dbg(T)). + +%% dbg/1 + +dbg(x) -> + [{M, x, []} || M <- [diameter_tcp, + diameter_etcp, + diameter_sctp, + diameter_peer_fsm, + diameter_watchdog]]; + +dbg(log) -> + {?MODULE, log, 4}; + +dbg({log = F, Mods}) + when is_list(Mods) -> + {?MODULE, F, [{['_','$1','_','_'], + [?ORCOND([{'==', '$1', M} || M <- Mods])], + []}]}; + +dbg({log = F, Mod}) -> + dbg({F, [Mod]}); + +dbg(send) -> + {diameter_peer, send, 2}; + +dbg(recv) -> + {diameter_peer, recv, 2}; + +dbg(sendrecv) -> + [{diameter_peer, send, 2}, + {diameter_peer, recv, 2}]; + +dbg(decode) -> + [{diameter_codec,decode,2}]; + +dbg(encode) -> + [{diameter_codec,encode,2,[]}, + {diameter_codec,encode,3,[]}, + {diameter_codec,encode,4}]; + +dbg(transition = T) -> + [{?MODULE, log, [{[T,M,'_','_'],[],[]}]} + || M <- [diameter_watchdog, diameter_peer_fsm]]; + +dbg(T) -> + T. + +%% dbg/2 + +dbg(TF, L) + when is_list(L) -> + {ok, lists:foldl(fun(T,A) -> {ok, X} = dbg(TF, T), [X|A] end, [], L)}; + +dbg(F, M) + when is_atom(M) -> + dbg(F, {M}); + +dbg(F, T) + when is_tuple(T) -> + [_|_] = A = tuple_to_list(T), + {ok,_} = apply(dbg, F, case is_list(lists:last(A)) of + false -> + A ++ [[{'_',[],[{exception_trace}]}]]; + true -> + A + end). + +%% =========================================================================== +%% =========================================================================== + +%% collect/1 + +collect(diameter_peer) -> + lists:flatmap(fun peers/1, diameter:services()); + +collect(diameter_reg) -> + diameter_reg:terms(); + +collect(Name) -> + c(ets:info(Name), Name). + +c(undefined, _) -> + []; +c(_, Name) -> + ets:tab2list(Name). + +%% peers/1 + +peers(Name) -> + peers(Name, diameter:service_info(Name, transport)). + +peers(_, undefined) -> + []; +peers(Name, {Cs,As}) -> + mk_peer(Name, connector, Cs) ++ mk_peer(Name, acceptor, As). + +mk_peer(Name, T, Ts) -> + [[Name | mk_peer(T,Vs)] || Vs <- Ts]. + +mk_peer(Type, Vs) -> + [Ref, State, Opts, WPid, TPid, SApps, Caps] + = get_values(Vs, [ref, state, options, watchdog, peer, apps, caps]), + [Ref, State, [{type, Type} | Opts], s(WPid), s(TPid), SApps, Caps]. + +get_values(Vs, Ks) -> + [proplists:get_value(K, Vs) || K <- Ks]. + +s(undefined = T) -> + T; + +%% Collect states from watchdog/transport pids. +s(Pid) -> + MRef = erlang:monitor(process, Pid), + Pid ! {state, self()}, + receive + {'DOWN', MRef, process, _, _} -> + Pid; + {Pid, _} = T -> + erlang:demonitor(MRef, [flush]), + T + end. + +%% fields/1 + +-define(FIELDS(Table), fields(Table) -> record_info(fields, Table)). + +fields(diameter_config) -> + []; + +fields(T) + when T == diameter_request; + T == diameter_sequence -> + fun kv/1; + +fields(diameter_stats) -> + fun({Ctr, N}) when not is_pid(Ctr) -> + {[counter, value], [Ctr, N]}; + (_) -> + [] + end; + +?FIELDS(diameter_service); +?FIELDS(diameter_event); +?FIELDS(diameter_uri); +?FIELDS(diameter_avp); +?FIELDS(diameter_header); +?FIELDS(diameter_packet); +?FIELDS(diameter_app); +?FIELDS(diameter_caps); + +fields(diameter_peer) -> + [service, ref, state, options, watchdog, peer, applications, capabilities]; + +fields(diameter_reg) -> + [property, pids]; + +fields(_) -> + undefined. + +kv({_,_}) -> + [key, value]; +kv(_) -> + []. diff --git a/lib/diameter/src/app/diameter_dict.erl b/lib/diameter/src/app/diameter_dict.erl new file mode 100644 index 0000000000..3b9ba00a3f --- /dev/null +++ b/lib/diameter/src/app/diameter_dict.erl @@ -0,0 +1,153 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This module provide OTP's dict interface built on top of ets. +%% +%% Note that while the interface is the same as dict the semantics +%% aren't quite. A Dict here is just a table identifier (although +%% this fact can't be used if you want dict/ets-based implementations +%% to be interchangeable) so changes made to the Dict modify the +%% underlying table. For merge/3, the first argument table is modified. +%% +%% The underlying ets table implementing a dict is deleted when the +%% process from which new() was invoked exits and the dict is only +%% writable from this process. +%% +%% The reason for this is to be able to swap dict/ets-based +%% implementations: the former is easier to debug, the latter is +%% faster for larger tables. It's also just a nice interface even +%% when there's no need for swapability. +%% + +-module(diameter_dict). + +-export([append/3, + append_list/3, + erase/2, + fetch/2, + fetch_keys/1, + filter/2, + find/2, + fold/3, + from_list/1, + is_key/2, + map/2, + merge/3, + new/0, + store/3, + to_list/1, + update/3, + update/4, + update_counter/3]). + +%%% ---------------------------------------------------------- +%%% EXPORTED INTERNAL FUNCTIONS +%%% ---------------------------------------------------------- + +append(Key, Value, Dict) -> + append_list(Key, [Value], Dict). + +append_list(Key, ValueList, Dict) + when is_list(ValueList) -> + update(Key, fun(V) -> V ++ ValueList end, ValueList, Dict). + +erase(Key, Dict) -> + ets:delete(Dict, Key), + Dict. + +fetch(Key, Dict) -> + {ok, V} = find(Key, Dict), + V. + +fetch_keys(Dict) -> + ets:foldl(fun({K,_}, Acc) -> [K | Acc] end, [], Dict). + +filter(Pred, Dict) -> + lists:foreach(fun({K,V}) -> filter(Pred(K,V), K, Dict) end, to_list(Dict)), + Dict. + +find(Key, Dict) -> + case ets:lookup(Dict, Key) of + [{Key, V}] -> + {ok, V}; + [] -> + error + end. + +fold(Fun, Acc0, Dict) -> + ets:foldl(fun({K,V}, Acc) -> Fun(K, V, Acc) end, Acc0, Dict). + +from_list(List) -> + lists:foldl(fun store/2, new(), List). + +is_key(Key, Dict) -> + ets:member(Dict, Key). + +map(Fun, Dict) -> + lists:foreach(fun({K,V}) -> store(K, Fun(K,V), Dict) end, to_list(Dict)), + Dict. + +merge(Fun, Dict1, Dict2) -> + fold(fun(K2,V2,_) -> + update(K2, fun(V1) -> Fun(K2, V1, V2) end, V2, Dict1) + end, + Dict1, + Dict2). + +new() -> + ets:new(?MODULE, [set]). + +store(Key, Value, Dict) -> + store({Key, Value}, Dict). + +to_list(Dict) -> + ets:tab2list(Dict). + +update(Key, Fun, Dict) -> + store(Key, Fun(fetch(Key, Dict)), Dict). + +update(Key, Fun, Initial, Dict) -> + store(Key, map(Key, Fun, Dict, Initial), Dict). + +update_counter(Key, Increment, Dict) + when is_integer(Increment) -> + update(Key, fun(V) -> V + Increment end, Increment, Dict). + +%%% --------------------------------------------------------- +%%% INTERNAL FUNCTIONS +%%% --------------------------------------------------------- + +store({_,_} = T, Dict) -> + ets:insert(Dict, T), + Dict. + +filter(true, _, _) -> + ok; +filter(false, K, Dict) -> + erase(K, Dict). + +map(Key, Fun, Dict, Error) -> + case find(Key, Dict) of + {ok, V} -> + Fun(V); + error -> + Error + end. + diff --git a/lib/diameter/src/app/diameter_exprecs.erl b/lib/diameter/src/app/diameter_exprecs.erl new file mode 100644 index 0000000000..5e120d6f44 --- /dev/null +++ b/lib/diameter/src/app/diameter_exprecs.erl @@ -0,0 +1,301 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Parse transform for generating record access functions +%% +%% This parse transform can be used to reduce compile-time +%% dependencies in large systems. +%% +%% In the old days, before records, Erlang programmers often wrote +%% access functions for tuple data. This was tedious and error-prone. +%% The record syntax made this easier, but since records were implemented +%% fully in the pre-processor, a nasty compile-time dependency was +%% introduced. +%% +%% This module automates the generation of access functions for +%% records. While this method cannot fully replace the utility of +%% pattern matching, it does allow a fair bit of functionality on +%% records without the need for compile-time dependencies. +%% +%% Whenever record definitions need to be exported from a module, +%% inserting a compiler attribute, +%% +%% export_records([RecName, ...]) +%% +%% causes this transform to lay out access functions for the exported +%% records: +%% +%% -module(foo) +%% -compile({parse_transform, diameter_exprecs}). +%% +%% -record(r, {a, b, c}). +%% -export_records([a]). +%% +%% -export(['#info-'/1, '#info-'/2, +%% '#new-'/1, '#new-'/2, +%% '#get-'/2, '#set-'/2, +%% '#new-a'/0, '#new-a'/1, +%% '#get-a'/2, '#set-a'/2, +%% '#info-a'/1]). +%% +%% '#info-'(RecName) -> +%% '#info-'(RecName, fields). +%% +%% '#info-'(r, Info) -> +%% '#info-r'(Info). +%% +%% '#new-'(r) -> #r{}. +%% '#new-'(r, Vals) -> '#new-r'(Vals) +%% +%% '#new-r'() -> #r{}. +%% '#new-r'(Vals) -> '#set-r'(Vals, #r{}). +%% +%% '#get-'(Attrs, #r{} = Rec) -> +%% '#get-r'(Attrs, Rec). +%% +%% '#get-r'(Attrs, Rec) when is_list(Attrs) -> +%% ['#get-r'(A, Rec) || A <- Attrs]; +%% '#get-r'(a, Rec) -> Rec#r.a; +%% '#get-r'(b, Rec) -> Rec#r.b; +%% '#get-r'(c, Rec) -> Rec#r.c. +%% +%% '#set-'(Vals, #r{} = Rec) -> +%% '#set-r'(Vals, Rec). +%% +%% '#set-r'(Vals, Rec) when is_list(Vals) -> +%% lists:foldl(fun '#set-r'/2, Rec, Vals); +%% '#set-r'({a,V}, Rec) -> Rec#r{a = V}; +%% '#set-r'({b,V}, Rec) -> Rec#r{b = V}; +%% '#set-r'({c,V}, Rec) -> Rec#r{c = V}. +%% +%% '#info-r'(fields) -> record_info(fields, r); +%% '#info-r'(size) -> record_info(size, r); +%% '#info-r'({index, a}) -> 1; +%% '#info-r'({index, b}) -> 2; +%% '#info-r'({index, c}) -> 3; +%% + +-module(diameter_exprecs). + +-export([parse_transform/2]). + +%% Form tag with line number. +-define(F(T), T, ?LINE). +%% Yes, that's right. The replacement is to the first unmatched ')'. + +-define(attribute, ?F(attribute)). +-define(clause, ?F(clause)). +-define(function, ?F(function)). +-define(call, ?F(call)). +-define('fun', ?F('fun')). +-define(generate, ?F(generate)). +-define(lc, ?F(lc)). +-define(match, ?F(match)). +-define(remote, ?F(remote)). +-define(record, ?F(record)). +-define(record_field, ?F(record_field)). +-define(record_index, ?F(record_index)). +-define(tuple, ?F(tuple)). + +-define(ATOM(T), {atom, ?LINE, T}). +-define(VAR(V), {var, ?LINE, V}). + +-define(CALL(F,A), {?call, ?ATOM(F), A}). +-define(APPLY(M,F,A), {?call, {?remote, ?ATOM(M), ?ATOM(F)}, A}). + +%% parse_transform/2 + +parse_transform(Forms, _Options) -> + Rs = [R || {attribute, _, record, R} <- Forms], + case lists:append([E || {attribute, _, export_records, E} <- Forms]) of + [] -> + Forms; + Es -> + {H,T} = lists:splitwith(fun is_head/1, Forms), + H ++ [a_export(Es) | f_accessors(Es, Rs)] ++ T + end. + +is_head(T) -> + not lists:member(element(1,T), [function, eof]). + +%% a_export/1 + +a_export(Exports) -> + {?attribute, export, [{fname(info), 1}, + {fname(info), 2}, + {fname(new), 1}, + {fname(new), 2}, + {fname(get), 2}, + {fname(set), 2} + | lists:flatmap(fun export/1, Exports)]}. + +export(Rname) -> + New = fname(new, Rname), + [{New, 0}, + {New, 1}, + {fname(get, Rname), 2}, + {fname(set, Rname), 2}, + {fname(info, Rname), 1}]. + +%% f_accessors/2 + +f_accessors(Es, Rs) -> + ['#info-/1'(), + '#info-/2'(Es), + '#new-/1'(Es), + '#new-/2'(Es), + '#get-/2'(Es), + '#set-/2'(Es) + | lists:flatmap(fun(N) -> accessors(N, fields(N, Rs)) end, Es)]. + +accessors(Rname, Fields) -> + ['#new-X/0'(Rname), + '#new-X/1'(Rname), + '#get-X/2'(Rname, Fields), + '#set-X/2'(Rname, Fields), + '#info-X/1'(Rname, Fields)]. + +fields(Rname, Recs) -> + {Rname, Fields} = lists:keyfind(Rname, 1, Recs), + lists:map(fun({record_field, _, {atom, _, N}}) -> N; + ({record_field, _, {atom, _, N}, _}) -> N + end, + Fields). + +fname_prefix(Op) -> + "#" ++ atom_to_list(Op) ++ "-". + +fname(Op) -> + list_to_atom(fname_prefix(Op)). + +fname(Op, Rname) -> + Prefix = fname_prefix(Op), + list_to_atom(Prefix ++ atom_to_list(Rname)). + +%% Generated functions. + +'#info-/1'() -> + Fname = fname(info), + {?function, Fname, 1, + [{?clause, [?VAR('RecName')], + [], + [?CALL(Fname, [?VAR('RecName'), ?ATOM(fields)])]}]}. + +'#info-/2'(Exports) -> + {?function, fname(info), 2, + lists:map(fun 'info-'/1, Exports)}. + +'info-'(R) -> + {?clause, [?ATOM(R), ?VAR('Info')], + [], + [?CALL(fname(info, R), [?VAR('Info')])]}. + +'#new-/1'(Exports) -> + {?function, fname(new), 1, + lists:map(fun 'new-'/1, Exports)}. + +'new-'(R) -> + {?clause, [?ATOM(R)], + [], + [{?record, R, []}]}. + +'#new-/2'(Exports) -> + {?function, fname(new), 2, + lists:map(fun 'new--'/1, Exports)}. + +'new--'(R) -> + {?clause, [?ATOM(R), ?VAR('Vals')], + [], + [?CALL(fname(new, R), [?VAR('Vals')])]}. + +'#get-/2'(Exports) -> + {?function, fname(get), 2, + lists:map(fun 'get-'/1, Exports)}. + +'get-'(R) -> + {?clause, [?VAR('Attrs'), + {?match, {?record, R, []}, ?VAR('Rec')}], + [], + [?CALL(fname(get, R), [?VAR('Attrs'), ?VAR('Rec')])]}. + +'#set-/2'(Exports) -> + {?function, fname(set), 2, + lists:map(fun 'set-'/1, Exports)}. + +'set-'(R) -> + {?clause, [?VAR('Vals'), {?match, {?record, R, []}, ?VAR('Rec')}], + [], + [?CALL(fname(set, R), [?VAR('Vals'), ?VAR('Rec')])]}. + +'#new-X/0'(Rname) -> + {?function, fname(new, Rname), 0, + [{?clause, [], + [], + [{?record, Rname, []}]}]}. + +'#new-X/1'(Rname) -> + {?function, fname(new, Rname), 1, + [{?clause, [?VAR('Vals')], + [], + [?CALL(fname(set, Rname), [?VAR('Vals'), {?record, Rname, []}])]}]}. + +'#set-X/2'(Rname, Fields) -> + {?function, fname(set, Rname), 2, + [{?clause, [?VAR('Vals'), ?VAR('Rec')], + [[?CALL(is_list, [?VAR('Vals')])]], + [?APPLY(lists, foldl, [{?'fun', {function, fname(set, Rname), 2}}, + ?VAR('Rec'), + ?VAR('Vals')])]} + | lists:map(fun(A) -> 'set-X'(Rname, A) end, Fields)]}. + +'set-X'(Rname, Attr) -> + {?clause, [{?tuple, [?ATOM(Attr), ?VAR('V')]}, ?VAR('Rec')], + [], + [{?record, ?VAR('Rec'), Rname, + [{?record_field, ?ATOM(Attr), ?VAR('V')}]}]}. + +'#get-X/2'(Rname, Fields) -> + FName = fname(get, Rname), + {?function, FName, 2, + [{?clause, [?VAR('Attrs'), ?VAR('Rec')], + [[?CALL(is_list, [?VAR('Attrs')])]], + [{?lc, ?CALL(FName, [?VAR('A'), ?VAR('Rec')]), + [{?generate, ?VAR('A'), ?VAR('Attrs')}]}]} + | lists:map(fun(A) -> 'get-X'(Rname, A) end, Fields)]}. + +'get-X'(Rname, Attr) -> + {?clause, [?ATOM(Attr), ?VAR('Rec')], + [], + [{?record_field, ?VAR('Rec'), Rname, ?ATOM(Attr)}]}. + +'#info-X/1'(Rname, Fields) -> + {?function, fname(info, Rname), 1, + [{?clause, [?ATOM(fields)], + [], + [?CALL(record_info, [?ATOM(fields), ?ATOM(Rname)])]}, + {?clause, [?ATOM(size)], + [], + [?CALL(record_info, [?ATOM(size), ?ATOM(Rname)])]} + | lists:map(fun(A) -> 'info-X'(Rname, A) end, Fields)]}. + +'info-X'(Rname, Attr) -> + {?clause, [{?tuple, [?ATOM(index), ?ATOM(Attr)]}], + [], + [{?record_index, Rname, ?ATOM(Attr)}]}. diff --git a/lib/diameter/src/app/diameter_gen_base_accounting.dia b/lib/diameter/src/app/diameter_gen_base_accounting.dia new file mode 100644 index 0000000000..64e95dddb5 --- /dev/null +++ b/lib/diameter/src/app/diameter_gen_base_accounting.dia @@ -0,0 +1,68 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@id 3 +@prefix diameter_base_accounting +@vendor 0 IETF + +@inherits diameter_gen_base_rfc3588 + +@messages + + ACR ::= < 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 ] + [ Acct-Interim-Interval ] + [ Accounting-Realtime-Required ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ACA ::= < 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 ] + [ Error-Reporting-Host ] + [ Acct-Interim-Interval ] + [ Accounting-Realtime-Required ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Proxy-Info ] + * [ AVP ] diff --git a/lib/diameter/src/app/diameter_gen_base_rfc3588.dia b/lib/diameter/src/app/diameter_gen_base_rfc3588.dia new file mode 100644 index 0000000000..4a12e21acd --- /dev/null +++ b/lib/diameter/src/app/diameter_gen_base_rfc3588.dia @@ -0,0 +1,413 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@id 0 +@prefix diameter_base +@vendor 0 IETF + +@avp_types + + Acct-Interim-Interval 85 Unsigned32 M + Accounting-Realtime-Required 483 Enumerated M + Acct-Multi-Session-Id 50 UTF8String M + Accounting-Record-Number 485 Unsigned32 M + Accounting-Record-Type 480 Enumerated M + Acct-Session-Id 44 OctetString M + Accounting-Sub-Session-Id 287 Unsigned64 M + Acct-Application-Id 259 Unsigned32 M + Auth-Application-Id 258 Unsigned32 M + Auth-Request-Type 274 Enumerated M + Authorization-Lifetime 291 Unsigned32 M + Auth-Grace-Period 276 Unsigned32 M + Auth-Session-State 277 Enumerated M + Re-Auth-Request-Type 285 Enumerated M + Class 25 OctetString M + Destination-Host 293 DiamIdent M + Destination-Realm 283 DiamIdent M + Disconnect-Cause 273 Enumerated M + E2E-Sequence 300 Grouped M + Error-Message 281 UTF8String - + Error-Reporting-Host 294 DiamIdent - + Event-Timestamp 55 Time M + Experimental-Result 297 Grouped M + Experimental-Result-Code 298 Unsigned32 M + Failed-AVP 279 Grouped M + Firmware-Revision 267 Unsigned32 - + Host-IP-Address 257 Address M + Inband-Security-Id 299 Unsigned32 M + Multi-Round-Time-Out 272 Unsigned32 M + Origin-Host 264 DiamIdent M + Origin-Realm 296 DiamIdent M + Origin-State-Id 278 Unsigned32 M + Product-Name 269 UTF8String - + Proxy-Host 280 DiamIdent M + Proxy-Info 284 Grouped M + Proxy-State 33 OctetString M + Redirect-Host 292 DiamURI M + Redirect-Host-Usage 261 Enumerated M + Redirect-Max-Cache-Time 262 Unsigned32 M + Result-Code 268 Unsigned32 M + Route-Record 282 DiamIdent M + Session-Id 263 UTF8String M + Session-Timeout 27 Unsigned32 M + Session-Binding 270 Unsigned32 M + Session-Server-Failover 271 Enumerated M + Supported-Vendor-Id 265 Unsigned32 M + Termination-Cause 295 Enumerated M + User-Name 1 UTF8String M + Vendor-Id 266 Unsigned32 M + Vendor-Specific-Application-Id 260 Grouped M + +@messages + + CER ::= < Diameter Header: 257, REQ > + { Origin-Host } + { Origin-Realm } + 1* { Host-IP-Address } + { Vendor-Id } + { Product-Name } + [ Origin-State-Id ] + * [ Supported-Vendor-Id ] + * [ Auth-Application-Id ] + * [ Inband-Security-Id ] + * [ Acct-Application-Id ] + * [ Vendor-Specific-Application-Id ] + [ Firmware-Revision ] + * [ AVP ] + + CEA ::= < Diameter Header: 257 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + 1* { Host-IP-Address } + { Vendor-Id } + { Product-Name } + [ Origin-State-Id ] + [ Error-Message ] + * [ Failed-AVP ] + * [ Supported-Vendor-Id ] + * [ Auth-Application-Id ] + * [ Inband-Security-Id ] + * [ Acct-Application-Id ] + * [ Vendor-Specific-Application-Id ] + [ Firmware-Revision ] + * [ AVP ] + + DPR ::= < Diameter Header: 282, REQ > + { Origin-Host } + { Origin-Realm } + { Disconnect-Cause } + + DPA ::= < Diameter Header: 282 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Error-Message ] + * [ Failed-AVP ] + + DWR ::= < Diameter Header: 280, REQ > + { Origin-Host } + { Origin-Realm } + [ Origin-State-Id ] + + DWA ::= < Diameter Header: 280 > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ Error-Message ] + * [ Failed-AVP ] + [ Origin-State-Id ] + + answer-message ::= < Diameter Header: code, ERR [PXY] > + 0*1< Session-Id > + { Origin-Host } + { Origin-Realm } + { Result-Code } + [ Origin-State-Id ] + [ Error-Reporting-Host ] + [ Proxy-Info ] + * [ AVP ] + + RAR ::= < 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-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + RAA ::= < Diameter Header: 258, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + STR ::= < Diameter Header: 275, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Auth-Application-Id } + { Termination-Cause } + [ User-Name ] + [ Destination-Host ] + * [ Class ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + STA ::= < Diameter Header: 275, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + * [ Class ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + [ Origin-State-Id ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + ASR ::= < Diameter Header: 274, REQ, PXY > + < Session-Id > + { Origin-Host } + { Origin-Realm } + { Destination-Realm } + { Destination-Host } + { Auth-Application-Id } + [ User-Name ] + [ Origin-State-Id ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ASA ::= < Diameter Header: 274, PXY > + < Session-Id > + { Result-Code } + { Origin-Host } + { Origin-Realm } + [ User-Name ] + [ Origin-State-Id ] + [ Error-Message ] + [ Error-Reporting-Host ] + * [ Failed-AVP ] + * [ Redirect-Host ] + [ Redirect-Host-Usage ] + [ Redirect-Max-Cache-Time ] + * [ Proxy-Info ] + * [ AVP ] + + ACR ::= < 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 ] + [ Acct-Interim-Interval ] + [ Accounting-Realtime-Required ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Proxy-Info ] + * [ Route-Record ] + * [ AVP ] + + ACA ::= < 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 ] + [ Error-Reporting-Host ] + [ Acct-Interim-Interval ] + [ Accounting-Realtime-Required ] + [ Origin-State-Id ] + [ Event-Timestamp ] + * [ Proxy-Info ] + * [ AVP ] + +@enum Disconnect-Cause + + REBOOTING 0 + BUSY 1 + DO_NOT_WANT_TO_TALK_TO_YOU 2 + +@enum Redirect-Host-Usage + + DONT_CACHE 0 + ALL_SESSION 1 + ALL_REALM 2 + REALM_AND_APPLICATION 3 + ALL_APPLICATION 4 + ALL_HOST 5 + ALL_USER 6 + +@enum Auth-Request-Type + + AUTHENTICATE_ONLY 1 + AUTHORIZE_ONLY 2 + AUTHORIZE_AUTHENTICATE 3 + +@enum Auth-Session-State + + STATE_MAINTAINED 0 + NO_STATE_MAINTAINED 1 + +@enum Re-Auth-Request-Type + + AUTHORIZE_ONLY 0 + AUTHORIZE_AUTHENTICATE 1 + +@enum Termination-Cause + + DIAMETER_LOGOUT 1 + DIAMETER_SERVICE_NOT_PROVIDED 2 + DIAMETER_BAD_ANSWER 3 + DIAMETER_ADMINISTRATIVE 4 + DIAMETER_LINK_BROKEN 5 + DIAMETER_AUTH_EXPIRED 6 + DIAMETER_USER_MOVED 7 + DIAMETER_SESSION_TIMEOUT 8 + +@enum Session-Server-Failover + + REFUSE_SERVICE 0 + TRY_AGAIN 1 + ALLOW_SERVICE 2 + TRY_AGAIN_ALLOW_SERVICE 3 + +@enum Accounting-Record-Type + + EVENT_RECORD 1 + START_RECORD 2 + INTERIM_RECORD 3 + STOP_RECORD 4 + +@enum Accounting-Realtime-Required + + DELIVER_AND_GRANT 1 + GRANT_AND_STORE 2 + GRANT_AND_LOSE 3 + +@result_code Result-Code + +;; 7.1.1. Informational + DIAMETER_MULTI_ROUND_AUTH 1001 + +;; 7.1.2. Success + DIAMETER_SUCCESS 2001 + DIAMETER_LIMITED_SUCCESS 2002 + +;; 7.1.3. Protocol Errors + DIAMETER_COMMAND_UNSUPPORTED 3001 + DIAMETER_UNABLE_TO_DELIVER 3002 + DIAMETER_REALM_NOT_SERVED 3003 + DIAMETER_TOO_BUSY 3004 + DIAMETER_LOOP_DETECTED 3005 + DIAMETER_REDIRECT_INDICATION 3006 + DIAMETER_APPLICATION_UNSUPPORTED 3007 + DIAMETER_INVALID_HDR_BITS 3008 + DIAMETER_INVALID_AVP_BITS 3009 + DIAMETER_UNKNOWN_PEER 3010 + +;; 7.1.4. Transient Failures + DIAMETER_AUTHENTICATION_REJECTED 4001 + DIAMETER_OUT_OF_SPACE 4002 + ELECTION_LOST 4003 + +;; 7.1.5. Permanent Failures + DIAMETER_AVP_UNSUPPORTED 5001 + DIAMETER_UNKNOWN_SESSION_ID 5002 + DIAMETER_AUTHORIZATION_REJECTED 5003 + DIAMETER_INVALID_AVP_VALUE 5004 + DIAMETER_MISSING_AVP 5005 + DIAMETER_RESOURCES_EXCEEDED 5006 + DIAMETER_CONTRADICTING_AVPS 5007 + DIAMETER_AVP_NOT_ALLOWED 5008 + DIAMETER_AVP_OCCURS_TOO_MANY_TIMES 5009 + DIAMETER_NO_COMMON_APPLICATION 5010 + DIAMETER_UNSUPPORTED_VERSION 5011 + DIAMETER_UNABLE_TO_COMPLY 5012 + DIAMETER_INVALID_BIT_IN_HEADER 5013 + DIAMETER_INVALID_AVP_LENGTH 5014 + DIAMETER_INVALID_MESSAGE_LENGTH 5015 + DIAMETER_INVALID_AVP_BIT_COMBO 5016 + DIAMETER_NO_COMMON_SECURITY 5017 + +@grouped + + Proxy-Info ::= < AVP Header: 284 > + { Proxy-Host } + { Proxy-State } + * [ AVP ] + + Failed-AVP ::= < AVP Header: 279 > + 1* {AVP} + + Experimental-Result ::= < AVP Header: 297 > + { Vendor-Id } + { Experimental-Result-Code } + + Vendor-Specific-Application-Id ::= < AVP Header: 260 > + 1* { Vendor-Id } + [ Auth-Application-Id ] + [ Acct-Application-Id ] + +;; The E2E-Sequence AVP is defined in RFC 3588 as Grouped, but +;; there is no definition of the group - only an informal text stating +;; that there should be a nonce (an OctetString) and a counter +;; (integer) +;; + E2E-Sequence ::= <AVP Header: 300 > + 2* { AVP } diff --git a/lib/diameter/src/app/diameter_gen_relay.dia b/lib/diameter/src/app/diameter_gen_relay.dia new file mode 100644 index 0000000000..d86446e368 --- /dev/null +++ b/lib/diameter/src/app/diameter_gen_relay.dia @@ -0,0 +1,24 @@ +;; +;; %CopyrightBegin% +;; +;; Copyright Ericsson AB 2010-2011. All Rights Reserved. +;; +;; The contents of this file are subject to the Erlang Public License, +;; Version 1.1, (the "License"); you may not use this file except in +;; compliance with the License. You should have received a copy of the +;; Erlang Public License along with this software. If not, it can be +;; retrieved online at http://www.erlang.org/. +;; +;; Software distributed under the License is distributed on an "AS IS" +;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +;; the License for the specific language governing rights and limitations +;; under the License. +;; +;; %CopyrightEnd% +;; + +@id 0xFFFFFFFF +@prefix diameter_relay +@vendor 0 IETF + +@inherits diameter_gen_base_rfc3588 diff --git a/lib/diameter/src/app/diameter_info.erl b/lib/diameter/src/app/diameter_info.erl new file mode 100644 index 0000000000..39d32d07cd --- /dev/null +++ b/lib/diameter/src/app/diameter_info.erl @@ -0,0 +1,869 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_info). + +-export([usage/1, + format/1, + format/2, + format/3, + format/4, + table/2, + tables/1, + tables/2, + split/2, + split/3, + tab2list/1, + modules/1, + versions/1, + version_info/1, + attrs/2, + compiled/1, + procs/1, + latest/1, + list/1]). + +%% Support for rolling your own. +-export([sep/0, + sep/1, + widest/1, + p/1, + p/3]). + +-compile({no_auto_import,[max/2]}). + +-export([collect/2]). + +-define(LONG_TIMEOUT, 30000). +-define(VALUES(Rec), tl(tuple_to_list(Rec))). + +%%% ---------------------------------------------------------- +%%% # usage(String) +%%% ---------------------------------------------------------- + +usage(Usage) -> + sep($+), + io:format("+ ~p~n", [?MODULE]), + io:format("~n~s~n~n", [compact(Usage)]), + sep($+). + +%%% +%%% The function format/3, for pretty-printing tables, comes in +%%% several flavours. +%%% + +%%% ---------------------------------------------------------- +%%% # format(TableName, Fields, SplitFun) +%%% +%%% Input: TableName = atom() name of table. +%%% +%%% Fields = List of field names for the records maintained +%%% in the specified table. Can be empty, in which +%%% case entries are listed unadorned of field names +%%% and SplitFun is unused. +%%% | Integer, equivalent to a list with this many '' atoms. +%%% | Arity 1 fun mapping a table entry to a Fields list +%%% or a tuple {Fields, Values} of lists of the same +%%% length. +%%% +%%% If Fields is a list then its length must be the same +%%% as or one less than the size of the tuples contained +%%% in the table. (The values printed then being those +%%% in the tuple or record in question.) +%%% +%%% SplitFun = Arity 3 fun applied as +%%% +%%% SplitFun(TableName, Fields, Values) +%%% +%%% in order to obtain a tuple +%%% +%%% {Field, RestFields, Value, RestValues} +%%% +%%% for which Field/Value will be formatted on +%%% STDOUT. (This is to allow a value to be +%%% transformed before being output by returning a +%%% new value and/or replacing the remainder of +%%% the list.) The returned lists must have the +%%% same length and Field here is an atom, '' causing +%%% a value to be listed unadorned of the field name. +%%% +%%% Field can also be list of field names, in +%%% which case Value must be a record of the +%%% corresponding type. +%%% +%%% | Arity 2 fun applied as SplitFun(Fields, Values). +%%% +%%% Output: Count | undefined +%%% +%%% Count = Number of entries output. +%%% +%%% Description: Pretty-print records in a named table. +%%% ---------------------------------------------------------- + +format(Table, Fields, SFun) + when is_atom(Table), is_function(SFun, 2) -> + ft(ets:info(Table), Table, SFun, Fields); + +format(Table, Fields, SFun) + when is_atom(Table), is_function(SFun, 3) -> + format(Table, Fields, fun(Fs,Vs) -> SFun(Table, Fs, Vs) end); + +%%% ---------------------------------------------------------- +%%% # format(Recs, Fields, SplitFun) +%%% +%%% Input: Recs = list of records/tuples +%%% Fields = As for format(Table, Fields, SplitFun), a table +%%% entry there being a member of Recs. +%%% SplitFun = Arity 3 fun applied as above but with the TableName +%%% replaced by the first element of the records in +%%% question. +%%% | Arity 2 fun as for format/3. +%%% +%%% Output: length(Recs) +%%% +%%% Description: Pretty print records/tuples. +%%% ---------------------------------------------------------- + +format(Recs, Fields, SFun) + when is_list(Recs), is_function(SFun, 3) -> + lists:foldl(fun(R,A) -> f(recsplit(SFun, R), 0, Fields, R, A) end, + 0, + Recs); + +format(Recs, Fields, SFun) + when is_list(Recs), is_function(SFun, 2) -> + lists:foldl(fun(R,A) -> f(SFun, 0, Fields, R, A) end, + 0, + Recs); + +%%% ---------------------------------------------------------- +%%% # format(Tables, SplitFun, CollectFun) +%%% +%%% Input: Tables = list of {TableName, Fields}. +%%% SplitFun = As for format(Table, Fields, SplitFun). +%%% CollectFun = arity 1 fun mapping a table name to a list +%%% of elements. A non-list can be returned to indicate +%%% that the table in question doesn't exist. +%%% +%%% Output: Number of entries output. +%%% +%%% Description: Pretty-print records in a named tables as collected +%%% from known nodes. Each table listing is preceeded by +%%% a banner. +%%% ---------------------------------------------------------- + +format(Tables, SFun, CFun) + when is_list(Tables), is_function(CFun, 1) -> + format_remote(Tables, + SFun, + rpc:multicall(nodes(known), + ?MODULE, + collect, + [CFun, lists:map(fun({T,_}) -> T end, Tables)], + ?LONG_TIMEOUT)); + +%%% ---------------------------------------------------------- +%%% # format(LocalTables, RemoteTables, SplitFun, CollectFun) +%%% # format(LocalTables, RemoteTables, SplitFun) +%%% +%%% Input: LocalTables = list of {TableName, Fields}. +%%% | list of {TableName, Recs, Fields} +%%% RemoteTable = list of {TableName, Fields}. +%%% SplitFun, CollectFun = As for format(Table, CollectFun, SplitFun). +%%% +%%% Output: Number of entries output. +%%% +%%% Description: Pretty-print records in a named tables as collected +%%% from local and remote nodes. Each table listing is +%%% preceeded by a banner. +%%% ---------------------------------------------------------- + +format(Local, Remote, SFun) -> + format(Local, Remote, SFun, fun tab2list/1). + +format(Local, Remote, SFun, CFun) + when is_list(Local), is_list(Remote), is_function(CFun, 1) -> + format_local(Local, SFun) + format(Remote, SFun, CFun). + +%%% ---------------------------------------------------------- +%%% # format(Tables, SplitFun) +%%% ---------------------------------------------------------- + +format(Tables, SFun) + when is_list(Tables), (is_function(SFun, 2) or is_function(SFun, 3)) -> + format(Tables, SFun, fun tab2list/1); + +format(Tables, CFun) + when is_list(Tables), is_function(CFun, 1) -> + format(Tables, fun split/2, CFun). + +%%% ---------------------------------------------------------- +%%% # format(Table|Tables) +%%% ---------------------------------------------------------- + +format(Table) + when is_atom(Table) -> + format(Table, [], fun split/2); + +format(Tables) + when is_list(Tables) -> + format(Tables, fun split/2, fun tab2list/1). + +%%% ---------------------------------------------------------- +%%% # split(TableName, Fields, Values) +%%% +%%% Description: format/3 SplitFun that does nothing special. +%%% ---------------------------------------------------------- + +split([F|FT], [V|VT]) -> + {F, FT, V, VT}. + +split(_, Fs, Vs) -> + split(Fs, Vs). + +%%% ---------------------------------------------------------- +%%% # tab2list(TableName) +%%% +%%% Description: format/4 CollectFun that extracts records from an +%%% existing ets table. +%%% ---------------------------------------------------------- + +tab2list(Table) -> + case ets:info(Table) of + undefined = No -> + No; + _ -> + ets:tab2list(Table) + end. + +list(Table) -> + l(tab2list(Table)). + +l(undefined = No) -> + No; +l(List) + when is_list(List) -> + io:format("~p~n", [List]), + length(List). + +%%% ---------------------------------------------------------- +%%% # table(TableName, Fields) +%%% ---------------------------------------------------------- + +table(Table, Fields) -> + format(Table, Fields, fun split/2). + +%%% ---------------------------------------------------------- +%%% # tables(LocalTables, RemoteTables) +%%% ---------------------------------------------------------- + +tables(Local, Remote) -> + format(Local, Remote, fun split/2). + +%%% ---------------------------------------------------------- +%%% # tables(Tables) +%%% ---------------------------------------------------------- + +tables(Tables) -> + format(Tables, fun split/2). + +%%% ---------------------------------------------------------- +%%% # modules(Prefix|Prefixes) +%%% +%%% Input: Prefix = atom() +%%% +%%% Description: Return the list of all loaded modules with the +%%% specified prefix. +%%% ---------------------------------------------------------- + +modules(Prefix) + when is_atom(Prefix) -> + lists:sort(mods(Prefix)); + +modules(Prefixes) + when is_list(Prefixes) -> + lists:sort(lists:flatmap(fun modules/1, Prefixes)). + +mods(Prefix) -> + P = atom_to_list(Prefix), + lists:filter(fun(M) -> + lists:prefix(P, atom_to_list(M)) + end, + erlang:loaded()). + +%%% ---------------------------------------------------------- +%%% # versions(Modules|Prefix) +%%% +%%% Output: Number of modules listed. +%%% +%%% Description: List the versions of the specified modules. +%%% ---------------------------------------------------------- + +versions(Modules) -> + {SysInfo, OsInfo, ModInfo} = version_info(Modules), + sep(), + print_sys_info(SysInfo), + sep(), + print_os_info(OsInfo), + sep(), + print_mod_info(ModInfo), + sep(). + +%%% ---------------------------------------------------------- +%%% # attrs(Modules|Prefix, Attr|FormatFun) +%%% +%%% Output: Number of modules listed. +%%% +%%% Description: List an attribute from module_info. +%%% ---------------------------------------------------------- + +attrs(Modules, Attr) + when is_atom(Attr) -> + attrs(Modules, fun(W,M) -> attr(W, M, Attr, fun attr/1) end); + +attrs(Modules, Fun) + when is_list(Modules) -> + sep(), + W = 2 + widest(Modules), + N = lists:foldl(fun(M,A) -> Fun(W,M), A+1 end, 0, Modules), + sep(), + N; + +attrs(Prefix, Fun) -> + attrs(modules(Prefix), Fun). + +%% attr/1 + +attr(T) when is_atom(T) -> + atom_to_list(T); +attr(N) when is_integer(N) -> + integer_to_list(N); +attr(V) -> + case is_list(V) andalso lists:all(fun is_char/1, V) of + true -> %% string + V; + false -> + io_lib:format("~p", [V]) + end. + +is_char(C) -> + 0 =< C andalso C < 256. + +%% attr/4 + +attr(Width, Mod, Attr, VFun) -> + io:format(": ~*s~s~n", [-Width, Mod, attr(Mod, Attr, VFun)]). + +attr(Mod, Attr, VFun) -> + Key = key(Attr), + try + VFun(val(Attr, keyfetch(Attr, Mod:module_info(Key)))) + catch + _:_ -> + "-" + end. + +attr(Mod, Attr) -> + attr(Mod, Attr, fun attr/1). + +key(time) -> compile; +key(_) -> attributes. + +val(time, {_,_,_,_,_,_} = T) -> + lists:flatten(io_lib:format("~p-~2..0B-~2..0B ~2..0B:~2..0B:~2..0B", + tuple_to_list(T))); +val(_, [V]) -> + V. + +%%% ---------------------------------------------------------- +%%% # compiled(Modules|Prefix) +%%% +%%% Output: Number of modules listed. +%%% +%%% Description: List the compile times of the specified modules. +%%% ---------------------------------------------------------- + +compiled(Modules) + when is_list(Modules) -> + attrs(Modules, fun compiled/2); + +compiled(Prefix) -> + compiled(modules(Prefix)). + +compiled(Width, Mod) -> + io:format(": ~*s~19s ~s~n", [-Width, + Mod, + attr(Mod, time), + opt(attr(Mod, date))]). + +opt("-") -> + ""; +opt(D) -> + "(" ++ D ++ ")". + +%%% ---------------------------------------------------------- +%%% # procs(Pred|Prefix|Prefixes|Pid|Pids) +%%% +%%% Input: Pred = arity 2 fun returning true|false when applied to a +%%% pid and its process info. +%%% +%%% Output: Number of processes listed. +%%% +%%% Description: List process info for all local processes that test +%%% true with the specified predicate. With the prefix +%%% form, those processes that are either currently +%%% executing in, started executing in, or have a +%%% registered name with a specified prefix are listed. +%%% With the pid forms, only those process that are local +%%% are listed and those that are dead list only the pid +%%% itself. +%%% ---------------------------------------------------------- + +procs(Pred) + when is_function(Pred, 2) -> + procs(Pred, erlang:processes()); + +procs([]) -> + 0; + +procs(Prefix) + when is_atom(Prefix) -> + procs(fun(_,I) -> info(fun pre1/2, I, atom_to_list(Prefix)) end); + +procs(Prefixes) + when is_atom(hd(Prefixes)) -> + procs(fun(_,I) -> info(fun pre/2, I, Prefixes) end); + +procs(Pid) + when is_pid(Pid) -> + procs(fun true2/2, [Pid]); + +procs(Pids) + when is_list(Pids) -> + procs(fun true2/2, Pids). + +true2(_,_) -> + true. + +%% procs/2 + +procs(Pred, Pids) -> + Procs = lists:foldl(fun(P,A) -> + procs_acc(Pred, P, catch process_info(P), A) + end, + [], + Pids), + sep(0 < length(Procs)), + lists:foldl(fun(T,N) -> p(T), sep(), N+1 end, 0, Procs). + +procs_acc(_, Pid, undefined, Acc) -> %% dead + [[{pid, Pid}] | Acc]; +procs_acc(Pred, Pid, Info, Acc) + when is_list(Info) -> + p_acc(Pred(Pid, Info), Pid, Info, Acc); +procs_acc(_, _, _, Acc) -> + Acc. + +p_acc(true, Pid, Info, Acc) -> + [[{pid, Pid} | Info] | Acc]; +p_acc(false, _, _, Acc) -> + Acc. + +%% info/3 + +info(Pred, Info, T) -> + lists:any(fun(I) -> i(Pred, I, T) end, Info). + +i(Pred, {K, {M,_,_}}, T) + when K == current_function; + K == initial_call -> + Pred(M,T); +i(Pred, {registered_name, N}, T) -> + Pred(N,T); +i(_,_,_) -> + false. + +pre1(A, Pre) -> + lists:prefix(Pre, atom_to_list(A)). + +pre(A, Prefixes) -> + lists:any(fun(P) -> pre1(A, atom_to_list(P)) end, Prefixes). + +%%% ---------------------------------------------------------- +%%% # latest(Modules|Prefix) +%%% +%%% Output: {Mod, {Y,M,D,HH,MM,SS}, Version} +%%% +%%% Description: Return the compile time of the most recently compiled +%%% module from the specified non-empty list. The modules +%%% are assumed to exist. +%%% ---------------------------------------------------------- + +latest(Prefix) + when is_atom(Prefix) -> + latest(modules(Prefix)); + +latest([_|_] = Modules) -> + {Mod, T} + = hd(lists:sort(fun latest/2, lists:map(fun compile_time/1, Modules))), + {Mod, T, app_vsn(Mod)}. + +app_vsn(Mod) -> + keyfetch(app_vsn, Mod:module_info(attributes)). + +compile_time(Mod) -> + T = keyfetch(time, Mod:module_info(compile)), + {Mod, T}. + +latest({_,T1},{_,T2}) -> + T1 > T2. + +%%% ---------------------------------------------------------- +%%% version_info(Modules|Prefix) +%%% +%%% Output: {SysInfo, OSInfo, [ModInfo]} +%%% +%%% SysInfo = {Arch, Vers} +%%% OSInfo = {Vers, {Fam, Name}} +%%% ModInfo = {Vsn, AppVsn, Time, CompilerVsn} +%%% ---------------------------------------------------------- + +version_info(Prefix) + when is_atom(Prefix) -> + version_info(modules(Prefix)); + +version_info(Mods) + when is_list(Mods) -> + {sys_info(), os_info(), [{M, mod_version_info(M)} || M <- Mods]}. + +mod_version_info(Mod) -> + try + Info = Mod:module_info(), + [[Vsn], AppVsn] = get_values(attributes, [vsn, app_vsn], Info), + [Ver, Time] = get_values(compile, [version, time], Info), + [Vsn, AppVsn, Ver, Time] + catch + _:_ -> + [] + end. + +get_values(Attr, Keys, Info) -> + As = proplists:get_value(Attr, Info), + [proplists:get_value(K, As, "?") || K <- Keys]. + +sys_info() -> + [A,V] = [chomp(erlang:system_info(K)) || K <- [system_architecture, + system_version]], + {A,V}. + +os_info() -> + {os:version(), case os:type() of + {_Fam, _Name} = T -> + T; + Fam -> + {Fam, ""} + end}. + +chomp(S) -> + string:strip(S, right, $\n). + +print_sys_info({Arch, Ver}) -> + io:format("System info:~n" + " architecture : ~s~n" + " version : ~s~n", + [Arch, Ver]). + +print_os_info({Vsn, {Fam, Name}}) -> + io:format("OS info:~n" + " family : ~s ~s~n" + " version : ~s~n", + [str(Fam), bkt(str(Name)), vsn(Vsn)]). + +print_mod_info(Mods) -> + io:format("Module info:~n", []), + lists:foreach(fun print_mod/1, Mods). + +print_mod({Mod, []}) -> + io:format(" ~w:~n", [Mod]); +print_mod({Mod, [Vsn, AppVsn, Ver, {Year, Month, Day, Hour, Min, Sec}]}) -> + Time = io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", + [Year, Month, Day, Hour, Min, Sec]), + io:format(" ~w:~n" + " vsn : ~s~n" + " app_vsn : ~s~n" + " compiled : ~s~n" + " compiler : ~s~n", + [Mod, str(Vsn), str(AppVsn), Time, Ver]). + +str(A) + when is_atom(A) -> + atom_to_list(A); +str(S) + when is_list(S) -> + S; +str(T) -> + io_lib:format("~p", [T]). + +bkt("" = S) -> + S; +bkt(S) -> + [$[, S, $]]. + +vsn(T) when is_tuple(T) -> + case [[$., integer_to_list(N)] || N <- tuple_to_list(T)] of + [[$.,S] | Rest] -> + [S | Rest]; + [] = S -> + S + end; +vsn(T) -> + str(T). + +%%% ---------------------------------------------------------- +%%% ---------------------------------------------------------- + +%% p/1 + +p(Info) -> + W = 2 + widest([K || {K,_} <- Info]), + lists:foreach(fun({K,V}) -> p(W,K,V) end, Info). + +p(Width, Key, Value) -> + io:format(": ~*s: ~p~n", [-Width, Key, Value]). + +%% sep/[01] + +sep() -> + sep($#). + +sep(true) -> + sep(); +sep(false) -> + ok; + +sep(Ch) -> + io:format("~c~65c~n", [Ch, $-]). + +%% widest/1 + +widest(List) -> + lists:foldl(fun widest/2, 0, List). + +widest(T, Max) + when is_atom(T) -> + widest(atom_to_list(T), Max); + +widest(T, Max) + when is_integer(T) -> + widest(integer_to_list(T), Max); + +widest(T, Max) + when is_list(T) -> %% string + max(length(T), Max). + +pt(T) -> + io:format(": ~p~n", [T]). + +recsplit(SFun, Rec) -> + fun(Fs,Vs) -> SFun(element(1, Rec), Fs, Vs) end. + +max(A, B) -> + if A > B -> A; true -> B end. + +keyfetch(Key, List) -> + {Key,V} = lists:keyfind(Key, 1, List), + V. + +%% ft/4 + +ft(undefined = No, _, _, _) -> + No; + +ft(_, Table, SFun, Fields) -> + ets:foldl(fun(R,A) -> + f(SFun, 0, Fields, R, A) + end, + 0, + Table). + +%% f/5 + +f(SFun, Width, Fields, Rec, Count) -> + ff(SFun, Width, fields(Fields, Rec), Rec, Count). + +ff(SFun, Width, Fields, Rec, Count) -> + sep(0 == Count), + f(SFun, Width, Fields, Rec), + sep(), + Count+1. + +fields(N, _) + when is_integer(N), N >= 0 -> + lists:duplicate(N, ''); %% list values unadorned +fields(Fields, R) + when is_function(Fields, 1) -> + fields(Fields(R), R); +fields({Fields, Values} = T, _) + when length(Fields) == length(Values) -> + T; +fields(Fields, _) + when is_list(Fields) -> + Fields. %% list field/value pairs, or tuples if [] + +%% f/4 + +%% Empty fields list: just print the entry. +f(_, _, [], Rec) + when is_tuple(Rec) -> + pt(Rec); + +%% Otherwise list field names/values. +f(SFun, Width, {Fields, Values}, _) -> + f(SFun, Width, Fields, Values); + +f(SFun, Width, Fields, Rec) + when is_tuple(Rec) -> + f(SFun, Width, Fields, values(Fields, Rec)); + +f(_, _, [], []) -> + ok; + +f(SFun, Width, [HF | _] = Fields, Values) -> + {F, FT, V, VT} = SFun(Fields, Values), + if is_list(F) -> %% V is a record + break($>, HF), + f(SFun, Width, F, values(F,V)), + break($<, HF), + f(SFun, Width, FT, VT); + F == '' -> %% no field name: just list value + pt(V), + f(SFun, Width, FT, VT); + true -> %% list field/value. + W = max(Width, 1 + widest(Fields)), + p(W, F, V), + f(SFun, W, FT, VT) + end. + +values(Fields, Rec) + when length(Fields) == size(Rec) - 1 -> + ?VALUES(Rec); +values(Fields, T) + when length(Fields) == size(T) -> + tuple_to_list(T). + +%% format_local/2 + +format_local(Tables, SFun) -> + lists:foldl(fun(T,A) -> fl(SFun, T, A) end, 0, Tables). + +fl(SFun, {Table, Recs, Fields}, Count) -> + sep(), + io:format("# ~p~n", [Table]), + N = fmt(Recs, Fields, SFun), + sep(0 == N), + Count + N; + +fl(SFun, {Table, Fields}, Count) -> + fl(SFun, {Table, Table, Fields}, Count). + +%% fmt/3 + +fmt(T, Fields, SFun) -> + case format(T, Fields, SFun) of + undefined -> + 0; + N -> + N + end. + +%% break/2 + +break(C, T) -> + io:format("~c ~p~n", [C, T]). + +%% collect/2 +%% +%% Output: {[{TableName, Recs}, ...], node()} + +collect(CFun, TableNames) -> + {lists:foldl(fun(N,A) -> c(CFun, N, A) end, [], TableNames), node()}. + +c(CFun, TableName, Acc) -> + case CFun(TableName) of + Recs when is_list(Recs) -> + [{TableName, Recs} | Acc]; + _ -> + Acc + end. + +%% format_remote/3 + +format_remote(Tables, SFun, {Replies, BadNodes}) -> + N = lists:foldl(fun(T,A) -> fr(Tables, SFun, T, A) end, + 0, + Replies), + sep(0 == N andalso [] /= BadNodes), + lists:foreach(fun(Node) -> io:format("# no reply from ~p~n", [Node]) end, + BadNodes), + sep([] /= BadNodes), + N. + +fr(Tables, SFun, {List, Node}, Count) + when is_list(List) -> %% guard against {badrpc, Reason} + lists:foldl(fun({T,Recs}, C) -> fr(Tables, SFun, Node, T, Recs,C) end, + Count, + List); +fr(_, _, _, Count) -> + Count. + +fr(Tables, SFun, Node, Table, Recs, Count) -> + Fields = keyfetch(Table, Tables), + sep(), + io:format("# ~p@~p~n", [Table, Node]), + N = format(Recs, Fields, tblsplit(SFun, Table)), + sep(0 == N), + Count + N. + +tblsplit(SFun, Table) + when is_function(SFun, 3) -> + fun(Fs,Vs) -> SFun(Table, Fs, Vs) end; +tblsplit(SFun, _) + when is_function(SFun, 2) -> + SFun. + +%% compact/1 +%% +%% Strip whitespace from both ends of a string. + +compact(Str) -> + compact(Str, true). + +compact([Ch|Rest], B) + when Ch == $\n; + Ch == $ ; + Ch == $\t; + Ch == $\v; + Ch == $\r -> + compact(Rest, B); + +compact(Str, false) -> + Str; + +compact(Str, true) -> + lists:reverse(compact(lists:reverse(Str), false)). diff --git a/lib/diameter/src/app/diameter_internal.hrl b/lib/diameter/src/app/diameter_internal.hrl new file mode 100644 index 0000000000..9de3914830 --- /dev/null +++ b/lib/diameter/src/app/diameter_internal.hrl @@ -0,0 +1,95 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% Our Erlang application. +-define(APPLICATION, diameter). + +%% The one and only. +-define(DIAMETER_VERSION, 1). + +%% Exception for use within a module with decent protection against +%% catching something we haven't thrown. Not foolproof but close +%% enough. ?MODULE is rudmentary protection against catching across +%% module boundaries, a root of much evil: always catch ?FAILURE(X), +%% never X. +-define(FAILURE(Reason), {{?MODULE}, {Reason}}). +-define(THROW(Reason), throw(?FAILURE(Reason))). + +%% A corresponding error when failure is the best option. +-define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})). + +%% Failure reports always get a stack trace. +-define(STACK, erlang:get_stacktrace()). + +%% Info report for anything unexpected. +-define(REPORT(Reason, Func, Args), + diameter_lib:report(Reason, {?MODULE, Func, Args})). + +%% Something to trace on. +-define(LOG(Slogan, Details), + diameter_dbg:log(Slogan, ?MODULE, ?LINE, Details)). +-define(LOGC(Bool, Slogan, Details), ((Bool) andalso ?LOG(Slogan, Details))). + +%% Compensate for no builtin ?FUNC for use in log reports. +-define(FUNC, element(2, element(2, process_info(self(), current_function)))). + +%% Disjunctive match spec condition. 'false' is to ensure that there's at +%% least one condition. +-define(ORCOND(List), list_to_tuple(['orelse', false | List])). + +%% 3588, 2.4: +-define(APP_ID_COMMON, 0). +-define(APP_ID_RELAY, 16#FFFFFFFF). + +-define(BASE, diameter_gen_base_rfc3588). + +%%% --------------------------------------------------------- + +%%% RFC 3588, ch 2.6 Peer table +-record(diameter_peer, + {host_id, + statusT, + is_dynamic, + expiration, + tls_enabled}). + +%%% RFC 3588, ch 2.7 Realm-based routing table +-record(diameter_realm, + {name, + app_id, + local_action, % LOCAL | RELAY | PROXY | REDIRECT + server_id, + is_dynamic, + expiration}). + +%%%---------------------------------------------------------------------- +%%% Error/warning/info message macro(s) +%%%---------------------------------------------------------------------- + +-define(diameter_info(F, A), + (catch error_logger:info_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n", + [?APPLICATION, ?MODULE, self()|A]))). + +-define(diameter_warning(F, A), + (catch error_logger:warning_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n", + [?APPLICATION, ?MODULE, self()|A]))). + +-define(diameter_error(F, A), + (catch error_logger:error_msg("[ ~w : ~w : ~p ] ~n" ++ F ++ "~n", + [?APPLICATION, ?MODULE, self()|A]))). diff --git a/lib/diameter/src/app/diameter_lib.erl b/lib/diameter/src/app/diameter_lib.erl new file mode 100644 index 0000000000..b5c0e1bf6a --- /dev/null +++ b/lib/diameter/src/app/diameter_lib.erl @@ -0,0 +1,266 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_lib). + +-export([report/2, info_report/2, + error_report/2, + warning_report/2, + now_diff/1, + time/1, + eval/1, + ip4address/1, + ip6address/1, + ipaddr/1, + spawn_opts/2, + wait/1, + fold_tuple/3]). + +-include("diameter_internal.hrl"). + +%% --------------------------------------------------------------------------- +%% # info_report(Reason, MFA) +%% +%% Input: Reason = Arbitrary term indicating the reason for the report. +%% MFA = {Module, Function, Args} to report. +%% +%% Output: true +%% --------------------------------------------------------------------------- + +report(Reason, MFA) -> + info_report(Reason, MFA). + +info_report(Reason, {M,F,A}) -> + error_logger:info_report(" Reason: ~p~n" + " Pid: ~p~n" + " Node: ~p~n" + " Module: ~p~n" + " Function: ~p~n" + "Arguments: ~p~n", + [Reason, self(), node(), M, F, A]). + +%%% --------------------------------------------------------------------------- +%%% # error_report(Reason, MFA) +%%% # warning_report(Reason, MFA) +%%% +%%% Output: false +%%% --------------------------------------------------------------------------- + +error_report(Reason, MFA) -> + report(fun error_logger:error_report/1, Reason, MFA). + +warning_report(Reason, MFA) -> + report(fun error_logger:warning_report/1, Reason, MFA). + +report(Fun, Reason, MFA) -> + Fun([{reason, Reason}, {who, self()}, {where, node()}, {what, MFA}]), + false. + +%%% --------------------------------------------------------------------------- +%%% # now_diff(Time) +%%% +%%% Description: Return timer:now_diff(now(), Time) as an {H, M, S, MicroS} +%%% tuple instead of as integer microseconds. +%%% --------------------------------------------------------------------------- + +now_diff({_,_,_} = Time) -> + time(timer:now_diff(erlang:now(), Time)). + +%%% --------------------------------------------------------------------------- +%%% # time(Time) +%%% +%%% Input: Time = {MegaSec, Sec, MicroSec} +%%% | MicroSec +%%% +%%% Output: {H, M, S, MicroS} +%%% --------------------------------------------------------------------------- + +time({_,_,_} = Time) -> %% time of day + %% 24 hours = 24*60*60*1000000 = 86400000000 microsec + time(timer:now_diff(Time, {0,0,0}) rem 86400000000); + +time(Micro) -> %% elapsed time + Seconds = Micro div 1000000, + H = Seconds div 3600, + M = (Seconds rem 3600) div 60, + S = Seconds rem 60, + {H, M, S, Micro rem 1000000}. + +%%% --------------------------------------------------------------------------- +%%% # eval(Func) +%%% --------------------------------------------------------------------------- + +eval({M,F,A}) -> + apply(M,F,A); + +eval([{M,F,A} | X]) -> + apply(M, F, X ++ A); + +eval([[F|A] | X]) -> + eval([F | X ++ A]); + +eval([F|A]) -> + apply(F,A); + +eval({F}) -> + eval(F); + +eval(F) -> + F(). + +%%% --------------------------------------------------------------------------- +%%% # ip4address(Addr) +%%% +%%% Input: string() (eg. "10.0.0.1") +%%% | list of integer() +%%% | tuple of integer() +%%% +%%% Output: {_,_,_,_} of integer +%%% +%%% Exceptions: error: {invalid_address, Addr, erlang:get_stacktrace()} +%%% --------------------------------------------------------------------------- + +ip4address([_,_,_,_] = Addr) -> %% Length 4 string can't be an address. + ipaddr(list_to_tuple(Addr)); + +%% Be brutal. +ip4address(Addr) -> + try + {_,_,_,_} = ipaddr(Addr) + catch + error: _ -> + erlang:error({invalid_address, Addr, ?STACK}) + end. + +%%% --------------------------------------------------------------------------- +%%% # ip6address(Addr) +%%% +%%% Input: string() (eg. "1080::8:800:200C:417A") +%%% | list of integer() +%%% | tuple of integer() +%%% +%%% Output: {_,_,_,_,_,_,_,_} of integer +%%% +%%% Exceptions: error: {invalid_address, Addr, erlang:get_stacktrace()} +%%% --------------------------------------------------------------------------- + +ip6address([_,_,_,_,_,_,_,_] = Addr) -> %% Length 8 string can't be an address. + ipaddr(list_to_tuple(Addr)); + +%% Be brutal. +ip6address(Addr) -> + try + {_,_,_,_,_,_,_,_} = ipaddr(Addr) + catch + error: _ -> + erlang:error({invalid_address, Addr, ?STACK}) + end. + +%%% --------------------------------------------------------------------------- +%%% # ipaddr(Addr) +%%% +%%% Input: string() | tuple of integer() +%%% +%%% Output: {_,_,_,_} | {_,_,_,_,_,_,_,_} +%%% +%%% Exceptions: error: {invalid_address, erlang:get_stacktrace()} +%%% --------------------------------------------------------------------------- + +-spec ipaddr(string() | tuple()) + -> inet:ip_address(). + +%% Don't convert lists of integers since a length 8 list like +%% [$1,$0,$.,$0,$.,$0,$.,$1] is ambiguous: is it "10.0.0.1" or +%% "49:48:46:48:46:48:46:49"? +%% +%% RFC 2373 defines the format parsed for v6 addresses. + +%% Be brutal. +ipaddr(Addr) -> + try + ip(Addr) + catch + error: _ -> + erlang:error({invalid_address, ?STACK}) + end. + +%% Already a tuple: ensure non-negative integers of the right size. +ip(T) + when size(T) == 4; + size(T) == 8 -> + Bs = 2*size(T), + [] = lists:filter(fun(N) when 0 =< N -> 0 < N bsr Bs end, + tuple_to_list(T)), + T; + +%% Or not: convert from '.'/':'-separated decimal/hex. +ip(Addr) -> + {ok, A} = inet_parse:address(Addr), %% documented in inet(3) + A. + +%%% --------------------------------------------------------------------------- +%%% # spawn_opts(Type, Opts) +%%% --------------------------------------------------------------------------- + +%% TODO: config variables. + +spawn_opts(server, Opts) -> + opts(75000, Opts); +spawn_opts(worker, Opts) -> + opts(5000, Opts). + +opts(HeapSize, Opts) -> + [{min_heap_size, HeapSize} | lists:keydelete(min_heap_size, 1, Opts)]. + +%%% --------------------------------------------------------------------------- +%%% # wait(MRefs) +%%% --------------------------------------------------------------------------- + +wait(L) -> + w([erlang:monitor(process, P) || P <- L]). + +w([]) -> + ok; +w(L) -> + receive + {'DOWN', MRef, process, _, _} -> + w(lists:delete(MRef, L)) + end. + +%%% --------------------------------------------------------------------------- +%%% # fold_tuple(N, T0, T) +%%% --------------------------------------------------------------------------- + +%% Replace fields in T0 by those of T starting at index N, unless the +%% new value is 'undefined'. +%% +%% eg. fold_tuple(2, Hdr, #diameter_header{end_to_end_id = 42}) + +fold_tuple(_, T, undefined) -> + T; + +fold_tuple(N, T0, T) -> + element(2, lists:foldl(fun(X, {M,_} = A) -> {M+1, ft(X, A)} end, + {N, T0}, + lists:nthtail(N-1, tuple_to_list(T)))). + +ft(undefined, T) -> + T; +ft(X, {N, T}) -> + setelement(N, T, X). diff --git a/lib/diameter/src/app/diameter_misc_sup.erl b/lib/diameter/src/app/diameter_misc_sup.erl new file mode 100644 index 0000000000..4e40476f14 --- /dev/null +++ b/lib/diameter/src/app/diameter_misc_sup.erl @@ -0,0 +1,58 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% The supervisor of the static server processes. +%% + +-module(diameter_misc_sup). + +-behaviour(supervisor). + +-export([start_link/0]). %% supervisor start + +%% supervisor callback +-export([init/1]). + +-define(CHILDREN, [diameter_sync, %% serialization + diameter_stats, %% statistics counter management + diameter_reg, %% service/property publishing + diameter_peer, %% remote peer manager + diameter_config]). %% configuration/restart + +%% start_link/0 + +start_link() -> + SupName = {local, ?MODULE}, + supervisor:start_link(SupName, ?MODULE, []). + +%% init/1 + +init([]) -> + Flags = {one_for_one, 1, 5}, + Workers = lists:map(fun spec/1, ?CHILDREN), + {ok, {Flags, Workers}}. + +spec(Mod) -> + {Mod, + {Mod, start_link, []}, + permanent, + 1000, + worker, + [Mod]}. diff --git a/lib/diameter/src/app/diameter_peer.erl b/lib/diameter/src/app/diameter_peer.erl new file mode 100644 index 0000000000..6b8971b8ea --- /dev/null +++ b/lib/diameter/src/app/diameter_peer.erl @@ -0,0 +1,230 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_peer). + +-behaviour(gen_server). + +%% Interface towards transport modules ... +-export([recv/2, + up/1, + up/2]). + +%% ... and the stack. +-export([start/3, + send/2, + close/1, + abort/1, + notify/2]). + +%% Server start. +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, + terminate/2, + handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3]). + +%% debug +-export([state/0, + uptime/0]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). + +%% Registered name of the server. +-define(SERVER, ?MODULE). + +%% Server state. +-record(state, {id = now()}). + +%%% --------------------------------------------------------------------------- +%%% # notify/2 +%%% --------------------------------------------------------------------------- + +notify(SvcName, T) -> + rpc:abcast(nodes(), ?SERVER, {notify, SvcName, T}). + +%%% --------------------------------------------------------------------------- +%%% # start/3 +%%% --------------------------------------------------------------------------- + +start(T, Opts, #diameter_service{} = Svc) -> + {Mod, Cfg} = split_transport(Opts), + apply(Mod, start, [T, Svc, Cfg]). + +%%% --------------------------------------------------------------------------- +%%% # up/[12] +%%% --------------------------------------------------------------------------- + +up(Pid) -> %% accepting transport + ifc_send(Pid, {self(), connected}). + +up(Pid, Remote) -> %% connecting transport + ifc_send(Pid, {self(), connected, Remote}). + +%%% --------------------------------------------------------------------------- +%%% # recv/2 +%%% --------------------------------------------------------------------------- + +recv(Pid, Pkt) -> + ifc_send(Pid, {recv, Pkt}). + +%%% --------------------------------------------------------------------------- +%%% # send/2 +%%% --------------------------------------------------------------------------- + +send(Pid, #diameter_packet{transport_data = undefined, + bin = Bin}) -> + send(Pid, Bin); + +send(Pid, Pkt) -> + ifc_send(Pid, {send, Pkt}). + +%%% --------------------------------------------------------------------------- +%%% # close/1 +%%% --------------------------------------------------------------------------- + +close(Pid) -> + ifc_send(Pid, {close, self()}). + +%%% --------------------------------------------------------------------------- +%%% # abort/1 +%%% --------------------------------------------------------------------------- + +abort(Pid) -> + exit(Pid, shutdown). + +%% --------------------------------------------------------------------------- +%% --------------------------------------------------------------------------- + +start_link() -> + ServerName = {local, ?SERVER}, + Module = ?MODULE, + Args = [], + Options = [{spawn_opt, diameter_lib:spawn_opts(server, [])}], + gen_server:start_link(ServerName, Module, Args, Options). + +state() -> + call(state). + +uptime() -> + call(uptime). + +%%% ---------------------------------------------------------- +%%% # init(Role) +%%% ---------------------------------------------------------- + +init([]) -> + {ok, #state{}}. + +%%% ---------------------------------------------------------- +%%% # handle_call(Request, From, State) +%%% ---------------------------------------------------------- + +handle_call(state, _, State) -> + {reply, State, State}; + +handle_call(uptime, _, #state{id = Time} = State) -> + {reply, diameter_lib:now_diff(Time), State}; + +handle_call(Req, From, State) -> + warning_msg("received unexpected request from ~p:~n~w", [From, Req]), + {reply, nok, State}. + +%%% ---------------------------------------------------------- +%%% # handle_cast(Request, State) +%%% ---------------------------------------------------------- + +handle_cast(Msg, State) -> + warning_msg("received unexpected message:~n~w", [Msg]), + {noreply, State}. + +%%% ---------------------------------------------------------- +%%% # handle_info(Request, State) +%%% ---------------------------------------------------------- + +%% Remote service is distributing a message. +handle_info({notify, SvcName, T}, S) -> + bang(diameter_service:whois(SvcName), T), + {noreply, S}; + +handle_info(Info, State) -> + warning_msg("received unexpected info:~n~w", [Info]), + {noreply, State}. + +%% ---------------------------------------------------------- +%% terminate(Reason, State) +%% ---------------------------------------------------------- + +terminate(_Reason, _State) -> + ok. + +%% ---------------------------------------------------------- +%% code_change(OldVsn, State, Extra) +%% ---------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%% --------------------------------------------------------- +%% INTERNAL FUNCTIONS +%% --------------------------------------------------------- + +%% ifc_send/2 +%% +%% Send something over the transport interface. + +ifc_send(Pid, T) -> + Pid ! {diameter, T}. + +%% bang/2 + +bang(undefined = No, _) -> + No; +bang(Pid, T) -> + Pid ! T. + +%% split_transport/1 +%% +%% Split options into transport module, transport config and +%% remaining options. + +split_transport(Opts) -> + {[M,C], _} = proplists:split(Opts, [transport_module, + transport_config]), + {value(M, diameter_tcp), value(C, [])}. + +value([{_,V}], _) -> + V; +value([], V) -> + V. + +%% call/1 + +call(Request) -> + gen_server:call(?SERVER, Request, infinity). + +%% warning_msg/2 + +warning_msg(F, A) -> + ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_peer_fsm.erl b/lib/diameter/src/app/diameter_peer_fsm.erl new file mode 100644 index 0000000000..0252fb3809 --- /dev/null +++ b/lib/diameter/src/app/diameter_peer_fsm.erl @@ -0,0 +1,746 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This module implements (as a process) the RFC 3588 Peer State +%% Machine modulo the necessity of adapting the peer election to the +%% fact that we don't know the identity of a peer until we've +%% received a CER/CEA from it. +%% + +-module(diameter_peer_fsm). +-behaviour(gen_server). + +%% Interface towards diameter_watchdog. +-export([start/3]). + +%% gen_server callbacks +-export([init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3]). + +%% diameter_peer_fsm_sup callback +-export([start_link/1]). + +%% internal callbacks +-export([match/1]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). +-include("diameter_types.hrl"). +-include("diameter_gen_base_rfc3588.hrl"). + +-define(GOAWAY, ?'DIAMETER_BASE_DISCONNECT-CAUSE_DO_NOT_WANT_TO_TALK_TO_YOU'). +-define(REBOOT, ?'DIAMETER_BASE_DISCONNECT-CAUSE_REBOOTING'). + +-define(LOOP_TIMEOUT, 2000). + +%% RFC 3588: +%% +%% Timeout An application-defined timer has expired while waiting +%% for some event. +%% +-define(EVENT_TIMEOUT, 10000). + +%% How long to wait for a DPA in response to DPR before simply +%% aborting. Used to distinguish between shutdown and not but there's +%% not really any need. Stopping a service will require a timeout if +%% the peer doesn't answer DPR so the value should be short-ish. +-define(DPA_TIMEOUT, 1000). + +-record(state, + {state = 'Wait-Conn-Ack' %% state of RFC 3588 Peer State Machine + :: 'Wait-Conn-Ack' | recv_CER | 'Wait-CEA' | 'Open', + mode :: accept | connect | {connect, reference()}, + parent :: pid(), + transport :: pid(), + service :: #diameter_service{}, + dpr = false :: false | {'Unsigned32'(), 'Unsigned32'()}}). + %% | hop by hop and end to end identifiers + +%% There are non-3588 states possible as a consequence of 5.6.1 of the +%% standard and the corresponding problem for incoming CEA's: we don't +%% know who we're talking to until either a CER or CEA has been +%% received. The CEA problem in particular makes it impossible to +%% follow the state machine exactly as documented in 3588: there can +%% be no election until the CEA arrives and we have an Origin-Host to +%% elect. + +%% +%% Once upon a time start/2 started a process akin to that started by +%% start/3 below, which in turn started a watchdog/transport process +%% with the result that the watchdog could send DWR/DWA regardless of +%% whether or not the corresponding Peer State Machine was in its open +%% state; that is, before capabilities exchange had taken place. This +%% is not what RFC's 3588 and 3539 say (albeit not very clearly). +%% Watchdog messages are only exchanged on *open* connections, so the +%% 3539 state machine is more naturally placed on top of the 3588 Peer +%% State Machine rather than closer to the transport. This is what we +%% now do below: connect/accept call diameter_watchdog and return the +%% pid of the watchdog process, and the watchdog in turn calls start/3 +%% below to start the process implementing the Peer State Machine. The +%% former is a "peer" in diameter_service while the latter is a +%% "conn". In a sense, diameter_service sees the watchdog as +%% implementing the Peer State Machine and the process implemented +%% here as being the transport, not being aware of the watchdog at +%% all. +%% + +%%% --------------------------------------------------------------------------- +%%% # start({connect|accept, Ref}, Opts, Service) +%%% +%%% Output: Pid +%%% --------------------------------------------------------------------------- + +%% diameter_config requires a non-empty list of applications on the +%% service but diameter_service then constrains the list to any +%% specified on the transport in question. Check here that the list is +%% still non-empty. + +start({_, Ref} = Type, Opts, #diameter_service{applications = Apps} = Svc) -> + [] /= Apps orelse ?ERROR({no_apps, Type, Opts}), + T = {self(), Type, Opts, Svc}, + {ok, Pid} = diameter_peer_fsm_sup:start_child(T), + diameter_stats:reg(Pid, Ref), + Pid. + +start_link(T) -> + {ok, _} = proc_lib:start_link(?MODULE, + init, + [T], + infinity, + diameter_lib:spawn_opts(server, [])). + +%%% --------------------------------------------------------------------------- +%%% --------------------------------------------------------------------------- + +%% init/1 + +init(T) -> + proc_lib:init_ack({ok, self()}), + gen_server:enter_loop(?MODULE, [], i(T)). + +i({WPid, {M, _} = T, Opts, #diameter_service{capabilities = Caps} = Svc0}) -> + putr(dwa, dwa(Caps)), + {ok, TPid, Svc} = start_transport(T, Opts, Svc0), + erlang:monitor(process, TPid), + erlang:monitor(process, WPid), + #state{parent = WPid, + transport = TPid, + mode = M, + service = Svc}. +%% The transport returns its local ip addresses so that different +%% transports on the same service can use different local addresses. +%% The local addresses are put into Host-IP-Address avps here when +%% sending capabilities exchange messages. +%% +%% Invalid transport config may cause us to crash but note that the +%% watchdog start (start/2) succeeds regardless so as not to crash the +%% service. + +start_transport(T, Opts, Svc) -> + case diameter_peer:start(T, Opts, Svc) of + {ok, TPid} -> + {ok, TPid, Svc}; + {ok, TPid, [_|_] = Addrs} -> + #diameter_service{capabilities = Caps0} = Svc, + Caps = Caps0#diameter_caps{host_ip_address = Addrs}, + {ok, TPid, Svc#diameter_service{capabilities = Caps}}; + No -> + exit({shutdown, No}) + end. + +%% handle_call/3 + +handle_call(_, _, State) -> + {reply, nok, State}. + +%% handle_cast/2 + +handle_cast(_, State) -> + {noreply, State}. + +%% handle_info/1 + +handle_info(T, #state{} = State) -> + try transition(T, State) of + ok -> + {noreply, State}; + #state{state = X} = S -> + ?LOGC(X =/= State#state.state, transition, X), + {noreply, S}; + {stop, Reason} -> + ?LOG(stop, Reason), + x(Reason, State); + stop -> + ?LOG(stop, T), + x(T, State) + catch + throw: {?MODULE, close = C, Reason} -> + ?LOG(C, {Reason, T}), + x(Reason, State); + throw: {?MODULE, abort, Reason} -> + {stop, {shutdown, Reason}, State} + end. + +x(Reason, #state{} = S) -> + close_wd(Reason, S), + {stop, {shutdown, Reason}, S}. + +%% terminate/2 + +terminate(_, _) -> + ok. + +%% code_change/3 + +code_change(_, State, _) -> + {ok, State}. + +%%% --------------------------------------------------------------------------- +%%% --------------------------------------------------------------------------- + +putr(Key, Val) -> + put({?MODULE, Key}, Val). + +getr(Key) -> + get({?MODULE, Key}). + +%% transition/2 + +%% Connection to peer. +transition({diameter, {TPid, connected, Remote}}, + #state{state = PS, + mode = M} + = S) -> + 'Wait-Conn-Ack' = PS, %% assert + connect = M, %% + send_CER(S#state{mode = {M, Remote}, + transport = TPid}); + +%% Connection from peer. +transition({diameter, {TPid, connected}}, + #state{state = PS, + mode = M, + parent = Pid} + = S) -> + 'Wait-Conn-Ack' = PS, %% assert + accept = M, %% + Pid ! {accepted, self()}, + start_timer(S#state{state = recv_CER, + transport = TPid}); + +%% Incoming message from the transport. +transition({diameter, {recv, Pkt}}, S) -> + recv(Pkt, S); + +%% Timeout when still in the same state ... +transition({timeout, PS}, #state{state = PS}) -> + stop; + +%% ... or not. +transition({timeout, _}, _) -> + ok; + +%% Outgoing message. +transition({send, Msg}, #state{transport = TPid}) -> + send(TPid, Msg), + ok; + +%% Request for graceful shutdown. +transition({shutdown, Pid}, #state{parent = Pid, dpr = false} = S) -> + dpr(?GOAWAY, S); +transition({shutdown, Pid}, #state{parent = Pid}) -> + ok; + +%% Application shutdown. +transition(shutdown, #state{dpr = false} = S) -> + dpr(?REBOOT, S); +transition(shutdown, _) -> %% DPR already send: ensure expected timeout + dpa_timer(), + ok; + +%% Request to close the transport connection. +transition({close = T, Pid}, #state{parent = Pid, + transport = TPid} + = S) -> + diameter_peer:close(TPid), + close(T,S); + +%% DPA reception has timed out. +transition(dpa_timeout, _) -> + stop; + +%% Someone wants to know a resolved port: forward to the transport process. +transition({resolve_port, _Pid} = T, #state{transport = TPid}) -> + TPid ! T, + ok; + +%% Parent or transport has died. +transition({'DOWN', _, process, P, _}, + #state{parent = Pid, + transport = TPid}) + when P == Pid; + P == TPid -> + stop; + +%% State query. +transition({state, Pid}, #state{state = S, transport = TPid}) -> + Pid ! {self(), [S, TPid]}, + ok. + +%% Crash on anything unexpected. + +%% send_CER/1 + +send_CER(#state{mode = {connect, Remote}, + service = #diameter_service{capabilities = Caps}, + transport = TPid} + = S) -> + req_send_CER(Caps#diameter_caps.origin_host, Remote) + orelse + close(connected, S), + CER = build_CER(S), + ?LOG(send, 'CER'), + send(TPid, encode(CER)), + start_timer(S#state{state = 'Wait-CEA'}). + +%% Register ourselves as connecting to the remote endpoint in +%% question. This isn't strictly necessary since a peer implementing +%% the 3588 Peer State Machine should reject duplicate connection's +%% from the same peer but there's little point in us setting up a +%% duplicate connection in the first place. This could also include +%% the transport protocol being used but since we're blind to +%% transport just avoid duplicate connections to the same host/port. +req_send_CER(OriginHost, Remote) -> + register_everywhere({?MODULE, connection, OriginHost, {remote, Remote}}). + +%% start_timer/1 + +start_timer(#state{state = PS} = S) -> + erlang:send_after(?EVENT_TIMEOUT, self(), {timeout, PS}), + S. + +%% build_CER/1 + +build_CER(#state{service = #diameter_service{capabilities = Caps}}) -> + {ok, CER} = diameter_capx:build_CER(Caps), + CER. + +%% encode/1 + +encode(Rec) -> + #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Rec), + Bin. + +%% recv/2 + +%% RFC 3588 has result code 5015 for an invalid length but if a +%% transport is detecting message boundaries using the length header +%% then a length error will likely lead to further errors. + +recv(#diameter_packet{header = #diameter_header{length = Len} + = Hdr, + bin = Bin}, + S) + when Len < 20; + (0 /= Len rem 4 orelse bit_size(Bin) /= 8*Len) -> + discard(invalid_message_length, recv, [size(Bin), + bit_size(Bin) rem 8, + Hdr, + S]); + +recv(#diameter_packet{header = #diameter_header{} = Hdr} + = Pkt, + #state{parent = Pid} + = S) -> + Name = diameter_codec:msg_name(Hdr), + Pid ! {recv, self(), Name, Pkt}, + diameter_stats:incr({msg_id(Name, Hdr), recv}), %% count received + rcv(Name, Pkt, S); + +recv(#diameter_packet{header = undefined, + bin = Bin} + = Pkt, + S) -> + recv(Pkt#diameter_packet{header = diameter_codec:decode_header(Bin)}, S); + +recv(Bin, S) + when is_binary(Bin) -> + recv(#diameter_packet{bin = Bin}, S); + +recv(#diameter_packet{header = false} = Pkt, S) -> + discard(truncated_header, recv, [Pkt, S]). + +msg_id({_,_,_} = T, _) -> + T; +msg_id(_, Hdr) -> + diameter_codec:msg_id(Hdr). + +%% Treat invalid length as a transport error and die. Especially in +%% the TCP case, in which there's no telling where the next message +%% begins in the incoming byte stream, keeping a crippled connection +%% alive may just make things worse. + +discard(Reason, F, A) -> + diameter_stats:incr(Reason), + diameter_lib:warning_report(Reason, {?MODULE, F, A}), + throw({?MODULE, abort, Reason}). + +%% rcv/3 + +%% Incoming CEA. +rcv('CEA', Pkt, #state{state = 'Wait-CEA'} = S) -> + handle_CEA(Pkt, S); + +%% Incoming CER +rcv('CER' = N, Pkt, #state{state = recv_CER} = S) -> + handle_request(N, Pkt, S); + +%% Anything but CER/CEA in a non-Open state is an error, as is +%% CER/CEA in anything but recv_CER/Wait-CEA. +rcv(Name, _, #state{state = PS} = S) + when PS /= 'Open'; + Name == 'CER'; + Name == 'CEA' -> + close({Name, PS}, S); + +rcv(N, Pkt, S) + when N == 'DWR'; + N == 'DPR' -> + handle_request(N, Pkt, S); + +%% DPA even though we haven't sent DPR: ignore. +rcv('DPA', _Pkt, #state{dpr = false}) -> + ok; + +%% DPA in response to DPR. We could check the sequence numbers but +%% don't bother, just close. +rcv('DPA' = N, _Pkt, #state{transport = TPid}) -> + diameter_peer:close(TPid), + {stop, N}; + +rcv(_, _, _) -> + ok. + +%% send/2 + +%% Msg here could be a #diameter_packet or a binary depending on who's +%% sending. In particular, the watchdog will send DWR as a binary +%% while messages coming from clients will be in a #diameter_packet. +send(Pid, Msg) -> + diameter_stats:incr({diameter_codec:msg_id(Msg), send}), + diameter_peer:send(Pid, Msg). + +%% handle_request/3 + +handle_request(Type, #diameter_packet{} = Pkt, S) -> + ?LOG(recv, Type), + send_answer(Type, diameter_codec:decode(?BASE, Pkt), S). + +%% send_answer/3 + +send_answer(Type, ReqPkt, #state{transport = TPid} = S) -> + #diameter_packet{header = #diameter_header{version = V, + end_to_end_id = Eid, + hop_by_hop_id = Hid, + is_proxiable = P}, + transport_data = TD} + = ReqPkt, + + {Answer, PostF} = build_answer(Type, V, ReqPkt, S), + + Pkt = #diameter_packet{header = #diameter_header{version = V, + end_to_end_id = Eid, + hop_by_hop_id = Hid, + is_proxiable = P}, + msg = Answer, + transport_data = TD}, + + send(TPid, diameter_codec:encode(?BASE, Pkt)), + eval(PostF, S). + +eval([F|A], S) -> + apply(F, A ++ [S]); +eval(ok, S) -> + S. + +%% build_answer/4 + +build_answer('CER', + ?DIAMETER_VERSION, + #diameter_packet{msg = CER, + header = #diameter_header{is_error = false}, + errors = []} + = Pkt, + #state{service = Svc} + = S) -> + #diameter_service{capabilities = #diameter_caps{origin_host = OH}} + = Svc, + + {SupportedApps, #diameter_caps{origin_host = DH} = RCaps, CEA} + = recv_CER(CER, S), + + try + [] == SupportedApps + andalso ?THROW({no_common_application, 5010}), + register_everywhere({?MODULE, connection, OH, DH}) + orelse ?THROW({election_lost, 4003}), + {CEA, [fun open/4, Pkt, SupportedApps, RCaps]} + catch + ?FAILURE({Reason, RC}) -> + {answer('CER', S) ++ [{'Result-Code', RC}], + [fun close/2, {'CER', Reason, DH}]} + end; + +%% The error checks below are similar to those in diameter_service for +%% other messages. Should factor out the commonality. + +build_answer(Type, V, #diameter_packet{header = H, errors = Es} = Pkt, S) -> + FailedAvp = failed_avp([A || {_,A} <- Es]), + Ans = answer(answer(Type, S), V, H, Es), + {set(Ans, FailedAvp), if 'CER' == Type -> + [fun close/2, {Type, V, Pkt}]; + true -> + ok + end}. + +failed_avp([] = No) -> + No; +failed_avp(Avps) -> + [{'Failed-AVP', [[{'AVP', Avps}]]}]. + +set(Ans, []) -> + Ans; +set(['answer-message' | _] = Ans, FailedAvp) -> + Ans ++ [{'AVP', [FailedAvp]}]; +set([_|_] = Ans, FailedAvp) -> + Ans ++ FailedAvp. + +answer([_, OH, OR | _], _, #diameter_header{is_error = true}, _) -> + ['answer-message', OH, OR, {'Result-Code', 3008}]; + +answer([_, OH, OR | _], _, _, [Bs|_]) + when is_bitstring(Bs) -> + ['answer-message', OH, OR, {'Result-Code', 3009}]; + +answer(Ans, ?DIAMETER_VERSION, _, Es) -> + Ans ++ [{'Result-Code', rc(Es)}]; + +answer(Ans, _, _, _) -> + Ans ++ [{'Result-Code', 5011}]. %% DIAMETER_UNSUPPORTED_VERSION + +rc([]) -> + 2001; %% DIAMETER_SUCCESS +rc([{RC,_}|_]) -> + RC; +rc([RC|_]) -> + RC. + +%% DIAMETER_INVALID_HDR_BITS 3008 +%% A request was received whose bits in the Diameter header were +%% either set to an invalid combination, or to a value that is +%% inconsistent with the command code's definition. + +%% DIAMETER_INVALID_AVP_BITS 3009 +%% A request was received that included an AVP whose flag bits are +%% set to an unrecognized value, or that is inconsistent with the +%% AVP's definition. + +%% ELECTION_LOST 4003 +%% The peer has determined that it has lost the election process and +%% has therefore disconnected the transport connection. + +%% DIAMETER_NO_COMMON_APPLICATION 5010 +%% This error is returned when a CER message is received, and there +%% are no common applications supported between the peers. + +%% DIAMETER_UNSUPPORTED_VERSION 5011 +%% This error is returned when a request was received, whose version +%% number is unsupported. + +%% answer/2 + +answer('DWR', _) -> + getr(dwa); + +answer(Name, #state{service = #diameter_service{capabilities = Caps}}) -> + a(Name, Caps). + +a('CER', #diameter_caps{vendor_id = Vid, + origin_host = Host, + origin_realm = Realm, + host_ip_address = Addrs, + product_name = Name}) -> + ['CEA', {'Origin-Host', Host}, + {'Origin-Realm', Realm}, + {'Host-IP-Address', Addrs}, + {'Vendor-Id', Vid}, + {'Product-Name', Name}]; + +a('DPR', #diameter_caps{origin_host = Host, + origin_realm = Realm}) -> + ['DPA', {'Origin-Host', Host}, + {'Origin-Realm', Realm}]. + +%% recv_CER/2 + +recv_CER(CER, #state{service = Svc}) -> + {ok, T} = diameter_capx:recv_CER(CER, Svc), + T. + +%% handle_CEA/1 + +handle_CEA(#diameter_packet{header = #diameter_header{version = V}, + bin = Bin} + = Pkt, + #state{service = Svc} + = S) + when is_binary(Bin) -> + ?LOG(recv, 'CEA'), + + ?DIAMETER_VERSION == V orelse close({version, V}, S), + + #diameter_packet{msg = CEA, errors = Errors} + = DPkt + = diameter_codec:decode(?BASE, Pkt), + + [] == Errors orelse close({errors, Errors}, S), + + {SApps, #diameter_caps{origin_host = DH} = RCaps} = recv_CEA(CEA, S), + + %% Ensure that we don't already have a connection to the peer in + %% question. This isn't the peer election of 3588 except in the + %% sense that, since we don't know who we're talking to until we + %% receive a CER/CEA, the first that arrives wins the right to a + %% connection with the peer. + + #diameter_service{capabilities = #diameter_caps{origin_host = OH}} + = Svc, + + register_everywhere({?MODULE, connection, OH, DH}) + orelse + close({'CEA', DH}, S), + + open(DPkt, SApps, RCaps, S). + +%% recv_CEA/2 + +recv_CEA(CEA, #state{service = Svc} = S) -> + case diameter_capx:recv_CEA(CEA, Svc) of + {ok, {[], _}} -> + close({'CEA', no_common_application}, S); + {ok, T} -> + T; + {error, Reason} -> + close({'CEA', Reason}, S) + end. + +%% open/4 + +open(Pkt, SupportedApps, RCaps, #state{parent = Pid, + service = Svc} + = S) -> + #diameter_service{capabilities = #diameter_caps{origin_host = OH} + = LCaps} + = Svc, + #diameter_caps{origin_host = DH} + = RCaps, + Pid ! {open, self(), {OH,DH}, {capz(LCaps, RCaps), SupportedApps, Pkt}}, + S#state{state = 'Open'}. + +capz(#diameter_caps{} = L, #diameter_caps{} = R) -> + #diameter_caps{} + = list_to_tuple([diameter_caps | lists:zip(tl(tuple_to_list(L)), + tl(tuple_to_list(R)))]). + +%% close/2 + +%% Tell the watchdog that our death isn't due to transport failure. +close(Reason, #state{parent = Pid}) -> + close_wd(Reason, Pid), + throw({?MODULE, close, Reason}). + +%% close_wd/2 + +%% Ensure the watchdog dies if DPR has been sent ... +close_wd(_, #state{dpr = false}) -> + ok; +close_wd(Reason, #state{parent = Pid}) -> + close_wd(Reason, Pid); + +%% ... or otherwise +close_wd(Reason, Pid) -> + Pid ! {close, self(), Reason}. + +%% dwa/1 + +dwa(#diameter_caps{origin_host = OH, + origin_realm = OR, + origin_state_id = OSI}) -> + ['DWA', {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Origin-State-Id', OSI}]. + +%% dpr/2 + +dpr(Cause, #state{transport = TPid, + service = #diameter_service{capabilities = Caps}} + = S) -> + #diameter_caps{origin_host = OH, + origin_realm = OR} + = Caps, + + Bin = encode(['DPR', {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Disconnect-Cause', Cause}]), + send(TPid, Bin), + dpa_timer(), + ?LOG(send, 'DPR'), + S#state{dpr = diameter_codec:sequence_numbers(Bin)}. + +dpa_timer() -> + erlang:send_after(?DPA_TIMEOUT, self(), dpa_timeout). + +%% register_everywhere/1 +%% +%% Register a term and ensure it's not registered elsewhere. Note that +%% two process that simultaneously register the same term may well +%% both fail to do so this isn't foolproof. + +register_everywhere(T) -> + diameter_reg:add_new(T) + andalso unregistered(T). + +unregistered(T) -> + {ResL, _} = rpc:multicall(?MODULE, match, [{node(), T}]), + lists:all(fun(L) -> [] == L end, ResL). + +match({Node, _}) + when Node == node() -> + []; +match({_, T}) -> + try + diameter_reg:match(T) + catch + _:_ -> [] + end. diff --git a/lib/diameter/src/app/diameter_peer_fsm_sup.erl b/lib/diameter/src/app/diameter_peer_fsm_sup.erl new file mode 100644 index 0000000000..995eaf74d0 --- /dev/null +++ b/lib/diameter/src/app/diameter_peer_fsm_sup.erl @@ -0,0 +1,63 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% The supervisor of peer_fsm processes. +%% + +-module(diameter_peer_fsm_sup). + +-behaviour(supervisor). + +-define(NAME, ?MODULE). %% supervisor name + +%%----------------------------------------------------------------- +%% External exports +%%----------------------------------------------------------------- + +-export([start_link/0, %% supervisor start + start_child/1]). %% peer fsm start + +-export([init/1]). + +%% start_link/0 + +start_link() -> + SupName = {local, ?NAME}, + supervisor:start_link(SupName, ?MODULE, []). + +%% start_child/1 +%% +%% Start a peer_fsm process. + +start_child(T) -> + supervisor:start_child(?NAME, [T]). + +%% init/1 + +init([]) -> + Mod = diameter_peer_fsm, + Flags = {simple_one_for_one, 0, 1}, + ChildSpec = {Mod, + {Mod, start_link, []}, + temporary, + 1000, + worker, + [Mod]}, + {ok, {Flags, [ChildSpec]}}. diff --git a/lib/diameter/src/app/diameter_reg.erl b/lib/diameter/src/app/diameter_reg.erl new file mode 100644 index 0000000000..8e5f34c2c3 --- /dev/null +++ b/lib/diameter/src/app/diameter_reg.erl @@ -0,0 +1,331 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% The module implements a simple term -> pid registry. +%% + +-module(diameter_reg). +-compile({no_auto_import, [monitor/2]}). + +-behaviour(gen_server). + +-export([add/1, + add_new/1, + del/1, + repl/2, + match/1]). + +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, + terminate/2, + handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3]). + +%% test +-export([pids/0, + terms/0]). + +%% debug +-export([state/0, + uptime/0]). + +-include("diameter_internal.hrl"). + +-define(SERVER, ?MODULE). +-define(TABLE, ?MODULE). + +%% Table entry used to keep from starting more than one monitor on the +%% same process. This isn't a problem but there's no point in starting +%% multiple monitors if we can avoid it. Note that we can't have a 2-tuple +%% keyed on Pid since a registered term can be anything. Want the entry +%% keyed on Pid so that lookup is fast. +-define(MONITOR(Pid, MRef), {Pid, monitor, MRef}). + +%% Table entry containing the Term -> Pid mapping. +-define(MAPPING(Term, Pid), {Term, Pid}). + +-record(state, {id = now()}). + +%%% ---------------------------------------------------------- +%%% # add(T) +%%% +%%% Input: Term = term() +%%% +%%% Output: true +%%% +%%% Description: Associate the specified term with self(). The list of pids +%%% having this or other assocations can be retrieved using +%%% match/1. +%%% +%%% An association is removed when the calling process dies +%%% or as a result of calling del/1. Adding the same term +%%% more than once is equivalent to adding it exactly once. +%%% +%%% Note that since match/1 takes a pattern as argument, +%%% specifying a term that contains match variables is +%%% probably not a good idea +%%% ---------------------------------------------------------- + +-spec add(any()) + -> true. + +add(T) -> + call({add, fun ets:insert/2, T, self()}). + +%%% ---------------------------------------------------------- +%%% # add_new(T) +%%% +%%% Input: T = term() +%%% +%%% Output: true | false +%%% +%%% Description: Like add/1 but only one process is allowed to have the +%%% the association, false being returned if an association +%%% already exists. +%%% ---------------------------------------------------------- + +-spec add_new(any()) + -> boolean(). + +add_new(T) -> + call({add, fun insert_new/2, T, self()}). + +%%% ---------------------------------------------------------- +%%% # repl(T, NewT) +%%% +%%% Input: T, NewT = term() +%%% +%%% Output: true | false +%%% +%%% Description: Like add/1 but only replace an existing association on T, +%%% false being returned if it doesn't exist. +%%% ---------------------------------------------------------- + +-spec repl(any(), any()) + -> boolean(). + +repl(T, U) -> + call({repl, T, U, self()}). + +%%% ---------------------------------------------------------- +%%% # del(Term) +%%% +%%% Input: Term = term() +%%% +%%% Output: true +%%% +%%% Description: Remove any existing association of Term with self(). +%%% ---------------------------------------------------------- + +-spec del(any()) + -> true. + +del(T) -> + call({del, T, self()}). + +%%% ---------------------------------------------------------- +%%% # match(Pat) +%%% +%%% Input: Pat = pattern in the sense of ets:match_object/2. +%%% +%%% Output: list of {Term, Pid} +%%% +%%% Description: Return the list of associations whose Term, as specified +%%% to add/1 or add_new/1, matches the specified pattern. +%%% +%%% Note that there's no guarantee that the returned processes +%%% are still alive. (Although one that isn't will soon have +%%% its associations removed.) +%%% ---------------------------------------------------------- + +-spec match(tuple()) + -> [{term(), pid()}]. + +match(Pat) -> + ets:match_object(?TABLE, ?MAPPING(Pat, '_')). + +%% --------------------------------------------------------- +%% EXPORTED INTERNAL FUNCTIONS +%% --------------------------------------------------------- + +start_link() -> + ServerName = {local, ?SERVER}, + Options = [{spawn_opt, diameter_lib:spawn_opts(server, [])}], + gen_server:start_link(ServerName, ?MODULE, [], Options). + +state() -> + call(state). + +uptime() -> + call(uptime). + +%% pids/0 +%% +%% Output: list of {Pid, [Term, ...]} + +pids() -> + to_list(fun swap/1). + +to_list(Fun) -> + ets:foldl(fun(T,A) -> acc(Fun, T, A) end, orddict:new(), ?TABLE). + +acc(Fun, ?MAPPING(Term, Pid), Dict) -> + append(Fun({Term, Pid}), Dict); +acc(_, _, Dict) -> + Dict. + +append({K,V}, Dict) -> + orddict:append(K, V, Dict). + +id(T) -> T. + +%% terms/0 +%% +%% Output: list of {Term, [Pid, ...]} + +terms() -> + to_list(fun id/1). + +swap({X,Y}) -> {Y,X}. + +%%% ---------------------------------------------------------- +%%% # init(Role) +%%% +%%% Output: {ok, State} +%%% ---------------------------------------------------------- + +init(_) -> + ets:new(?TABLE, [bag, named_table]), + {ok, #state{}}. + +%%% ---------------------------------------------------------- +%%% # handle_call(Request, From, State) +%%% ---------------------------------------------------------- + +handle_call({add, Fun, Key, Pid}, _, State) -> + B = Fun(?TABLE, {Key, Pid}), + monitor(B andalso no_monitor(Pid), Pid), + {reply, B, State}; + +handle_call({del, Key, Pid}, _, State) -> + {reply, ets:delete_object(?TABLE, ?MAPPING(Key, Pid)), State}; + +handle_call({repl, T, U, Pid}, _, State) -> + MatchSpec = [{?MAPPING('$1', Pid), + [{'=:=', '$1', {const, T}}], + ['$_']}], + {reply, repl(ets:select(?TABLE, MatchSpec), U, Pid), State}; + +handle_call(state, _, State) -> + {reply, State, State}; + +handle_call(uptime, _, #state{id = Time} = State) -> + {reply, diameter_lib:now_diff(Time), State}; + +handle_call(_Req, _From, State) -> + {reply, nok, State}. + +%%% ---------------------------------------------------------- +%%% # handle_cast(Request, State) +%%% ---------------------------------------------------------- + +handle_cast(Msg, State)-> + warning_msg("received unexpected message:~n~w", [Msg]), + {noreply, State}. + +%%% ---------------------------------------------------------- +%%% # handle_info(Request, State) +%%% ---------------------------------------------------------- + +handle_info({'DOWN', MRef, process, Pid, _}, State) -> + ets:delete_object(?TABLE, ?MONITOR(Pid, MRef)), + ets:match_delete(?TABLE, ?MAPPING('_', Pid)), + {noreply, State}; + +handle_info(Info, State) -> + warning_msg("received unknown info:~n~w", [Info]), + {noreply, State}. + +%%% ---------------------------------------------------------- +%%% # terminate(Reason, State) +%%% ---------------------------------------------------------- + +terminate(_Reason, _State)-> + ok. + +%%% ---------------------------------------------------------- +%%% # code_change(OldVsn, State, Extra) +%%% ---------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%% --------------------------------------------------------- +%% INTERNAL FUNCTIONS +%% --------------------------------------------------------- + +monitor(true, Pid) -> + ets:insert(?TABLE, ?MONITOR(Pid, erlang:monitor(process, Pid))); +monitor(false, _) -> + ok. + +%% Do we need a monitor for the specified Pid? +no_monitor(Pid) -> + [] == ets:match_object(?TABLE, ?MONITOR(Pid, '_')). + +%% insert_new/2 + +insert_new(?TABLE, {Key, _} = T) -> + flush(ets:lookup(?TABLE, Key)), + ets:insert_new(?TABLE, T). + +%% Remove any processes that are dead but for which we may not have +%% received 'DOWN' yet. This is to ensure that add_new can be used +%% to register a unique name each time a process restarts. +flush(List) -> + lists:foreach(fun({_,P} = T) -> + del(erlang:is_process_alive(P), T) + end, + List). + +del(Alive, T) -> + Alive orelse ets:delete_object(?TABLE, T). + +%% repl/3 + +repl([?MAPPING(_, Pid) = M], Key, Pid) -> + ets:delete_object(?TABLE, M), + true = ets:insert(?TABLE, ?MAPPING(Key, Pid)); +repl([], _, _) -> + false. + +%% call/1 + +call(Request) -> + gen_server:call(?SERVER, Request, infinity). + +%% warning_msg/2 + +warning_msg(F, A) -> + ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/app/diameter_service.erl new file mode 100644 index 0000000000..63b0649dc4 --- /dev/null +++ b/lib/diameter/src/app/diameter_service.erl @@ -0,0 +1,2925 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Implements the process that represents a service. +%% + +-module(diameter_service). +-behaviour(gen_server). + +-export([start/1, + stop/1, + start_transport/2, + stop_transport/2, + info/2, + call/4]). + +%% towards diameter_watchdog +-export([receive_message/3]). + +%% service supervisor +-export([start_link/1]). + +-export([subscribe/1, + unsubscribe/1, + subscriptions/1, + subscriptions/0, + services/0, + services/1, + whois/1, + flush_stats/1]). + +%% test/debug +-export([call_module/3, + state/1, + uptime/1]). + +%%% gen_server callbacks +-export([init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3]). + +%% Other callbacks. +-export([send/1]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). +-include("diameter_types.hrl"). + +-define(STATE_UP, up). +-define(STATE_DOWN, down). + +-define(DEFAULT_TC, 30000). %% RFC 3588 ch 2.1 +-define(DEFAULT_TIMEOUT, 5000). %% for outgoing requests +-define(RESTART_TC, 1000). %% if restart was this recent + +%% Used to be able to swap this with anything else dict-like but now +%% rely on the fact that a service's #state{} record does not change +%% in storing in it ?STATE table and not always going through the +%% service process. In particular, rely on the fact that operations on +%% a ?Dict don't change the handle to it. +-define(Dict, diameter_dict). + +%% Table containing outgoing requests for which a reply has yet to be +%% received. +-define(REQUEST_TABLE, diameter_request). + +%% Maintains state in a table. In contrast to previously, a service's +%% stat is not constant and is accessed outside of the service +%% process. +-define(STATE_TABLE, ?MODULE). + +%% Workaround for dialyzer's lack of understanding of match specs. +-type match(T) + :: T | '_' | '$1' | '$2' | '$3' | '$4'. + +%% State of service gen_server. +-record(state, + {id = now(), + service_name, %% as passed to start_service/2, key in ?STATE_TABLE + service :: #diameter_service{}, + peerT = ets_new(peers) :: ets:tid(), %% #peer{} at start_fsm + connT = ets_new(conns) :: ets:tid(), %% #conn{} at connection_up + share_peers = false :: boolean(), %% broadcast peers to remote nodes? + use_shared_peers = false :: boolean(), %% use broadcasted peers? + shared_peers = ?Dict:new(), %% Alias -> [{TPid, Caps}, ...] + local_peers = ?Dict:new(), %% Alias -> [{TPid, Caps}, ...] + monitor = false :: false | pid()}). %% process to die with +%% shared_peers reflects the peers broadcast from remote nodes. Note +%% that the state term itself doesn't change, which is relevant for +%% the stateless application callbacks since the state is retrieved +%% from ?STATE_TABLE from outside the service process. The pid in the +%% service record is used to determine whether or not we need to call +%% the process for a pick_peer callback. + +%% Record representing a watchdog process. +-record(peer, + {pid :: match(pid()), + type :: match(connect | accept), + ref :: match(reference()), %% key into diameter_config + options :: match([transport_opt()]), %% as passed to start_transport + op_state = ?STATE_DOWN :: match(?STATE_DOWN | ?STATE_UP), + started = now(), %% at process start + conn = false :: match(boolean() | pid())}). + %% true at accept, pid() at connection_up (connT key) + +%% Record representing a peer_fsm process. +-record(conn, + {pid :: pid(), + apps :: [{0..16#FFFFFFFF, app_alias()}], %% {Id, Alias} + caps :: #diameter_caps{}, + started = now(), %% at process start + peer :: pid()}). %% key into peerT + +%% Record stored in diameter_request for each outgoing request. +-record(request, + {from, %% arg 2 of handle_call/3 + handler :: match(pid()), %% request process + transport :: match(pid()), %% peer process + caps :: match(#diameter_caps{}), + app :: match(app_alias()), %% #diameter_app.alias + dictionary :: match(module()), %% #diameter_app.dictionary + module :: match(nonempty_improper_list(module(), list())), + %% #diameter_app.module + filter :: match(peer_filter()), + packet :: match(#diameter_packet{})}). + +%% Record call/4 options are parsed into. +-record(options, + {filter = none :: peer_filter(), + extra = [] :: list(), + timeout = ?DEFAULT_TIMEOUT :: 0..16#FFFFFFFF, + detach = false :: boolean()}). + +%% Since RFC 3588 requires that a Diameter agent not modify End-to-End +%% Identifiers, the possibility of explicitly setting an End-to-End +%% Identifier would be needed to be able to implement an agent in +%% which one side of the communication is not implemented on top of +%% diameter. For example, Diameter being sent or received encapsulated +%% in some other protocol, or even another Diameter stack in a +%% non-Erlang environment. (Not that this is likely to be a normal +%% case.) +%% +%% The implemented solution is not an option but to respect any header +%% values set in a diameter_header record returned from a +%% prepare_request callback. A call to diameter:call/4 can communicate +%% values to the callback using the 'extra' option if so desired. + +%%% --------------------------------------------------------------------------- +%%% # start(SvcName) +%%% --------------------------------------------------------------------------- + +start(SvcName) -> + diameter_service_sup:start_child(SvcName). + +start_link(SvcName) -> + Options = [{spawn_opt, diameter_lib:spawn_opts(server, [])}], + gen_server:start_link(?MODULE, [SvcName], Options). +%% Put the arbitrary term SvcName in a list in case we ever want to +%% send more than this and need to distinguish old from new. + +%%% --------------------------------------------------------------------------- +%%% # stop(SvcName) +%%% --------------------------------------------------------------------------- + +stop(SvcName) -> + case whois(SvcName) of + undefined -> + {error, not_started}; + Pid -> + stop(call_service(Pid, stop), Pid) + end. + +stop(ok, Pid) -> + MRef = erlang:monitor(process, Pid), + receive {'DOWN', MRef, process, _, _} -> ok end; +stop(No, _) -> + No. + +%%% --------------------------------------------------------------------------- +%%% # start_transport(SvcName, {Ref, Type, Opts}) +%%% --------------------------------------------------------------------------- + +start_transport(SvcName, {_,_,_} = T) -> + call_service_by_name(SvcName, {start, T}). + +%%% --------------------------------------------------------------------------- +%%% # stop_transport(SvcName, Refs) +%%% --------------------------------------------------------------------------- + +stop_transport(_, []) -> + ok; +stop_transport(SvcName, [_|_] = Refs) -> + call_service_by_name(SvcName, {stop, Refs}). + +%%% --------------------------------------------------------------------------- +%%% # info(SvcName, Item) +%%% --------------------------------------------------------------------------- + +info(SvcName, Item) -> + info_rc(call_service_by_name(SvcName, {info, Item})). + +info_rc({error, _}) -> + undefined; +info_rc(Info) -> + Info. + +%%% --------------------------------------------------------------------------- +%%% # receive_message(TPid, Pkt, MessageData) +%%% --------------------------------------------------------------------------- + +%% Handle an incoming message in the watchdog process. This used to +%% come through the service process but this avoids that becoming a +%% bottleneck. + +receive_message(TPid, Pkt, T) + when is_pid(TPid) -> + #diameter_packet{header = #diameter_header{is_request = R}} = Pkt, + recv(R, (not R) andalso lookup_request(Pkt, TPid), TPid, Pkt, T). + +%% Incoming request ... +recv(true, false, TPid, Pkt, T) -> + try + spawn(fun() -> recv_request(TPid, Pkt, T) end) + catch + error: system_limit = E -> %% discard + ?LOG({error, E}, now()) + end; + +%% ... answer to known request ... +recv(false, #request{from = {_, Ref}, handler = Pid} = Req, _, Pkt, _) -> + Pid ! {answer, Ref, Req, Pkt}; +%% Note that failover could have happened prior to this message being +%% received and triggering failback. That is, both a failover message +%% and answer may be on their way to the handler process. In the worst +%% case the request process gets notification of the failover and +%% sends to the alternate peer before an answer arrives, so it's +%% always the case that we can receive more than one answer after +%% failover. The first answer received by the request process wins, +%% any others are discarded. + +%% ... or not. +recv(false, false, _, _, _) -> + ok. + +%%% --------------------------------------------------------------------------- +%%% # call(SvcName, App, Msg, Options) +%%% --------------------------------------------------------------------------- + +call(SvcName, App, Msg, Options) + when is_list(Options) -> + Rec = make_options(Options), + Ref = make_ref(), + Caller = {self(), Ref}, + Fun = fun() -> exit({Ref, call(SvcName, App, Msg, Rec, Caller)}) end, + try spawn_monitor(Fun) of + {_, MRef} -> + recv(MRef, Ref, Rec#options.detach, false) + catch + error: system_limit = E -> + {error, E} + end. + +%% Don't rely on gen_server:call/3 for the timeout handling since it +%% makes no guarantees about not leaving a reply message in the +%% mailbox if we catch its exit at timeout. It currently *can* do so, +%% which is also undocumented. + +recv(MRef, _, true, true) -> + erlang:demonitor(MRef, [flush]), + ok; + +recv(MRef, Ref, Detach, Sent) -> + receive + Ref -> %% send has been attempted + recv(MRef, Ref, Detach, true); + {'DOWN', MRef, process, _, Reason} -> + call_rc(Reason, Ref, Sent) + end. + +%% call/5 has returned ... +call_rc({Ref, Ans}, Ref, _) -> + Ans; + +%% ... or not. In this case failure/encode are documented. +call_rc(_, _, Sent) -> + {error, choose(Sent, failure, encode)}. + +%% call/5 +%% +%% In the process spawned for the outgoing request. + +call(SvcName, App, Msg, Opts, Caller) -> + c(ets:lookup(?STATE_TABLE, SvcName), App, Msg, Opts, Caller). + +c([#state{service_name = SvcName} = S], App, Msg, Opts, Caller) -> + case find_transport(App, Msg, Opts, S) of + {_,_,_} = T -> + send_request(T, Msg, Opts, Caller, SvcName); + false -> + {error, no_connection}; + {error, _} = No -> + No + end; + +c([], _, _, _, _) -> + {error, no_service}. + +%% make_options/1 + +make_options(Options) -> + lists:foldl(fun mo/2, #options{}, Options). + +mo({timeout, T}, Rec) + when is_integer(T), 0 =< T -> + Rec#options{timeout = T}; + +mo({filter, F}, #options{filter = none} = Rec) -> + Rec#options{filter = F}; +mo({filter, F}, #options{filter = {all, Fs}} = Rec) -> + Rec#options{filter = {all, [F | Fs]}}; +mo({filter, F}, #options{filter = F0} = Rec) -> + Rec#options{filter = {all, [F0, F]}}; + +mo({extra, L}, #options{extra = X} = Rec) + when is_list(L) -> + Rec#options{extra = X ++ L}; + +mo(detach, Rec) -> + Rec#options{detach = true}; + +mo(T, _) -> + ?ERROR({invalid_option, T}). + +%%% --------------------------------------------------------------------------- +%%% # subscribe(SvcName) +%%% # unsubscribe(SvcName) +%%% --------------------------------------------------------------------------- + +subscribe(SvcName) -> + diameter_reg:add({?MODULE, subscriber, SvcName}). + +unsubscribe(SvcName) -> + diameter_reg:del({?MODULE, subscriber, SvcName}). + +subscriptions(Pat) -> + pmap(diameter_reg:match({?MODULE, subscriber, Pat})). + +subscriptions() -> + subscriptions('_'). + +pmap(Props) -> + lists:map(fun({{?MODULE, _, Name}, Pid}) -> {Name, Pid} end, Props). + +%%% --------------------------------------------------------------------------- +%%% # services(Pattern) +%%% --------------------------------------------------------------------------- + +services(Pat) -> + pmap(diameter_reg:match({?MODULE, service, Pat})). + +services() -> + services('_'). + +whois(SvcName) -> + case diameter_reg:match({?MODULE, service, SvcName}) of + [{_, Pid}] -> + Pid; + [] -> + undefined + end. + +%%% --------------------------------------------------------------------------- +%%% # flush_stats/1 +%%% +%%% Output: list of {{SvcName, Alias, Counter}, Value} +%%% --------------------------------------------------------------------------- + +flush_stats(TPid) -> + diameter_stats:flush(TPid). + +%% =========================================================================== +%% =========================================================================== + +state(Svc) -> + call_service(Svc, state). + +uptime(Svc) -> + call_service(Svc, uptime). + +%% call_module/3 + +call_module(Service, AppMod, Request) -> + call_service(Service, {call_module, AppMod, Request}). + +%%% --------------------------------------------------------------------------- +%%% # init([SvcName]) +%%% --------------------------------------------------------------------------- + +init([SvcName]) -> + process_flag(trap_exit, true), %% ensure terminate(shutdown, _) + i(SvcName, diameter_reg:add_new({?MODULE, service, SvcName})). + +i(SvcName, true) -> + {ok, i(SvcName)}; +i(_, false) -> + {stop, {shutdown, already_started}}. + +%%% --------------------------------------------------------------------------- +%%% # handle_call(Req, From, State) +%%% --------------------------------------------------------------------------- + +handle_call(state, _, S) -> + {reply, S, S}; + +handle_call(uptime, _, #state{id = T} = S) -> + {reply, diameter_lib:now_diff(T), S}; + +%% Start a transport. +handle_call({start, {Ref, Type, Opts}}, _From, S) -> + {reply, start(Ref, {Type, Opts}, S), S}; + +%% Stop transports. +handle_call({stop, Refs}, _From, S) -> + shutdown(Refs, S), + {reply, ok, S}; + +%% pick_peer with mutable state +handle_call({pick_peer, Local, Remote, App}, _From, S) -> + #diameter_app{mutable = true} = App, %% assert + {reply, pick_peer(Local, Remote, self(), S#state.service_name, App), S}; + +handle_call({call_module, AppMod, Req}, From, S) -> + call_module(AppMod, Req, From, S); + +handle_call({info, Item}, _From, S) -> + {reply, service_info(Item, S), S}; + +handle_call(stop, _From, S) -> + shutdown(S), + {stop, normal, ok, S}; +%% The server currently isn't guaranteed to be dead when the caller +%% gets the reply. We deal with this in the call to the server, +%% stating a monitor that waits for DOWN before returning. + +handle_call(Req, From, S) -> + ?REPORT(unknown_request, ?FUNC, [Req, From]), + {reply, nok, S}. + +%%% --------------------------------------------------------------------------- +%%% # handle_cast(Req, State) +%%% --------------------------------------------------------------------------- + +handle_cast(Req, S) -> + ?REPORT(unknown_request, ?FUNC, [Req]), + {noreply, S}. + +%%% --------------------------------------------------------------------------- +%%% # handle_info(Req, State) +%%% --------------------------------------------------------------------------- + +handle_info(T,S) -> + case transition(T,S) of + ok -> + {noreply, S}; + #state{} = NS -> + {noreply, NS}; + {stop, Reason} -> + {stop, {shutdown, Reason}, S} + end. + +%% transition/2 + +%% Peer process is telling us to start a new accept process. +transition({accepted, Pid, TPid}, S) -> + accepted(Pid, TPid, S), + ok; + +%% Peer process has a new open connection. +transition({connection_up, Pid, T}, S) -> + connection_up(Pid, T, S); + +%% Peer process has left state open. +transition({connection_down, Pid}, S) -> + connection_down(Pid, S); + +%% Peer process has returned to state open. +transition({connection_up, Pid}, S) -> + connection_up(Pid, S); + +%% Accepting transport has lost connectivity. +transition({close, Pid}, S) -> + close(Pid, S), + ok; + +%% Connecting transport is being restarted by watchdog. +transition({reconnect, Pid}, S) -> + reconnect(Pid, S), + ok; + +%% Monitor process has died. Just die with a reason that tells +%% diameter_config about the happening. If a cleaner shutdown is +%% required then someone should stop us. +transition({'DOWN', MRef, process, _, Reason}, #state{monitor = MRef}) -> + {stop, {monitor, Reason}}; + +%% Local peer process has died. +transition({'DOWN', _, process, Pid, Reason}, S) + when node(Pid) == node() -> + peer_down(Pid, Reason, S); + +%% Remote service wants to know about shared transports. +transition({service, Pid}, S) -> + share_peers(Pid, S), + ok; + +%% Remote service is communicating a shared peer. +transition({peer, TPid, Aliases, Caps}, S) -> + remote_peer_up(TPid, Aliases, Caps, S); + +%% Remote peer process has died. +transition({'DOWN', _, process, TPid, _}, S) -> + remote_peer_down(TPid, S); + +%% Restart after tc expiry. +transition({tc_timeout, T}, S) -> + tc_timeout(T, S), + ok; + +%% Request process is telling us it may have missed a failover message +%% after a transport went down and the service process looked up +%% outstanding requests. +transition({failover, TRef, Seqs}, S) -> + failover(TRef, Seqs, S), + ok; + +transition(Req, _) -> + ?REPORT(unknown_request, ?FUNC, [Req]), + ok. + +%%% --------------------------------------------------------------------------- +%%% # terminate(Reason, State) +%%% --------------------------------------------------------------------------- + +terminate(Reason, #state{service_name = Name} = S) -> + ets:delete(?STATE_TABLE, Name), + shutdown == Reason %% application shutdown + andalso shutdown(S). + +%%% --------------------------------------------------------------------------- +%%% # code_change(FromVsn, State, Extra) +%%% --------------------------------------------------------------------------- + +code_change(FromVsn, + #state{service_name = SvcName, + service = #diameter_service{applications = Apps}} + = S, + Extra) -> + lists:foreach(fun(A) -> + code_change(FromVsn, SvcName, Extra, A) + end, + Apps), + {ok, S}. + +code_change(FromVsn, SvcName, Extra, #diameter_app{alias = Alias} = A) -> + {ok, S} = cb(A, code_change, [FromVsn, + mod_state(Alias), + Extra, + SvcName]), + mod_state(Alias, S). + +%% =========================================================================== +%% =========================================================================== + +cb([_|_] = M, F, A) -> + eval(M, F, A); +cb(Rec, F, A) -> + {_, M} = app(Rec), + eval(M, F, A). + +app(#request{app = A, module = M}) -> + {A,M}; +app(#diameter_app{alias = A, module = M}) -> + {A,M}. + +eval([M|X], F, A) -> + apply(M, F, A ++ X). + +%% Callback with state. + +state_cb(#diameter_app{mutable = false, init_state = S}, {ModX, F, A}) -> + eval(ModX, F, A ++ [S]); + +state_cb(#diameter_app{mutable = true, alias = Alias}, {_,_,_} = MFA) -> + state_cb(MFA, Alias); + +state_cb({ModX,F,A}, Alias) + when is_list(ModX) -> + eval(ModX, F, A ++ [mod_state(Alias)]). + +choose(true, X, _) -> X; +choose(false, _, X) -> X. + +ets_new(Tbl) -> + ets:new(Tbl, [{keypos, 2}]). + +insert(Tbl, Rec) -> + ets:insert(Tbl, Rec), + Rec. + +monitor(Pid) -> + erlang:monitor(process, Pid), + Pid. + +%% Using the process dictionary for the callback state was initially +%% just a way to make what was horrendous trace (big state record and +%% much else everywhere) somewhat more readable. There's not as much +%% need for it now but it's no worse (except possibly that we don't +%% see the table identifier being passed around) than an ets table so +%% keep it. + +mod_state(Alias) -> + get({?MODULE, mod_state, Alias}). + +mod_state(Alias, ModS) -> + put({?MODULE, mod_state, Alias}, ModS). + +%% have_transport/2 + +have_transport(SvcName, Ref) -> + [] /= diameter_config:have_transport(SvcName, Ref). + +%%% --------------------------------------------------------------------------- +%%% # shutdown/2 +%%% --------------------------------------------------------------------------- + +shutdown(Refs, #state{peerT = PeerT}) -> + ets:foldl(fun(P,ok) -> s(P, Refs), ok end, ok, PeerT). + +s(#peer{ref = Ref, pid = Pid}, Refs) -> + s(lists:member(Ref, Refs), Pid); + +s(true, Pid) -> + Pid ! {shutdown, self()}; %% 'DOWN' will cleanup as usual +s(false, _) -> + ok. + +%%% --------------------------------------------------------------------------- +%%% # shutdown/1 +%%% --------------------------------------------------------------------------- + +shutdown(#state{peerT = PeerT}) -> + %% A transport might not be alive to receive the shutdown request + %% but give those that are a chance to shutdown gracefully. + wait(fun st/2, PeerT), + %% Kill the watchdogs explicitly in case there was no transport. + wait(fun sw/2, PeerT). + +wait(Fun, T) -> + diameter_lib:wait(ets:foldl(Fun, [], T)). + +st(#peer{conn = B}, Acc) + when is_boolean(B) -> + Acc; +st(#peer{conn = Pid}, Acc) -> + Pid ! shutdown, + [Pid | Acc]. + +sw(#peer{pid = Pid}, Acc) -> + exit(Pid, shutdown), + [Pid | Acc]. + +%%% --------------------------------------------------------------------------- +%%% # call_service/2 +%%% --------------------------------------------------------------------------- + +call_service(Pid, Req) + when is_pid(Pid) -> + cs(Pid, Req); +call_service(SvcName, Req) -> + call_service_by_name(SvcName, Req). + +call_service_by_name(SvcName, Req) -> + cs(whois(SvcName), Req). + +cs(Pid, Req) + when is_pid(Pid) -> + try + gen_server:call(Pid, Req, infinity) + catch + E: Reason when E == exit -> + {error, {E, Reason}} + end; + +cs(undefined, _) -> + {error, no_service}. + +%%% --------------------------------------------------------------------------- +%%% # i/1 +%%% +%%% Output: #state{} +%%% --------------------------------------------------------------------------- + +%% Intialize the state of a service gen_server. + +i(SvcName) -> + %% Split the config into a server state and a list of transports. + {#state{} = S, CL} = lists:foldl(fun cfg_acc/2, + {false, []}, + diameter_config:lookup(SvcName)), + + %% Publish the state in order to be able to access it outside of + %% the service process. Originally table identifiers were only + %% known to the service process but we now want to provide the + %% option of application callbacks being 'stateless' in order to + %% avoid having to go through a common process. (Eg. An agent that + %% sends a request for every incoming request.) + true = ets:insert_new(?STATE_TABLE, S), + + %% Start fsms for each transport. + lists:foreach(fun(T) -> start_fsm(T,S) end, CL), + + init_shared(S), + S. + +cfg_acc({SvcName, #diameter_service{applications = Apps} = Rec, Opts}, + {false, Acc}) -> + lists:foreach(fun init_mod/1, Apps), + S = #state{service_name = SvcName, + service = Rec#diameter_service{pid = self()}, + share_peers = get_value(share_peers, Opts), + use_shared_peers = get_value(use_shared_peers, Opts), + monitor = mref(get_value(monitor, Opts))}, + {S, Acc}; + +cfg_acc({_Ref, Type, _Opts} = T, {S, Acc}) + when Type == connect; + Type == listen -> + {S, [T | Acc]}. + +mref(false = No) -> + No; +mref(P) -> + erlang:monitor(process, P). + +init_shared(#state{use_shared_peers = true, + service_name = Svc}) -> + diameter_peer:notify(Svc, {service, self()}); +init_shared(#state{use_shared_peers = false}) -> + ok. + +init_mod(#diameter_app{alias = Alias, + init_state = S}) -> + mod_state(Alias, S). + +start_fsm({Ref, Type, Opts}, S) -> + start(Ref, {Type, Opts}, S). + +get_value(Key, Vs) -> + {_, V} = lists:keyfind(Key, 1, Vs), + V. + +%%% --------------------------------------------------------------------------- +%%% # start/3 +%%% --------------------------------------------------------------------------- + +%% If the initial start/3 at service/transport start succeeds then +%% subsequent calls to start/4 on the same service will also succeed +%% since they involve the same call to merge_service/2. We merge here +%% rather than earlier since the service may not yet be configured +%% when the transport is configured. + +start(Ref, {T, Opts}, S) + when T == connect; + T == listen -> + try + {ok, start(Ref, type(T), Opts, S)} + catch + ?FAILURE(Reason) -> + {error, Reason} + end. +%% TODO: don't actually raise any errors yet + +%% There used to be a difference here between the handling of +%% configured listening and connecting transports but now we simply +%% tell the transport_module to start an accepting or connecting +%% process respectively, the transport implementation initiating +%% listening on a port as required. +type(listen) -> accept; +type(accept) -> listen; +type(connect = T) -> T. + +%% start/4 + +start(Ref, Type, Opts, #state{peerT = PeerT, + connT = ConnT, + service_name = SvcName, + service = Svc}) + when Type == connect; + Type == accept -> + Pid = monitor(s(Type, Ref, {ConnT, + Opts, + SvcName, + merge_service(Opts, Svc)})), + insert(PeerT, #peer{pid = Pid, + type = Type, + ref = Ref, + options = Opts}), + Pid. + +%% Note that the service record passed into the watchdog is the merged +%% record so that each watchdog (and peer_fsm) may get a different +%% record. This record is what is passed back into application +%% callbacks. + +s(Type, Ref, T) -> + diameter_watchdog:start({Type, Ref}, T). + +%% merge_service/2 + +merge_service(Opts, Svc) -> + lists:foldl(fun ms/2, Svc, Opts). + +%% Limit the applications known to the fsm to those in the 'apps' +%% option. That this might be empty is checked by the fsm. It's not +%% checked at config-time since there's no requirement that the +%% service be configured first. (Which could be considered a bit odd.) +ms({applications, As}, #diameter_service{applications = Apps} = S) + when is_list(As) -> + S#diameter_service{applications + = [A || A <- Apps, + lists:member(A#diameter_app.alias, As)]}; + +%% The fact that all capabilities can be configured on the transports +%% means that the service doesn't necessarily represent a single +%% locally implemented Diameter peer as identified by Origin-Host: a +%% transport can configure its own Origin-Host. This means that the +%% service little more than a placeholder for default capabilities +%% plus a list of applications that individual transports can choose +%% to support (or not). +ms({capabilities, Opts}, #diameter_service{capabilities = Caps0} = Svc) + when is_list(Opts) -> + %% make_caps has already succeeded in diameter_config so it will succeed + %% again here. + {ok, Caps} = diameter_capx:make_caps(Caps0, Opts), + Svc#diameter_service{capabilities = Caps}; + +ms(_, Svc) -> + Svc. + +%%% --------------------------------------------------------------------------- +%%% # accepted/3 +%%% --------------------------------------------------------------------------- + +accepted(Pid, _TPid, #state{peerT = PeerT} = S) -> + #peer{ref = Ref, type = accept = T, conn = false, options = Opts} + = P + = fetch(PeerT, Pid), + insert(PeerT, P#peer{conn = true}), %% mark replacement transport started + start(Ref, T, Opts, S). %% start new peer + +fetch(Tid, Key) -> + [T] = ets:lookup(Tid, Key), + T. + +%%% --------------------------------------------------------------------------- +%%% # connection_up/3 +%%% +%%% Output: #state{} +%%% --------------------------------------------------------------------------- + +%% Peer process has reached the open state. + +connection_up(Pid, {TPid, {Caps, SApps, Pkt}}, #state{peerT = PeerT, + connT = ConnT} + = S) -> + P = fetch(PeerT, Pid), + C = #conn{pid = TPid, + apps = SApps, + caps = Caps, + peer = Pid}, + + insert(ConnT, C), + connection_up([Pkt], P#peer{conn = TPid}, C, S). + +%%% --------------------------------------------------------------------------- +%%% # connection_up/2 +%%% +%%% Output: #state{} +%%% --------------------------------------------------------------------------- + +%% Peer process has transitioned back into the open state. Note that there +%% has been no new capabilties exchange in this case. + +connection_up(Pid, #state{peerT = PeerT, + connT = ConnT} + = S) -> + #peer{conn = TPid} = P = fetch(PeerT, Pid), + C = fetch(ConnT, TPid), + connection_up([], P, C, S). + +%% connection_up/4 + +connection_up(T, P, C, #state{peerT = PeerT, + local_peers = LDict, + service_name = SvcName, + service + = #diameter_service{applications = Apps}} + = S) -> + #peer{conn = TPid, op_state = ?STATE_DOWN} + = P, + #conn{apps = SApps, caps = Caps} + = C, + + insert(PeerT, P#peer{op_state = ?STATE_UP}), + + request_peer_up(TPid), + report_status(up, P, C, S, T), + S#state{local_peers = insert_local_peer(SApps, + {{TPid, Caps}, {SvcName, Apps}}, + LDict)}. + +insert_local_peer(SApps, T, LDict) -> + lists:foldl(fun(A,D) -> ilp(A, T, D) end, LDict, SApps). + +ilp({Id, Alias}, {TC, SA}, LDict) -> + init_conn(Id, Alias, TC, SA), + ?Dict:append(Alias, TC, LDict). + +init_conn(Id, Alias, TC, {SvcName, Apps}) -> + #diameter_app{module = ModX, + id = Id} %% assert + = find_app(Alias, Apps), + + peer_cb({ModX, peer_up, [SvcName, TC]}, Alias). + +find_app(Alias, Apps) -> + lists:keyfind(Alias, #diameter_app.alias, Apps). + +%% A failing peer callback brings down the service. In the case of +%% peer_up we could just kill the transport and emit an error but for +%% peer_down we have no way to cleanup any state change that peer_up +%% may have introduced. +peer_cb(MFA, Alias) -> + try state_cb(MFA, Alias) of + ModS -> + mod_state(Alias, ModS) + catch + E: Reason -> + ?ERROR({E, Reason, MFA, ?STACK}) + end. + +%%% --------------------------------------------------------------------------- +%%% # connection_down/2 +%%% +%%% Output: #state{} +%%% --------------------------------------------------------------------------- + +%% Peer process has transitioned out of the open state. + +connection_down(Pid, #state{peerT = PeerT, + connT = ConnT} + = S) -> + #peer{conn = TPid} + = P + = fetch(PeerT, Pid), + + C = fetch(ConnT, TPid), + insert(PeerT, P#peer{op_state = ?STATE_DOWN}), + connection_down(P,C,S). + +%% connection_down/3 + +connection_down(#peer{conn = TPid, + op_state = ?STATE_UP} + = P, + #conn{caps = Caps, + apps = SApps} + = C, + #state{service_name = SvcName, + service = #diameter_service{applications = Apps}, + local_peers = LDict} + = S) -> + report_status(down, P, C, S, []), + NewS = S#state{local_peers + = remove_local_peer(SApps, + {{TPid, Caps}, {SvcName, Apps}}, + LDict)}, + request_peer_down(TPid, NewS), + NewS. + +remove_local_peer(SApps, T, LDict) -> + lists:foldl(fun(A,D) -> rlp(A, T, D) end, LDict, SApps). + +rlp({Id, Alias}, {TC, SA}, LDict) -> + L = ?Dict:fetch(Alias, LDict), + down_conn(Id, Alias, TC, SA), + ?Dict:store(Alias, lists:delete(TC, L), LDict). + +down_conn(Id, Alias, TC, {SvcName, Apps}) -> + #diameter_app{module = ModX, + id = Id} %% assert + = find_app(Alias, Apps), + + peer_cb({ModX, peer_down, [SvcName, TC]}, Alias). + +%%% --------------------------------------------------------------------------- +%%% # peer_down/3 +%%% +%%% Output: #state{} +%%% --------------------------------------------------------------------------- + +%% Peer process has died. + +peer_down(Pid, _Reason, #state{peerT = PeerT} = S) -> + P = fetch(PeerT, Pid), + ets:delete_object(PeerT, P), + restart(P,S), + peer_down(P,S). + +%% peer_down/2 + +%% The peer has never come up ... +peer_down(#peer{conn = B}, S) + when is_boolean(B) -> + S; + +%% ... or it has. +peer_down(#peer{ref = Ref, + conn = TPid, + type = Type, + options = Opts} + = P, + #state{service_name = SvcName, + connT = ConnT} + = S) -> + #conn{caps = Caps} + = C + = fetch(ConnT, TPid), + ets:delete_object(ConnT, C), + try + pd(P,C,S) + after + send_event(SvcName, {closed, Ref, {TPid, Caps}, {type(Type), Opts}}) + end. + +pd(#peer{op_state = ?STATE_DOWN}, _, S) -> + S; +pd(#peer{op_state = ?STATE_UP} = P, C, S) -> + connection_down(P,C,S). + +%% restart/2 + +restart(P,S) -> + q_restart(restart(P), S). + +%% restart/1 + +%% Always try to reconnect. +restart(#peer{ref = Ref, + type = connect = T, + options = Opts, + started = Time}) -> + {Time, {Ref, T, Opts}}; + +%% Transport connection hasn't yet been accepted ... +restart(#peer{ref = Ref, + type = accept = T, + options = Opts, + conn = false, + started = Time}) -> + {Time, {Ref, T, Opts}}; + +%% ... or it has: a replacement transport has already been spawned. +restart(#peer{type = accept}) -> + false. + +%% q_restart/2 + +%% Start the reconnect timer. +q_restart({Time, {_Ref, Type, Opts} = T}, S) -> + start_tc(tc(Time, default_tc(Type, Opts)), T, S); +q_restart(false, _) -> + ok. + +%% RFC 3588, 2.1: +%% +%% When no transport connection exists with a peer, an attempt to +%% connect SHOULD be periodically made. This behavior is handled via +%% the Tc timer, whose recommended value is 30 seconds. There are +%% certain exceptions to this rule, such as when a peer has terminated +%% the transport connection stating that it does not wish to +%% communicate. + +default_tc(connect, Opts) -> + proplists:get_value(reconnect_timer, Opts, ?DEFAULT_TC); +default_tc(accept, _) -> + 0. + +%% Bound tc below if the peer was restarted recently to avoid +%% continuous in case of faulty config or other problems. +tc(Time, Tc) -> + choose(Tc > ?RESTART_TC + orelse timer:now_diff(now(), Time) > 1000*?RESTART_TC, + Tc, + ?RESTART_TC). + +start_tc(0, T, S) -> + tc_timeout(T, S); +start_tc(Tc, T, _) -> + erlang:send_after(Tc, self(), {tc_timeout, T}). + +%% tc_timeout/2 + +tc_timeout({Ref, _Type, _Opts} = T, #state{service_name = SvcName} = S) -> + tc(have_transport(SvcName, Ref), T, S). + +tc(true, {Ref, Type, Opts}, #state{service_name = SvcName} + = S) -> + send_event(SvcName, {reconnect, Ref, Opts}), + start(Ref, Type, Opts, S); +tc(false = No, _, _) -> %% removed + No. + +%%% --------------------------------------------------------------------------- +%%% # close/2 +%%% --------------------------------------------------------------------------- + +%% The watchdog doesn't start a new fsm in the accept case, it +%% simply stays alive until someone tells it to die in order for +%% another watchdog to be able to detect that it should transition +%% from initial into reopen rather than okay. That someone is either +%% the accepting watchdog upon reception of a CER from the previously +%% connected peer, or us after reconnect_timer timeout. + +close(Pid, #state{service_name = SvcName, + peerT = PeerT}) -> + #peer{pid = Pid, + type = accept, + ref = Ref, + options = Opts} + = fetch(PeerT, Pid), + + c(Pid, have_transport(SvcName, Ref), Opts). + +%% Tell watchdog to (maybe) die later ... +c(Pid, true, Opts) -> + Tc = proplists:get_value(reconnect_timer, Opts, 2*?DEFAULT_TC), + erlang:send_after(Tc, Pid, close); + +%% ... or now. +c(Pid, false, _Opts) -> + Pid ! close. + +%% The RFC's only document the behaviour of Tc, our reconnect_timer, +%% for the establishment of connections but we also give +%% reconnect_timer semantics for a listener, being the time within +%% which a new connection attempt is expected of a connecting peer. +%% The value should be greater than the peer's Tc + jitter. + +%%% --------------------------------------------------------------------------- +%%% # reconnect/2 +%%% --------------------------------------------------------------------------- + +reconnect(Pid, #state{service_name = SvcName, + peerT = PeerT}) -> + #peer{ref = Ref, + type = connect, + options = Opts} + = fetch(PeerT, Pid), + send_event(SvcName, {reconnect, Ref, Opts}). + +%%% --------------------------------------------------------------------------- +%%% # call_module/4 +%%% --------------------------------------------------------------------------- + +%% Backwards compatibility and never documented/advertised. May be +%% removed. + +call_module(Mod, Req, From, #state{service + = #diameter_service{applications = Apps}, + service_name = Svc} + = S) -> + case cm([A || A <- Apps, Mod == hd(A#diameter_app.module)], + Req, + From, + Svc) + of + {reply = T, RC} -> + {T, RC, S}; + noreply = T -> + {T, S}; + Reason -> + {reply, {error, Reason}, S} + end. + +cm([#diameter_app{module = ModX, alias = Alias}], Req, From, Svc) -> + MFA = {ModX, handle_call, [Req, From, Svc]}, + + try state_cb(MFA, Alias) of + {noreply = T, ModS} -> + mod_state(Alias, ModS), + T; + {reply = T, RC, ModS} -> + mod_state(Alias, ModS), + {T, RC}; + T -> + diameter_lib:error_report({invalid, T}, MFA), + invalid + catch + E: Reason -> + diameter_lib:error_report({failure, {E, Reason, ?STACK}}, MFA), + failure + end; + +cm([], _, _, _) -> + unknown; + +cm([_,_|_], _, _, _) -> + multiple. + +%%% --------------------------------------------------------------------------- +%%% # send_request/5 +%%% --------------------------------------------------------------------------- + +%% Send an outgoing request in its dedicated process. +%% +%% Note that both encode of the outgoing request and of the received +%% answer happens in this process. It's also this process that replies +%% to the caller. The service process only handles the state-retaining +%% callbacks. +%% +%% The mod field of the #diameter_app{} here includes any extra +%% arguments passed to diameter:call/2. + +send_request({TPid, Caps, App}, Msg, Opts, Caller, SvcName) -> + #diameter_app{module = ModX} + = App, + + Pkt = make_packet(Msg), + + case cb(ModX, prepare_request, [Pkt, SvcName, {TPid, Caps}]) of + {send, P} -> + send_request(make_packet(P, Pkt), + TPid, + Caps, + App, + Opts, + Caller, + SvcName); + {discard, Reason} -> + {error, Reason}; + discard -> + {error, discarded}; + T -> + ?ERROR({invalid_return, prepare_request, App, T}) + end. + +%% make_packet/1 +%% +%% Turn an outgoing request as passed to call/4 into a diameter_packet +%% record in preparation for a prepare_request callback. + +make_packet(Bin) + when is_binary(Bin) -> + #diameter_packet{header = diameter_codec:decode_header(Bin), + bin = Bin}; + +make_packet(#diameter_packet{msg = [#diameter_header{} = Hdr | Avps]} = Pkt) -> + Pkt#diameter_packet{msg = [make_header(Hdr) | Avps]}; + +make_packet(#diameter_packet{header = Hdr} = Pkt) -> + Pkt#diameter_packet{header = make_header(Hdr)}; + +make_packet(Msg) -> + make_packet(#diameter_packet{msg = Msg}). + +%% make_header/1 + +make_header(undefined) -> + Seq = diameter_session:sequence(), + make_header(#diameter_header{end_to_end_id = Seq, + hop_by_hop_id = Seq}); + +make_header(#diameter_header{version = undefined} = Hdr) -> + make_header(Hdr#diameter_header{version = ?DIAMETER_VERSION}); + +make_header(#diameter_header{end_to_end_id = undefined} = H) -> + Seq = diameter_session:sequence(), + make_header(H#diameter_header{end_to_end_id = Seq}); + +make_header(#diameter_header{hop_by_hop_id = undefined} = H) -> + Seq = diameter_session:sequence(), + make_header(H#diameter_header{hop_by_hop_id = Seq}); + +make_header(#diameter_header{} = Hdr) -> + Hdr; + +make_header(T) -> + ?ERROR({invalid_header, T}). + +%% make_packet/2 +%% +%% Reconstruct a diameter_packet from the return value of +%% prepare_request or prepare_retransmit callback. + +make_packet(Bin, _) + when is_binary(Bin) -> + make_packet(Bin); + +make_packet(#diameter_packet{msg = [#diameter_header{} | _]} = Pkt, _) -> + Pkt; + +%% Returning a diameter_packet with no header from a prepare_request +%% or prepare_retransmit callback retains the header passed into it. +%% This is primarily so that the end to end and hop by hop identifiers +%% are retained. +make_packet(#diameter_packet{header = Hdr} = Pkt, + #diameter_packet{header = Hdr0}) -> + Pkt#diameter_packet{header = fold_record(Hdr0, Hdr)}; + +make_packet(Msg, Pkt) -> + Pkt#diameter_packet{msg = Msg}. + +%% fold_record/2 + +fold_record(undefined, R) -> + R; +fold_record(Rec, R) -> + diameter_lib:fold_tuple(2, Rec, R). + +%% send_request/7 + +send_request(Pkt, TPid, Caps, App, Opts, Caller, SvcName) -> + #diameter_app{alias = Alias, + dictionary = Dict, + module = ModX, + answer_errors = AE} + = App, + + EPkt = encode(Dict, Pkt), + + #options{filter = Filter, + timeout = Timeout} + = Opts, + + Req = #request{packet = Pkt, + from = Caller, + handler = self(), + transport = TPid, + caps = Caps, + app = Alias, + filter = Filter, + dictionary = Dict, + module = ModX}, + + try + TRef = send_request(TPid, EPkt, Req, Timeout), + ack(Caller), + handle_answer(SvcName, AE, recv_answer(Timeout, SvcName, {TRef, Req})) + after + erase_request(EPkt) + end. + +%% Tell caller a send has been attempted. +ack({Pid, Ref}) -> + Pid ! Ref. + +%% recv_answer/3 + +recv_answer(Timeout, + SvcName, + {TRef, #request{from = {_, Ref}, packet = RPkt} = Req} + = T) -> + + %% Matching on TRef below ensures we ignore messages that pertain + %% to a previous transport prior to failover. The answer message + %% includes the #request{} since it's not necessarily Req; that + %% is, from the last peer to which we've transmitted. + + receive + {answer = A, Ref, Rq, Pkt} -> %% Answer from peer. + {A, Rq, Pkt}; + {timeout = Reason, TRef, _} -> %% No timely reply + {error, Req, Reason}; + {failover = Reason, TRef, false} -> %% No alternative peer. + {error, Req, Reason}; + {failover, TRef, Transport} -> %% Resend to alternate peer. + try_retransmit(Timeout, SvcName, Req, Transport); + {failover, TRef} -> %% May have missed failover notification. + Seqs = diameter_codec:sequence_numbers(RPkt), + Pid = whois(SvcName), + is_pid(Pid) andalso (Pid ! {failover, TRef, Seqs}), + recv_answer(Timeout, SvcName, T) + end. +%% Note that failover starts a new timer and that expiry of an old +%% timer value is ignored. This means that an answer could be accepted +%% from a peer after timeout in the case of failover. + +try_retransmit(Timeout, SvcName, Req, Transport) -> + try retransmit(Transport, Req, SvcName, Timeout) of + T -> recv_answer(Timeout, SvcName, T) + catch + ?FAILURE(Reason) -> {error, Req, Reason} + end. + +%% handle_error/3 + +handle_error(Req, Reason, SvcName) -> + #request{module = ModX, + packet = Pkt, + transport = TPid, + caps = Caps} + = Req, + cb(ModX, handle_error, [Reason, msg(Pkt), SvcName, {TPid, Caps}]). + +msg(#diameter_packet{msg = undefined, bin = Bin}) -> + Bin; +msg(#diameter_packet{msg = Msg}) -> + Msg. + +%% encode/2 + +%% Note that prepare_request can return a diameter_packet containing +%% header or transport_data. Even allow the returned record to contain +%% an encoded binary. This isn't the usual case but could some in +%% handy, for test at least. (For example, to send garbage.) + +%% The normal case: encode the returned message. +encode(Dict, #diameter_packet{msg = Msg, bin = undefined} = Pkt) -> + D = pick_dictionary([Dict, ?BASE], Msg), + diameter_codec:encode(D, Pkt); + +%% Callback has returned an encoded binary: just send. +encode(_, #diameter_packet{} = Pkt) -> + Pkt. + +%% pick_dictionary/2 + +%% Pick the first dictionary that declares the application id in the +%% specified header. +pick_dictionary(Ds, [#diameter_header{application_id = Id} | _]) -> + pd(Ds, fun(D) -> Id = D:id() end); + +%% Pick the first dictionary that knows the specified message name. +pick_dictionary(Ds, [MsgName|_]) -> + pd(Ds, fun(D) -> D:msg2rec(MsgName) end); + +%% Pick the first dictionary that knows the name of the specified +%% message record. +pick_dictionary(Ds, Rec) -> + Name = element(1, Rec), + pd(Ds, fun(D) -> D:rec2msg(Name) end). + +pd([D|Ds], F) -> + try + F(D), + D + catch + error:_ -> + pd(Ds, F) + end; + +pd([], _) -> + ?ERROR(no_dictionary). + +%% send_request/4 + +send_request(TPid, #diameter_packet{bin = Bin} = Pkt, Req, Timeout) + when node() == node(TPid) -> + %% Store the outgoing request before sending to avoid a race with + %% reply reception. + TRef = store_request(TPid, Bin, Req, Timeout), + send(TPid, Pkt), + TRef; + +%% Send using a remote transport: spawn a process on the remote node +%% to relay the answer. +send_request(TPid, #diameter_packet{} = Pkt, Req, Timeout) -> + TRef = erlang:start_timer(Timeout, self(), timeout), + T = {TPid, Pkt, Req, Timeout, TRef}, + spawn(node(TPid), ?MODULE, send, [T]), + TRef. + +%% send/1 + +send({TPid, Pkt, #request{handler = Pid} = Req, Timeout, TRef}) -> + Ref = send_request(TPid, Pkt, Req#request{handler = self()}, Timeout), + Pid ! reref(receive T -> T end, Ref, TRef). + +reref({T, Ref, R}, Ref, TRef) -> + {T, TRef, R}; +reref(T, _, _) -> + T. + +%% send/2 + +send(Pid, Pkt) -> + Pid ! {send, Pkt}. + +%% retransmit/4 + +retransmit({TPid, Caps, #diameter_app{alias = Alias} = App}, + #request{app = Alias, + packet = Pkt} + = Req, + SvcName, + Timeout) -> + have_request(Pkt, TPid) %% Don't failover to a peer we've + andalso ?THROW(timeout), %% already sent to. + + case cb(App, prepare_retransmit, [Pkt, SvcName, {TPid, Caps}]) of + {send, P} -> + retransmit(make_packet(P, Pkt), TPid, Caps, Req, Timeout); + {discard, Reason} -> + ?THROW(Reason); + discard -> + ?THROW(discarded); + T -> + ?ERROR({invalid_return, prepare_retransmit, App, T}) + end. + +%% retransmit/5 + +retransmit(Pkt, TPid, Caps, #request{dictionary = Dict} = Req, Timeout) -> + EPkt = encode(Dict, Pkt), + + NewReq = Req#request{transport = TPid, + packet = Pkt, + caps = Caps}, + + ?LOG(retransmission, NewReq), + TRef = send_request(TPid, EPkt, NewReq, Timeout), + {TRef, NewReq}. + +%% store_request/4 + +store_request(TPid, Bin, Req, Timeout) -> + Seqs = diameter_codec:sequence_numbers(Bin), + TRef = erlang:start_timer(Timeout, self(), timeout), + ets:insert(?REQUEST_TABLE, {Seqs, Req, TRef}), + ets:member(?REQUEST_TABLE, TPid) + orelse (self() ! {failover, TRef}), %% possibly missed failover + TRef. + +%% lookup_request/2 + +lookup_request(Msg, TPid) + when is_pid(TPid) -> + lookup(Msg, TPid, '_'); + +lookup_request(Msg, TRef) + when is_reference(TRef) -> + lookup(Msg, '_', TRef). + +lookup(Msg, TPid, TRef) -> + Seqs = diameter_codec:sequence_numbers(Msg), + Spec = [{{Seqs, #request{transport = TPid, _ = '_'}, TRef}, + [], + ['$_']}], + case ets:select(?REQUEST_TABLE, Spec) of + [{_, Req, _}] -> + Req; + [] -> + false + end. + +%% erase_request/1 + +erase_request(Pkt) -> + ets:delete(?REQUEST_TABLE, diameter_codec:sequence_numbers(Pkt)). + +%% match_requests/1 + +match_requests(TPid) -> + Pat = {'_', #request{transport = TPid, _ = '_'}, '_'}, + ets:select(?REQUEST_TABLE, [{Pat, [], ['$_']}]). + +%% have_request/2 + +have_request(Pkt, TPid) -> + Seqs = diameter_codec:sequence_numbers(Pkt), + Pat = {Seqs, #request{transport = TPid, _ = '_'}, '_'}, + '$end_of_table' /= ets:select(?REQUEST_TABLE, [{Pat, [], ['$_']}], 1). + +%% request_peer_up/1 + +request_peer_up(TPid) -> + ets:insert(?REQUEST_TABLE, {TPid}). + +%% request_peer_down/2 + +request_peer_down(TPid, S) -> + ets:delete(?REQUEST_TABLE, TPid), + lists:foreach(fun(T) -> failover(T,S) end, match_requests(TPid)). +%% Note that a request process can store its request after failover +%% notifications are sent here: store_request/4 sends the notification +%% in that case. Note also that we'll send as many notifications to a +%% given handler as there are peers its sent to. All but one of these +%% will be ignored. + +%%% --------------------------------------------------------------------------- +%%% recv_request/3 +%%% --------------------------------------------------------------------------- + +recv_request(TPid, Pkt, {ConnT, SvcName, Apps}) -> + try ets:lookup(ConnT, TPid) of + [C] -> + recv_request(C, TPid, Pkt, SvcName, Apps); + [] -> %% transport has gone down + ok + catch + error: badarg -> %% service has gone down (and taken table with it) + ok + end. + +%% recv_request/5 + +recv_request(#conn{apps = SApps, caps = Caps}, TPid, Pkt, SvcName, Apps) -> + #diameter_caps{origin_host = {OH,_}, + origin_realm = {OR,_}} + = Caps, + + #diameter_packet{header = #diameter_header{application_id = Id}} + = Pkt, + + recv_request(find_recv_app(Id, SApps), + {SvcName, OH, OR}, + TPid, + Apps, + Caps, + Pkt). + +%% find_recv_app/2 + +%% No one should be sending the relay identifier. +find_recv_app(?APP_ID_RELAY, _) -> + false; + +%% With any other id we either support it locally or as a relay. +find_recv_app(Id, SApps) -> + keyfind([Id, ?APP_ID_RELAY], 1, SApps). + +%% keyfind/3 + +keyfind([], _, _) -> + false; +keyfind([Key | Rest], Pos, L) -> + case lists:keyfind(Key, Pos, L) of + false -> + keyfind(Rest, Pos, L); + T -> + T + end. + +%% recv_request/6 + +recv_request({Id, Alias}, T, TPid, Apps, Caps, Pkt) -> + #diameter_app{dictionary = Dict} + = A + = find_app(Alias, Apps), + recv_request(T, {TPid, Caps}, A, diameter_codec:decode(Id, Dict, Pkt)); +%% Note that the decode is different depending on whether or not Id is +%% ?APP_ID_RELAY. + +%% DIAMETER_APPLICATION_UNSUPPORTED 3007 +%% A request was sent for an application that is not supported. + +recv_request(false, {_, OH, OR}, TPid, _, _, Pkt) -> + ?LOG({error, application}, Pkt), + reply(answer_message({OH, OR, 3007}, collect_avps(Pkt)), ?BASE, TPid, Pkt). + +collect_avps(Pkt) -> + case diameter_codec:collect_avps(Pkt) of + {_Bs, As} -> + As; + As -> + As + end. + +%% recv_request/4 + +%% Wrong number of bits somewhere in the message: reply. +%% +%% DIAMETER_INVALID_AVP_BITS 3009 +%% A request was received that included an AVP whose flag bits are +%% set to an unrecognized value, or that is inconsistent with the +%% AVP's definition. +%% +recv_request({_, OH, OR}, {TPid, _}, _, #diameter_packet{errors = [Bs | _], + bin = Bin, + avps = Avps} + = Pkt) + when is_bitstring(Bs) -> + ?LOG({error, invalid_avp_bits}, Bin), + reply(answer_message({OH, OR, 3009}, Avps), ?BASE, TPid, Pkt); + +%% Either we support this application but don't recognize the command +%% or we're a relay and the command isn't proxiable. +%% +%% DIAMETER_COMMAND_UNSUPPORTED 3001 +%% The Request contained a Command-Code that the receiver did not +%% recognize or support. This MUST be used when a Diameter node +%% receives an experimental command that it does not understand. +%% +recv_request({_, OH, OR}, + {TPid, _}, + #diameter_app{id = Id}, + #diameter_packet{header = #diameter_header{is_proxiable = P}, + msg = M, + avps = Avps, + bin = Bin} + = Pkt) + when ?APP_ID_RELAY /= Id, undefined == M; + ?APP_ID_RELAY == Id, not P -> + ?LOG({error, command_unsupported}, Bin), + reply(answer_message({OH, OR, 3001}, Avps), ?BASE, TPid, Pkt); + +%% Error bit was set on a request. +%% +%% DIAMETER_INVALID_HDR_BITS 3008 +%% A request was received whose bits in the Diameter header were +%% either set to an invalid combination, or to a value that is +%% inconsistent with the command code's definition. +%% +recv_request({_, OH, OR}, + {TPid, _}, + _, + #diameter_packet{header = #diameter_header{is_error = true}, + avps = Avps, + bin = Bin} + = Pkt) -> + ?LOG({error, error_bit}, Bin), + reply(answer_message({OH, OR, 3008}, Avps), ?BASE, TPid, Pkt); + +%% A message in a locally supported application or a proxiable message +%% in the relay application. Don't distinguish between the two since +%% each application has its own callback config. That is, the user can +%% easily distinguish between the two cases. +recv_request(T, TC, App, Pkt) -> + request_cb(T, TC, App, examine(Pkt)). + +%% Note that there may still be errors but these aren't protocol +%% (3xxx) errors that lead to an answer-message. + +request_cb({SvcName, _OH, _OR} = T, TC, App, Pkt) -> + request_cb(cb(App, handle_request, [Pkt, SvcName, TC]), App, T, TC, Pkt). + +%% examine/1 +%% +%% Look for errors in a decoded message. Length errors result in +%% decode failure in diameter_codec. + +examine(#diameter_packet{header = #diameter_header{version + = ?DIAMETER_VERSION}} + = Pkt) -> + Pkt; + +%% DIAMETER_UNSUPPORTED_VERSION 5011 +%% This error is returned when a request was received, whose version +%% number is unsupported. + +examine(#diameter_packet{errors = Es} = Pkt) -> + Pkt#diameter_packet{errors = [5011 | Es]}. +%% It's odd/unfortunate that this isn't a protocol error. + +%% request_cb/5 + +%% A reply may be an answer-message, constructed either here or by +%% the handle_request callback. The header from the incoming request +%% is passed into the encode so that it can retrieve the relevant +%% command code in this case. It will also then ignore Dict and use +%% the base encoder. +request_cb({reply, Ans}, + #diameter_app{dictionary = Dict}, + _, + {TPid, _}, + Pkt) -> + reply(Ans, Dict, TPid, Pkt); + +%% An 3xxx result code, for which the E-bit is set in the header. +request_cb({protocol_error, RC}, _, T, {TPid, _}, Pkt) + when 3000 =< RC, RC < 4000 -> + protocol_error(RC, T, TPid, Pkt); + +%% RFC 3588 says we must reply 3001 to anything unrecognized or +%% unsupported. 'noreply' is undocumented (and inappropriately named) +%% backwards compatibility for this, protocol_error the documented +%% alternative. +request_cb(noreply, _, T, {TPid, _}, Pkt) -> + protocol_error(3001, T, TPid, Pkt); + +%% Relay a request to another peer. This is equivalent to doing an +%% explicit call/4 with the message in question except that (1) a loop +%% will be detected by examining Route-Record AVP's, (3) a +%% Route-Record AVP will be added to the outgoing request and (3) the +%% End-to-End Identifier will default to that in the +%% #diameter_header{} without the need for an end_to_end_identifier +%% option. +%% +%% relay and proxy are similar in that they require the same handling +%% with respect to Route-Record and End-to-End identifier. The +%% difference is that a proxy advertises specific applications, while +%% a relay advertises the relay application. If a callback doesn't +%% want to distinguish between the cases in the callback return value +%% then 'resend' is a neutral alternative. +%% +request_cb({A, Opts}, + #diameter_app{id = Id} + = App, + T, + TC, + Pkt) + when A == relay, Id == ?APP_ID_RELAY; + A == proxy, Id /= ?APP_ID_RELAY; + A == resend -> + resend(Opts, App, T, TC, Pkt); + +request_cb(discard, _, _, _, _) -> + ok; + +request_cb({eval, RC, F}, App, T, TC, Pkt) -> + request_cb(RC, App, T, TC, Pkt), + diameter_lib:eval(F). + +%% protocol_error/4 + +protocol_error(RC, {_, OH, OR}, TPid, #diameter_packet{avps = Avps} = Pkt) -> + ?LOG({error, RC}, Pkt), + reply(answer_message({OH, OR, RC}, Avps), ?BASE, TPid, Pkt). + +%% resend/5 +%% +%% Resend a message as a relay or proxy agent. + +resend(Opts, + #diameter_app{} = App, + {_SvcName, OH, _OR} = T, + {_TPid, _Caps} = TC, + #diameter_packet{avps = Avps} = Pkt) -> + {Code, _Flags, Vid} = ?BASE:avp_header('Route-Record'), + resend(is_loop(Code, Vid, OH, Avps), Opts, App, T, TC, Pkt). + +%% DIAMETER_LOOP_DETECTED 3005 +%% An agent detected a loop while trying to get the message to the +%% intended recipient. The message MAY be sent to an alternate peer, +%% if one is available, but the peer reporting the error has +%% identified a configuration problem. + +resend(true, _, _, T, {TPid, _}, Pkt) -> %% Route-Record loop + protocol_error(3005, T, TPid, Pkt); + +%% 6.1.8. Relaying and Proxying Requests +%% +%% A relay or proxy agent MUST append a Route-Record AVP to all requests +%% forwarded. The AVP contains the identity of the peer the request was +%% received from. + +resend(false, + Opts, + App, + {SvcName, _, _}, + {TPid, #diameter_caps{origin_host = {_, OH}}}, + #diameter_packet{header = Hdr0, + avps = Avps} + = Pkt) -> + Route = #diameter_avp{data = {?BASE, 'Route-Record', OH}}, + Seq = diameter_session:sequence(), + Hdr = Hdr0#diameter_header{hop_by_hop_id = Seq}, + Msg = [Hdr, Route | Avps], + %% Filter sender as ineligible receiver. + reply(call(SvcName, App, Msg, [{filter, {neg, {host, OH}}} | Opts]), + TPid, + Pkt). +%% The incoming request is relayed with the addition of a +%% Route-Record. Note the requirement on the return from call/4. +%% This places a requirement on the values returned by the +%% handle_answer and handle_error callbacks of the application module +%% in question. +%% +%% RFC 6.3 says that a relay agent does not modify Origin-Host but +%% says nothing about a proxy. Assume it should behave the same way. + +%% reply/3 +%% +%% Relay a reply to a relayed request. + +%% Answer from the peer: reset the hop by hop identifier and send. +reply(#diameter_packet{bin = B} + = Pkt, + TPid, + #diameter_packet{header = #diameter_header{hop_by_hop_id = Id}, + transport_data = TD}) -> + send(TPid, Pkt#diameter_packet{bin = diameter_codec:hop_by_hop_id(Id, B), + transport_data = TD}); +%% TODO: counters + +%% Not. Ignoring the error feels harsh but there is no appropriate +%% Result-Code for a protocol error (which this isn't really anyway) +%% and the RFC doesn't provide any guidance how to act. A weakness +%% here is that we don't deal well with a decode error: the request +%% will simply timeout on the peer's end. Better would be to just send +%% the answer (with modified hop by hop identifier) on regardless, at +%% least in the relay case in which there's no examination of the +%% answer. In the proxy case it's not clear that the callback won't +%% examine the answer. Just be quiet here since a decode error causes +%% the request process to crash (or not depending on the error and +%% config and/or handle_answer callback). +reply(_, _, _) -> + ok. + +%% is_loop/4 +%% +%% Is there a Route-Record AVP with our Origin-Host? + +is_loop(Code, + Vid, + Bin, + [#diameter_avp{code = Code, vendor_id = Vid, data = Bin} | _]) -> + true; + +is_loop(_, _, _, []) -> + false; + +is_loop(Code, Vid, OH, [_ | Avps]) + when is_binary(OH) -> + is_loop(Code, Vid, OH, Avps); + +is_loop(Code, Vid, OH, Avps) -> + is_loop(Code, Vid, ?BASE:avp(encode, OH, 'Route-Record'), Avps). + +%% reply/4 +%% +%% Send a locally originating reply. + +%% No errors or a diameter_header/avp list. +reply(Msg, Dict, TPid, #diameter_packet{errors = Es, + transport_data = TD} + = ReqPkt) + when [] == Es; + is_record(hd(Msg), diameter_header) -> + Pkt = diameter_codec:encode(Dict, make_reply_packet(Msg, ReqPkt)), + incr(send, Pkt, Dict, TPid), %% count result codes in sent answers + send(TPid, Pkt#diameter_packet{transport_data = TD}); + +%% Or not: set Result-Code and Failed-AVP AVP's. +reply(Msg, Dict, TPid, #diameter_packet{errors = [H|_] = Es} = Pkt) -> + reply(rc(Msg, rc(H), [A || {_,A} <- Es], Dict), + Dict, + TPid, + Pkt#diameter_packet{errors = []}). + +%% make_reply_packet/2 + +make_reply_packet(Bin, _) + when is_binary(Bin) -> + #diameter_packet{bin = Bin}; + +make_reply_packet([#diameter_header{} | _] = Msg, _) -> + #diameter_packet{msg = Msg}; + +make_reply_packet(Msg, #diameter_packet{header = ReqHdr}) -> + #diameter_header{end_to_end_id = EId, + hop_by_hop_id = Hid, + is_proxiable = P} + = ReqHdr, + + Hdr = #diameter_header{version = ?DIAMETER_VERSION, + end_to_end_id = EId, + hop_by_hop_id = Hid, + is_proxiable = P, + is_retransmitted = false}, + #diameter_packet{header = Hdr, + msg = Msg}. + +%% rc/1 + +rc({RC, _}) -> + RC; +rc(RC) -> + RC. + +%% rc/4 + +rc(Rec, RC, Failed, Dict) + when is_integer(RC) -> + set(Rec, [{'Result-Code', RC} | failed_avp(Rec, Failed, Dict)], Dict). + +%% Reply as name and tuple list ... +set([_|_] = Ans, Avps, _) -> + Ans ++ Avps; %% Values nearer tail take precedence. + +%% ... or record. +set(Rec, Avps, Dict) -> + Dict:'#set-'(Avps, Rec). + +%% failed_avp/3 + +failed_avp(_, [] = No, _) -> + No; + +failed_avp(Rec, Failed, Dict) -> + [fa(Rec, [{'AVP', Failed}], Dict)]. + +%% Reply as name and tuple list ... +fa([MsgName | Values], FailedAvp, Dict) -> + R = Dict:msg2rec(MsgName), + try + Dict:'#info-'(R, {index, 'Failed-AVP'}), + {'Failed-AVP', [FailedAvp]} + catch + error: _ -> + Avps = proplists:get_value('AVP', Values, []), + A = #diameter_avp{name = 'Failed-AVP', + value = FailedAvp}, + {'AVP', [A|Avps]} + end; + +%% ... or record. +fa(Rec, FailedAvp, Dict) -> + try + {'Failed-AVP', [FailedAvp]} + catch + error: _ -> + Avps = Dict:'get-'('AVP', Rec), + A = #diameter_avp{name = 'Failed-AVP', + value = FailedAvp}, + {'AVP', [A|Avps]} + end. + +%% 3. Diameter Header +%% +%% E(rror) - If set, the message contains a protocol error, +%% and the message will not conform to the ABNF +%% described for this command. Messages with the 'E' +%% bit set are commonly referred to as error +%% messages. This bit MUST NOT be set in request +%% messages. See Section 7.2. + +%% 3.2. Command Code ABNF specification +%% +%% e-bit = ", ERR" +%% ; If present, the 'E' bit in the Command +%% ; Flags is set, indicating that the answer +%% ; message contains a Result-Code AVP in +%% ; the "protocol error" class. + +%% 7.1.3. Protocol Errors +%% +%% Errors that fall within the Protocol Error category SHOULD be treated +%% on a per-hop basis, and Diameter proxies MAY attempt to correct the +%% error, if it is possible. Note that these and only these errors MUST +%% only be used in answer messages whose 'E' bit is set. + +%% Thus, only construct answers to protocol errors. Other errors +%% require an message-specific answer and must be handled by the +%% application. + +%% 6.2. Diameter Answer Processing +%% +%% When a request is locally processed, the following procedures MUST be +%% applied to create the associated answer, in addition to any +%% additional procedures that MAY be discussed in the Diameter +%% application defining the command: +%% +%% - The same Hop-by-Hop identifier in the request is used in the +%% answer. +%% +%% - The local host's identity is encoded in the Origin-Host AVP. +%% +%% - The Destination-Host and Destination-Realm AVPs MUST NOT be +%% present in the answer message. +%% +%% - The Result-Code AVP is added with its value indicating success or +%% failure. +%% +%% - If the Session-Id is present in the request, it MUST be included +%% in the answer. +%% +%% - Any Proxy-Info AVPs in the request MUST be added to the answer +%% message, in the same order they were present in the request. +%% +%% - The 'P' bit is set to the same value as the one in the request. +%% +%% - The same End-to-End identifier in the request is used in the +%% answer. +%% +%% Note that the error messages (see Section 7.3) are also subjected to +%% the above processing rules. + +%% 7.3. Error-Message AVP +%% +%% The Error-Message AVP (AVP Code 281) is of type UTF8String. It MAY +%% accompany a Result-Code AVP as a human readable error message. The +%% Error-Message AVP is not intended to be useful in real-time, and +%% SHOULD NOT be expected to be parsed by network entities. + +%% answer_message/2 + +answer_message({OH, OR, RC}, Avps) -> + {Code, _, Vid} = ?BASE:avp_header('Session-Id'), + ['answer-message', {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Result-Code', RC} + | session_id(Code, Vid, Avps)]. + +session_id(Code, Vid, Avps) + when is_list(Avps) -> + try + {value, #diameter_avp{} = Avp} = find_avp(Code, Vid, Avps), + Avp + catch + error: _ -> + [] + end; + +session_id(Code, Vid, Avps) + when is_list(Avps) -> + try + {value, #diameter_avp{data = D}} = find_avp(Code, Vid, Avps), + [{'Session-Id', [?BASE:avp(decode, D, 'Session-Id')]}] + catch + error: _ -> + [] + end. + +%% find_avp/3 + +find_avp(Code, Vid, Avps) + when is_integer(Code), (undefined == Vid orelse is_integer(Vid)) -> + find(fun(A) -> is_avp(Code, Vid, A) end, Avps). + +%% The final argument here could be a list of AVP's, depending on the case, +%% but we're only searching at the top level. +is_avp(Code, Vid, #diameter_avp{code = Code, vendor_id = Vid}) -> + true; +is_avp(_, _, _) -> + false. + +find(_, []) -> + false; +find(Pred, [H|T]) -> + case Pred(H) of + true -> + {value, H}; + false -> + find(Pred, T) + end. + +%% 7. Error Handling +%% +%% There are certain Result-Code AVP application errors that require +%% additional AVPs to be present in the answer. In these cases, the +%% Diameter node that sets the Result-Code AVP to indicate the error +%% MUST add the AVPs. Examples are: +%% +%% - An unrecognized AVP is received with the 'M' bit (Mandatory bit) +%% set, causes an answer to be sent with the Result-Code AVP set to +%% DIAMETER_AVP_UNSUPPORTED, and the Failed-AVP AVP containing the +%% offending AVP. +%% +%% - An AVP that is received with an unrecognized value causes an +%% answer to be returned with the Result-Code AVP set to +%% DIAMETER_INVALID_AVP_VALUE, with the Failed-AVP AVP containing the +%% AVP causing the error. +%% +%% - A command is received with an AVP that is omitted, yet is +%% mandatory according to the command's ABNF. The receiver issues an +%% answer with the Result-Code set to DIAMETER_MISSING_AVP, and +%% creates an AVP with the AVP Code and other fields set as expected +%% in the missing AVP. The created AVP is then added to the Failed- +%% AVP AVP. +%% +%% The Result-Code AVP describes the error that the Diameter node +%% encountered in its processing. In case there are multiple errors, +%% the Diameter node MUST report only the first error it encountered +%% (detected possibly in some implementation dependent order). The +%% specific errors that can be described by this AVP are described in +%% the following section. + +%% 7.5. Failed-AVP AVP +%% +%% The Failed-AVP AVP (AVP Code 279) is of type Grouped and provides +%% debugging information in cases where a request is rejected or not +%% fully processed due to erroneous information in a specific AVP. The +%% value of the Result-Code AVP will provide information on the reason +%% for the Failed-AVP AVP. +%% +%% The possible reasons for this AVP are the presence of an improperly +%% constructed AVP, an unsupported or unrecognized AVP, an invalid AVP +%% value, the omission of a required AVP, the presence of an explicitly +%% excluded AVP (see tables in Section 10), or the presence of two or +%% more occurrences of an AVP which is restricted to 0, 1, or 0-1 +%% occurrences. +%% +%% A Diameter message MAY contain one Failed-AVP AVP, containing the +%% entire AVP that could not be processed successfully. If the failure +%% reason is omission of a required AVP, an AVP with the missing AVP +%% code, the missing vendor id, and a zero filled payload of the minimum +%% required length for the omitted AVP will be added. + +%%% --------------------------------------------------------------------------- +%%% # handle_answer/3 +%%% --------------------------------------------------------------------------- + +%% Process an answer message in call-specific process. + +handle_answer(SvcName, _, {error, Req, Reason}) -> + handle_error(Req, Reason, SvcName); + +handle_answer(SvcName, + AnswerErrors, + {answer, #request{dictionary = Dict} = Req, Pkt}) -> + a(examine(diameter_codec:decode(Dict, Pkt)), + SvcName, + AnswerErrors, + Req). + +%% We don't really need to do a full decode if we're a relay and will +%% just resend with a new hop by hop identifier, but might a proxy +%% want to examine the answer? + +a(#diameter_packet{errors = []} + = Pkt, + SvcName, + AE, + #request{transport = TPid, + dictionary = Dict, + caps = Caps, + packet = P} + = Req) -> + try + incr(in, Pkt, Dict, TPid) + of + _ -> + cb(Req, handle_answer, [Pkt, msg(P), SvcName, {TPid, Caps}]) + catch + exit: {invalid_error_bit, _} = E -> + e(Pkt#diameter_packet{errors = [E]}, SvcName, AE, Req) + end; + +a(#diameter_packet{} = Pkt, SvcName, AE, Req) -> + e(Pkt, SvcName, AE, Req). + +e(Pkt, SvcName, callback, #request{transport = TPid, + caps = Caps, + packet = Pkt} + = Req) -> + cb(Req, handle_answer, [Pkt, msg(Pkt), SvcName, {TPid, Caps}]); +e(Pkt, SvcName, report, Req) -> + x(errors, handle_answer, [SvcName, Req, Pkt]); +e(Pkt, SvcName, discard, Req) -> + x({errors, handle_answer, [SvcName, Req, Pkt]}). + +%% Note that we don't check that the application id in the answer's +%% header is what we expect. (TODO: Does the rfc says anything about +%% this?) + +%% incr/4 +%% +%% Increment a stats counter for an incoming or outgoing message. + +%% TODO: fix +incr(_, #diameter_packet{msg = undefined}, _, _) -> + ok; + +incr(Dir, Pkt, Dict, TPid) + when is_pid(TPid) -> + #diameter_packet{header = #diameter_header{is_error = E} + = Hdr, + msg = Rec} + = Pkt, + + D = choose(E, ?BASE, Dict), + RC = int(get_avp_value(D, 'Result-Code', Rec)), + PE = is_protocol_error(RC), + + %% Check that the E bit is set only for 3xxx result codes. + (not (E orelse PE)) + orelse (E andalso PE) + orelse x({invalid_error_bit, RC}, answer, [Dir, Pkt]), + + Ctr = rc_counter(D, Rec, RC), + is_tuple(Ctr) + andalso incr(TPid, {diameter_codec:msg_id(Hdr), Dir, Ctr}). + +%% incr/2 + +incr(TPid, Counter) -> + diameter_stats:incr(Counter, TPid, 1). + +%% RFC 3588, 7.6: +%% +%% All Diameter answer messages defined in vendor-specific +%% applications MUST include either one Result-Code AVP or one +%% Experimental-Result AVP. +%% +%% Maintain statistics assuming one or the other, not both, which is +%% surely the intent of the RFC. + +rc_counter(_, _, RC) + when is_integer(RC) -> + {'Result-Code', RC}; +rc_counter(D, Rec, _) -> + rcc(get_avp_value(D, 'Experimental-Result', Rec)). + +%% Outgoing answers may be in any of the forms messages can be sent +%% in. Incoming messages will be records. We're assuming here that the +%% arity of the result code AVP's is 0 or 1. + +rcc([{_,_,RC} = T]) + when is_integer(RC) -> + T; +rcc({_,_,RC} = T) + when is_integer(RC) -> + T; +rcc(_) -> + undefined. + +int([N]) + when is_integer(N) -> + N; +int(N) + when is_integer(N) -> + N; +int(_) -> + undefined. + +is_protocol_error(RC) -> + 3000 =< RC andalso RC < 4000. + +-spec x(any(), atom(), list()) -> no_return(). + +%% Warn and exit request process on errors in an incoming answer. +x(Reason, F, A) -> + diameter_lib:warning_report(Reason, {?MODULE, F, A}), + x(Reason). + +x(T) -> + exit(T). + +%%% --------------------------------------------------------------------------- +%%% # failover/[23] +%%% --------------------------------------------------------------------------- + +%% Failover as a consequence of request_peer_down/2. +failover({_, #request{handler = Pid} = Req, TRef}, S) -> + Pid ! {failover, TRef, rt(Req, S)}. + +%% Failover as a consequence of store_request/4. +failover(TRef, Seqs, S) + when is_reference(TRef) -> + case lookup_request(Seqs, TRef) of + #request{} = Req -> + failover({Seqs, Req, TRef}, S); + false -> + ok + end. + +%% prepare_request returned a binary ... +rt(#request{packet = #diameter_packet{msg = undefined}}, _) -> + false; %% TODO: Not what we should do. + +%% ... or not. +rt(#request{packet = #diameter_packet{msg = Msg}, dictionary = D} = Req, S) -> + find_transport(get_destination(Msg, D), Req, S). + +%%% --------------------------------------------------------------------------- +%%% # report_status/5 +%%% --------------------------------------------------------------------------- + +report_status(Status, + #peer{ref = Ref, + conn = TPid, + type = Type, + options = Opts}, + #conn{apps = [_|_] = As, + caps = Caps}, + #state{service_name = SvcName} + = S, + Extra) -> + share_peer(Status, Caps, As, TPid, S), + Info = [Status, Ref, {TPid, Caps}, {type(Type), Opts} | Extra], + send_event(SvcName, list_to_tuple(Info)). + +%% send_event/2 + +send_event(SvcName, Info) -> + send_event(#diameter_event{service = SvcName, + info = Info}). + +send_event(#diameter_event{service = SvcName} = E) -> + lists:foreach(fun({_, Pid}) -> Pid ! E end, subscriptions(SvcName)). + +%%% --------------------------------------------------------------------------- +%%% # share_peer/5 +%%% --------------------------------------------------------------------------- + +share_peer(up, Caps, Aliases, TPid, #state{share_peers = true, + service_name = Svc}) -> + diameter_peer:notify(Svc, {peer, TPid, Aliases, Caps}); + +share_peer(_, _, _, _, _) -> + ok. + +%%% --------------------------------------------------------------------------- +%%% # share_peers/2 +%%% --------------------------------------------------------------------------- + +share_peers(Pid, #state{share_peers = true, + local_peers = PDict}) -> + ?Dict:fold(fun(A,Ps,ok) -> sp(Pid, A, Ps), ok end, ok, PDict); + +share_peers(_, #state{share_peers = false}) -> + ok. + +sp(Pid, Alias, Peers) -> + lists:foreach(fun({P,C}) -> Pid ! {peer, P, [Alias], C} end, Peers). + +%%% --------------------------------------------------------------------------- +%%% # remote_peer_up/4 +%%% --------------------------------------------------------------------------- + +remote_peer_up(Pid, Aliases, Caps, #state{use_shared_peers = true, + service = Svc, + shared_peers = PDict} + = S) -> + #diameter_service{applications = Apps} = Svc, + Update = lists:filter(fun(A) -> + lists:keymember(A, #diameter_app.alias, Apps) + end, + Aliases), + S#state{shared_peers = rpu(Pid, Caps, PDict, Update)}; + +remote_peer_up(_, _, _, #state{use_shared_peers = false} = S) -> + S. + +rpu(_, _, PDict, []) -> + PDict; +rpu(Pid, Caps, PDict, Aliases) -> + erlang:monitor(process, Pid), + T = {Pid, Caps}, + lists:foldl(fun(A,D) -> ?Dict:append(A, T, D) end, + PDict, + Aliases). + +%%% --------------------------------------------------------------------------- +%%% # remote_peer_down/2 +%%% --------------------------------------------------------------------------- + +remote_peer_down(Pid, #state{use_shared_peers = true, + shared_peers = PDict} + = S) -> + S#state{shared_peers = lists:foldl(fun(A,D) -> rpd(Pid, A, D) end, + PDict, + ?Dict:fetch_keys(PDict))}. + +rpd(Pid, Alias, PDict) -> + ?Dict:update(Alias, fun(Ps) -> lists:keydelete(Pid, 1, Ps) end, PDict). + +%%% --------------------------------------------------------------------------- +%%% find_transport/[34] +%%% +%%% Output: {TransportPid, #diameter_caps{}, #diameter_app{}} +%%% | false +%%% --------------------------------------------------------------------------- + +%% Initial call, from an arbitrary process. +find_transport({alias, Alias}, Msg, Opts, #state{service = Svc} = S) -> + #diameter_service{applications = Apps} = Svc, + ft(find_send_app(Alias, Apps), Msg, Opts, S); + +%% Relay or proxy send. +find_transport(#diameter_app{} = App, Msg, Opts, S) -> + ft(App, Msg, Opts, S). + +ft(#diameter_app{module = Mod, dictionary = D} = App, Msg, Opts, S) -> + #options{filter = Filter, + extra = Xtra} + = Opts, + pick_peer(App#diameter_app{module = Mod ++ Xtra}, + get_destination(Msg, D), + Filter, + S); +ft(false = No, _, _, _) -> + No. + +%% This can't be used if we're a relay and sending a message +%% in an application not known locally. (TODO) +find_send_app(Alias, Apps) -> + case lists:keyfind(Alias, #diameter_app.alias, Apps) of + #diameter_app{id = ?APP_ID_RELAY} -> + false; + T -> + T + end. + +%% Retransmission, in the service process. +find_transport([_,_] = RH, + Req, + #state{service = #diameter_service{pid = Pid, + applications = Apps}} + = S) + when self() == Pid -> + #request{app = Alias, + filter = Filter, + module = ModX} + = Req, + #diameter_app{} + = App + = lists:keyfind(Alias, #diameter_app.alias, Apps), + + pick_peer(App#diameter_app{module = ModX}, + RH, + Filter, + S). + +%% get_destination/2 + +get_destination(Msg, Dict) -> + [str(get_avp_value(Dict, 'Destination-Realm', Msg)), + str(get_avp_value(Dict, 'Destination-Host', Msg))]. + +%% TODO: +%% +%% Should add some way of specifying destination directly so that the +%% only requirement is that the prepare_request callback returns +%% something specific. (eg. {host, DH}; that is, let the caller specify.) +%% +%% Also, there is no longer any need to call get_destination at all in +%% the default case. + +str(T) + when T == undefined; + T == [] -> + undefined; +str([X]) + when is_list(X) -> + X; +str(T) -> + T. + +%% get_avp_value/3 +%% +%% Support outgoing messages in one of three forms: +%% +%% - a message record (as generated from a .dia spec) or +%% - a list of an atom message name followed by 2-tuple, avp name/value pairs. +%% - a list of a #diameter_header{} followed by #diameter_avp{} records, +%% +%% In the first two forms a dictionary module is used at encode to +%% identify the type of the AVP and its arity in the message in +%% question. The third form allows messages to be sent as is, without +%% a dictionary, which is needed in the case of relay agents, for one. + +get_avp_value(Dict, Name, [#diameter_header{} | Avps]) -> + try + {Code, _, VId} = Dict:avp_header(Name), + [A|_] = lists:dropwhile(fun(#diameter_avp{code = C, vendor_id = V}) -> + C /= Code orelse V /= VId + end, + Avps), + avp_decode(Dict, Name, A) + catch + error: _ -> + undefined + end; + +get_avp_value(_, Name, [_MsgName | Avps]) -> + case lists:keyfind(Name, 1, Avps) of + {_, V} -> + V; + _ -> + undefined + end; + +get_avp_value(Dict, Name, Rec) + when is_tuple(Rec) -> + try + Dict:'#get-'(Name, Rec) + catch + error:_ -> + undefined + end. + +avp_decode(Dict, Name, #diameter_avp{value = undefined, + data = Bin}) -> + Dict:avp(decode, Bin, Name); +avp_decode(_, _, #diameter_avp{value = V}) -> + V. + +%%% --------------------------------------------------------------------------- +%%% # pick_peer(App, [DestRealm, DestHost], Filter, #state{}) +%%% +%%% Output: {TransportPid, #diameter_caps{}, App} +%%% | false +%%% | {error, Reason} +%%% --------------------------------------------------------------------------- + +%% Find transports to a given realm/host. + +pick_peer(#diameter_app{alias = Alias} + = App, + [_,_] = RH, + Filter, + #state{local_peers = L, + shared_peers = S, + service_name = SvcName, + service = #diameter_service{pid = Pid}}) -> + pick_peer(peers(Alias, RH, Filter, L), + peers(Alias, RH, Filter, S), + Pid, + SvcName, + App). + +%% pick_peer/5 + +pick_peer([], [], _, _, _) -> + false; + +%% App state is mutable but we're not in the service process: go there. +pick_peer(Local, Remote, Pid, _SvcName, #diameter_app{mutable = true} = App) + when self() /= Pid -> + call_service(Pid, {pick_peer, Local, Remote, App}); + +%% App state isn't mutable or it is and we're in the service process: +%% do the deed. +pick_peer(Local, + Remote, + _Pid, + SvcName, + #diameter_app{module = ModX, + alias = Alias, + init_state = S, + mutable = M} + = App) -> + MFA = {ModX, pick_peer, [Local, Remote, SvcName]}, + + try state_cb(App, MFA) of + {ok, {TPid, #diameter_caps{} = Caps}} when is_pid(TPid) -> + {TPid, Caps, App}; + {{TPid, #diameter_caps{} = Caps}, ModS} when is_pid(TPid), M -> + mod_state(Alias, ModS), + {TPid, Caps, App}; + {false = No, ModS} when M -> + mod_state(Alias, ModS), + No; + {ok, false = No} -> + No; + false = No -> + No; + {{TPid, #diameter_caps{} = Caps}, S} when is_pid(TPid) -> + {TPid, Caps, App}; %% Accept returned state in the immutable + {false = No, S} -> %% case as long it isn't changed. + No; + T -> + diameter_lib:error_report({invalid, T, App}, MFA) + catch + E: Reason -> + diameter_lib:error_report({failure, {E, Reason, ?STACK}}, MFA) + end. + +%% peers/4 + +peers(Alias, RH, Filter, Peers) -> + case ?Dict:find(Alias, Peers) of + {ok, L} -> + ps(L, RH, Filter, {[],[]}); + error -> + [] + end. + +%% Place a peer whose Destination-Host/Realm matches those of the +%% request at the front of the result list. + +ps([], _, _, {Ys, Ns}) -> + lists:reverse(Ys, Ns); +ps([{_TPid, #diameter_caps{} = Caps} = TC | Rest], RH, Filter, Acc) -> + ps(Rest, RH, Filter, pacc(caps_filter(Caps, RH, Filter), + caps_filter(Caps, RH, {all, [host, realm]}), + TC, + Acc)). + +pacc(true, true, TC, {Ts, Fs}) -> + {[TC|Ts], Fs}; +pacc(true, false, TC, {Ts, Fs}) -> + {Ts, [TC|Fs]}; +pacc(false, _, _, Acc) -> + Acc. + +%% caps_filter/3 + +caps_filter(C, RH, {neg, F}) -> + not caps_filter(C, RH, F); + +caps_filter(C, RH, {all, L}) -> + lists:all(fun(F) -> caps_filter(C, RH, F) end, L); + +caps_filter(C, RH, {any, L}) -> + lists:any(fun(F) -> caps_filter(C, RH, F) end, L); + +caps_filter(#diameter_caps{origin_host = {_,H}}, [_,DH], host) -> + eq(undefined, DH, H); + +caps_filter(#diameter_caps{origin_realm = {_,R}}, [DR,_], realm) -> + eq(undefined, DR, R); + +caps_filter(C, _, Filter) -> + caps_filter(C, Filter). + +%% caps_filter/2 + +caps_filter(_, none) -> + true; + +caps_filter(#diameter_caps{origin_host = {_,OH}}, {host, H}) -> + eq(any, H, OH); + +caps_filter(#diameter_caps{origin_realm = {_,OR}}, {realm, R}) -> + eq(any, R, OR); + +caps_filter(C, T) -> + try + {eval, F} = T, + diameter_lib:eval([F,C]) + catch + _:_ -> false + end. + +eq(X, A, B) -> + X == A orelse A == B. + +%% transports/1 + +transports(#state{peerT = PeerT}) -> + ets:select(PeerT, [{#peer{conn = '$1', _ = '_'}, + [{'is_pid', '$1'}], + ['$1']}]). + +%%% --------------------------------------------------------------------------- +%%% # service_info/2 +%%% --------------------------------------------------------------------------- + +%% The config passed to diameter:start_service/2. +-define(CAP_INFO, ['Origin-Host', + 'Origin-Realm', + 'Vendor-Id', + 'Product-Name', + 'Origin-State-Id', + 'Host-IP-Address', + 'Supported-Vendor-Id', + 'Auth-Application-Id', + 'Inband-Security-Id', + 'Acct-Application-Id', + 'Vendor-Specific-Application-Id', + 'Firmware-Revision']). + +-define(ALL_INFO, [capabilities, + applications, + transport, + pending, + statistics]). + +service_info(Items, S) + when is_list(Items) -> + [{complete(I), service_info(I,S)} || I <- Items]; +service_info(Item, S) + when is_atom(Item) -> + service_info(Item, S, true). + +service_info(Item, #state{service = Svc} = S, Complete) -> + case Item of + name -> + S#state.service_name; + 'Origin-Host' -> + (Svc#diameter_service.capabilities) + #diameter_caps.origin_host; + 'Origin-Realm' -> + (Svc#diameter_service.capabilities) + #diameter_caps.origin_realm; + 'Vendor-Id' -> + (Svc#diameter_service.capabilities) + #diameter_caps.vendor_id; + 'Product-Name' -> + (Svc#diameter_service.capabilities) + #diameter_caps.product_name; + 'Origin-State-Id' -> + (Svc#diameter_service.capabilities) + #diameter_caps.origin_state_id; + 'Host-IP-Address' -> + (Svc#diameter_service.capabilities) + #diameter_caps.host_ip_address; + 'Supported-Vendor-Id' -> + (Svc#diameter_service.capabilities) + #diameter_caps.supported_vendor_id; + 'Auth-Application-Id' -> + (Svc#diameter_service.capabilities) + #diameter_caps.auth_application_id; + 'Inband-Security-Id' -> + (Svc#diameter_service.capabilities) + #diameter_caps.inband_security_id; + 'Acct-Application-Id' -> + (Svc#diameter_service.capabilities) + #diameter_caps.acct_application_id; + 'Vendor-Specific-Application-Id' -> + (Svc#diameter_service.capabilities) + #diameter_caps.vendor_specific_application_id; + 'Firmware-Revision' -> + (Svc#diameter_service.capabilities) + #diameter_caps.firmware_revision; + capabilities -> service_info(?CAP_INFO, S); + applications -> info_apps(S); + transport -> info_transport(S); + pending -> info_pending(S); + statistics -> info_stats(S); + keys -> ?ALL_INFO ++ ?CAP_INFO; %% mostly for test + all -> service_info(?ALL_INFO, S); + _ when Complete -> service_info(complete(Item), S, false); + _ -> undefined + end. + +complete(Pre) -> + P = atom_to_list(Pre), + case [I || I <- [name | ?ALL_INFO] ++ ?CAP_INFO, + lists:prefix(P, atom_to_list(I))] + of + [I] -> I; + _ -> Pre + end. + +info_stats(#state{peerT = PeerT}) -> + Peers = ets:select(PeerT, [{#peer{ref = '$1', conn = '$2', _ = '_'}, + [{'is_pid', '$2'}], + [['$1', '$2']]}]), + diameter_stats:read(lists:append(Peers)). +%% TODO: include peer identities in return value + +info_transport(#state{peerT = PeerT, connT = ConnT}) -> + dict:fold(fun it/3, + [], + ets:foldl(fun(T,A) -> it_acc(ConnT, A, T) end, + dict:new(), + PeerT)). + +it(Ref, [[{type, connect} | _] = L], Acc) -> + [[{ref, Ref} | L] | Acc]; +it(Ref, [[{type, accept}, {options, Opts} | _] | _] = L, Acc) -> + [[{ref, Ref}, + {type, listen}, + {options, Opts}, + {accept, [lists:nthtail(2,A) || A <- L]}] + | Acc]. +%% Each entry has the same Opts. (TODO) + +it_acc(ConnT, Acc, #peer{pid = Pid, + type = Type, + ref = Ref, + options = Opts, + op_state = OS, + started = T, + conn = TPid}) -> + dict:append(Ref, + [{type, Type}, + {options, Opts}, + {watchdog, {Pid, T, OS}} + | info_conn(ConnT, TPid)], + Acc). + +info_conn(ConnT, TPid) -> + info_conn(ets:lookup(ConnT, TPid)). + +info_conn([#conn{pid = Pid, apps = SApps, caps = Caps, started = T}]) -> + [{peer, {Pid, T}}, + {apps, SApps}, + {caps, info_caps(Caps)}]; +info_conn([] = No) -> + No. + +info_caps(#diameter_caps{} = C) -> + lists:zip(record_info(fields, diameter_caps), tl(tuple_to_list(C))). + +info_apps(#state{service = #diameter_service{applications = Apps}}) -> + lists:map(fun mk_app/1, Apps). + +mk_app(#diameter_app{alias = Alias, + dictionary = Dict, + module = ModX, + id = Id}) -> + [{alias, Alias}, + {dictionary, Dict}, + {module, ModX}, + {id, Id}]. + +info_pending(#state{} = S) -> + MatchSpec = [{{'$1', + #request{transport = '$2', + from = '$3', + app = '$4', + _ = '_'}, + '_'}, + [?ORCOND([{'==', T, '$2'} || T <- transports(S)])], + [{{'$1', [{{app, '$4'}}, + {{transport, '$2'}}, + {{from, '$3'}}]}}]}], + + ets:select(?REQUEST_TABLE, MatchSpec). diff --git a/lib/diameter/src/app/diameter_service_sup.erl b/lib/diameter/src/app/diameter_service_sup.erl new file mode 100644 index 0000000000..153fff902f --- /dev/null +++ b/lib/diameter/src/app/diameter_service_sup.erl @@ -0,0 +1,64 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% The supervisor of service processes. +%% + +-module(diameter_service_sup). + +-behaviour(supervisor). + +-export([start_link/0, %% supervisor start + start_child/1]). %% service start + +%% supervisor callback +-export([init/1]). + +-define(NAME, ?MODULE). %% supervisor name + +%% start_link/0 + +start_link() -> + SupName = {local, ?NAME}, + supervisor:start_link(SupName, ?MODULE, []). + +%% start_child/1 +%% +%% A service and its related processes (transport, peer_fwm and +%% watchdog) are all temporary since they're all restarted in +%% application code. A Transport and peer_fsm is restarted by a +%% watchdog as required by the RFC 3539 state machine, a watchdog is +%% restarted by service, and services are restarted by diameter_config. + +start_child(ServiceName) -> + supervisor:start_child(?NAME, [ServiceName]). + +%% init/1 + +init([]) -> + Mod = diameter_service, + Flags = {simple_one_for_one, 0, 1}, + ChildSpec = {Mod, + {Mod, start_link, []}, + temporary, + 1000, + worker, + [Mod]}, + {ok, {Flags, [ChildSpec]}}. diff --git a/lib/diameter/src/app/diameter_session.erl b/lib/diameter/src/app/diameter_session.erl new file mode 100644 index 0000000000..bb91e97f39 --- /dev/null +++ b/lib/diameter/src/app/diameter_session.erl @@ -0,0 +1,172 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_session). + +-export([sequence/0, + session_id/1, + origin_state_id/0]). + +%% towards diameter_sup +-export([init/0]). + +-include("diameter_types.hrl"). + +-define(INT64, 16#FFFFFFFFFFFFFFFF). +-define(INT32, 16#FFFFFFFF). + +%% --------------------------------------------------------------------------- +%% # sequence/0 +%% +%% Output: 32-bit +%% --------------------------------------------------------------------------- + +%% 3588, 3: +%% +%% Hop-by-Hop Identifier +%% The Hop-by-Hop Identifier is an unsigned 32-bit integer field (in +%% network byte order) and aids in matching requests and replies. +%% The sender MUST ensure that the Hop-by-Hop identifier in a request +%% is unique on a given connection at any given time, and MAY attempt +%% to ensure that the number is unique across reboots. The sender of +%% an Answer message MUST ensure that the Hop-by-Hop Identifier field +%% contains the same value that was found in the corresponding +%% request. The Hop-by-Hop identifier is normally a monotonically +%% increasing number, whose start value was randomly generated. An +%% answer message that is received with an unknown Hop-by-Hop +%% Identifier MUST be discarded. +%% +%% End-to-End Identifier +%% The End-to-End Identifier is an unsigned 32-bit integer field (in +%% network byte order) and is used to detect duplicate messages. +%% Upon reboot implementations MAY set the high order 12 bits to +%% contain the low order 12 bits of current time, and the low order +%% 20 bits to a random value. Senders of request messages MUST +%% insert a unique identifier on each message. The identifier MUST +%% remain locally unique for a period of at least 4 minutes, even +%% across reboots. The originator of an Answer message MUST ensure +%% that the End-to-End Identifier field contains the same value that +%% was found in the corresponding request. The End-to-End Identifier +%% MUST NOT be modified by Diameter agents of any kind. The +%% combination of the Origin-Host (see Section 6.3) and this field is +%% used to detect duplicates. Duplicate requests SHOULD cause the +%% same answer to be transmitted (modulo the hop-by-hop Identifier +%% field and any routing AVPs that may be present), and MUST NOT +%% affect any state that was set when the original request was +%% processed. Duplicate answer messages that are to be locally +%% consumed (see Section 6.2) SHOULD be silently discarded. + +-spec sequence() + -> 'Unsigned32'(). + +sequence() -> + Instr = {_Pos = 2, _Incr = 1, _Threshold = ?INT32, _SetVal = 0}, + ets:update_counter(diameter_sequence, sequence, Instr). + +%% --------------------------------------------------------------------------- +%% # origin_state_id/0 +%% --------------------------------------------------------------------------- + +%% 3588, 8.16: +%% +%% The Origin-State-Id AVP (AVP Code 278), of type Unsigned32, is a +%% monotonically increasing value that is advanced whenever a Diameter +%% entity restarts with loss of previous state, for example upon reboot. +%% Origin-State-Id MAY be included in any Diameter message, including +%% CER. +%% +%% A Diameter entity issuing this AVP MUST create a higher value for +%% this AVP each time its state is reset. A Diameter entity MAY set +%% Origin-State-Id to the time of startup, or it MAY use an incrementing +%% counter retained in non-volatile memory across restarts. + +-spec origin_state_id() + -> 'Unsigned32'(). + +origin_state_id() -> + ets:lookup_element(diameter_sequence, origin_state_id, 2). + +%% --------------------------------------------------------------------------- +%% # session_id/1 +%% --------------------------------------------------------------------------- + +%% 3588, 8.8: +%% +%% The Session-Id MUST begin with the sender's identity encoded in the +%% DiameterIdentity type (see Section 4.4). The remainder of the +%% Session-Id is delimited by a ";" character, and MAY be any sequence +%% that the client can guarantee to be eternally unique; however, the +%% following format is recommended, (square brackets [] indicate an +%% optional element): +%% +%% <DiameterIdentity>;<high 32 bits>;<low 32 bits>[;<optional value>] +%% +%% <high 32 bits> and <low 32 bits> are decimal representations of the +%% high and low 32 bits of a monotonically increasing 64-bit value. The +%% 64-bit value is rendered in two part to simplify formatting by 32-bit +%% processors. At startup, the high 32 bits of the 64-bit value MAY be +%% initialized to the time, and the low 32 bits MAY be initialized to +%% zero. This will for practical purposes eliminate the possibility of +%% overlapping Session-Ids after a reboot, assuming the reboot process +%% takes longer than a second. Alternatively, an implementation MAY +%% keep track of the increasing value in non-volatile memory. +%% +%% <optional value> is implementation specific but may include a modem's +%% device Id, a layer 2 address, timestamp, etc. + +-spec session_id('DiameterIdentity'()) + -> 'OctetString'(). +%% Note that Session-Id has type UTF8String and that any OctetString +%% is a UTF8String. + +session_id(Host) -> + Instr = {_Pos = 2, _Incr = 1, _Threshold = ?INT64, _Set = 0}, + N = ets:update_counter(diameter_sequence, session_base, Instr), + Hi = N bsr 32, + Lo = N band ?INT32, + [Host, ";", integer_to_list(Hi), + ";", integer_to_list(Lo), + ";", atom_to_list(node())]. + +%% --------------------------------------------------------------------------- +%% # init/0 +%% --------------------------------------------------------------------------- + +init() -> + Now = now(), + random:seed(Now), + Time = time32(Now), + Seq = (?INT32 band (Time bsl 20)) bor (random:uniform(1 bsl 20) - 1), + ets:insert(diameter_sequence, [{origin_state_id, Time}, + {session_base, Time bsl 32}, + {sequence, Seq}]), + Time. + +%% --------------------------------------------------------- +%% INTERNAL FUNCTIONS +%% --------------------------------------------------------- + +%% The minimum value represented by a Time value. (See diameter_types.) +%% 32 bits extends to 2104. +-define(TIME0, 62105714048). %% {{1968,1,20},{3,14,8}} + +time32(Now) -> + Time = calendar:now_to_universal_time(Now), + Diff = calendar:datetime_to_gregorian_seconds(Time) - ?TIME0, + Diff band ?INT32. diff --git a/lib/diameter/src/app/diameter_stats.erl b/lib/diameter/src/app/diameter_stats.erl new file mode 100644 index 0000000000..b52d4cdcfb --- /dev/null +++ b/lib/diameter/src/app/diameter_stats.erl @@ -0,0 +1,347 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Statistics collector. +%% + +-module(diameter_stats). +-compile({no_auto_import, [monitor/2]}). + +-behaviour(gen_server). + +-export([reg/1, reg/2, + incr/1, incr/2, incr/3, + read/1, + flush/0, flush/1]). + +%% supervisor callback +-export([start_link/0]). + +%% gen_server callbacks +-export([init/1, + terminate/2, + handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3]). + +%% debug +-export([state/0, + uptime/0]). + +-include("diameter_internal.hrl"). + +%% ets table containing stats. reg(Pid, Ref) inserts a {Pid, Ref}, +%% incr(Counter, X, N) updates the counter keyed at {Counter, X}, and +%% Pid death causes counters keyed on {Counter, Pid} to be deleted and +%% added to those keyed on {Counter, Ref}. +-define(TABLE, ?MODULE). + +%% Name of registered server. +-define(SERVER, ?MODULE). + +%% Entries in the table. +-define(REC(Key, Value), {Key, Value}). + +%% Server state. +-record(state, {id = now()}). + +-type counter() :: any(). +-type contrib() :: any(). + +%%% --------------------------------------------------------------------------- +%%% # reg(Pid, Contrib) +%%% +%%% Description: Register a process as a contributor of statistics +%%% associated with a specified term. Statistics can be +%%% contributed by specifying either Pid or Contrib as +%%% the second argument to incr/3. Statistics contributed +%%% by Pid are folded into the corresponding entry for +%%% Contrib when the process dies. +%%% +%%% Contrib can be any term but should not be a pid +%%% passed as the first argument to reg/2. Subsequent +%%% registrations for the same Pid overwrite the association +%%% --------------------------------------------------------------------------- + +-spec reg(pid(), contrib()) + -> true. + +reg(Pid, Contrib) + when is_pid(Pid) -> + call({reg, Pid, Contrib}). + +-spec reg(contrib()) + -> true. + +reg(Ref) -> + reg(self(), Ref). + +%%% --------------------------------------------------------------------------- +%%% # incr(Counter, Contrib, N) +%%% +%%% Description: Increment a counter for the specified contributor. +%%% +%%% Contrib will typically be an argument passed to reg/2 +%%% but there's nothing that requires this. In particular, +%%% if Contrib is a pid that hasn't been registered then +%%% counters are unaffected by the death of the process. +%%% --------------------------------------------------------------------------- + +-spec incr(counter(), contrib(), integer()) + -> integer(). + +incr(Ctr, Contrib, N) -> + update_counter({Ctr, Contrib}, N). + +incr(Ctr, N) + when is_integer(N) -> + incr(Ctr, self(), N); + +incr(Ctr, Contrib) -> + incr(Ctr, Contrib, 1). + +incr(Ctr) -> + incr(Ctr, self(), 1). + +%%% --------------------------------------------------------------------------- +%%% # read(Contribs) +%%% +%%% Description: Retrieve counters for the specified contributors. +%%% --------------------------------------------------------------------------- + +-spec read([contrib()]) + -> [{contrib(), [{counter(), integer()}]}]. + +read(Contribs) -> + lists:foldl(fun(?REC({T,C}, N), D) -> orddict:append(C, {T,N}, D) end, + orddict:new(), + ets:select(?TABLE, [{?REC({'_', '$1'}, '_'), + [?ORCOND([{'=:=', '$1', {const, C}} + || C <- Contribs])], + ['$_']}])). + +%%% --------------------------------------------------------------------------- +%%% # flush(Contrib) +%%% +%%% Description: Retrieve and delete statistics for the specified +%%% contributor. +%%% +%%% If Contrib is a pid registered with reg/2 then statistics +%%% for both and its associated contributor are retrieved. +%%% --------------------------------------------------------------------------- + +-spec flush(contrib()) + -> [{counter(), integer()}]. + +flush(Contrib) -> + try + call({flush, Contrib}) + catch + exit: _ -> + [] + end. + +flush() -> + flush(self()). + +%%% --------------------------------------------------------- +%%% EXPORTED INTERNAL FUNCTIONS +%%% --------------------------------------------------------- + +start_link() -> + ServerName = {local, ?SERVER}, + Module = ?MODULE, + Args = [], + Options = [{spawn_opt, diameter_lib:spawn_opts(server, [])}], + gen_server:start_link(ServerName, Module, Args, Options). + +state() -> + call(state). + +uptime() -> + call(uptime). + +%%% ---------------------------------------------------------- +%%% # init(_) +%%% +%%% Output: {ok, State} +%%% ---------------------------------------------------------- + +init([]) -> + ets:new(?TABLE, [named_table, ordered_set, public]), + {ok, #state{}}. + +%% ---------------------------------------------------------- +%% handle_call(Request, From, State) +%% ---------------------------------------------------------- + +handle_call(state, _, State) -> + {reply, State, State}; + +handle_call(uptime, _, #state{id = Time} = State) -> + {reply, diameter_lib:now_diff(Time), State}; + +handle_call({reg, Pid, Contrib}, _From, State) -> + monitor(not ets:member(?TABLE, Pid), Pid), + {reply, insert(?REC(Pid, Contrib)), State}; + +handle_call({flush, Contrib}, _From, State) -> + {reply, fetch(Contrib), State}; + +handle_call(Req, From, State) -> + warning_msg("received unexpected request from ~p:~n~w", [From, Req]), + {reply, nok, State}. + +%% ---------------------------------------------------------- +%% handle_cast(Request, State) +%% ---------------------------------------------------------- + +handle_cast({incr, Rec}, State) -> + update_counter(Rec), + {noreply, State}; + +handle_cast(Msg, State) -> + warning_msg("received unexpected message:~n~w", [Msg]), + {noreply, State}. + +%% ---------------------------------------------------------- +%% handle_info(Request, State) +%% ---------------------------------------------------------- + +handle_info({'DOWN', _MRef, process, Pid, _}, State) -> + down(Pid), + {noreply, State}; + +handle_info(Info, State) -> + warning_msg("received unknown info:~n~w", [Info]), + {noreply, State}. + +%% ---------------------------------------------------------- +%% terminate(Reason, State) +%% ---------------------------------------------------------- + +terminate(_Reason, _State) -> + ok. + +%% ---------------------------------------------------------- +%% code_change(OldVsn, State, Extra) +%% ---------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%% --------------------------------------------------------- +%%% INTERNAL FUNCTIONS +%%% --------------------------------------------------------- + +%% monitor/2 + +monitor(true, Pid) -> + erlang:monitor(process, Pid); +monitor(false = No, _) -> + No. + +%% down/1 + +down(Pid) -> + L = ets:match_object(?TABLE, ?REC({'_', Pid}, '_')), + [?REC(_, Ref) = T] = lookup(Pid), + fold(Ref, L), + delete_object(T), + delete(L). + +%% Fold Pid-based entries into Ref-based ones. +fold(Ref, L) -> + lists:foreach(fun(?REC({K, _}, V)) -> update_counter({{K, Ref}, V}) end, + L). + +delete(Objs) -> + lists:foreach(fun delete_object/1, Objs). + +%% fetch/1 + +fetch(X) -> + MatchSpec = [{?REC({'_', '$1'}, '_'), + [?ORCOND([{'==', '$1', {const, T}} || T <- [X | ref(X)]])], + ['$_']}], + L = ets:select(?TABLE, MatchSpec), + delete(L), + D = lists:foldl(fun sum/2, dict:new(), L), + dict:to_list(D). + +sum({{Ctr, _}, N}, Dict) -> + dict:update(Ctr, fun(V) -> V+N end, N, Dict). + +ref(Pid) + when is_pid(Pid) -> + ets:select(?TABLE, [{?REC(Pid, '$1'), [], ['$1']}]); +ref(_) -> + []. + +%% update_counter/2 +%% +%% From an arbitrary request process. Cast to the server process to +%% insert a new element if the counter doesn't exists so that two +%% processes don't do so simultaneously. + +update_counter(Key, N) -> + try + ets:update_counter(?TABLE, Key, N) + catch + error: badarg -> + cast({incr, ?REC(Key, N)}) + end. + +%% update_counter/1 +%% +%% From the server process. + +update_counter(?REC(Key, N) = T) -> + try + ets:update_counter(?TABLE, Key, N) + catch + error: badarg -> + insert(T) + end. + +insert(T) -> + ets:insert(?TABLE, T). + +lookup(Key) -> + ets:lookup(?TABLE, Key). + +delete_object(T) -> + ets:delete_object(?TABLE, T). + +%% cast/1 + +cast(Msg) -> + gen_server:cast(?SERVER, Msg). + +%% call/1 + +call(Request) -> + gen_server:call(?SERVER, Request, infinity). + +%% warning_msg/2 + +warning_msg(F, A) -> + ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_sup.erl b/lib/diameter/src/app/diameter_sup.erl new file mode 100644 index 0000000000..e5afd23dcd --- /dev/null +++ b/lib/diameter/src/app/diameter_sup.erl @@ -0,0 +1,101 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% The top supervisor for the diameter application. +%% + +-module(diameter_sup). + +-behaviour(supervisor). + +%% interface +-export([start_link/0, %% supervisor start + tree/0]). %% supervision tree + +%% supervisor callback +-export([init/1]). + +-define(CHILDREN, [diameter_misc_sup, + diameter_watchdog_sup, + diameter_peer_fsm_sup, + diameter_transport_sup, + diameter_service_sup]). + +-define(TABLES, [{diameter_sequence, [set]}, + {diameter_service, [set, {keypos, 3}]}, + {diameter_request, [bag]}, + {diameter_config, [bag, {keypos, 2}]}]). + +%% start_link/0 + +start_link() -> + SupName = {local, ?MODULE}, + supervisor:start_link(SupName, ?MODULE, []). + +%% init/1 + +init([]) -> + ets_new(?TABLES), + diameter_session:init(), + Flags = {one_for_one, 1, 5}, + ChildSpecs = lists:map(fun spec/1, ?CHILDREN), + {ok, {Flags, ChildSpecs}}. + +%% spec/1 + +spec(Mod) -> + {Mod, + {Mod, start_link, []}, + permanent, + 1000, + supervisor, + [Mod]}. + +%% ets_new/1 + +ets_new(List) + when is_list(List) -> + lists:foreach(fun ets_new/1, List); + +ets_new({Table, Opts}) -> + ets:new(Table, [named_table, public | Opts]). + +%% tree/0 + +tree() -> + [{?MODULE, whereis(?MODULE), tree(?MODULE)}]. + +tree(Sup) -> + lists:map(fun t/1, supervisor:which_children(Sup)). + +t({Name, Pid, supervisor, _}) -> + t(Name, Pid, tree(Pid)); +t({Name, Pid, worker, _}) -> + t(Name, Pid). + +t(undefined, Pid, Children) -> + {Pid, Children}; +t(Name, Pid, Children) -> + {Name, Pid, Children}. + +t(undefined, Pid) -> + Pid; +t(Name, Pid) -> + {Name, Pid}. diff --git a/lib/diameter/src/app/diameter_sync.erl b/lib/diameter/src/app/diameter_sync.erl new file mode 100644 index 0000000000..f7777ae809 --- /dev/null +++ b/lib/diameter/src/app/diameter_sync.erl @@ -0,0 +1,555 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This module implements a server that serializes requests in named +%% queues. A request is an MFA or fun and a name can be any term. A +%% request is applied in a dedicated process that terminates when +%% the request function returns. +%% + +-module(diameter_sync). +-behaviour(gen_server). + +-export([call/4, call/5, + cast/4, cast/5, + carp/1, carp/2]). + +%% supervisor callback +-export([start_link/0]). + +%% gen_server interface +-export([init/1, + terminate/2, + handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3]). + +%% test/debug +-export([state/0, + uptime/0, + flush/1, + pending/0, + pending/1, + queues/0, + pids/1]). + +-include("diameter_internal.hrl"). + +%% Locally registered server name. +-define(SERVER, ?MODULE). + +%% Message to the server to queue a request ... +-define(REQUEST(CallOrCast, Name, Req, Max, Timeout), + {request, CallOrCast, Name, Req, Max, Timeout}). + +%% ... and to retrieve the pid of the prevailing request process. +-define(CARP(Name), + {carp, Name}). + +%% Forever ... +-define(TIMEOUT, 30000). + +%% Server state. +-record(state, + {time = now(), + pending = 0 :: non_neg_integer(), %% outstanding requests + monitor = new() :: ets:tid(), %% MonitorRef -> {Name, From} + queue = new() :: ets:tid()}). %% Name -> queue of {Pid, Ref} + +%% ---------------------------------------------------------- +%% # call(Node, Name, Req, Max, Timeout) +%% # call(Name, Req, Max, Timeout) +%% +%% Input: Name = term() identifying the queue in which the request is +%% to be evaluated. +%% Req = {M,F,A} +%% | {Fun, Arg} +%% | [Fun | Args] +%% | Fun +%% Max = Upper bound for the number of outstanding requests +%% in the named queue for Req to be queued. +%% If more than this number are in the queue then +%% 'rejected' is returned to the caller. Can be any +%% term but integer() | infinity is sufficient. +%% Timeout = 32 bit integer() number of milliseconds after which +%% request is cancelled (if not already started), causing +%% 'timeout' to be returned to the caller. +%% | infinity +%% +%% Output: Req() | rejected | timeout +%% +%% Description: Serialize a request in a named queue. Note that if +%% 'timeout' is returned and the request itself does not +%% return this atom then request has not been evaluated. +%% ---------------------------------------------------------- + +call(Name, Req, Max, Timeout) -> + call(node(), Name, Req, Max, Timeout). + +call(Node, Name, Req, Max, Timeout) -> + gen_call({?SERVER, Node}, ?REQUEST(call, Name, Req, Max, Timeout)). + +%%% ---------------------------------------------------------- +%%% # cast(Node, Name, Req, Max, Timeout) +%%% # cast(Name, Req, Max, Timeout) +%%% +%%% Output: ok | rejected | timeout +%%% +%%% Description: Serialize a request without returning the result to the +%%% caller. Returns after the task is queued. +%%% ---------------------------------------------------------- + +cast(Name, Req, Max, Timeout) -> + cast(node(), Name, Req, Max, Timeout). + +cast(Node, Name, Req, Max, Timeout) -> + gen_call({?SERVER, Node}, ?REQUEST(cast, Name, Req, Max, Timeout)). + +%% 'timeout' is only return if the server process that processes +%% requests isn't alive. Ditto for call/carp. + +%%% ---------------------------------------------------------- +%%% # carp(Node, Name) +%%% # carp(Name) +%%% +%%% Output: {value, Pid} | false | timeout +%%% +%%% Description: Return the pid of the process processing the task +%%% at the head of the named queue. Note that the value +%%% returned by subsequent calls changes as tasks are +%%% completed, each task executing in a dedicated +%%% process. The exit value of this process will be +%%% {value, Req()} if the task returns. +%%% ---------------------------------------------------------- + +%% The intention of this is to let a process enqueue a task that waits +%% for a message before completing, the target pid being retrieved +%% with carp/[12]. + +carp(Name) -> + carp(node(), Name). + +carp(Node, Name) -> + gen_call({?SERVER, Node}, ?CARP(Name)). + +%%% --------------------------------------------------------- +%%% EXPORTED INTERNAL FUNCTIONS +%%% --------------------------------------------------------- + +state() -> + call(state). + +uptime() -> + call(uptime). + +flush(Name) -> + call({flush, Name}). + +pending() -> + call(pending). + +pending(Name) -> + call({pending, Name}). + +queues() -> + call(queues). + +pids(Name) -> + call({pids, Name}). + +%%% ---------------------------------------------------------- +%%% # start_link() +%%% ---------------------------------------------------------- + +start_link() -> + ServerName = {local, ?SERVER}, + Module = ?MODULE, + Args = [], + Options = [{spawn_opt, diameter_lib:spawn_opts(server, [])}], + gen_server:start_link(ServerName, Module, Args, Options). + +%%% ---------------------------------------------------------- +%%% # init(_) +%%% ---------------------------------------------------------- + +init(_) -> + {ok, #state{}}. + +%%% ---------------------------------------------------------- +%%% # handle_call(Request, From, State) +%%% ---------------------------------------------------------- + +%% Enqueue a new request. +handle_call(?REQUEST(Type, Name, Req, Max, Timeout), + From, + #state{queue = QD} = State) -> + T = find(Name, QD), + nq(queued(T) =< Max, T, {Type, From}, Name, Req, Timeout, State); + +handle_call(Request, _From, State) -> + {reply, call(Request, State), State}. + +%% call/2 + +call(?CARP(Name), #state{queue = QD}) -> + pcar(find(Name, QD)); + +call(state, State) -> + State; + +call(uptime, #state{time = T}) -> + diameter_lib:now_diff(T); + +call({flush, Name}, #state{queue = QD}) -> + cancel(find(Name, QD)); + +call(pending, #state{pending = N}) -> + N; + +call({pending, Name}, #state{queue = QD}) -> + queued(find(Name, QD)); + +call(queues, #state{queue = QD}) -> + fetch_keys(QD); + +call({pids, Name}, #state{queue = QD}) -> + plist(find(Name, QD)); + +call(Req, _State) -> %% ignore + warning_msg("received unexpected request:~n~w", [Req]), + nok. + +%%% ---------------------------------------------------------- +%%% handle_cast(Request, State) +%%% ---------------------------------------------------------- + +handle_cast(Msg, State) -> + warning_msg("received unexpected message:~n~w", [Msg]), + {noreply, State}. + +%%% ---------------------------------------------------------- +%%% handle_info(Request, State) +%%% ---------------------------------------------------------- + +handle_info(Request, State) -> + {noreply, info(Request, State)}. + +%% info/2 + +%% A request has completed execution or timed out. +info({'DOWN', MRef, process, Pid, Info}, + #state{pending = N, + monitor = MD, + queue = QD} + = State) -> + {Name, From} = fetch(MRef, MD), + reply(From, rc(Info)), + State#state{pending = N-1, + monitor = erase(MRef, MD), + queue = dq(fetch(Name, QD), Pid, Info, Name, QD)}; + +info(Info, State) -> + warning_msg("received unknown info:~n~w", [Info]), + State. + +reply({call, From}, T) -> + gen_server:reply(From, T); +reply(cast, _) -> + ok. + +rc({value, T}) -> + T; +rc(_) -> + timeout. + +%%% ---------------------------------------------------------- +%%% code_change(OldVsn, State, Extra) +%%% ---------------------------------------------------------- + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%% ---------------------------------------------------------- +%%% terminate(Reason, State) +%%% ---------------------------------------------------------- + +terminate(_Reason, _State)-> + ok. + +%%% --------------------------------------------------------- +%%% INTERNAL FUNCTIONS +%%% --------------------------------------------------------- + +%% queued/1 + +queued({ok, {N,_}}) -> + N; +queued(error) -> + 0. + +%% nq/7 + +%% Maximum number of pending requests exceeded ... +nq(false, _, _, _Name, _Req, _Timeout, State) -> + {reply, rejected, State}; + +%% ... or not. +nq(true, T, From, Name, Req, Timeout, #state{pending = N, + monitor = MD, + queue = QD} + = State) -> + Ref = make_ref(), + Pid = init(Ref, Req, timeout(Timeout, T)), + MRef = erlang:monitor(process, Pid), + {noreply, State#state{pending = N+1, + monitor = store(MRef, {Name, from(From)}, MD), + queue = store(Name, nq(T, {Pid, Ref}), QD)}}. + +from({call, _} = T) -> + T; +from({cast = T, From}) -> + gen_server:reply(From, ok), + T. + +%% nq/2 + +%% Other requests in the queue: append. +nq({ok, {N,Q}}, T) -> + {N+1, queue:in(T,Q)}; + +%% Queue is empty: start execution. +nq(error, T) -> + go(T), + {1, queue:from_list([T])}. + +%% Don't timeout if the request is evaluated immediately so as to +%% avoid a race between getting a 'go' and a 'timeout'. Queueing a +%% request in an empty queue always results in execution. +timeout(_, error) -> + infinity; +timeout(Timeout, _) -> + Timeout. + +%% dq/5 +%% +%% A request process has terminated. + +dq({N,Q}, Pid, _Info, Name, QD) -> + {{value, T}, TQ} = queue:out(Q), + dq(N-1, Pid, T, TQ, Name, QD). + +%% dq/6 + +%% Request was at the head of the queue: start another. +dq(N, Pid, {Pid, _}, TQ, Name, QD) -> + dq(N, TQ, Name, QD); + +%% Or not: remove the offender from the queue. +dq(N, Pid, T, TQ, Name, QD) -> + store(Name, {N, req(Pid, queue:from_list([T]), TQ)}, QD). + +%% dq/4 + +%% Queue is empty: erase. +dq(0, TQ, Name, QD) -> + true = queue:is_empty(TQ), %% assert + erase(Name, QD); + +%% Start the next request. +dq(N, TQ, Name, QD) -> + go(queue:head(TQ)), + store(Name, {N, TQ}, QD). + +%% req/3 +%% +%% Find and remove the queue element for the specified pid. + +req(Pid, HQ, Q) -> + {{value, T}, TQ} = queue:out(Q), + req(Pid, T, HQ, TQ). + +req(Pid, {Pid, _}, HQ, TQ) -> + queue:join(HQ, TQ); +req(Pid, T, HQ, TQ) -> + req(Pid, queue:in(T,HQ), TQ). + +%% go/1 + +go({Pid, Ref}) -> + Pid ! {Ref, ok}. + +%% init/4 +%% +%% Start the dedicated process for handling a request. The exit value +%% is as promised by carp/1. + +init(Ref, Req, Timeout) -> + spawn(fun() -> exit(i(Ref, Req, Timeout)) end). + +i(Ref, Req, Timeout) -> + Timer = send_timeout(Ref, Timeout), + MRef = erlang:monitor(process, ?SERVER), + receive + {Ref, ok} -> %% Do the deed. + %% Ensure we don't leave messages in the mailbox since the + %% request itself might receive. Alternatively, could have + %% done the eval in a new process but then we'd have to + %% relay messages arriving at this one. + cancel_timer(Timer), + erlang:demonitor(MRef, [flush]), + %% Ref is to ensure that we don't extract any message that + %% a client may have sent after retrieving self() with + %% carp/1, there being no guarantee that the message + %% banged by go/1 is received before the pid becomes + %% accessible. + {value, eval(Req)}; + {Ref, timeout = T} -> + T; + {'DOWN', MRef, process, _Pid, _Info} = D -> %% server death + D + end. + +send_timeout(_Ref, infinity = No) -> + No; +send_timeout(Ref, Ms) -> + Msg = {Ref, timeout}, + TRef = erlang:send_after(Ms, self(), Msg), + {TRef, Msg}. + +cancel_timer(infinity = No) -> + No; +cancel_timer({TRef, Msg}) -> + flush(Msg, erlang:cancel_timer(TRef)). + +flush(Msg, false) -> %% Message has already been sent ... + %% 'error' should never happen but crash if it does so as not to + %% hang the process. + ok = receive Msg -> ok after ?TIMEOUT -> error end; +flush(_, _) -> %% ... or not. + ok. + +eval({M,F,A}) -> + apply(M,F,A); +eval([Fun | Args]) -> + apply(Fun, Args); +eval({Fun, A}) -> + Fun(A); +eval(Fun) -> + Fun(). + +%% pcar/1 + +pcar({ok, {_,Q}}) -> + {Pid, _Ref} = queue:head(Q), + {value, Pid}; +pcar(error) -> + false. + +%% plist/1 + +plist({ok, {_,Q}}) -> + lists:map(fun({Pid, _Ref}) -> Pid end, queue:to_list(Q)); +plist(error) -> + []. + +%% cancel/1 +%% +%% Cancel all but the active request from the named queue. Return the +%% number of requests cancelled. + +%% Just send timeout messages to each request to make them die. Note +%% that these are guaranteed to arrive before a go message after the +%% current request completes since both messages are sent from the +%% server process. +cancel({ok, {N,Q}}) -> + {_,TQ} = queue:split(1,Q), + foreach(fun({Pid, Ref}) -> Pid ! {Ref, timeout} end, N-1, TQ), + N-1; +cancel(error) -> + 0. + +%% foreach/3 + +foreach(_, 0, _) -> + ok; +foreach(Fun, N, Q) -> + Fun(queue:head(Q)), + foreach(Fun, N-1, queue:tail(Q)). + +%% call/1 + +%% gen_server:call/3 will exit if the target process dies. +call(Request) -> + try + gen_server:call(?SERVER, Request, ?TIMEOUT) + catch + exit: Reason -> + {error, Reason} + end. + +%% dict-like table manipulation. + +erase(Key, Dict) -> + ets:delete(Dict, Key), + Dict. + +fetch(Key, Dict) -> + {ok, V} = find(Key, Dict), + V. + +fetch_keys(Dict) -> + ets:foldl(fun({K,_}, Acc) -> [K | Acc] end, [], Dict). + +find(Key, Dict) -> + case ets:lookup(Dict, Key) of + [{Key, V}] -> + {ok, V}; + [] -> + error + end. + +new() -> + ets:new(?MODULE, [set]). + +store(Key, Value, Dict) -> + store({Key, Value}, Dict). + +store({_,_} = T, Dict) -> + ets:insert(Dict, T), + Dict. + +%% gen_call/1 + +gen_call(Server, Req) -> + gen_call(Server, Req, infinity). + +gen_call(Server, Req, Timeout) -> + try + gen_server:call(Server, Req, Timeout) + catch + exit: _ -> + timeout + end. + +%% warning_msg/2 + +warning_msg(F, A) -> + ?diameter_warning("~p: " ++ F, [?MODULE | A]). diff --git a/lib/diameter/src/app/diameter_types.erl b/lib/diameter/src/app/diameter_types.erl new file mode 100644 index 0000000000..6b1b1b8d39 --- /dev/null +++ b/lib/diameter/src/app/diameter_types.erl @@ -0,0 +1,537 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_types). + +%% +%% Encode/decode of RFC 3588 Data Formats, Basic (section 4.2) and +%% Derived (section 4.3). +%% + +%% Basic types. +-export(['OctetString'/2, + 'Integer32'/2, + 'Integer64'/2, + 'Unsigned32'/2, + 'Unsigned64'/2, + 'Float32'/2, + 'Float64'/2]). + +%% Derived types. +-export(['Address'/2, + 'Time'/2, + 'UTF8String'/2, + 'DiameterIdentity'/2, + 'DiameterURI'/2, + 'IPFilterRule'/2, + 'QoSFilterRule'/2]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). + +-define(UINT(N,X), ((0 =< X) andalso (X < 1 bsl N))). +-define(SINT(N,X), ((-1*(1 bsl (N-1)) < X) andalso (X < 1 bsl (N-1)))). + +%% The Grouped and Enumerated types are dealt with directly in +%% generated decode modules by way of diameter_gen.hrl and +%% diameter_codec.erl. Padding and the setting of Length and other +%% fields are also dealt with there. + +%% 3588: +%% +%% DIAMETER_INVALID_AVP_LENGTH 5014 +%% The request contained an AVP with an invalid length. A Diameter +%% message indicating this error MUST include the offending AVPs +%% within a Failed-AVP AVP. +%% +-define(INVALID_LENGTH(Bin), erlang:error({'DIAMETER', 5014, Bin})). + +%% ------------------------------------------------------------------------- +%% 3588, 4.2. Basic AVP Data Formats +%% +%% The Data field is zero or more octets and contains information +%% specific to the Attribute. The format and length of the Data field +%% is determined by the AVP Code and AVP Length fields. The format of +%% the Data field MUST be one of the following base data types or a data +%% type derived from the base data types. In the event that a new Basic +%% AVP Data Format is needed, a new version of this RFC must be created. +%% -------------------- + +'OctetString'(decode, Bin) + when is_binary(Bin) -> + binary_to_list(Bin); + +'OctetString'(encode = M, zero) -> + 'OctetString'(M, []); + +'OctetString'(encode, Str) -> + iolist_to_binary(Str). + +%% -------------------- + +'Integer32'(decode, <<X:32/signed>>) -> + X; + +'Integer32'(decode, B) -> + ?INVALID_LENGTH(B); + +'Integer32'(encode = M, zero) -> + 'Integer32'(M, 0); + +'Integer32'(encode, I) + when ?SINT(32,I) -> + <<I:32/signed>>. + +%% -------------------- + +'Integer64'(decode, <<X:64/signed>>) -> + X; + +'Integer64'(decode, B) -> + ?INVALID_LENGTH(B); + +'Integer64'(encode = M, zero) -> + 'Integer64'(M, 0); + +'Integer64'(encode, I) + when ?SINT(64,I) -> + <<I:64/signed>>. + +%% -------------------- + +'Unsigned32'(decode, <<X:32>>) -> + X; + +'Unsigned32'(decode, B) -> + ?INVALID_LENGTH(B); + +'Unsigned32'(encode = M, zero) -> + 'Unsigned32'(M, 0); + +'Unsigned32'(encode, I) + when ?UINT(32,I) -> + <<I:32>>. + +%% -------------------- + +'Unsigned64'(decode, <<X:64>>) -> + X; + +'Unsigned64'(decode, B) -> + ?INVALID_LENGTH(B); + +'Unsigned64'(encode = M, zero) -> + 'Unsigned64'(M, 0); + +'Unsigned64'(encode, I) + when ?UINT(64,I) -> + <<I:64>>. + +%% -------------------- + +%% Decent summaries of the IEEE floating point formats can be +%% found at http://en.wikipedia.org/wiki/IEEE_754-1985 and +%% http://www.psc.edu/general/software/packages/ieee/ieee.php. +%% +%% That the bit syntax uses these formats isn't well documented but +%% this does indeed appear to be the case. However, the bit syntax +%% only encodes numeric values, not the standard's (signed) infinity +%% or NaN. It also encodes any large value as 'infinity', never 'NaN'. +%% Treat these equivalently on decode for this reason. +%% +%% An alternative would be to decode infinity/NaN to the largest +%% possible float but could likely lead to misleading results if +%% arithmetic is performed on the decoded value. Better to be explicit +%% that precision has been lost. + +'Float32'(decode, <<S:1, 255:8, _:23>>) -> + choose(S, infinity, '-infinity'); + +'Float32'(decode, <<X:32/float>>) -> + X; + +'Float32'(decode, B) -> + ?INVALID_LENGTH(B); + +'Float32'(encode = M, zero) -> + 'Float32'(M, 0.0); + +'Float32'(encode, infinity) -> + <<0:1, 255:8, 0:23>>; + +'Float32'(encode, '-infinity') -> + <<1:1, 255:8, 0:23>>; + +'Float32'(encode, X) + when is_float(X) -> + <<X:32/float>>. +%% Note that this could also encode infinity/-infinity for large +%% (signed) numeric values. Note also that precision is lost just in +%% using the floating point syntax. For example: +%% +%% 1> B = <<3.14159:32/float>>. +%% <<64,73,15,208>> +%% 2> <<F:32/float>> = B. +%% <<64,73,15,208>> +%% 3> F. +%% 3.141590118408203 +%% +%% (The 64 bit type does better.) + +%% -------------------- + +%% The 64 bit format is entirely analogous to the 32 bit format. + +'Float64'(decode, <<S:1, 2047:11, _:52>>) -> + choose(S, infinity, '-infinity'); + +'Float64'(decode, <<X:64/float>>) -> + X; + +'Float64'(decode, B) -> + ?INVALID_LENGTH(B); + +'Float64'(encode, infinity) -> + <<0:1, 2047:11, 0:52>>; + +'Float64'(encode, '-infinity') -> + <<1:1, 2047:11, 0:52>>; + +'Float64'(encode = M, zero) -> + 'Float64'(M, 0.0); + +'Float64'(encode, X) + when is_float(X) -> + <<X:64/float>>. + +%% ------------------------------------------------------------------------- +%% 3588, 4.3. Derived AVP Data Formats +%% +%% In addition to using the Basic AVP Data Formats, applications may +%% define data formats derived from the Basic AVP Data Formats. An +%% application that defines new AVP Derived Data Formats MUST include +%% them in a section entitled "AVP Derived Data Formats", using the same +%% format as the definitions below. Each new definition must be either +%% defined or listed with a reference to the RFC that defines the +%% format. +%% -------------------- + +'Address'(encode, zero) -> + <<0:48>>; + +'Address'(decode, <<1:16, B/binary>>) + when size(B) == 4 -> + list_to_tuple(binary_to_list(B)); + +'Address'(decode, <<2:16, B/binary>>) + when size(B) == 16 -> + list_to_tuple(v6dec(B, [])); + +'Address'(decode, <<A:16, _/binary>> = B) + when 1 == A; + 2 == A -> + ?INVALID_LENGTH(B); + +'Address'(encode, T) -> + ipenc(diameter_lib:ipaddr(T)). + +ipenc(T) + when is_tuple(T), size(T) == 4 -> + B = list_to_binary(tuple_to_list(T)), + <<1:16, B/binary>>; + +ipenc(T) + when is_tuple(T), size(T) == 8 -> + B = v6enc(lists:reverse(tuple_to_list(T)), <<>>), + <<2:16, B/binary>>. + +v6dec(<<N:16, B/binary>>, Acc) -> + v6dec(B, [N | Acc]); + +v6dec(<<>>, Acc) -> + lists:reverse(Acc). + +v6enc([N | Rest], B) + when ?UINT(16,N) -> + v6enc(Rest, <<N:16, B/binary>>); + +v6enc([], B) -> + B. + +%% -------------------- + +%% A DiameterIdentity is a FQDN as definined in RFC 1035, which is at +%% least one character. + +'DiameterIdentity'(encode = M, zero) -> + 'OctetString'(M, [0]); + +'DiameterIdentity'(encode = M, X) -> + <<_,_/binary>> = 'OctetString'(M, X); + +'DiameterIdentity'(decode = M, <<_,_/binary>> = X) -> + 'OctetString'(M, X). + +%% -------------------- + +'DiameterURI'(decode, Bin) + when is_binary(Bin) -> + scan_uri(Bin); + +%% The minimal DiameterURI is "aaa://x", 7 characters. +'DiameterURI'(encode = M, zero) -> + 'OctetString'(M, lists:duplicate(0,7)); + +'DiameterURI'(encode, #diameter_uri{type = Type, + fqdn = D, + port = P, + transport = T, + protocol = Prot} + = U) -> + S = lists:append([atom_to_list(Type), "://", D, + ":", integer_to_list(P), + ";transport=", atom_to_list(T), + ";protocol=", atom_to_list(Prot)]), + U = scan_uri(S), %% assert + list_to_binary(S); + +'DiameterURI'(encode, Str) -> + Bin = iolist_to_binary(Str), + #diameter_uri{} = scan_uri(Bin), %% type check + Bin. + +%% -------------------- + +%% This minimal rule is "deny in 0 from 0.0.0.0 to 0.0.0.0", 33 characters. +'IPFilterRule'(encode = M, zero) -> + 'OctetString'(M, lists:duplicate(0,33)); + +%% TODO: parse grammar. +'IPFilterRule'(M, X) -> + 'OctetString'(M, X). + +%% -------------------- + +%% This minimal rule is the same as for an IPFilterRule. +'QoSFilterRule'(encode = M, zero = X) -> + 'IPFilterRule'(M, X); + +%% TODO: parse grammar. +'QoSFilterRule'(M, X) -> + 'OctetString'(M, X). + +%% -------------------- + +'UTF8String'(decode, Bin) -> + udec(Bin, []); + +'UTF8String'(encode = M, zero) -> + 'UTF8String'(M, []); + +'UTF8String'(encode, S) -> + uenc(S, []). + +udec(<<>>, Acc) -> + lists:reverse(Acc); + +udec(<<C/utf8, Rest/binary>>, Acc) -> + udec(Rest, [C | Acc]). + +uenc(E, Acc) + when E == []; + E == <<>> -> + list_to_binary(lists:reverse(Acc)); + +uenc(<<C/utf8, Rest/binary>>, Acc) -> + uenc(Rest, [<<C/utf8>> | Acc]); + +uenc([[] | Rest], Acc) -> + uenc(Rest, Acc); + +uenc([[H|T] | Rest], Acc) -> + uenc([H, T | Rest], Acc); + +uenc([C | Rest], Acc) -> + uenc(Rest, [<<C/utf8>> | Acc]). + +%% -------------------- + +%% RFC 3588, 4.3: +%% +%% Time +%% The Time format is derived from the OctetString AVP Base Format. +%% The string MUST contain four octets, in the same format as the +%% first four bytes are in the NTP timestamp format. The NTP +%% Timestamp format is defined in chapter 3 of [SNTP]. +%% +%% This represents the number of seconds since 0h on 1 January 1900 +%% with respect to the Coordinated Universal Time (UTC). +%% +%% On 6h 28m 16s UTC, 7 February 2036 the time value will overflow. +%% SNTP [SNTP] describes a procedure to extend the time to 2104. +%% This procedure MUST be supported by all DIAMETER nodes. + +%% RFC 2030, 3: +%% +%% As the NTP timestamp format has been in use for the last 17 years, +%% it remains a possibility that it will be in use 40 years from now +%% when the seconds field overflows. As it is probably inappropriate +%% to archive NTP timestamps before bit 0 was set in 1968, a +%% convenient way to extend the useful life of NTP timestamps is the +%% following convention: If bit 0 is set, the UTC time is in the +%% range 1968-2036 and UTC time is reckoned from 0h 0m 0s UTC on 1 +%% January 1900. If bit 0 is not set, the time is in the range 2036- +%% 2104 and UTC time is reckoned from 6h 28m 16s UTC on 7 February +%% 2036. Note that when calculating the correspondence, 2000 is not a +%% leap year. Note also that leap seconds are not counted in the +%% reckoning. +%% +%% The statement regarding year 2000 is wrong: errata id 518 at +%% http://www.rfc-editor.org/errata_search.php?rfc=2030 notes this. + +-define(TIME_1900, 59958230400). %% {{1900,1,1},{0,0,0}} +-define(TIME_2036, 64253197696). %% {{2036,2,7},{6,28,16}} +%% TIME_2036 = TIME_1900 + (1 bsl 32) + +%% Time maps [0, 1 bsl 31) onto [TIME_1900 + 1 bsl 31, TIME_2036 + 1 bsl 31) +%% by taking integers with the high-order bit set relative to TIME_1900 +%% and those without relative to TIME_2036. This corresponds to the +%% following dates. +-define(TIME_MIN, {{1968,1,20},{3,14,8}}). %% TIME_1900 + 1 bsl 31 +-define(TIME_MAX, {{2104,2,26},{9,42,24}}). %% TIME_2036 + 1 bsl 31 + +'Time'(decode, <<Time:32>>) -> + Offset = msb(1 == Time bsr 31), + calendar:gregorian_seconds_to_datetime(Time + Offset); + +'Time'(decode, B) -> + ?INVALID_LENGTH(B); + +'Time'(encode, {{_Y,_M,_D},{_HH,_MM,_SS}} = Datetime) + when ?TIME_MIN =< Datetime, Datetime < ?TIME_MAX -> + S = calendar:datetime_to_gregorian_seconds(Datetime), + T = S - msb(S < ?TIME_2036), + 0 = T bsr 32, %% sanity check + <<T:32>>; + +'Time'(encode, zero) -> + <<0:32>>. + +%% =========================================================================== +%% =========================================================================== + +choose(0, X, _) -> X; +choose(1, _, X) -> X. + +msb(true) -> ?TIME_1900; +msb(false) -> ?TIME_2036. + +%% RFC 3588, 4.3: +%% +%% The DiameterURI MUST follow the Uniform Resource Identifiers (URI) +%% syntax [URI] rules specified below: +%% +%% "aaa://" FQDN [ port ] [ transport ] [ protocol ] +%% +%% ; No transport security +%% +%% "aaas://" FQDN [ port ] [ transport ] [ protocol ] +%% +%% ; Transport security used +%% +%% FQDN = Fully Qualified Host Name +%% +%% port = ":" 1*DIGIT +%% +%% ; One of the ports used to listen for +%% ; incoming connections. +%% ; If absent, +%% ; the default Diameter port (3868) is +%% ; assumed. +%% +%% transport = ";transport=" transport-protocol +%% +%% ; One of the transports used to listen +%% ; for incoming connections. If absent, +%% ; the default SCTP [SCTP] protocol is +%% ; assumed. UDP MUST NOT be used when +%% ; the aaa-protocol field is set to +%% ; diameter. +%% +%% transport-protocol = ( "tcp" / "sctp" / "udp" ) +%% +%% protocol = ";protocol=" aaa-protocol +%% +%% ; If absent, the default AAA protocol +%% ; is diameter. +%% +%% aaa-protocol = ( "diameter" / "radius" / "tacacs+" ) + +scan_uri(Bin) + when is_binary(Bin) -> + scan_uri(binary_to_list(Bin)); +scan_uri("aaa://" ++ Rest) -> + scan_fqdn(Rest, #diameter_uri{type = aaa}); +scan_uri("aaas://" ++ Rest) -> + scan_fqdn(Rest, #diameter_uri{type = aaas}). + +scan_fqdn(S, U) -> + {[_|_] = F, Rest} = lists:splitwith(fun is_fqdn/1, S), + scan_opt_port(Rest, U#diameter_uri{fqdn = F}). + +scan_opt_port(":" ++ S, U) -> + {[_|_] = P, Rest} = lists:splitwith(fun is_digit/1, S), + scan_opt_transport(Rest, U#diameter_uri{port = list_to_integer(P)}); +scan_opt_port(S, U) -> + scan_opt_transport(S, U). + +scan_opt_transport(";transport=" ++ S, U) -> + {P, Rest} = transport(S), + scan_opt_protocol(Rest, U#diameter_uri{transport = P}); +scan_opt_transport(S, U) -> + scan_opt_protocol(S, U). + +scan_opt_protocol(";protocol=" ++ S, U) -> + {P, ""} = protocol(S), + U#diameter_uri{protocol = P}; +scan_opt_protocol("", U) -> + U. + +transport("tcp" ++ S) -> + {tcp, S}; +transport("sctp" ++ S) -> + {sctp, S}; +transport("udp" ++ S) -> + {udp, S}. + +protocol("diameter" ++ S) -> + {diameter, S}; +protocol("radius" ++ S) -> + {radius, S}; +protocol("tacacs+" ++ S) -> + {'tacacs+', S}. + +is_fqdn(C) -> + is_digit(C) orelse is_alpha(C) orelse C == $. orelse C == $-. + +is_alpha(C) -> + ($a =< C andalso C =< $z) orelse ($A =< C andalso C =< $Z). + +is_digit(C) -> + $0 =< C andalso C =< $9. diff --git a/lib/diameter/src/app/diameter_types.hrl b/lib/diameter/src/app/diameter_types.hrl new file mode 100644 index 0000000000..02bf8a74dd --- /dev/null +++ b/lib/diameter/src/app/diameter_types.hrl @@ -0,0 +1,139 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Types for function specifications, primarily in diameter.erl. This +%% has nothing specifically to do with diameter_types.erl. +%% + +-type evaluable() + :: {module(), atom(), list()} + | fun() + | nonempty_improper_list(evaluable(), list()). %% [evaluable() | Args] + +-type app_alias() + :: any(). + +-type service_name() + :: any(). + +%% Diameter basic types + +-type 'OctetString'() :: iolist(). +-type 'Integer32'() :: -2147483647..2147483647. +-type 'Integer64'() :: -9223372036854775807..9223372036854775807. +-type 'Unsigned32'() :: 0..4294967295. +-type 'Unsigned64'() :: 0..18446744073709551615. +-type 'Float32'() :: '-infinity' | float() | infinity. +-type 'Float64'() :: '-infinity' | float() | infinity. +-type 'Grouped'() :: list() | tuple(). + +%% Diameter derived types + +-type 'Address'() + :: inet:ip_address() + | string(). + +-type 'Time'() :: {{integer(), 1..12, 1..31}, + {0..23, 0..59, 0..59}}. +-type 'UTF8String'() :: iolist(). +-type 'DiameterIdentity'() :: 'OctetString'(). +-type 'DiameterURI'() :: 'OctetString'(). +-type 'Enumerated'() :: 'Integer32'(). +-type 'IPFilterRule'() :: 'OctetString'(). +-type 'QoSFilterRule'() :: 'OctetString'(). + +%% Capabilities options/avps on start_service/2 and/or add_transport/2 + +-type capability() + :: {'Origin-Host', 'DiameterIdentity'()} + | {'Origin-Realm', 'DiameterIdentity'()} + | {'Host-IP-Address', ['Address'()]} + | {'Vendor-Id', 'Unsigned32'()} + | {'Product-Name', 'UTF8String'()} + | {'Supported-Vendor-Id', ['Unsigned32'()]} + | {'Auth-Application-Id', ['Unsigned32'()]} + | {'Vendor-Specific-Application-Id', ['Grouped'()]} + | {'Firmware-Revision', 'Unsigned32'()}. + +%% Filters for call/4 + +-type peer_filter() + :: none + | host + | realm + | {host, any|'DiameterIdentity'()} + | {realm, any|'DiameterIdentity'()} + | {eval, evaluable()} + | {neg, peer_filter()} + | {all, [peer_filter()]} + | {any, [peer_filter()]}. + +%% Options passed to start_service/2 + +-type service_opt() + :: capability() + | {application, [application_opt()]}. + +-type application_opt() + :: {alias, app_alias()} + | {dictionary, module()} + | {module, app_module()} + | {state, any()} + | {call_mutates_state, boolean()} + | {answer_errors, callback|report|discard}. + +-type app_module() + :: module() + | nonempty_improper_list(module(), list()). %% list with module() head + +%% Identifier returned by add_transport/2 + +-type transport_ref() + :: reference(). + +%% Options passed to add_transport/2 + +-type transport_opt() + :: {transport_module, atom()} + | {transport_config, any()} + | {applications, [app_alias()]} + | {capabilities, [capability()]} + | {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}} + | {reconnect_timer, 'Unsigned32'()} + | {private, any()}. + +%% Predicate passed to remove_transport/2 + +-type transport_pred() + :: fun((reference(), connect|listen, list()) -> boolean()) + | fun((reference(), list()) -> boolean()) + | fun((list()) -> boolean()) + | reference() + | list() + | {connect|listen, transport_pred()} + | {atom(), atom(), list()}. + +%% Options passed to call/4 + +-type call_opt() + :: {extra, list()} + | {filter, peer_filter()} + | {timeout, 'Unsigned32'()} + | detach. diff --git a/lib/diameter/src/app/diameter_watchdog.erl b/lib/diameter/src/app/diameter_watchdog.erl new file mode 100644 index 0000000000..b7c1491f4b --- /dev/null +++ b/lib/diameter/src/app/diameter_watchdog.erl @@ -0,0 +1,571 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This module implements (as a process) the state machine documented +%% in Appendix A of RFC 3539. +%% + +-module(diameter_watchdog). +-behaviour(gen_server). + +%% towards diameter_service +-export([start/2]). + +%% gen_server callbacks +-export([init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + terminate/2, + code_change/3]). + +%% diameter_watchdog_sup callback +-export([start_link/1]). + +-include_lib("diameter/include/diameter.hrl"). +-include("diameter_internal.hrl"). + +-define(DEFAULT_TW_INIT, 30000). %% RFC 3539 ch 3.4.1 + +-record(watchdog, + {%% PCB - Peer Control Block; see RFC 3539, Appendix A + status = initial :: initial | okay | suspect | down | reopen, + pending = false :: boolean(), + tw :: 6000..16#FFFFFFFF | {module(), atom(), list()}, + %% {M,F,A} -> integer() >= 0 + num_dwa = 0 :: -1 | non_neg_integer(), + %% number of DWAs received during reopen + %% end PCB + parent = self() :: pid(), + transport :: pid(), + tref :: reference(), %% reference for current watchdog timer + message_data}). %% term passed into diameter_service with message + +%% start/2 + +start({_,_} = Type, T) -> + {ok, Pid} = diameter_watchdog_sup:start_child({Type, self(), T}), + Pid. + +start_link(T) -> + {ok, _} = proc_lib:start_link(?MODULE, + init, + [T], + infinity, + diameter_lib:spawn_opts(server, [])). + +%% =========================================================================== +%% =========================================================================== + +%% init/1 + +init(T) -> + proc_lib:init_ack({ok, self()}), + gen_server:enter_loop(?MODULE, [], i(T)). + +i({T, Pid, {ConnT, Opts, SvcName, #diameter_service{applications = Apps, + capabilities = Caps} + = Svc}}) -> + {M,S,U} = now(), + random:seed(M,S,U), + putr(restart, {T, Opts, Svc}), %% save seeing it in trace + putr(dwr, dwr(Caps)), %% + #watchdog{parent = monitor(Pid), + transport = monitor(diameter_peer_fsm:start(T, Opts, Svc)), + tw = proplists:get_value(watchdog_timer, + Opts, + ?DEFAULT_TW_INIT), + message_data = {ConnT, SvcName, Apps}}. + +%% handle_call/3 + +handle_call(_, _, State) -> + {reply, nok, State}. + +%% handle_cast/2 + +handle_cast(_, State) -> + {noreply, State}. + +%% handle_info/2 + +handle_info(T, State) -> + case transition(T, State) of + ok -> + {noreply, State}; + #watchdog{status = X} = S -> + ?LOGC(X =/= State#watchdog.status, transition, X), + {noreply, S}; + stop -> + ?LOG(stop, T), + {stop, {shutdown, T}, State} + end. + +%% terminate/2 + +terminate(_, _) -> + ok. + +%% code_change/3 + +code_change(_, State, _) -> + {ok, State}. + +%% =========================================================================== +%% =========================================================================== + +%% transition/2 +%% +%% The state transitions documented here are extracted from RFC 3539, +%% the commentary is ours. + +%% Service or watchdog is telling the watchdog of an accepting +%% transport to die after reconnect_timer expiry or reestablished +%% connection (in another transport process) respectively. +transition(close, #watchdog{status = down}) -> + {{accept, _}, _, _} = getr(restart), %% assert + stop; +transition(close, #watchdog{}) -> + ok; + +%% Service is asking for the peer to be taken down gracefully. +transition({shutdown, Pid}, #watchdog{parent = Pid, + transport = undefined, + status = S}) -> + down = S, %% sanity check + stop; +transition({shutdown = T, Pid}, #watchdog{parent = Pid, + transport = TPid}) -> + TPid ! {T, self()}, + ok; + +%% Parent process has died, +transition({'DOWN', _, process, Pid, _Reason}, + #watchdog{parent = Pid}) -> + stop; + +%% Transport has accepted a connection. +transition({accepted = T, TPid}, #watchdog{transport = TPid, + parent = Pid}) -> + Pid ! {T, self(), TPid}, + ok; + +%% Transport is telling us that its impending death isn't failure. +transition({close, TPid, _Reason}, #watchdog{transport = TPid}) -> + stop; + +%% STATE Event Actions New State +%% ===== ------ ------- ---------- +%% INITIAL Connection up SetWatchdog() OKAY + +%% By construction, the watchdog timer isn't set until we move into +%% state okay as the result of the Peer State Machine reaching the +%% Open state. +%% +%% If we're an acceptor then we may be resuming a connection that went +%% down in another acceptor process, in which case this is the +%% transition below, from down into reopen. That is, it's not until +%% we know the identity of the peer (ie. now) that we know that we're +%% in state down rather than initial. + +transition({open, TPid, Hosts, T} = Open, + #watchdog{transport = TPid, + status = initial, + parent = Pid} + = S) -> + case okay(getr(restart), Hosts) of + okay -> + open(Pid, {TPid, T}), + set_watchdog(S#watchdog{status = okay}); + reopen -> + transition(Open, S#watchdog{status = down}) + end; + +%% DOWN Connection up NumDWA = 0 +%% SendWatchdog() +%% SetWatchdog() +%% Pending = TRUE REOPEN + +transition({open = P, TPid, _Hosts, T}, + #watchdog{transport = TPid, + status = down} + = S) -> + %% Store the info we need to notify the parent to reopen the + %% connection after the requisite DWA's are received, at which + %% time we eraser(open). + putr(P, {TPid, T}), + set_watchdog(send_watchdog(S#watchdog{status = reopen, + num_dwa = 0})); + +%% OKAY Connection down CloseConnection() +%% Failover() +%% SetWatchdog() DOWN +%% SUSPECT Connection down CloseConnection() +%% SetWatchdog() DOWN +%% REOPEN Connection down CloseConnection() +%% SetWatchdog() DOWN + +transition({'DOWN', _, process, TPid, _}, + #watchdog{transport = TPid, + status = initial}) -> + stop; + +transition({'DOWN', _, process, Pid, _}, + #watchdog{transport = Pid} + = S) -> + failover(S), + close(S), + set_watchdog(S#watchdog{status = down, + pending = false, + transport = undefined}); +%% Any outstanding pending (or other messages from the transport) will +%% have arrived before 'DOWN' since the message comes from the same +%% process. Note that we could also get this message in the initial +%% state. + +%% Incoming message. +transition({recv, TPid, Name, Pkt}, #watchdog{transport = TPid} = S) -> + recv(Name, Pkt, S); + +%% Current watchdog has timed out. +transition({timeout, TRef, tw}, #watchdog{tref = TRef} = S) -> + set_watchdog(timeout(S)); + +%% Timer was canceled after message was already sent. +transition({timeout, _, tw}, #watchdog{}) -> + ok; + +%% State query. +transition({state, Pid}, #watchdog{status = S}) -> + Pid ! {self(), S}, + ok. + +%% =========================================================================== + +monitor(Pid) -> + erlang:monitor(process, Pid), + Pid. + +putr(Key, Val) -> + put({?MODULE, Key}, Val). + +getr(Key) -> + get({?MODULE, Key}). + +eraser(Key) -> + erase({?MODULE, Key}). + +%% encode/1 + +encode(Msg) -> + #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg), + Bin. + +%% okay/2 + +okay({{accept, Ref}, _, _}, Hosts) -> + T = {?MODULE, connection, Ref, Hosts}, + diameter_reg:add(T), + okay(diameter_reg:match(T)); +%% Register before matching so that at least one of two registering +%% processes will match the other. (Which can't happen as long as +%% diameter_peer_fsm guarantees at most one open connection to the same +%% peer.) + +okay({{connect, _}, _, _}, _) -> + okay. + +%% The peer hasn't been connected recently ... +okay([{_,P}]) -> + P = self(), %% assert + okay; + +%% ... or it has. +okay(C) -> + [_|_] = [P ! close || {_,P} <- C, self() /= P], + reopen. + +%% set_watchdog/1 + +set_watchdog(#watchdog{tw = TwInit, + tref = TRef} + = S) -> + cancel(TRef), + S#watchdog{tref = erlang:start_timer(tw(TwInit), self(), tw)}. + +cancel(undefined) -> + ok; +cancel(TRef) -> + erlang:cancel_timer(TRef). + +tw(T) + when is_integer(T), T >= 6000 -> + T - 2000 + (random:uniform(4001) - 1); %% RFC3539 jitter of +/- 2 sec. +tw({M,F,A}) -> + apply(M,F,A). + +%% open/2 + +open(Pid, {_,_} = T) -> + Pid ! {connection_up, self(), T}. + +%% failover/1 + +failover(#watchdog{status = okay, + parent = Pid}) -> + Pid ! {connection_down, self()}; + +failover(_) -> + ok. + +%% close/1 + +close(#watchdog{status = down}) -> + ok; + +close(#watchdog{parent = Pid}) -> + {{T, _}, _, _} = getr(restart), + T == accept andalso (Pid ! {close, self()}). + +%% send_watchdog/1 + +send_watchdog(#watchdog{pending = false, + transport = TPid} + = S) -> + TPid ! {send, encode(getr(dwr))}, + ?LOG(send, 'DWR'), + S#watchdog{pending = true}. + +%% recv/3 + +recv(Name, Pkt, S) -> + try rcv(Name, S) of + #watchdog{} = NS -> + rcv(Name, Pkt, S), + NS + catch + throw: {?MODULE, throwaway, #watchdog{} = NS} -> + NS + end. + +%% rcv/3 + +rcv(N, _, _) + when N == 'CER'; + N == 'CEA'; + N == 'DWR'; + N == 'DWA'; + N == 'DPR'; + N == 'DPA' -> + false; + +rcv(_, Pkt, #watchdog{transport = TPid, + message_data = T}) -> + diameter_service:receive_message(TPid, Pkt, T). + +throwaway(S) -> + throw({?MODULE, throwaway, S}). + +%% rcv/2 + +%% INITIAL Receive DWA Pending = FALSE +%% Throwaway() INITIAL +%% INITIAL Receive non-DWA Throwaway() INITIAL + +rcv('DWA', #watchdog{status = initial} = S) -> + throwaway(S#watchdog{pending = false}); + +rcv(_, #watchdog{status = initial} = S) -> + throwaway(S); + +%% DOWN Receive DWA Pending = FALSE +%% Throwaway() DOWN +%% DOWN Receive non-DWA Throwaway() DOWN + +rcv('DWA', #watchdog{status = down} = S) -> + throwaway(S#watchdog{pending = false}); + +rcv(_, #watchdog{status = down} = S) -> + throwaway(S); + +%% OKAY Receive DWA Pending = FALSE +%% SetWatchdog() OKAY +%% OKAY Receive non-DWA SetWatchdog() OKAY + +rcv('DWA', #watchdog{status = okay} = S) -> + set_watchdog(S#watchdog{pending = false}); + +rcv(_, #watchdog{status = okay} = S) -> + set_watchdog(S); + +%% SUSPECT Receive DWA Pending = FALSE +%% Failback() +%% SetWatchdog() OKAY +%% SUSPECT Receive non-DWA Failback() +%% SetWatchdog() OKAY + +rcv('DWA', #watchdog{status = suspect} = S) -> + failback(S), + set_watchdog(S#watchdog{status = okay, + pending = false}); + +rcv(_, #watchdog{status = suspect} = S) -> + failback(S), + set_watchdog(S#watchdog{status = okay}); + +%% REOPEN Receive DWA & Pending = FALSE +%% NumDWA == 2 NumDWA++ +%% Failback() OKAY + +rcv('DWA', #watchdog{status = reopen, + num_dwa = 2 = N, + parent = Pid} + = S) -> + open(Pid, eraser(open)), + S#watchdog{status = okay, + num_dwa = N+1, + pending = false}; + +%% REOPEN Receive DWA & Pending = FALSE +%% NumDWA < 2 NumDWA++ REOPEN + +rcv('DWA', #watchdog{status = reopen, + num_dwa = N} + = S) -> + S#watchdog{num_dwa = N+1, + pending = false}; + +%% REOPEN Receive non-DWA Throwaway() REOPEN + +rcv(_, #watchdog{status = reopen} = S) -> + throwaway(S). + +%% failback/1 + +failback(#watchdog{parent = Pid}) -> + Pid ! {connection_up, self()}. + +%% timeout/1 +%% +%% The caller sets the watchdog on the return value. + +%% OKAY Timer expires & SendWatchdog() +%% !Pending SetWatchdog() +%% Pending = TRUE OKAY +%% REOPEN Timer expires & SendWatchdog() +%% !Pending SetWatchdog() +%% Pending = TRUE REOPEN + +timeout(#watchdog{status = T, + pending = false} + = S) + when T == okay; + T == reopen -> + send_watchdog(S); + +%% OKAY Timer expires & Failover() +%% Pending SetWatchdog() SUSPECT + +timeout(#watchdog{status = okay, + pending = true} + = S) -> + failover(S), + S#watchdog{status = suspect}; + +%% SUSPECT Timer expires CloseConnection() +%% SetWatchdog() DOWN +%% REOPEN Timer expires & CloseConnection() +%% Pending & SetWatchdog() +%% NumDWA < 0 DOWN + +timeout(#watchdog{status = T, + pending = P, + num_dwa = N, + transport = TPid} + = S) + when T == suspect; + T == reopen, P, N < 0 -> + exit(TPid, shutdown), + close(S), + S#watchdog{status = down}; + +%% REOPEN Timer expires & NumDWA = -1 +%% Pending & SetWatchdog() +%% NumDWA >= 0 REOPEN + +timeout(#watchdog{status = reopen, + pending = true, + num_dwa = N} + = S) + when 0 =< N -> + S#watchdog{num_dwa = -1}; + +%% DOWN Timer expires AttemptOpen() +%% SetWatchdog() DOWN +%% INITIAL Timer expires AttemptOpen() +%% SetWatchdog() INITIAL + +%% RFC 3539, 3.4.1: +%% +%% [5] While the connection is in the closed state, the AAA client MUST +%% NOT attempt to send further watchdog messages on the connection. +%% However, after the connection is closed, the AAA client continues +%% to periodically attempt to reopen the connection. +%% +%% The AAA client SHOULD wait for the transport layer to report +%% connection failure before attempting again, but MAY choose to +%% bound this wait time by the watchdog interval, Tw. + +%% Don't bound, restarting the peer process only when the previous +%% process has died. We only need to handle state down since we start +%% the first watchdog when transitioning out of initial. + +timeout(#watchdog{status = down} = S) -> + restart(S). + +%% restart/1 + +restart(#watchdog{transport = undefined} = S) -> + restart(getr(restart), S); +restart(S) -> + S. + +%% Only restart the transport in the connecting case. For an accepting +%% transport, we've registered the peer connection when leaving state +%% initial and this is used by a new accepting process to realize that +%% it's actually in state down rather then initial when receiving +%% notification of an open connection. + +restart({{connect, _} = T, Opts, Svc}, #watchdog{parent = Pid} = S) -> + Pid ! {reconnect, self()}, + S#watchdog{transport = monitor(diameter_peer_fsm:start(T, Opts, Svc))}; +restart({{accept, _}, _, _}, S) -> + S. +%% Don't currently use Opts/Svc in the accept case but having them in +%% the process dictionary is helpful if the process dies unexpectedly. + +%% dwr/1 + +dwr(#diameter_caps{origin_host = OH, + origin_realm = OR, + origin_state_id = OSI}) -> + ['DWR', {'Origin-Host', OH}, + {'Origin-Realm', OR}, + {'Origin-State-Id', OSI}]. diff --git a/lib/diameter/src/app/diameter_watchdog_sup.erl b/lib/diameter/src/app/diameter_watchdog_sup.erl new file mode 100644 index 0000000000..fc837fe4ef --- /dev/null +++ b/lib/diameter/src/app/diameter_watchdog_sup.erl @@ -0,0 +1,60 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Supervisor for all watchdog processes. +%% + +-module(diameter_watchdog_sup). + +-behaviour(supervisor). + +%% interface +-export([start_link/0, %% supervisor start + start_child/1]). %% watchdog start + +-export([init/1]). + +-define(NAME, ?MODULE). %% supervisor name + +%% start_link/0 + +start_link() -> + SupName = {local, ?NAME}, + supervisor:start_link(SupName, ?MODULE, []). + +%% start_child/1 +%% +%% Start a watchdog process. + +start_child(T) -> + supervisor:start_child(?NAME, [T]). + +%% init/1 + +init([]) -> + Mod = diameter_watchdog, + Flags = {simple_one_for_one, 0, 1}, + ChildSpec = {Mod, + {Mod, start_link, []}, + temporary, + 1000, + worker, + [Mod]}, + {ok, {Flags, [ChildSpec]}}. diff --git a/lib/diameter/src/app/modules.mk b/lib/diameter/src/app/modules.mk new file mode 100644 index 0000000000..a7a78b1a9d --- /dev/null +++ b/lib/diameter/src/app/modules.mk @@ -0,0 +1,68 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +SPEC_FILES = \ + diameter_gen_base_rfc3588.dia \ + diameter_gen_base_accounting.dia \ + diameter_gen_relay.dia + +MODULES = \ + diameter \ + diameter_app \ + diameter_callback \ + diameter_capx \ + diameter_config \ + diameter_dbg \ + diameter_codec \ + diameter_dict \ + diameter_exprecs \ + diameter_info \ + diameter_lib \ + diameter_misc_sup \ + diameter_peer \ + diameter_peer_fsm \ + diameter_peer_fsm_sup \ + diameter_reg \ + diameter_service \ + diameter_service_sup \ + diameter_session \ + diameter_stats \ + diameter_sup \ + diameter_sync \ + diameter_types \ + diameter_watchdog \ + diameter_watchdog_sup + +INTERNAL_HRL_FILES = \ + diameter_internal.hrl \ + diameter_types.hrl + +EXTERNAL_HRL_FILES = \ + ../../include/diameter.hrl \ + ../../include/diameter_gen.hrl + +EXAMPLE_FILES = \ + ../../examples/GNUmakefile \ + ../../examples/peer.erl \ + ../../examples/client.erl \ + ../../examples/client_cb.erl \ + ../../examples/server.erl \ + ../../examples/server_cb.erl \ + ../../examples/relay.erl \ + ../../examples/relay_cb.erl diff --git a/lib/diameter/src/compiler/.gitignore b/lib/diameter/src/compiler/.gitignore new file mode 100644 index 0000000000..d9f072e262 --- /dev/null +++ b/lib/diameter/src/compiler/.gitignore @@ -0,0 +1,3 @@ + +/depend.mk + diff --git a/lib/diameter/src/compiler/Makefile b/lib/diameter/src/compiler/Makefile new file mode 100644 index 0000000000..3ab76064ac --- /dev/null +++ b/lib/diameter/src/compiler/Makefile @@ -0,0 +1,141 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/target.mk +EBIN = ../../ebin +include $(ERL_TOP)/make/$(TARGET)/otp.mk +else +include $(DIAMETER_TOP)/make/target.mk +EBIN = ../../ebin +include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk +endif + + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk +VSN=$(DIAMETER_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- + +RELSYSDIR = $(RELEASE_PATH)/lib/diameter-$(VSN) + +INCDIR = ../../include + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +include modules.mk + +ERL_FILES = \ + $(MODULES:%=%.erl) + +TARGET_FILES = \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug +endif + +include ../app/diameter.mk + +ERL_COMPILE_FLAGS += \ + $(DIAMETER_ERL_COMPILE_FLAGS) \ + -I$(INCDIR) + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug: + @${MAKE} TYPE=debug opt + +opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + rm -f depend.mk + +docs: + +info: + @echo "" + @echo "ERL_FILES = $(ERL_FILES)" + @echo "HRL_FILES = $(HRL_FILES)" + @echo "" + @echo "TARGET_FILES = $(TARGET_FILES)" + @echo "" + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +# Invoked from ../app to add modules to the app file. +$(APP_TARGET): force + M=`echo $(MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \ + echo "/%COMPILER_MODULES%/s//$$M/;w;q" | tr ';' '\n' \ + | ed -s $@ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/otp_release_targets.mk +else +include $(DIAMETER_TOP)/make/release_targets.mk +endif + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/src/compiler + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/compiler + +release_docs_spec: + +force: + +# ---------------------------------------------------- +# Dependencies +# ---------------------------------------------------- + +depend: depend.mk + +# Generate dependencies makefile. +depend.mk: ../app/depend.sed $(ERL_FILES) Makefile + for f in $(MODULES); do \ + sed -f $< $$f.erl | sed "s@/@/$$f@"; \ + done \ + > $@ + +-include depend.mk + +.PHONY: clean debug depend docs force info opt release_docs_spec release_spec diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl new file mode 100644 index 0000000000..213ba0d22c --- /dev/null +++ b/lib/diameter/src/compiler/diameter_codegen.erl @@ -0,0 +1,788 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_codegen). + +%% +%% This module generates .erl and .hrl files for encode/decode +%% modules from the orddict parsed from a .dia (aka spec) file by +%% dis_spec_util. The generated code is very simple (one-liners), the +%% generated functions being called by code included from dis_gen.hrl +%% in order to encode/decode messages and AVPs. The orddict itself is +%% returned by dict/0 in the generated module and dis_spec_util calls +%% this function when importing spec files. (That is, beam has to be +%% compiled from an imported spec file before it can be imported.) +%% + +-export([from_spec/4]). + +%% Internal exports (for test). +-export([file/1, + file/2, + file/3]). + +-include_lib("diameter/src/app/diameter_internal.hrl"). +-include("diameter_forms.hrl"). + +%% Generated functions that could have no generated clauses will have +%% a trailing ?UNEXPECTED clause that should never execute. +-define(UNEXPECTED(N), {?clause, [?VAR('_') || _ <- lists:seq(1,N)], + [], + [?APPLY(erlang, + error, + [?TERM({unexpected, getr(module)})])]}). + + +from_spec(File, Spec, Opts, Mode) -> + Outdir = proplists:get_value(outdir, Opts, "."), + putr(verbose, lists:member(verbose, Opts)), + putr(debug, lists:member(debug, Opts)), + codegen(File, Spec, Outdir, Mode). + +%% Optional reports when running verbosely. +report(What, Data) -> + report(getr(verbose), What, Data), + Data. + +report(true, Tag, Data) -> + io:format(">>~n>> ~p ~p~n", [Tag, Data]); +report(false, _, _) -> + ok. + +putr(Key, Value) -> + put({?MODULE, Key}, Value). + +getr(Key) -> + get({?MODULE, Key}). + +%% =========================================================================== +%% =========================================================================== + +%% Generate from parsed spec in a file. + +file(F) -> + file(F, spec). + +file(F, Mode) -> + file(F, ".", Mode). + +file(F, Outdir, Mode) -> + {ok, [Spec]} = file:consult(F), + from_spec(F, Spec, Outdir, Mode). + +%% =========================================================================== +%% =========================================================================== + +choose(true, X, _) -> X; +choose(false, _, X) -> X. + +get_value(Key, Plist) -> + proplists:get_value(Key, Plist, []). + +write(Path, [C|_] = Spec) + when is_integer(C) -> + w(Path, Spec, "~s"); +write(Path, Spec) -> + w(Path, Spec, "~p."). + +w(Path, Spec, Fmt) -> + {ok, Fd} = file:open(Path, [write]), + io:fwrite(Fd, Fmt ++ "~n", [Spec]), + file:close(Fd). + +codegen(File, Spec, Outdir, Mode) -> + Mod = mod(File, orddict:find(name, Spec)), + Path = filename:join(Outdir, Mod), %% minus extension + gen(Mode, Spec, Mod, Path), + ok. + +mod(File, error) -> + filename:rootname(filename:basename(File)); +mod(_, {ok, Mod}) -> + atom_to_list(Mod). + +gen(spec, Spec, _Mod, Path) -> + write(Path ++ ".spec", Spec); + +gen(hrl, Spec, Mod, Path) -> + gen_hrl(Path ++ ".hrl", Mod, Spec); + +gen(erl = Mode, Spec, Mod, Path) + when is_list(Mod) -> + gen(Mode, Spec, list_to_atom(Mod), Path); + +gen(erl, Spec, Mod, Path) -> + putr(module, Mod), %% used by ?UNEXPECTED. + + Forms = [{?attribute, module, Mod}, + {?attribute, compile, [{parse_transform, diameter_exprecs}]}, + {?attribute, compile, [nowarn_unused_function]}, + {?attribute, export, [{name, 0}, + {id, 0}, + {vendor_id, 0}, + {vendor_name, 0}, + {decode_avps, 2}, %% in diameter_gen.hrl + {encode_avps, 2}, %% + {msg_name, 2}, + {msg_header, 1}, + {rec2msg, 1}, + {msg2rec, 1}, + {name2rec, 1}, + {avp_name, 2}, + {avp_arity, 2}, + {avp_header, 1}, + {avp, 3}, + {grouped_avp, 3}, + {enumerated_avp, 3}, + {empty_value, 1}, + {dict, 0}]}, + %% diameter.hrl is included for #diameter_avp + {?attribute, include_lib, "diameter/include/diameter.hrl"}, + {?attribute, include_lib, "diameter/include/diameter_gen.hrl"}, + f_name(Mod), + f_id(Spec), + f_vendor_id(Spec), + f_vendor_name(Spec), + f_msg_name(Spec), + f_msg_header(Spec), + f_rec2msg(Spec), + f_msg2rec(Spec), + f_name2rec(Spec), + f_avp_name(Spec), + f_avp_arity(Spec), + f_avp_header(Spec), + f_avp(Spec), + f_enumerated_avp(Spec), + f_empty_value(Spec), + f_dict(Spec), + {eof, ?LINE}], + + gen_erl(Path, insert_hrl_forms(Spec, Forms)). + +gen_erl(Path, Forms) -> + getr(debug) andalso write(Path ++ ".forms", Forms), + write(Path ++ ".erl", + header() ++ erl_prettypr:format(erl_syntax:form_list(Forms))). + +insert_hrl_forms(Spec, Forms) -> + {H,T} = lists:splitwith(fun is_header/1, Forms), + H ++ make_hrl_forms(Spec) ++ T. + +is_header({attribute, _, export, _}) -> + false; +is_header(_) -> + true. + +make_hrl_forms(Spec) -> + {_Prefix, MsgRecs, GrpRecs, ImportedGrpRecs} + = make_record_forms(Spec), + + RecordForms = MsgRecs ++ GrpRecs ++ lists:flatmap(fun({_,Fs}) -> Fs end, + ImportedGrpRecs), + + RecNames = lists:map(fun({attribute,_,record,{N,_}}) -> N end, + RecordForms), + + %% export_records is used by the diameter_exprecs parse transform. + [{?attribute, export_records, RecNames} | RecordForms]. + +make_record_forms(Spec) -> + Prefix = prefix(Spec), + + MsgRecs = a_record(Prefix, fun msg_proj/1, get_value(messages, Spec)), + GrpRecs = a_record(Prefix, fun grp_proj/1, get_value(grouped, Spec)), + + ImportedGrpRecs = [{M, a_record(Prefix, fun grp_proj/1, Gs)} + || {M,Gs} <- get_value(import_groups, Spec)], + + {Prefix, MsgRecs, GrpRecs, ImportedGrpRecs}. + +msg_proj({Name, _, _, _, Avps}) -> + {Name, Avps}. + +grp_proj({Name, _, _, Avps}) -> + {Name, Avps}. + +%% a_record/3 + +a_record(Prefix, ProjF, L) -> + lists:map(fun(T) -> a_record(ProjF(T), Prefix) end, L). + +a_record({Nm, Avps}, Prefix) -> + Name = list_to_atom(Prefix ++ atom_to_list(Nm)), + Fields = lists:map(fun field/1, Avps), + {?attribute, record, {Name, Fields}}. + +field(Avp) -> + {Name, Arity} = avp_info(Avp), + if 1 == Arity -> + {?record_field, ?ATOM(Name)}; + true -> + {?record_field, ?ATOM(Name), ?NIL} + end. + +%%% ------------------------------------------------------------------------ +%%% # name/0 +%%% ------------------------------------------------------------------------ + +f_name(Name) -> + {?function, name, 0, + [{?clause, [], [], [?ATOM(Name)]}]}. + +%%% ------------------------------------------------------------------------ +%%% # id/0 +%%% ------------------------------------------------------------------------ + +f_id(Spec) -> + Id = orddict:fetch(id, Spec), + {?function, id, 0, + [{?clause, [], [], [?INTEGER(Id)]}]}. + +%%% ------------------------------------------------------------------------ +%%% # vendor_id/0 +%%% ------------------------------------------------------------------------ + +f_vendor_id(Spec) -> + {Id, _} = orddict:fetch(vendor, Spec), + {?function, vendor_id, 0, + [{?clause, [], [], [?INTEGER(Id)]}]}. + +%%% ------------------------------------------------------------------------ +%%% # vendor_name/0 +%%% ------------------------------------------------------------------------ + +f_vendor_name(Spec) -> + {_, Name} = orddict:fetch(vendor, Spec), + {?function, vendor_name, 0, + [{?clause, [], [], [?ATOM(Name)]}]}. + +%%% ------------------------------------------------------------------------ +%%% # msg_name/1 +%%% ------------------------------------------------------------------------ + +f_msg_name(Spec) -> + {?function, msg_name, 2, msg_name(Spec)}. + +%% Return the empty name for any unknown command to which +%% DIAMETER_COMMAND_UNSUPPORTED should be replied. + +msg_name(Spec) -> + lists:flatmap(fun c_msg_name/1, + proplists:get_value(command_codes, Spec, [])) + ++ [{?clause, [?VAR('_'), ?VAR('_')], [], [?ATOM('')]}]. + +c_msg_name({Code, Req, Ans}) -> + [{?clause, [?INTEGER(Code), ?ATOM(true)], + [], + [?ATOM(mname(Req))]}, + {?clause, [?INTEGER(Code), ?ATOM(false)], + [], + [?ATOM(mname(Ans))]}]. + +mname({N, _Abbr}) -> + N; +mname(N) -> + N. + +%%% ------------------------------------------------------------------------ +%%% # msg2rec/1 +%%% ------------------------------------------------------------------------ + +f_msg2rec(Spec) -> + {?function, msg2rec, 1, msg2rec(Spec)}. + +msg2rec(Spec) -> + Pre = prefix(Spec), + Dict = dict:from_list(lists:flatmap(fun msgs/1, + get_value(command_codes, Spec))), + lists:flatmap(fun(T) -> msg2rec(T, Dict, Pre) end, + get_value(messages, Spec)) + ++ [?UNEXPECTED(1)]. + +msgs({_Code, Req, Ans}) -> + [{mname(Req), Req}, {mname(Ans), Ans}]. + +msg2rec({N,_,_,_,_}, Dict, Pre) -> + c_msg2rec(fetch_names(N, Dict), Pre). + +fetch_names(Name, Dict) -> + case dict:find(Name, Dict) of + {ok, N} -> + N; + error -> + Name + end. + +c_msg2rec({N,A}, Pre) -> + [c_name2rec(N, N, Pre), c_name2rec(A, N, Pre)]; +c_msg2rec(N, Pre) -> + [c_name2rec(N, N, Pre)]. + +%%% ------------------------------------------------------------------------ +%%% # rec2msg/1 +%%% ------------------------------------------------------------------------ + +f_rec2msg(Spec) -> + {?function, rec2msg, 1, rec2msg(Spec)}. + +rec2msg(Spec) -> + Pre = prefix(Spec), + lists:map(fun(T) -> c_rec2msg(T, Pre) end, get_value(messages, Spec)) + ++ [?UNEXPECTED(1)]. + +c_rec2msg({N,_,_,_,_}, Pre) -> + {?clause, [?ATOM(rec_name(N, Pre))], [], [?ATOM(N)]}. + +%%% ------------------------------------------------------------------------ +%%% # name2rec/1 +%%% ------------------------------------------------------------------------ + +f_name2rec(Spec) -> + {?function, name2rec, 1, name2rec(Spec)}. + +name2rec(Spec) -> + Pre = prefix(Spec), + Groups = get_value(grouped, Spec) + ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)), + lists:map(fun({N,_,_,_}) -> c_name2rec(N, N, Pre) end, Groups) + ++ [{?clause, [?VAR('T')], [], [?CALL(msg2rec, [?VAR('T')])]}]. + +c_name2rec(Name, Rname, Pre) -> + {?clause, [?ATOM(Name)], [], [?ATOM(rec_name(Rname, Pre))]}. + +avps({_Mod, Avps}) -> + Avps. + +%%% ------------------------------------------------------------------------ +%%% # avp_name/1 +%%% ------------------------------------------------------------------------ + +f_avp_name(Spec) -> + {?function, avp_name, 2, avp_name(Spec)}. + +%% 3588, 4.1: +%% +%% AVP Code +%% The AVP Code, combined with the Vendor-Id field, identifies the +%% attribute uniquely. AVP numbers 1 through 255 are reserved for +%% backward compatibility with RADIUS, without setting the Vendor-Id +%% field. AVP numbers 256 and above are used for Diameter, which are +%% allocated by IANA (see Section 11.1). + +avp_name(Spec) -> + Avps = get_value(avp_types, Spec) + ++ lists:flatmap(fun avps/1, get_value(import_avps, Spec)), + {Vid, _} = orddict:fetch(vendor, Spec), + Vs = lists:flatmap(fun({V,Ns}) -> [{N,V} || N <- Ns] end, + get_value(avp_vendor_id, Spec)), + + lists:map(fun(T) -> c_avp_name(T, Vid, Vs) end, Avps) + ++ [{?clause, [?VAR('_'), ?VAR('_')], [], [?ATOM('AVP')]}]. + +c_avp_name({Name, Code, Type, Flags, _Encr}, Vid, Vs) -> + c_avp_name({Name, Type}, + Code, + lists:member('V', Flags), + Vid, + proplists:get_value(Name, Vs)). + +c_avp_name(T, Code, false, _, undefined = U) -> + {?clause, [?INTEGER(Code), ?ATOM(U)], + [], + [?TERM(T)]}; + +c_avp_name(T, Code, true, Vid, V) + when is_integer(Vid) -> + {?clause, [?INTEGER(Code), ?INTEGER(choose(V == undefined, Vid, V))], + [], + [?TERM(T)]}. + +%%% ------------------------------------------------------------------------ +%%% # avp_arity/2 +%%% ------------------------------------------------------------------------ + +f_avp_arity(Spec) -> + {?function, avp_arity, 2, avp_arity(Spec)}. + +avp_arity(Spec) -> + Msgs = get_value(messages, Spec), + Groups = get_value(grouped, Spec) + ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)), + c_avp_arity(Msgs ++ Groups) + ++ [{?clause, [?VAR('_'), ?VAR('_')], [], [?INTEGER(0)]}]. + +c_avp_arity(L) + when is_list(L) -> + lists:flatmap(fun c_avp_arity/1, L); + +c_avp_arity({N,_,_,_,As}) -> + c_avp_arity(N,As); +c_avp_arity({N,_,_,As}) -> + c_avp_arity(N,As). + +c_avp_arity(Name, Avps) -> + lists:map(fun(A) -> c_arity(Name, A) end, Avps). + +c_arity(Name, Avp) -> + {AvpName, Arity} = avp_info(Avp), + {?clause, [?ATOM(Name), ?ATOM(AvpName)], [], [?TERM(Arity)]}. + +%%% ------------------------------------------------------------------------ +%%% # avp/3 +%%% ------------------------------------------------------------------------ + +f_avp(Spec) -> + {?function, avp, 3, avp(Spec) ++ [?UNEXPECTED(3)]}. + +avp(Spec) -> + Native = get_value(avp_types, Spec), + Custom = get_value(custom_types, Spec), + Imported = get_value(import_avps, Spec), + avp([{N,T} || {N,_,T,_,_} <- Native], Imported, Custom). + +avp(Native, Imported, Custom) -> + Dict = orddict:from_list(Native), + + report(native, Dict), + report(imported, Imported), + report(custom, Custom), + + CustomNames = lists:flatmap(fun({_,Ns}) -> Ns end, Custom), + + lists:map(fun c_base_avp/1, + lists:filter(fun({N,_}) -> + false == lists:member(N, CustomNames) + end, + Native)) + ++ lists:flatmap(fun c_imported_avp/1, Imported) + ++ lists:flatmap(fun(C) -> c_custom_avp(C, Dict) end, Custom). + +c_base_avp({AvpName, T}) -> + {?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)], + [], + [base_avp(AvpName, T)]}. + +base_avp(AvpName, 'Enumerated') -> + ?CALL(enumerated_avp, [?VAR('T'), ?ATOM(AvpName), ?VAR('Data')]); + +base_avp(AvpName, 'Grouped') -> + ?CALL(grouped_avp, [?VAR('T'), ?ATOM(AvpName), ?VAR('Data')]); + +base_avp(_, Type) -> + ?APPLY(diameter_types, Type, [?VAR('T'), ?VAR('Data')]). + +c_imported_avp({Mod, Avps}) -> + lists:map(fun(A) -> imported_avp(Mod, A) end, Avps). + +imported_avp(_Mod, {AvpName, _, 'Grouped' = T, _, _}) -> + c_base_avp({AvpName, T}); + +imported_avp(Mod, {AvpName, _, _, _, _}) -> + {?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)], + [], + [?APPLY(Mod, avp, [?VAR('T'), + ?VAR('Data'), + ?ATOM(AvpName)])]}. + +c_custom_avp({Mod, Avps}, Dict) -> + lists:map(fun(N) -> custom_avp(Mod, N, orddict:fetch(N, Dict)) end, Avps). + +custom_avp(Mod, AvpName, Type) -> + {?clause, [?VAR('T'), ?VAR('Data'), ?ATOM(AvpName)], + [], + [?APPLY(Mod, AvpName, [?VAR('T'), ?ATOM(Type), ?VAR('Data')])]}. + +%%% ------------------------------------------------------------------------ +%%% # enumerated_avp/3 +%%% ------------------------------------------------------------------------ + +f_enumerated_avp(Spec) -> + {?function, enumerated_avp, 3, enumerated_avp(Spec) ++ [?UNEXPECTED(3)]}. + +enumerated_avp(Spec) -> + lists:flatmap(fun c_enumerated_avp/1, get_value(enums, Spec)). + +c_enumerated_avp({AvpName, Values}) -> + lists:flatmap(fun(V) -> c_enumerated_avp(AvpName, V) end, Values). + +c_enumerated_avp(AvpName, {I,_}) -> + [{?clause, [?ATOM(decode), ?ATOM(AvpName), ?TERM(<<I:32/integer>>)], + [], + [?TERM(I)]}, + {?clause, [?ATOM(encode), ?ATOM(AvpName), ?INTEGER(I)], + [], + [?TERM(<<I:32/integer>>)]}]. + +%%% ------------------------------------------------------------------------ +%%% msg_header/1 +%%% ------------------------------------------------------------------------ + +f_msg_header(Spec) -> + {?function, msg_header, 1, msg_header(Spec) ++ [?UNEXPECTED(1)]}. + +msg_header(Spec) -> + ApplId = orddict:fetch(id, Spec), + + lists:map(fun({M,C,F,_,_}) -> c_msg_header(M, C, F, ApplId) end, + get_value(messages, Spec)). + +%% Note that any application id in the message header spec is ignored. + +c_msg_header(Name, Code, Flags, ApplId) -> + {?clause, [?ATOM(Name)], + [], + [?TERM({Code, encode_msg_flags(Flags), ApplId})]}. + +encode_msg_flags(Flags) -> + lists:foldl(fun emf/2, 0, Flags). + +emf('REQ', N) -> N bor 2#10000000; +emf('PXY', N) -> N bor 2#01000000; +emf('ERR', N) -> N bor 2#00100000. + +%%% ------------------------------------------------------------------------ +%%% # avp_header/1 +%%% ------------------------------------------------------------------------ + +f_avp_header(Spec) -> + {?function, avp_header, 1, avp_header(Spec) ++ [?UNEXPECTED(1)]}. + +avp_header(Spec) -> + Native = get_value(avp_types, Spec), + Imported = get_value(import_avps, Spec), + {Vid, _} = orddict:fetch(vendor, Spec), + Vs = lists:flatmap(fun({V,Ns}) -> [{N,V} || N <- Ns] end, + get_value(avp_vendor_id, Spec)), + + lists:flatmap(fun(A) -> c_avp_header({Vid, Vs}, A) end, + Native ++ Imported). + +c_avp_header({Vid, Vs}, {Name, Code, _Type, Flags, _Encr}) -> + [{?clause, [?ATOM(Name)], + [], + [?TERM({Code, encode_avp_flags(Flags), vid(Name, Flags, Vs, Vid)})]}]; + +c_avp_header({_, Vs}, {Mod, Avps}) -> + lists:map(fun(A) -> c_avp_header(Vs, Mod, A) end, Avps). + +c_avp_header(Vs, Mod, {Name, _, _, Flags, _}) -> + Apply = ?APPLY(Mod, avp_header, [?ATOM(Name)]), + {?clause, [?ATOM(Name)], + [], + [case proplists:get_value(Name, Vs) of + undefined -> + Apply; + Vid -> + true = lists:member('V', Flags), %% sanity check + ?CALL(setelement, [?INTEGER(3), Apply, ?INTEGER(Vid)]) + end]}. + +encode_avp_flags(Fs) -> + lists:foldl(fun eaf/2, 0, Fs). + +eaf('V', F) -> 2#10000000 bor F; +eaf('M', F) -> 2#01000000 bor F; +eaf('P', F) -> 2#00100000 bor F. + +vid(Name, Flags, Vs, Vid) -> + v(lists:member('V', Flags), Name, Vs, Vid). + +v(true, Name, Vs, Vid) -> + proplists:get_value(Name, Vs, Vid); +v(false, _, _, _) -> + undefined. + +%%% ------------------------------------------------------------------------ +%%% # empty_value/0 +%%% ------------------------------------------------------------------------ + +f_empty_value(Spec) -> + {?function, empty_value, 1, empty_value(Spec)}. + +empty_value(Spec) -> + Groups = get_value(grouped, Spec) + ++ lists:flatmap(fun avps/1, get_value(import_groups, Spec)), + Enums = get_value(enums, Spec) + ++ lists:flatmap(fun avps/1, get_value(import_enums, Spec)), + lists:map(fun c_empty_value/1, Groups ++ Enums) + ++ [{?clause, [?VAR('Name')], [], [?CALL(empty, [?VAR('Name')])]}]. + +c_empty_value({Name, _, _, _}) -> + {?clause, [?ATOM(Name)], + [], + [?CALL(empty_group, [?ATOM(Name)])]}; + +c_empty_value({Name, _}) -> + {?clause, [?ATOM(Name)], + [], + [?TERM(<<0:32/integer>>)]}. + +%%% ------------------------------------------------------------------------ +%%% # dict/0 +%%% ------------------------------------------------------------------------ + +f_dict(Spec) -> + {?function, dict, 0, + [{?clause, [], [], [?TERM(Spec)]}]}. + +%%% ------------------------------------------------------------------------ +%%% # gen_hrl/3 +%%% ------------------------------------------------------------------------ + +gen_hrl(Path, Mod, Spec) -> + {ok, Fd} = file:open(Path, [write]), + + {Prefix, MsgRecs, GrpRecs, ImportedGrpRecs} + = make_record_forms(Spec), + + file:write(Fd, hrl_header(Mod)), + + forms("Message records", Fd, MsgRecs), + forms("Grouped AVP records", Fd, GrpRecs), + + lists:foreach(fun({M,Fs}) -> + forms("Grouped AVP records from " ++ atom_to_list(M), + Fd, + Fs) + end, + ImportedGrpRecs), + + PREFIX = to_upper(Prefix), + + write("ENUM Macros", + Fd, + m_enums(PREFIX, false, get_value(enums, Spec))), + write("RESULT CODE Macros", + Fd, + m_enums(PREFIX, false, get_value(result_codes, Spec))), + + lists:foreach(fun({M,Es}) -> + write("ENUM Macros from " ++ atom_to_list(M), + Fd, + m_enums(PREFIX, true, Es)) + end, + get_value(import_enums, Spec)), + + file:close(Fd). + +forms(_, _, []) -> + ok; +forms(Banner, Fd, Forms) -> + write(Banner, Fd, prettypr(Forms)). + +write(_, _, []) -> + ok; +write(Banner, Fd, Str) -> + banner(Fd, Banner), + io:fwrite(Fd, "~s~n", [Str]). + +prettypr(Forms) -> + erl_prettypr:format(erl_syntax:form_list(Forms)). + +banner(Fd, Heading) -> + file:write(Fd, banner(Heading)). + +banner(Heading) -> + ("\n\n" + "%%% -------------------------------------------------------\n" + "%%% " ++ Heading ++ ":\n" + "%%% -------------------------------------------------------\n\n"). + +z(S) -> + string:join(string:tokens(S, "\s\t"), "\s"). + +m_enums(Prefix, Wrap, Enums) -> + lists:map(fun(T) -> m_enum(Prefix, Wrap, T) end, Enums). + +m_enum(Prefix, B, {Name, Values}) -> + P = Prefix ++ to_upper(Name) ++ "_", + lists:map(fun({I,A}) -> + N = ["'", P, to_upper(z(atom_to_list(A))), "'"], + wrap(B, + N, + ["-define(", N, ", ", integer_to_list(I), ").\n"]) + end, + Values). + +wrap(true, Name, Def) -> + ["-ifndef(", Name, ").\n", Def, "-endif.\n"]; +wrap(false, _, Def) -> + Def. + +to_upper(A) when is_atom(A) -> + to_upper(atom_to_list(A)); +to_upper(S) -> + lists:map(fun tu/1, S). + +tu(C) when C >= $a, C =< $z -> + C + $A - $a; +tu(C) -> + C. + +header() -> + ("%% -------------------------------------------------------------------\n" + "%% This is a generated file.\n" + "%% -------------------------------------------------------------------\n" + "\n" + "%%\n" + "%% Copyright (c) Ericsson AB. All rights reserved.\n" + "%%\n" + "%% The information in this document is the property of Ericsson.\n" + "%%\n" + "%% Except as specifically authorized in writing by Ericsson, the\n" + "%% receiver of this document shall keep the information contained\n" + "%% herein confidential and shall protect the same in whole or in\n" + "%% part from disclosure and dissemination to third parties.\n" + "%%\n" + "%% Disclosure and disseminations to the receivers employees shall\n" + "%% only be made on a strict need to know basis.\n" + "%%\n\n"). + +hrl_header(Name) -> + header() ++ "-hrl_name('" ++ Name ++ ".hrl').\n". + +%% avp_info/1 + +avp_info(Entry) -> %% {Name, Arity} + case Entry of + {'<',A,'>'} -> {A, 1}; + {A} -> {A, 1}; + [A] -> {A, {0,1}}; + {Q,T} -> + {A,_} = avp_info(T), + {A, arity(Q)} + end. + +%% Normalize arity to 1 or {N,X} where N is an integer. A record field +%% for an AVP is list-valued iff the normalized arity is not 1. +arity('*' = Inf) -> {0, Inf}; +arity({'*', N}) -> {0, N}; +arity({1,1}) -> 1; +arity(T) -> T. + +prefix(Spec) -> + case orddict:find(prefix, Spec) of + {ok, P} -> + atom_to_list(P) ++ "_"; + error -> + "" + end. + +rec_name(Name, Prefix) -> + list_to_atom(Prefix ++ atom_to_list(Name)). diff --git a/lib/diameter/src/compiler/diameter_forms.hrl b/lib/diameter/src/compiler/diameter_forms.hrl new file mode 100644 index 0000000000..d93131df34 --- /dev/null +++ b/lib/diameter/src/compiler/diameter_forms.hrl @@ -0,0 +1,52 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Macros used when building abstract code. +%% + +%% Form tag with line number. +-define(F(T), T, ?LINE). +%% Yes, that's right. The replacement is to the first unmatched ')'. + +-define(attribute, ?F(attribute)). +-define(clause, ?F(clause)). +-define(function, ?F(function)). +-define(call, ?F(call)). +-define('fun', ?F('fun')). +-define(generate, ?F(generate)). +-define(lc, ?F(lc)). +-define(match, ?F(match)). +-define(remote, ?F(remote)). +-define(record, ?F(record)). +-define(record_field, ?F(record_field)). +-define(record_index, ?F(record_index)). +-define(tuple, ?F(tuple)). + +-define(ATOM(T), {atom, ?LINE, T}). +-define(INTEGER(N), {integer, ?LINE, N}). +-define(VAR(V), {var, ?LINE, V}). +-define(NIL, {nil, ?LINE}). + +-define(CALL(F,A), {?call, ?ATOM(F), A}). +-define(APPLY(M,F,A), {?call, {?remote, ?ATOM(M), ?ATOM(F)}, A}). +-define(FIELDS(Fs), [{?record_field, ?ATOM(F), V} || {F,V} <- Fs]). + +%% Literal term. +-define(TERM(T), erl_parse:abstract(T, ?LINE)). diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl new file mode 100644 index 0000000000..4431b88c4d --- /dev/null +++ b/lib/diameter/src/compiler/diameter_make.erl @@ -0,0 +1,120 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Driver for the encoder generator utility. +%% + +-module(diameter_make). + +-export([spec/0, + hrl/0, + erl/0]). + +-spec spec() -> no_return(). +-spec hrl() -> no_return(). +-spec erl() -> no_return(). + +spec() -> + make(spec). + +hrl() -> + make(hrl). + +erl() -> + make(erl). + +%% make/1 + +make(Mode) -> + Args = init:get_plain_arguments(), + Opts = try options(Args) catch throw: help -> help(Mode) end, + Files = proplists:get_value(files, Opts, []), + lists:foreach(fun(F) -> from_file(F, Mode, Opts) end, Files), + halt(0). + +%% from_file/3 + +from_file(F, Mode, Opts) -> + try to_spec(F, Mode, Opts) of + Spec -> + from_spec(F, Spec, Mode, Opts) + catch + error: Reason -> + io:format("==> ~p parse failure:~n~p~n", + [F, {Reason, erlang:get_stacktrace()}]), + halt(1) + end. + +%% to_spec/2 + +%% Try to read the input as an already parsed file or else parse it. +to_spec(F, spec, Opts) -> + diameter_spec_util:parse(F, Opts); +to_spec(F, _, _) -> + {ok, [Spec]} = file:consult(F), + Spec. + +%% from_spec/4 + +from_spec(File, Spec, Mode, Opts) -> + try + diameter_codegen:from_spec(File, Spec, Opts, Mode) + catch + error: Reason -> + io:format("==> ~p codegen failure:~n~p~n~p~n", + [Mode, File, {Reason, erlang:get_stacktrace()}]), + halt(1) + end. + +%% options/1 + +options(["-v" | Rest]) -> + [verbose | options(Rest)]; + +options(["-o", Outdir | Rest]) -> + [{outdir, Outdir} | options(Rest)]; + +options(["-i", Incdir | Rest]) -> + [{include, Incdir} | options(Rest)]; + +options(["-h" | _]) -> + throw(help); + +options(["--" | Fs]) -> + [{files, Fs}]; + +options(["-" ++ _ = Opt | _]) -> + io:fwrite("==> unknown option: ~s~n", [Opt]), + throw(help); + +options(Fs) -> %% trailing arguments + options(["--" | Fs]). + +%% help/1 + +help(M) -> + io:fwrite("Usage: ~p ~p [Options] [--] File ...~n" + "Options:~n" + " -v verbose output~n" + " -h shows this help message~n" + " -o OutDir where to put the output files~n" + " -i IncludeDir where to search for beams to import~n", + [?MODULE, M]), + halt(1). diff --git a/lib/diameter/src/compiler/diameter_spec_scan.erl b/lib/diameter/src/compiler/diameter_spec_scan.erl new file mode 100644 index 0000000000..bc0448882a --- /dev/null +++ b/lib/diameter/src/compiler/diameter_spec_scan.erl @@ -0,0 +1,157 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_spec_scan). + +%% +%% Functions used by the spec file parser in diameter_spec_util. +%% + +-export([split/1, + split/2, + parse/1]). + +%%% ----------------------------------------------------------- +%%% # parse/1 +%%% +%%% Output: list of Token +%%% +%%% Token = '{' | '}' | '<' | '>' | '[' | ']' +%%% | '*' | '::=' | ':' | ',' | '-' +%%% | {name, string()} +%%% | {tag, atom()} +%%% | {number, integer() >= 0} +%%% +%%% Tokenize a string. Fails if the string does not parse. +%%% ----------------------------------------------------------- + +parse(S) -> + parse(S, []). + +%% parse/2 + +parse(S, Acc) -> + acc(split(S), Acc). + +acc({T, Rest}, Acc) -> + parse(Rest, [T | Acc]); +acc("", Acc) -> + lists:reverse(Acc). + +%%% ----------------------------------------------------------- +%%% # split/2 +%%% +%%% Output: {list() of Token, Rest} +%%% +%%% Extract a specified number of tokens from a string. Returns a list +%%% of length less than the specified number if there are less than +%%% this number of tokens to be parsed. +%%% ----------------------------------------------------------- + +split(Str, N) + when N >= 0 -> + split(N, Str, []). + +split(0, Str, Acc) -> + {lists:reverse(Acc), Str}; + +split(N, Str, Acc) -> + case split(Str) of + {T, Rest} -> + split(N-1, Rest, [T|Acc]); + "" = Rest -> + {lists:reverse(Acc), Rest} + end. + +%%% ----------------------------------------------------------- +%%% # split/1 +%%% +%%% Output: {Token, Rest} | "" +%%% +%%% Extract the next token from a string. +%%% ----------------------------------------------------------- + +split("" = Rest) -> + Rest; + +split("::=" ++ T) -> + {'::=', T}; + +split([H|T]) + when H == ${; H == $}; + H == $<; H == $>; + H == $[; H == $]; + H == $*; H == $:; H == $,; H == $- -> + {list_to_atom([H]), T}; + +split([H|T]) when $A =< H, H =< $Z; + $0 =< H, H =< $9 -> + {P, Rest} = splitwith(fun is_name_ch/1, [H], T), + Tok = try + {number, read_int(P)} + catch + error:_ -> + {name, P} + end, + {Tok, Rest}; + +split([H|T]) when $a =< H, H =< $z -> + {P, Rest} = splitwith(fun is_name_ch/1, [H], T), + {{tag, list_to_atom(P)}, Rest}; + +split([H|T]) when H == $\t; + H == $\s; + H == $\n -> + split(T). + +%% read_int/1 + +read_int([$0,X|S]) + when X == $X; + X == $x -> + {ok, [N], []} = io_lib:fread("~16u", S), + N; + +read_int(S) -> + list_to_integer(S). + +%% splitwith/3 + +splitwith(Fun, Acc, S) -> + split([] /= S andalso Fun(hd(S)), Fun, Acc, S). + +split(true, Fun, Acc, [H|T]) -> + splitwith(Fun, [H|Acc], T); +split(false, _, Acc, S) -> + {lists:reverse(Acc), S}. + +is_name_ch(C) -> + is_alphanum(C) orelse C == $- orelse C == $_. + +is_alphanum(C) -> + is_lower(C) orelse is_upper(C) orelse is_digit(C). + +is_lower(C) -> + $a =< C andalso C =< $z. + +is_upper(C) -> + $A =< C andalso C =< $Z. + +is_digit(C) -> + $0 =< C andalso C =< $9. diff --git a/lib/diameter/src/compiler/diameter_spec_util.erl b/lib/diameter/src/compiler/diameter_spec_util.erl new file mode 100644 index 0000000000..322d53a199 --- /dev/null +++ b/lib/diameter/src/compiler/diameter_spec_util.erl @@ -0,0 +1,1052 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This module turns a .dia (aka spec) file into the orddict that +%% diameter_codegen.erl in turn morphs into .erl and .hrl files for +%% encode and decode of Diameter messages and AVPs. +%% + +-module(diameter_spec_util). + +-export([parse/2]). + +-define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})). +-define(ATOM, list_to_atom). + +%% parse/1 +%% +%% Output: orddict() + +parse(Path, Options) -> + put({?MODULE, verbose}, lists:member(verbose, Options)), + {ok, B} = file:read_file(Path), + Chunks = chunk(B), + Spec = make_spec(Chunks), + true = enums_defined(Spec), %% sanity checks + true = groups_defined(Spec), %% + true = customs_defined(Spec), %% + Full = import_enums(import_groups(import_avps(insert_codes(Spec), + Options))), + true = v_flags_set(Spec), + Full. + +%% Optional reports when running verbosely. +report(What, Data) -> + report(get({?MODULE, verbose}), What, Data). + +report(true, Tag, Data) -> + io:format("##~n## ~p ~p~n", [Tag, Data]); +report(false, _, _) -> + ok. + +%% chunk/1 + +chunk(B) -> + chunkify(normalize(binary_to_list(B))). + +%% normalize/1 +%% +%% Replace CR NL by NL, multiple NL by one, tab by space, and strip +%% comments and leading/trailing space from each line. Precludes +%% semicolons being used for any other purpose than comments. + +normalize(Str) -> + nh(Str, []). + +nh([], Acc) -> + lists:reverse(Acc); + +%% Trim leading whitespace. +nh(Str, Acc) -> + nb(trim(Str), Acc). + +%% tab -> space +nb([$\t|Rest], Acc) -> + nb(Rest, [$\s|Acc]); + +%% CR NL -> NL +nb([$\r,$\n|Rest], Acc) -> + nt(Rest, Acc); + +%% Gobble multiple newlines before starting over again. +nb([$\n|Rest], Acc) -> + nt(Rest, Acc); + +%% Comment. +nb([$;|Rest], Acc) -> + nb(lists:dropwhile(fun(C) -> C /= $\n end, Rest), Acc); + +%% Just an ordinary character. Boring ... +nb([C|Rest], Acc) -> + nb(Rest, [C|Acc]); + +nb([] = Str, Acc) -> + nt(Str, Acc). + +%% Discard a subsequent newline. +nt(T, [$\n|_] = Acc) -> + nh(T, trim(Acc)); + +%% Trim whitespace from the end of the line before continuing. +nt(T, Acc) -> + nh(T, [$\n|trim(Acc)]). + +trim(S) -> + lists:dropwhile(fun(C) -> lists:member(C, "\s\t") end, S). + +%% chunkify/1 +%% +%% Split the spec file into pieces delimited by lines starting with +%% @Tag. Returns a list of {Tag, Args, Chunk} where Chunk is the +%% string extending to the next delimiter. Note that leading +%% whitespace has already been stripped. + +chunkify(Str) -> + %% Drop characters to the start of the first chunk. + {_, Rest} = split_chunk([$\n|Str]), + chunkify(Rest, []). + +chunkify([], Acc) -> + lists:reverse(Acc); + +chunkify(Rest, Acc) -> + {H,T} = split_chunk(Rest), + chunkify(T, [split_tag(H) | Acc]). + +split_chunk(Str) -> + split_chunk(Str, []). + +split_chunk([] = Rest, Acc) -> + {lists:reverse(Acc), Rest}; +split_chunk([$@|Rest], [$\n|_] = Acc) -> + {lists:reverse(Acc), Rest}; +split_chunk([C|Rest], Acc) -> + split_chunk(Rest, [C|Acc]). + +%% Expect a tag and its arguments on a single line. +split_tag(Str) -> + {L, Rest} = get_until($\n, Str), + [{tag, Tag} | Toks] = diameter_spec_scan:parse(L), + {Tag, Toks, trim(Rest)}. + +get_until(EndT, L) -> + {H, [EndT | T]} = lists:splitwith(fun(C) -> C =/= EndT end, L), + {H,T}. + +%% ------------------------------------------------------------------------ +%% make_spec/1 +%% +%% Turn chunks into spec. + +make_spec(Chunks) -> + lists:foldl(fun(T,A) -> report(chunk, T), chunk(T,A) end, + orddict:new(), + Chunks). + +chunk({T, [X], []}, Dict) + when T == name; + T == prefix -> + store(T, atomize(X), Dict); + +chunk({id = T, [{number, I}], []}, Dict) -> + store(T, I, Dict); + +chunk({vendor = T, [{number, I}, N], []}, Dict) -> + store(T, {I, atomize(N)}, Dict); + +%% inherits -> [{Mod, [AvpName, ...]}, ...] +chunk({inherits = T, [_,_|_] = Args, []}, Acc) -> + Mods = [atomize(A) || A <- Args], + append_list(T, [{M,[]} || M <- Mods], Acc); +chunk({inherits = T, [Mod], Body}, Acc) -> + append(T, {atomize(Mod), parse_avp_names(Body)}, Acc); + +%% avp_types -> [{AvpName, Code, Type, Flags, Encr}, ...] +chunk({avp_types = T, [], Body}, Acc) -> + store(T, parse_avp_types(Body), Acc); + +%% custom_types -> [{Mod, [AvpName, ...]}, ...] +chunk({custom_types = T, [Mod], Body}, Dict) -> + [_|_] = Avps = parse_avp_names(Body), + append(T, {atomize(Mod), Avps}, Dict); + +%% messages -> [{MsgName, Code, Type, Appl, Avps}, ...] +chunk({messages = T, [], Body}, Acc) -> + store(T, parse_messages(Body), Acc); + +%% grouped -> [{AvpName, Code, Vendor, Avps}, ...] +chunk({grouped = T, [], Body}, Acc) -> + store(T, parse_groups(Body), Acc); + +%% avp_vendor_id -> [{Id, [AvpName, ...]}, ...] +chunk({avp_vendor_id = T, [{number, I}], Body}, Dict) -> + [_|_] = Names = parse_avp_names(Body), + append(T, {I, Names}, Dict); + +%% enums -> [{AvpName, [{Value, Name}, ...]}, ...] +chunk({enum, [N], Str}, Dict) -> + append(enums, {atomize(N), parse_enums(Str)}, Dict); + +%% result_codes -> [{ResultName, [{Value, Name}, ...]}, ...] +chunk({result_code, [N], Str}, Dict) -> + append(result_codes, {atomize(N), parse_enums(Str)}, Dict); + +%% commands -> [{Name, Abbrev}, ...] +chunk({commands = T, [], Body}, Dict) -> + store(T, parse_commands(Body), Dict); + +chunk(T, _) -> + ?ERROR({unknown_tag, T}). + +store(Key, Value, Dict) -> + error == orddict:find(Key, Dict) orelse ?ERROR({duplicate, Key}), + orddict:store(Key, Value, Dict). +append(Key, Value, Dict) -> + orddict:append(Key, Value, Dict). +append_list(Key, Values, Dict) -> + orddict:append_list(Key, Values, Dict). + +atomize({tag, T}) -> + T; +atomize({name, T}) -> + ?ATOM(T). + +get_value(Keys, Spec) + when is_list(Keys) -> + [get_value(K, Spec) || K <- Keys]; +get_value(Key, Spec) -> + proplists:get_value(Key, Spec, []). + +%% ------------------------------------------------------------------------ +%% enums_defined/1 +%% groups_defined/1 +%% customs_defined/1 +%% +%% Ensure that every local enum/grouped/custom is defined as an avp +%% with an appropriate type. + +enums_defined(Spec) -> + is_defined(Spec, 'Enumerated', enums). + +groups_defined(Spec) -> + is_defined(Spec, 'Grouped', grouped). + +is_defined(Spec, Type, Key) -> + Avps = get_value(avp_types, Spec), + lists:all(fun(T) -> true = is_local(name(Key, T), Type, Avps) end, + get_value(Key, Spec)). + +name(enums, {N,_}) -> N; +name(grouped, {N,_,_,_}) -> N. + +is_local(Name, Type, Avps) -> + case lists:keyfind(Name, 1, Avps) of + {Name, _, Type, _, _} -> + true; + {Name, _, T, _, _} -> + ?ERROR({avp_has_wrong_type, Name, Type, T}); + false -> + ?ERROR({avp_not_defined, Name, Type}) + end. + +customs_defined(Spec) -> + Avps = get_value(avp_types, Spec), + lists:all(fun(A) -> true = is_local(A, Avps) end, + lists:flatmap(fun last/1, get_value(custom_types, Spec))). + +is_local(Name, Avps) -> + case lists:keyfind(Name, 1, Avps) of + {Name, _, T, _, _} when T == 'Grouped'; + T == 'Enumerated' -> + ?ERROR({avp_has_invalid_custom_type, Name, T}); + {Name, _, _, _, _} -> + true; + false -> + ?ERROR({avp_not_defined, Name}) + end. + +last({_,Xs}) -> Xs. + +%% ------------------------------------------------------------------------ +%% v_flags_set/1 + +v_flags_set(Spec) -> + Avps = get_value(avp_types, Spec) + ++ lists:flatmap(fun last/1, get_value(import_avps, Spec)), + Vs = lists:flatmap(fun last/1, get_value(avp_vendor_id, Spec)), + + lists:all(fun(N) -> vset(N, Avps) end, Vs). + +vset(Name, Avps) -> + A = lists:keyfind(Name, 1, Avps), + false == A andalso ?ERROR({avp_not_defined, Name}), + {Name, _Code, _Type, Flags, _Encr} = A, + lists:member('V', Flags) orelse ?ERROR({v_flag_not_set, A}). + +%% ------------------------------------------------------------------------ +%% insert_codes/1 + +insert_codes(Spec) -> + [Msgs, Cmds] = get_value([messages, commands], Spec), + + %% Code -> [{Name, Flags}, ...] + Dict = lists:foldl(fun({N,C,Fs,_,_}, D) -> dict:append(C,{N,Fs},D) end, + dict:new(), + Msgs), + + %% list() of {Code, {ReqName, ReqAbbr}, {AnsName, AnsAbbr}} + %% If the name and abbreviation are the same then the 2-tuples + %% are replaced by the common atom()-valued name. + Codes = dict:fold(fun(C,Ns,A) -> [make_code(C, Ns, Cmds) | A] end, + [], + dict:erase(-1, Dict)), %% answer-message + + orddict:store(command_codes, Codes, Spec). + +make_code(Code, [_,_] = Ns, Cmds) -> + {Req, Ans} = make_names(Ns, lists:map(fun({_,Fs}) -> + lists:member('REQ', Fs) + end, + Ns)), + {Code, abbrev(Req, Cmds), abbrev(Ans, Cmds)}; + +make_code(Code, Cs, _) -> + ?ERROR({missing_request_or_answer, Code, Cs}). + +%% 3.3. Diameter Command Naming Conventions +%% +%% Diameter command names typically includes one or more English words +%% followed by the verb Request or Answer. Each English word is +%% delimited by a hyphen. A three-letter acronym for both the request +%% and answer is also normally provided. + +make_names([{Rname,_},{Aname,_}], [true, false]) -> + {Rname, Aname}; +make_names([{Aname,_},{Rname,_}], [false, true]) -> + {Rname, Aname}; +make_names([_,_] = Names, _) -> + ?ERROR({inconsistent_command_flags, Names}). + +abbrev(Name, Cmds) -> + case abbr(Name, get_value(Name, Cmds)) of + Name -> + Name; + Abbr -> + {Name, Abbr} + end. + +%% No explicit abbreviation: construct. +abbr(Name, []) -> + ?ATOM(abbr(string:tokens(atom_to_list(Name), "-"))); + +%% Abbreviation was specified. +abbr(_Name, Abbr) -> + Abbr. + +%% No hyphens: already abbreviated. +abbr([Abbr]) -> + Abbr; + +%% XX-Request/Answer ==> XXR/XXA +abbr([[_,_] = P, T]) + when T == "Request"; + T == "Answer" -> + P ++ [hd(T)]; + +%% XXX-...-YYY-Request/Answer ==> X...YR/X...YA +abbr([_,_|_] = L) -> + lists:map(fun erlang:hd/1, L). + +%% ------------------------------------------------------------------------ +%% import_avps/2 + +import_avps(Spec, Options) -> + Msgs = get_value(messages, Spec), + Groups = get_value(grouped, Spec), + + %% Messages and groups require AVP's referenced by them. + NeededAvps + = ordsets:from_list(lists:flatmap(fun({_,_,_,_,As}) -> + [avp_name(A) || A <- As] + end, + Msgs) + ++ lists:flatmap(fun({_,_,_,As}) -> + [avp_name(A) || A <- As] + end, + Groups)), + MissingAvps = missing_avps(NeededAvps, Spec), + + report(needed, NeededAvps), + report(missing, MissingAvps), + + Import = inherit(get_value(inherits, Spec), Options), + + report(imported, Import), + + ImportedAvps = lists:map(fun({N,_,_,_,_}) -> N end, + lists:flatmap(fun last/1, Import)), + + Unknown = MissingAvps -- ImportedAvps, + + [] == Unknown orelse ?ERROR({undefined_avps, Unknown}), + + orddict:store(import_avps, Import, orddict:erase(inherits, Spec)). + +%% missing_avps/2 +%% +%% Given a list of AVP names and parsed spec, return the list of +%% AVP's that aren't defined in this spec. + +missing_avps(NeededNames, Spec) -> + Avps = get_value(avp_types, Spec), + Groups = lists:map(fun({N,_,_,As}) -> + {N, [avp_name(A) || A <- As]} + end, + get_value(grouped, Spec)), + Names = ordsets:from_list(['AVP' | lists:map(fun({N,_,_,_,_}) -> N end, + Avps)]), + missing_avps(NeededNames, [], {Names, Groups}). + +avp_name({'<',A,'>'}) -> A; +avp_name({A}) -> A; +avp_name([A]) -> A; +avp_name({_, A}) -> avp_name(A). + +missing_avps(NeededNames, MissingNames, {Names, _} = T) -> + missing(ordsets:filter(fun(N) -> lists:member(N, NeededNames) end, Names), + ordsets:union(NeededNames, MissingNames), + T). + +%% Nothing found locally. +missing([], MissingNames, _) -> + MissingNames; + +%% Or not. Keep looking for for the AVP's needed by the found AVP's of +%% type Grouped. +missing(FoundNames, MissingNames, {_, Groups} = T) -> + NeededNames = lists:flatmap(fun({N,As}) -> + choose(lists:member(N, FoundNames), As, []) + end, + Groups), + missing_avps(ordsets:from_list(NeededNames), + ordsets:subtract(MissingNames, FoundNames), + T). + +%% inherit/2 + +inherit(Inherits, Options) -> + Dirs = [D || {include, D} <- Options] ++ ["."], + lists:foldl(fun(T,A) -> find_avps(T, A, Dirs) end, [], Inherits). + +find_avps({Mod, AvpNames}, Acc, Path) -> + report(inherit_from, Mod), + Avps = avps_from_beam(find_beam(Mod, Path), Mod), %% could be empty + [{Mod, lists:sort(find_avps(AvpNames, Avps))} | Acc]. + +find_avps([], Avps) -> + Avps; +find_avps(Names, Avps) -> + lists:filter(fun({N,_,_,_,_}) -> lists:member(N, Names) end, Avps). + +%% find_beam/2 + +find_beam(Mod, Dirs) + when is_atom(Mod) -> + find_beam(atom_to_list(Mod), Dirs); +find_beam(Mod, Dirs) -> + Beam = Mod ++ code:objfile_extension(), + case try_path(Dirs, Beam) of + {value, Path} -> + Path; + false -> + ?ERROR({beam_not_on_path, Beam, Dirs}) + end. + +try_path([D|Ds], Fname) -> + Path = filename:join(D, Fname), + case file:read_file_info(Path) of + {ok, _} -> + {value, Path}; + _ -> + try_path(Ds, Fname) + end; +try_path([], _) -> + false. + +%% avps_from_beam/2 + +avps_from_beam(Path, Mod) -> + report(beam, Path), + ok = load_module(code:is_loaded(Mod), Mod, Path), + orddict:fetch(avp_types, Mod:dict()). + +load_module(false, Mod, Path) -> + R = filename:rootname(Path, code:objfile_extension()), + {module, Mod} = code:load_abs(R), + ok; +load_module({file, _}, _, _) -> + ok. + +choose(true, X, _) -> X; +choose(false, _, X) -> X. + +%% ------------------------------------------------------------------------ +%% import_groups/1 +%% import_enums/1 + +import_groups(Spec) -> + orddict:store(import_groups, import(grouped, Spec), Spec). + +import_enums(Spec) -> + orddict:store(import_enums, import(enums, Spec), Spec). + +import(Key, Spec) -> + lists:flatmap(fun(T) -> import_key(Key, T) end, + get_value(import_avps, Spec)). + +import_key(Key, {Mod, Avps}) -> + Imports = lists:flatmap(fun(T) -> + choose(lists:keymember(element(1,T), + 1, + Avps), + [T], + []) + end, + get_value(Key, Mod:dict())), + if Imports == [] -> + []; + true -> + [{Mod, Imports}] + end. + +%% ------------------------------------------------------------------------ +%% parse_enums/1 +%% +%% Enums are specified either as the integer value followed by the +%% name or vice-versa. In the former case the name of the enum is +%% taken to be the string up to the end of line, which may contain +%% whitespace. In the latter case the integer may be parenthesized, +%% specified in hex and followed by an inline comment. This is +%% historical and will likely be changed to require a precise input +%% format. +%% +%% Output: list() of {integer(), atom()} + +parse_enums(Str) -> + lists:flatmap(fun(L) -> parse_enum(trim(L)) end, string:tokens(Str, "\n")). + +parse_enum([]) -> + []; + +parse_enum(Str) -> + REs = [{"^(0[xX][0-9A-Fa-f]+|[0-9]+)\s+(.*?)\s*$", 1, 2}, + {"^(.+?)\s+(0[xX][0-9A-Fa-f]+|[0-9]+)(\s+.*)?$", 2, 1}, + {"^(.+?)\s+\\((0[xX][0-9A-Fa-f]+|[0-9]+)\\)(\s+.*)?$", 2, 1}], + parse_enum(Str, REs). + +parse_enum(Str, REs) -> + try lists:foreach(fun(R) -> enum(Str, R) end, REs) of + ok -> + ?ERROR({bad_enum, Str}) + catch + throw: {enum, T} -> + [T] + end. + +enum(Str, {Re, I, N}) -> + case re:run(Str, Re, [{capture, all_but_first, list}]) of + {match, Vs} -> + T = list_to_tuple(Vs), + throw({enum, {to_int(element(I,T)), ?ATOM(element(N,T))}}); + nomatch -> + ok + end. + +to_int([$0,X|Hex]) + when X == $x; + X == $X -> + {ok, [I], _} = io_lib:fread("~#", "16#" ++ Hex), + I; +to_int(I) -> + list_to_integer(I). + +%% ------------------------------------------------------------------------ +%% parse_messages/1 +%% +%% Parse according to the ABNF for message specifications in 3.2 of +%% RFC 3588 (shown below). We require all message and AVP names to +%% start with a digit or uppercase character, except for the base +%% answer-message, which is treated as a special case. Allowing names +%% that start with a digit is more than the RFC specifies but the name +%% doesn't affect what's sent over the wire. (Certains 3GPP standards +%% use names starting with a digit. eg 3GPP-Charging-Id in TS32.299.) + +%% +%% Sadly, not even the RFC follows this grammar. In particular, except +%% in the example in 3.2, it wraps each command-name in angle brackets +%% ('<' '>') which makes parsing a sequence of specifications require +%% lookahead: after 'optional' avps have been parsed, it's not clear +%% whether a '<' is a 'fixed' or whether it's the start of a +%% subsequent message until we see whether or not '::=' follows the +%% closing '>'. Require the grammar as specified. +%% +%% Output: list of {Name, Code, Flags, ApplId, Avps} +%% +%% Name = atom() +%% Code = integer() +%% Flags = integer() +%% ApplId = [] | [integer()] +%% Avps = see parse_avps/1 + +parse_messages(Str) -> + p_cmd(trim(Str), []). + +%% command-def = command-name "::=" diameter-message +%% +%% command-name = diameter-name +%% +%% diameter-name = ALPHA *(ALPHA / DIGIT / "-") +%% +%% diameter-message = header [ *fixed] [ *required] [ *optional] +%% [ *fixed] +%% +%% header = "<" Diameter-Header:" command-id +%% [r-bit] [p-bit] [e-bit] [application-id]">" +%% +%% The header spec (and example that follows it) is slightly mangled +%% and, given the examples in the RFC should as follows: +%% +%% header = "<" "Diameter Header:" command-id +%% [r-bit] [p-bit] [e-bit] [application-id]">" +%% +%% This is what's required/parsed below, modulo whitespace. This is +%% also what's specified in the current draft standard at +%% http://ftp.ietf.org/drafts/wg/dime. +%% +%% Note that the grammar specifies the order fixed, required, +%% optional. In practise there seems to be little difference between +%% the latter two since qualifiers can be used to change the +%% semantics. For example 1*[XXX] and *1{YYY} specify 1 or more of the +%% optional avp XXX and 0 or 1 of the required avp YYY, making the +%% iotional avp required and the required avp optional. The current +%% draft addresses this somewhat by requiring that min for a qualifier +%% on an optional avp must be 0 if present. It doesn't say anything +%% about required avps however, so specifying a min of 0 would still +%% be possible. The draft also does away with the trailing *fixed. +%% +%% What will be parsed here will treat required and optional +%% interchangeably. That is. only require that required/optional +%% follow and preceed fixed, not that optional avps must follow +%% required ones. We already have several specs for which this parsing +%% is necessary and there seems to be no harm in accepting it. + +p_cmd("", Acc) -> + lists:reverse(Acc); + +p_cmd(Str, Acc) -> + {Next, Rest} = split_def(Str), + report(command, Next), + p_cmd(Rest, [p_cmd(Next) | Acc]). + +p_cmd("answer-message" ++ Str) -> + p_header([{name, 'answer-message'} | diameter_spec_scan:parse(Str)]); + +p_cmd(Str) -> + p_header(diameter_spec_scan:parse(Str)). + +%% p_header/1 + +p_header(['<', {name, _} = N, '>' | Toks]) -> + p_header([N | Toks]); + +p_header([{name, 'answer-message' = N}, '::=', + '<', {name, "Diameter"}, {name, "Header"}, ':', {tag, code}, + ',', {name, "ERR"}, '[', {name, "PXY"}, ']', '>' + | Toks]) -> + {N, -1, ['ERR', 'PXY'], [], parse_avps(Toks)}; + +p_header([{name, Name}, '::=', + '<', {name, "Diameter"}, {name, "Header"}, ':', {number, Code} + | Toks]) -> + {Flags, Rest} = p_flags(Toks), + {ApplId, [C|_] = R} = p_appl(Rest), + '>' == C orelse ?ERROR({invalid_flag, {Name, Code, Flags, ApplId}, R}), + {?ATOM(Name), Code, Flags, ApplId, parse_avps(tl(R))}; + +p_header(Toks) -> + ?ERROR({invalid_header, Toks}). + +%% application-id = 1*DIGIT +%% +%% command-id = 1*DIGIT +%% ; The Command Code assigned to the command +%% +%% r-bit = ", REQ" +%% ; If present, the 'R' bit in the Command +%% ; Flags is set, indicating that the message +%% ; is a request, as opposed to an answer. +%% +%% p-bit = ", PXY" +%% ; If present, the 'P' bit in the Command +%% ; Flags is set, indicating that the message +%% ; is proxiable. +%% +%% e-bit = ", ERR" +%% ; If present, the 'E' bit in the Command +%% ; Flags is set, indicating that the answer +%% ; message contains a Result-Code AVP in +%% ; the "protocol error" class. + +p_flags(Toks) -> + lists:foldl(fun p_flags/2, {[], Toks}, ["REQ", "PXY", "ERR"]). + +p_flags(N, {Acc, [',', {name, N} | Toks]}) -> + {[?ATOM(N) | Acc], Toks}; + +p_flags(_, T) -> + T. + +%% The RFC doesn't specify ',' before application-id but this seems a +%% bit inconsistent. Accept a comma if it exists. +p_appl([',', {number, I} | Toks]) -> + {[I], Toks}; +p_appl([{number, I} | Toks]) -> + {[I], Toks}; +p_appl(Toks) -> + {[], Toks}. + +%% parse_avps/1 +%% +%% Output: list() of Avp | {Qual, Avp} +%% +%% Qual = '*' | {Min, '*'} | {'*', Max} | {Min, Max} +%% Avp = {'<', Name, '>'} | {Name} | [Name] +%% +%% Min, Max = integer() >= 0 + +parse_avps(Toks) -> + p_avps(Toks, ['<', '|', '<'], []). +%% The list corresponds to the delimiters expected at the front, middle +%% and back of the avp specification, '|' representing '{' and '['. + +%% fixed = [qual] "<" avp-spec ">" +%% ; Defines the fixed position of an AVP +%% +%% required = [qual] "{" avp-spec "}" +%% ; The AVP MUST be present and can appear +%% ; anywhere in the message. +%% +%% optional = [qual] "[" avp-name "]" +%% ; The avp-name in the 'optional' rule cannot +%% ; evaluate to any AVP Name which is included +%% ; in a fixed or required rule. The AVP can +%% ; appear anywhere in the message. +%% +%% qual = [min] "*" [max] +%% ; See ABNF conventions, RFC 2234 Section 6.6. +%% ; The absence of any qualifiers depends on whether +%% ; it precedes a fixed, required, or optional +%% ; rule. If a fixed or required rule has no +%% ; qualifier, then exactly one such AVP MUST +%% ; be present. If an optional rule has no +%% ; qualifier, then 0 or 1 such AVP may be +%% ; present. +%% ; +%% ; NOTE: "[" and "]" have a different meaning +%% ; than in ABNF (see the optional rule, above). +%% ; These braces cannot be used to express +%% ; optional fixed rules (such as an optional +%% ; ICV at the end). To do this, the convention +%% ; is '0*1fixed'. +%% +%% min = 1*DIGIT +%% ; The minimum number of times the element may +%% ; be present. The default value is zero. +%% +%% max = 1*DIGIT +%% ; The maximum number of times the element may +%% ; be present. The default value is infinity. A +%% ; value of zero implies the AVP MUST NOT be +%% ; present. +%% +%% avp-spec = diameter-name +%% ; The avp-spec has to be an AVP Name, defined +%% ; in the base or extended Diameter +%% ; specifications. +%% +%% avp-name = avp-spec / "AVP" +%% ; The string "AVP" stands for *any* arbitrary +%% ; AVP Name, which does not conflict with the +%% ; required or fixed position AVPs defined in +%% ; the command code definition. +%% + +p_avps([], _, Acc) -> + lists:reverse(Acc); + +p_avps(Toks, Delim, Acc) -> + {Qual, Rest} = p_qual(Toks), + {Avp, R, D} = p_avp(Rest, Delim), + T = if Qual == false -> + Avp; + true -> + {Qual, Avp} + end, + p_avps(R, D, [T | Acc]). + +p_qual([{number, Min}, '*', {number, Max} | Toks]) -> + {{Min, Max}, Toks}; +p_qual([{number, Min}, '*' = Max | Toks]) -> + {{Min, Max}, Toks}; +p_qual(['*' = Min, {number, Max} | Toks]) -> + {{Min, Max}, Toks}; +p_qual(['*' = Q | Toks]) -> + {Q, Toks}; +p_qual(Toks) -> + {false, Toks}. + +p_avp([B, {name, Name}, E | Toks], [_|_] = Delim) -> + {avp(B, ?ATOM(Name), E), + Toks, + delim(choose(B == '<', B, '|'), Delim)}; +p_avp(Toks, Delim) -> + ?ERROR({invalid_avp, Toks, Delim}). + +avp('<' = B, Name, '>' = E) -> + {B, Name, E}; +avp('{', Name, '}') -> + {Name}; +avp('[', Name, ']') -> + [Name]; +avp(B, Name, E) -> + ?ERROR({invalid_avp, B, Name, E}). + +delim(B, D) -> + if B == hd(D) -> D; true -> tl(D) end. + +%% split_def/1 +%% +%% Strip one command definition off head of a string. + +split_def(Str) -> + sdh(Str, []). + +%% Look for the "::=" starting off the definition. +sdh("", _) -> + ?ERROR({missing, '::='}); +sdh("::=" ++ Rest, Acc) -> + sdb(Rest, [$=,$:,$:|Acc]); +sdh([C|Rest], Acc) -> + sdh(Rest, [C|Acc]). + +%% Look for the "::=" starting off the following definition. +sdb("::=" ++ _ = Rest, Acc) -> + sdt(trim(Acc), Rest); +sdb("" = Rest, Acc) -> + sd(Acc, Rest); +sdb([C|Rest], Acc) -> + sdb(Rest, [C|Acc]). + +%% Put name characters of the subsequent specification back into Rest. +sdt([C|Acc], Rest) + when C /= $\n, C /= $\s -> + sdt(Acc, [C|Rest]); + +sdt(Acc, Rest) -> + sd(Acc, Rest). + +sd(Acc, Rest) -> + {trim(lists:reverse(Acc)), Rest}. +%% Note that Rest is already trimmed of leading space. + +%% ------------------------------------------------------------------------ +%% parse_groups/1 +%% +%% Parse according to the ABNF for message specifications in 4.4 of +%% RFC 3588 (shown below). Again, allow names starting with a digit +%% and also require "AVP Header" without "-" since this is what +%% the RFC uses in all examples. +%% +%% Output: list of {Name, Code, Vendor, Avps} +%% +%% Name = atom() +%% Code = integer() +%% Vendor = [] | [integer()] +%% Avps = see parse_avps/1 + +parse_groups(Str) -> + p_group(trim(Str), []). + +%% grouped-avp-def = name "::=" avp +%% +%% name-fmt = ALPHA *(ALPHA / DIGIT / "-") +%% +%% name = name-fmt +%% ; The name has to be the name of an AVP, +%% ; defined in the base or extended Diameter +%% ; specifications. +%% +%% avp = header [ *fixed] [ *required] [ *optional] +%% [ *fixed] +%% +%% header = "<" "AVP-Header:" avpcode [vendor] ">" +%% +%% avpcode = 1*DIGIT +%% ; The AVP Code assigned to the Grouped AVP +%% +%% vendor = 1*DIGIT +%% ; The Vendor-ID assigned to the Grouped AVP. +%% ; If absent, the default value of zero is +%% ; used. + +p_group("", Acc) -> + lists:reverse(Acc); + +p_group(Str, Acc) -> + {Next, Rest} = split_def(Str), + report(group, Next), + p_group(Rest, [p_group(diameter_spec_scan:parse(Next)) | Acc]). + +p_group([{name, Name}, '::=', '<', {name, "AVP"}, {name, "Header"}, + ':', {number, Code} + | Toks]) -> + {Id, [C|_] = R} = p_vendor(Toks), + C == '>' orelse ?ERROR({invalid_group_header, R}), + {?ATOM(Name), Code, Id, parse_avps(tl(R))}; + +p_group(Toks) -> + ?ERROR({invalid_group, Toks}). + +p_vendor([{number, I} | Toks]) -> + {[I], Toks}; +p_vendor(Toks) -> + {[], Toks}. + +%% ------------------------------------------------------------------------ +%% parse_avp_names/1 + +parse_avp_names(Str) -> + [p_name(N) || N <- diameter_spec_scan:parse(Str)]. + +p_name({name, N}) -> + ?ATOM(N); +p_name(T) -> + ?ERROR({invalid_avp_name, T}). + +%% ------------------------------------------------------------------------ +%% parse_avp_types/1 +%% +%% Output: list() of {Name, Code, Type, Flags, Encr} + +parse_avp_types(Str) -> + p_avp_types(Str, []). + +p_avp_types(Str, Acc) -> + p_type(diameter_spec_scan:split(Str, 3), Acc). + +p_type({[],[]}, Acc) -> + lists:reverse(Acc); + +p_type({[{name, Name}, {number, Code}, {name, Type}], Str}, Acc) -> + {Flags, Encr, Rest} = try + p_avp_flags(trim(Str), []) + catch + throw: {?MODULE, Reason} -> + ?ERROR({invalid_avp_type, Reason}) + end, + p_avp_types(Rest, [{?ATOM(Name), Code, ?ATOM(type(Type)), Flags, Encr} + | Acc]); + +p_type(T, _) -> + ?ERROR({invalid_avp_type, T}). + +p_avp_flags([C|Str], Acc) + when C == $M; + C == $P; + C == $V -> + p_avp_flags(Str, [?ATOM([C]) | Acc]); +%% Could support lowercase here if there's a use for distinguishing +%% between Must and Should in the future in deciding whether or not +%% to set a flag. + +p_avp_flags([$-|Str], Acc) -> + %% Require encr on same line as flags if specified. + {H,T} = lists:splitwith(fun(C) -> C /= $\n end, Str), + + {[{name, [$X|X]} | Toks], Rest} = diameter_spec_scan:split([$X|H], 2), + + "" == X orelse throw({?MODULE, {invalid_avp_flag, Str}}), + + Encr = case Toks of + [] -> + "-"; + [{_, E}] -> + (E == "Y" orelse E == "N") + orelse throw({?MODULE, {invalid_encr, E}}), + E + end, + + Flags = ordsets:from_list(lists:reverse(Acc)), + + {Flags, ?ATOM(Encr), Rest ++ T}; + +p_avp_flags(Str, Acc) -> + p_avp_flags([$-|Str], Acc). + +type("DiamIdent") -> "DiameterIdentity"; %% RFC 3588 +type("DiamURI") -> "DiameterURI"; %% RFC 3588 +type("IPFltrRule") -> "IPFilterRule"; %% RFC 4005 +type("QoSFltrRule") -> "QoSFilterRule"; %% RFC 4005 +type(N) + when N == "OctetString"; + N == "Integer32"; + N == "Integer64"; + N == "Unsigned32"; + N == "Unsigned64"; + N == "Float32"; + N == "Float64"; + N == "Grouped"; + N == "Enumerated"; + N == "Address"; + N == "Time"; + N == "UTF8String"; + N == "DiameterIdentity"; + N == "DiameterURI"; + N == "IPFilterRule"; + N == "QoSFilterRule" -> + N; +type(N) -> + ?ERROR({invalid_avp_type, N}). + +%% ------------------------------------------------------------------------ +%% parse_commands/1 + +parse_commands(Str) -> + p_abbr(diameter_spec_scan:parse(Str), []). + + p_abbr([{name, Name}, {name, Abbrev} | Toks], Acc) + when length(Abbrev) < length(Name) -> + p_abbr(Toks, [{?ATOM(Name), ?ATOM(Abbrev)} | Acc]); + +p_abbr([], Acc) -> + lists:reverse(Acc); + +p_abbr(T, _) -> + ?ERROR({invalid_command, T}). diff --git a/lib/diameter/src/compiler/modules.mk b/lib/diameter/src/compiler/modules.mk new file mode 100644 index 0000000000..17a311dacf --- /dev/null +++ b/lib/diameter/src/compiler/modules.mk @@ -0,0 +1,27 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +MODULES = \ + diameter_codegen \ + diameter_spec_scan \ + diameter_spec_util + +HRL_FILES = \ + diameter_forms.hrl + diff --git a/lib/diameter/src/subdirs.mk b/lib/diameter/src/subdirs.mk new file mode 100644 index 0000000000..3e12d935bc --- /dev/null +++ b/lib/diameter/src/subdirs.mk @@ -0,0 +1,21 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +SUB_DIRS = compiler app transport +SUB_DIRECTORIES = $(SUB_DIRS)
\ No newline at end of file diff --git a/lib/diameter/src/transport/.gitignore b/lib/diameter/src/transport/.gitignore new file mode 100644 index 0000000000..d9f072e262 --- /dev/null +++ b/lib/diameter/src/transport/.gitignore @@ -0,0 +1,3 @@ + +/depend.mk + diff --git a/lib/diameter/src/transport/Makefile b/lib/diameter/src/transport/Makefile new file mode 100644 index 0000000000..4b53100fd2 --- /dev/null +++ b/lib/diameter/src/transport/Makefile @@ -0,0 +1,141 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/target.mk +EBIN = ../../ebin +include $(ERL_TOP)/make/$(TARGET)/otp.mk +else +include $(DIAMETER_TOP)/make/target.mk +EBIN = ../../ebin +include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk +endif + + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- + +include ../../vsn.mk +VSN=$(DIAMETER_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- + +RELSYSDIR = $(RELEASE_PATH)/lib/diameter-$(VSN) + +INCDIR = ../../include + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +include modules.mk + +ERL_FILES = \ + $(MODULES:%=%.erl) + +TARGET_FILES = \ + $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +ifeq ($(TYPE),debug) +ERL_COMPILE_FLAGS += -Ddebug +endif + +include ../app/diameter.mk + +ERL_COMPILE_FLAGS += \ + $(DIAMETER_ERL_COMPILE_FLAGS) \ + -I$(INCDIR) + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug: + @${MAKE} TYPE=debug opt + +opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f errs core *~ + rm -f depend.mk + +docs: + +info: + @echo "" + @echo "ERL_FILES = $(ERL_FILES)" + @echo "HRL_FILES = $(HRL_FILES)" + @echo "" + @echo "TARGET_FILES = $(TARGET_FILES)" + @echo "" + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +# Invoked from ../app to add modules to the app file. +$(APP_TARGET): force + M=`echo $(MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \ + echo "/%TRANSPORT_MODULES%/s//$$M/;w;q" | tr ';' '\n' \ + | ed -s $@ + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/otp_release_targets.mk +else +include $(DIAMETER_TOP)/make/release_targets.mk +endif + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + $(INSTALL_DIR) $(RELSYSDIR)/src/transport + $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/transport + +release_docs_spec: + +force: + +# ---------------------------------------------------- +# Dependencies +# ---------------------------------------------------- + +depend: depend.mk + +# Generate dependencies makefile. +depend.mk: ../app/depend.sed $(ERL_FILES) Makefile + for f in $(MODULES); do \ + sed -f $< $$f.erl | sed "s@/@/$$f@"; \ + done \ + > $@ + +-include depend.mk + +.PHONY: clean debug depend docs force info opt release_docs_spec release_spec diff --git a/lib/diameter/src/transport/diameter_etcp.erl b/lib/diameter/src/transport/diameter_etcp.erl new file mode 100644 index 0000000000..d925d62545 --- /dev/null +++ b/lib/diameter/src/transport/diameter_etcp.erl @@ -0,0 +1,311 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% This module implements a transport_module that uses Erlang message +%% passing for transport. +%% + +-module(diameter_etcp). + +-behaviour(gen_server). + +%% transport_module interface. +-export([start/3]). + +%% gen_tcp-ish interface used by diameter_tcp. +-export([listen/2, + accept/1, + connect/3, + send/2, + close/1, + setopts/2, + port/1]). + +%% child start +-export([start_link/1]). + +%% gen_server callbacks +-export([init/1, + handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3, + terminate/2]). + +%% Server states. + +-record(listener, + {acceptors = [] :: [pid()]}). + +-record(connection, + {parent :: pid(), + peer :: {connect, reference()} %% {connect, MRef} + | accept + | pid()}). + +%% start/3 + +%% 'module' option makes diameter_tcp call here instead of gen_tcp/inet. +start(T, Svc, Opts) + when is_list(Opts) -> + diameter_etcp_sup:start(), + diameter_tcp:start(T, Svc, [{module, ?MODULE} | Opts]). + +%% listen/2 +%% +%% Spawn a process that represents the listening socket. The local +%% port number can be any term, not just an integer. The listener +%% process registers its host/port with diameter_reg and this is the +%% handle with which connect/3 finds the appropriate listening +%% process. + +listen(LPort, Opts) -> + Parent = self(), + diameter_etcp_sup:start_child({listen, Parent, LPort, Opts}). + +%% accept/1 +%% +%% Output: pid() + +accept(LPid) -> + start(fun(Ref, Parent) -> acceptor(LPid, Ref, Parent) end). + +%% connect/3 +%% +%% Output: pid() + +%% RAddr here can either be a 4/8-tuple address or {Node, Addr}. +connect(RAddr, RPort, _Opts) -> + start(fun(Ref, Parent) -> connector(RAddr, RPort, Ref, Parent) end). + +%% send/2 + +send(Pid, Bin) -> + Pid ! {send, Bin}, + ok. + +%% close/1 + +close(Pid) -> + Pid ! close, + monitor(Pid), + receive {'DOWN', _, process, Pid, _} -> ok end. + +%% setopts/2 + +setopts(_, _) -> + ok. + +%% port/1 + +port(_) -> + 3868. %% We have no local port: fake it. + +%% start_link/1 + +start_link(T) -> + gen_server:start_link(?MODULE, T, []). + +%% --------------------------------------------------------------------------- +%% # init/1 +%% --------------------------------------------------------------------------- + +%% Maintain a list of acceptor pids as the process state. Each accept +%% adds a pid to the list, each connect removes one. +init({listen, Parent, LPort, Opts}) -> + monitor(Parent), + {ip, LAddr} = lists:keyfind(ip, 1, Opts), + true = diameter_reg:add_new({?MODULE, listener, LAddr, LPort}), + {ok, #listener{}}; + +init({connect, Fun, Ref, Parent}) -> + {ok, #connection{parent = Parent, + peer = Fun(Ref, Parent)}}. + +%% --------------------------------------------------------------------------- +%% # handle_call/3 +%% --------------------------------------------------------------------------- + +handle_call(_, _, State) -> + {reply, nok, State}. + +%% --------------------------------------------------------------------------- +%% # handle_cast/2 +%% --------------------------------------------------------------------------- + +handle_cast(_, State) -> + {noreply, State}. + +%% --------------------------------------------------------------------------- +%% # handle_info/2 +%% --------------------------------------------------------------------------- + +handle_info(T, #listener{acceptors = L} = S) -> + {noreply, S#listener{acceptors = l(T,L)}}; + +handle_info(T, State) -> + {noreply, transition(T, State)}. + +%% --------------------------------------------------------------------------- +%% # code_change/3 +%% --------------------------------------------------------------------------- + +code_change(_, State, _) -> + {ok, State}. + +%% --------------------------------------------------------------------------- +%% # terminate/2 +%% --------------------------------------------------------------------------- + +terminate(_, _) -> + ok. + +%% --------------------------------------------------------------------------- + +monitor(Pid) -> + erlang:monitor(process, Pid). + +putr(Key, Val) -> + put({?MODULE, Key}, Val). + +eraser(Key) -> + erase({?MODULE, Key}). + +%% l/2 + +l({'DOWN', _, process, _, _} = T, _) -> + x(T); + +%% New accepting process. +l({accept, APid}, As) -> + As ++ [APid]; + +%% Peer wants to connect but we have no acceptor ... +l({connect, Peer}, [] = As) -> + Peer ! {refused, self()}, + As; + +%% ... or we do. +l({connect, Peer}, [APid | Rest]) -> + Peer ! {accepted, APid}, + Rest. + +x(T) -> + exit({shutdown, T}). + +%% start/1 + +start(Fun) -> + Ref = make_ref(), + {ok, Pid} + = T + = diameter_etcp_sup:start_child({connect, Fun, Ref, self()}), + MRef = monitor(Pid), + receive + {ok, Ref} -> + T; + {'DOWN', MRef, process, _, Reason} -> + {error, Reason} + end. + +%% acceptor/3 + +acceptor(LPid, Ref, Parent) -> + LPid ! {accept, self()}, %% announce that we're accepting + putr(ref, {ok, Ref}), + monitor(Parent), + monitor(LPid), + accept. + +%% connector/4 + +connector(RAddr, RPort, Ref, Parent) -> + c(match(RAddr, RPort), Ref, Parent). + +c([], _, _) -> + x(refused); + +c([{_,LPid}], Ref, Parent) -> + LPid ! {connect, self()}, + putr(ref, {ok, Ref}), + monitor(Parent), + {connect, monitor(LPid)}. + +match({Node, RAddr}, RPort) -> + rpc:call(Node, diameter_reg, match, [{?MODULE, listener, RAddr, RPort}]); + +match(RAddr, RPort) -> + match({node(), RAddr}, RPort). + +%% transition/2 + +%% Unexpected parent or peer death. +transition({'DOWN', _, process, _, _} = T, S) -> + element(2,S) ! {tcp_error, self(), T}, + x(T); + +%% Connector is receiving acceptor pid from listener. +transition({accepted, Peer}, #connection{parent = Parent, + peer = {connect, MRef}}) -> + monitor(Peer), + erlang:demonitor(MRef, [flush]), + Peer ! {connect, self()}, + Parent ! {ok, _} = eraser(ref), + #connection{parent = Parent, + peer = Peer}; + +%% Connector is receiving connection refusal from listener. +transition({refused, _} = T, #connection{peer = {connect, _}}) -> + x(T); + +%% Acceptor is receiving peer connect. +transition({connect, Peer}, #connection{parent = Parent, + peer = accept}) -> + monitor(Peer), + Parent ! {ok, _} = eraser(ref), + #connection{parent = Parent, + peer = Peer}; + +%% Incoming message. +transition({recv, Bin}, #connection{parent = Parent} = S) -> + Parent ! {tcp, self(), Bin}, + S; + +%% Outgoing message. +transition({send, Bin}, #connection{peer = Peer} = S) -> + Peer ! {recv, Bin}, + S; + +%% diameter_etcp:close/1 call when a peer is connected ... +transition(close = T, #connection{peer = Peer}) + when is_pid(Peer) -> + Peer ! {close, self()}, + x(T); + +%% ... or not. +transition(close = T, #connection{}) -> + x(T); + +%% Peer is closing the connection. +transition({close, Peer} = T, #connection{parent = Parent, + peer = Peer}) + when is_pid(Peer) -> + Parent ! {tcp_closed, self()}, + x(T). diff --git a/lib/diameter/src/transport/diameter_etcp_sup.erl b/lib/diameter/src/transport/diameter_etcp_sup.erl new file mode 100644 index 0000000000..bd089cf041 --- /dev/null +++ b/lib/diameter/src/transport/diameter_etcp_sup.erl @@ -0,0 +1,64 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_etcp_sup). + +-behaviour(supervisor). + +%% interface +-export([start/0, + start_child/1]). + +%% internal exports +-export([start_link/1, + init/1]). + +%% start/0 +%% +%% Start the etcp top supervisor. + +start() -> + diameter_transport_sup:start_child(?MODULE, ?MODULE). + +%% start_child/1 +%% +%% Start a worker under the etcp supervisor. + +start_child(T) -> + supervisor:start_child(?MODULE, [T]). + +%% start_link/1 +%% +%% Callback from diameter_transport_sup as a result of start/0. +%% Starts a child supervisor under the transport supervisor. + +start_link(?MODULE) -> + SupName = {local, ?MODULE}, + supervisor:start_link(SupName, ?MODULE, []). + +init([]) -> + Mod = diameter_etcp, + Flags = {simple_one_for_one, 0, 1}, + ChildSpec = {Mod, + {Mod, start_link, []}, + temporary, + 1000, + worker, + [Mod]}, + {ok, {Flags, [ChildSpec]}}. diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl new file mode 100644 index 0000000000..92aa8488a0 --- /dev/null +++ b/lib/diameter/src/transport/diameter_sctp.erl @@ -0,0 +1,624 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_sctp). + +-behaviour(gen_server). + +%% interface +-export([start/3]). + +%% child start from supervisor +-export([start_link/1]). + +%% child start from here +-export([init/1]). + +%% gen_server callbacks +-export([handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3, + terminate/2]). + +-include_lib("kernel/include/inet_sctp.hrl"). +-include_lib("diameter/include/diameter.hrl"). + +-define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})). + +%% The default port for a listener. +-define(DEFAULT_PORT, 3868). %% RFC 3588, ch 2.1 + +%% How long a listener with no associations lives before offing +%% itself. +-define(LISTENER_TIMEOUT, 30000). + +%% How long to wait for a transport process to attach after +%% association establishment. +-define(ACCEPT_TIMEOUT, 5000). + +-type uint() :: non_neg_integer(). + +%% Accepting/connecting transport process state. +-record(transport, + {parent :: pid(), + mode :: {accept, pid()} + | {connect, {list(inet:ip_address()), uint(), list()}} + %% {RAs, RP, Errors} + | connect, + socket :: gen_sctp:sctp_socket(), + assoc_id :: gen_sctp:assoc_id(), %% association identifier + peer :: {[inet:ip_address()], uint()}, %% {RAs, RP} + streams :: {uint(), uint()}, %% {InStream, OutStream} counts + os = 0 :: uint()}). %% next output stream + +%% Listener process state. +-record(listener, + {ref :: reference(), + socket :: gen_sctp:sctp_socket(), + count = 0 :: uint(), + tmap = ets:new(?MODULE, []) :: ets:tid(), + %% {MRef, Pid|AssocId}, {AssocId, Pid} + pending = {0, ets:new(?MODULE, [ordered_set])}, + tref :: reference()}). +%% Field tmap is used to map an incoming message or event to the +%% relevent transport process. Field pending implements a queue of +%% transport processes to which an association has been assigned (at +%% comm_up and written into tmap) but for which diameter hasn't yet +%% spawned a transport process: a short-lived state of affairs as a +%% new transport is spawned as a consequence of a peer being taken up, +%% transport processes being spawned by the listener on demand. In +%% case diameter starts a transport before comm_up on a new +%% association, pending is set to an improper list with the spawned +%% transport as head and the queue as tail. + +%% --------------------------------------------------------------------------- +%% # start/3 +%% --------------------------------------------------------------------------- + +start(T, #diameter_service{capabilities = Caps}, Opts) + when is_list(Opts) -> + diameter_sctp_sup:start(), %% start supervisors on demand + Addrs = Caps#diameter_caps.host_ip_address, + s(T, Addrs, lists:map(fun ip/1, Opts)). + +ip({ifaddr, A}) -> + {ip, A}; +ip(T) -> + T. + +%% A listener spawns transports either as a consequence of this call +%% when there is not yet an association to associate with it, or at +%% comm_up on a new association in which case the call retrieves a +%% transport from the pending queue. +s({accept, Ref} = A, Addrs, Opts) -> + {LPid, LAs} = listener(Ref, {Opts, Addrs}), + try gen_server:call(LPid, {A, self()}, infinity) of + {ok, TPid} -> {ok, TPid, LAs} + catch + exit: Reason -> {error, Reason} + end; +%% This implementation is due to there being no accept call in +%% gen_sctp in order to be able to accept a new association only +%% *after* an accepting transport has been spawned. + +s({connect = C, _}, Addrs, Opts) -> + diameter_sctp_sup:start_child({C, self(), Opts, Addrs}). + +%% start_link/1 + +start_link(T) -> + proc_lib:start_link(?MODULE, + init, + [T], + infinity, + diameter_lib:spawn_opts(server, [])). + +%% --------------------------------------------------------------------------- +%% # init/1 +%% --------------------------------------------------------------------------- + +init(T) -> + gen_server:enter_loop(?MODULE, [], i(T)). + +%% i/1 + +%% A process owning a listening socket. +i({listen, Ref, {Opts, Addrs}}) -> + {LAs, Sock} = AS = open(Addrs, Opts, ?DEFAULT_PORT), + proc_lib:init_ack({ok, self(), LAs}), + ok = gen_sctp:listen(Sock, true), + true = diameter_reg:add_new({?MODULE, listener, {Ref, AS}}), + start_timer(#listener{ref = Ref, + socket = Sock}); + +%% A connecting transport. +i({connect, Pid, Opts, Addrs}) -> + {[As, Ps], Rest} = proplists:split(Opts, [raddr, rport]), + RAs = [diameter_lib:ipaddr(A) || {raddr, A} <- As], + [RP] = [P || {rport, P} <- Ps] ++ [P || P <- [?DEFAULT_PORT], [] == Ps], + {LAs, Sock} = open(Addrs, Rest, 0), + proc_lib:init_ack({ok, self(), LAs}), + erlang:monitor(process, Pid), + #transport{parent = Pid, + mode = {connect, connect(Sock, RAs, RP, [])}, + socket = Sock}; + +%% An accepting transport spawned by diameter. +i({accept, Pid, LPid, Sock}) -> + proc_lib:init_ack({ok, self()}), + erlang:monitor(process, Pid), + erlang:monitor(process, LPid), + #transport{parent = Pid, + mode = {accept, LPid}, + socket = Sock}; + +%% An accepting transport spawned at association establishment. +i({accept, Ref, LPid, Sock, Id}) -> + proc_lib:init_ack({ok, self()}), + MRef = erlang:monitor(process, LPid), + %% Wait for a signal that the transport has been started before + %% processing other messages. + receive + {Ref, Pid} -> %% transport started + #transport{parent = Pid, + mode = {accept, LPid}, + socket = Sock}; + {'DOWN', MRef, process, _, _} = T -> %% listener down + close(Sock, Id), + x(T) + after ?ACCEPT_TIMEOUT -> + close(Sock, Id), + x(timeout) + end. + +%% close/2 + +close(Sock, Id) -> + gen_sctp:eof(Sock, #sctp_assoc_change{assoc_id = Id}). +%% Having to pass a record here is hokey. + +%% listener/2 + +listener(LRef, T) -> + l(diameter_reg:match({?MODULE, listener, {LRef, '_'}}), LRef, T). + +%% Existing process with the listening socket ... +l([{{?MODULE, listener, {_, AS}}, LPid}], _, _) -> + {LAs, _Sock} = AS, + {LPid, LAs}; + +%% ... or not: start one. +l([], LRef, T) -> + {ok, LPid, LAs} = diameter_sctp_sup:start_child({listen, LRef, T}), + {LPid, LAs}. + +%% open/3 + +open(Addrs, Opts, PortNr) -> + {LAs, Os} = addrs(Addrs, Opts), + {LAs, case gen_sctp:open(gen_opts(portnr(Os, PortNr))) of + {ok, Sock} -> + Sock; + {error, Reason} -> + x({open, Reason}) + end}. + +addrs(Addrs, Opts) -> + case proplists:split(Opts, [ip]) of + {[[]], _} -> + {Addrs, Opts ++ [{ip, A} || A <- Addrs]}; + {[As], Os} -> + LAs = [diameter_lib:ipaddr(A) || {ip, A} <- As], + {LAs, Os ++ [{ip, A} || A <- LAs]} + end. + +portnr(Opts, PortNr) -> + case proplists:get_value(port, Opts) of + undefined -> + [{port, PortNr} | Opts]; + _ -> + Opts + end. + +%% x/1 + +x(Reason) -> + exit({shutdown, Reason}). + +%% gen_opts/1 + +gen_opts(Opts) -> + {L,_} = proplists:split(Opts, [binary, list, mode, active, sctp_events]), + [[],[],[],[],[]] == L orelse ?ERROR({reserved_options, Opts}), + [binary, {active, once} | Opts]. + +%% --------------------------------------------------------------------------- +%% # handle_call/3 +%% --------------------------------------------------------------------------- + +handle_call({{accept, Ref}, Pid}, _, #listener{ref = Ref, + count = N} + = S) -> + {TPid, NewS} = accept(Pid, S), + {reply, {ok, TPid}, NewS#listener{count = N+1}}; + +handle_call(_, _, State) -> + {reply, nok, State}. + +%% --------------------------------------------------------------------------- +%% # handle_cast/2 +%% --------------------------------------------------------------------------- + +handle_cast(_, State) -> + {noreply, State}. + +%% --------------------------------------------------------------------------- +%% # handle_info/2 +%% --------------------------------------------------------------------------- + +handle_info(T, #transport{} = S) -> + {noreply, #transport{} = t(T,S)}; + +handle_info(T, #listener{} = S) -> + {noreply, #listener{} = l(T,S)}. + +%% --------------------------------------------------------------------------- +%% # code_change/3 +%% --------------------------------------------------------------------------- + +code_change(_, State, _) -> + {ok, State}. + +%% --------------------------------------------------------------------------- +%% # terminate/2 +%% --------------------------------------------------------------------------- + +terminate(_, #transport{assoc_id = undefined}) -> + ok; + +terminate(_, #transport{socket = Sock, + mode = {accept, _}, + assoc_id = Id}) -> + close(Sock, Id); + +terminate(_, #transport{socket = Sock}) -> + gen_sctp:close(Sock); + +terminate(_, #listener{socket = Sock}) -> + gen_sctp:close(Sock). + +%% --------------------------------------------------------------------------- + +%% start_timer/1 + +start_timer(#listener{count = 0} = S) -> + S#listener{tref = erlang:start_timer(?LISTENER_TIMEOUT, self(), close)}; +start_timer(S) -> + S. + +%% l/2 +%% +%% Transition listener state. + +%% Incoming message from SCTP. +l({sctp, Sock, _RA, _RP, Data} = Msg, #listener{socket = Sock} = S) -> + setopts(Sock), + case find(Data, S) of + {TPid, NewS} -> + TPid ! Msg, + NewS; + false -> + S + end; + +%% Transport is asking message to be sent. See send/3 for why the send +%% isn't directly from the transport. +l({send, AssocId, StreamId, Bin}, #listener{socket = Sock} = S) -> + send(Sock, AssocId, StreamId, Bin), + S; + +%% Accepting transport has died. One that's awaiting an association ... +l({'DOWN', MRef, process, TPid, _}, #listener{pending = [TPid | Q], + tmap = T, + count = N} + = S) -> + ets:delete(T, MRef), + ets:delete(T, TPid), + start_timer(S#listener{count = N-1, + pending = Q}); + +%% ... ditto and a new transport has already been started ... +l({'DOWN', _, process, _, _} = T, #listener{pending = [TPid | Q]} + = S) -> + #listener{pending = NQ} + = NewS + = l(T, S#listener{pending = Q}), + NewS#listener{pending = [TPid | NQ]}; + +%% ... or not. +l({'DOWN', MRef, process, TPid, _}, #listener{socket = Sock, + tmap = T, + count = N, + pending = {P,Q}} + = S) -> + [{MRef, Id}] = ets:lookup(T, MRef), %% Id = TPid | AssocId + ets:delete(T, MRef), + ets:delete(T, Id), + Id == TPid orelse close(Sock, Id), + case ets:lookup(Q, TPid) of + [{TPid, _}] -> %% transport in the pending queue ... + ets:delete(Q, TPid), + S#listener{pending = {P-1, Q}}; + [] -> %% ... or not + start_timer(S#listener{count = N-1}) + end; + +%% Timeout after the last accepting process has died. +l({timeout, TRef, close = T}, #listener{tref = TRef, + count = 0}) -> + x(T); +l({timeout, _, close}, #listener{} = S) -> + S. + +%% t/2 +%% +%% Transition transport state. + +t(T,S) -> + case transition(T,S) of + ok -> + S; + #transport{} = NS -> + NS; + stop -> + x(T) + end. + +%% transition/2 + +%% Incoming message. +transition({sctp, Sock, _RA, _RP, Data}, #transport{socket = Sock, + mode = {accept, _}} + = S) -> + recv(Data, S); + +transition({sctp, Sock, _RA, _RP, Data}, #transport{socket = Sock} = S) -> + setopts(Sock), + recv(Data, S); + +%% Outgoing message. +transition({diameter, {send, Msg}}, S) -> + send(Msg, S); + +%% Request to close the transport connection. +transition({diameter, {close, Pid}}, #transport{parent = Pid}) -> + stop; + +%% Listener process has died. +transition({'DOWN', _, process, Pid, _}, #transport{mode = {accept, Pid}}) -> + stop; + +%% Parent process has died. +transition({'DOWN', _, process, Pid, _}, #transport{parent = Pid}) -> + stop. + +%% Crash on anything unexpected. + +%% accept/2 +%% +%% Start a new transport process or use one that's already been +%% started as a consequence of association establishment. + +%% No pending associations: spawn a new transport. +accept(Pid, #listener{socket = Sock, + tmap = T, + pending = {0,_} = Q} + = S) -> + Arg = {accept, Pid, self(), Sock}, + {ok, TPid} = diameter_sctp_sup:start_child(Arg), + MRef = erlang:monitor(process, TPid), + ets:insert(T, [{MRef, TPid}, {TPid, MRef}]), + {TPid, S#listener{pending = [TPid | Q]}}; +%% Placing the transport in the pending field makes it available to +%% the next association. The stack starts a new accepting transport +%% only after this one brings the connection up (or dies). + +%% Accepting transport has died. This can happen if a new transport is +%% started before the DOWN has arrived. +accept(Pid, #listener{pending = [TPid | {0,_} = Q]} = S) -> + false = is_process_alive(TPid), %% assert + accept(Pid, S#listener{pending = Q}); + +%% Pending associations: attach to the first in the queue. +accept(Pid, #listener{ref = Ref, pending = {N,Q}} = S) -> + TPid = ets:first(Q), + TPid ! {Ref, Pid}, + ets:delete(Q, TPid), + {TPid, S#listener{pending = {N-1, Q}}}. + +%% send/2 + +%% Outbound Diameter message on a specified stream ... +send(#diameter_packet{bin = Bin, transport_data = {stream, SId}}, S) -> + send(SId, Bin, S), + S; + +%% ... or not: rotate through all steams. +send(Bin, #transport{streams = {_, OS}, + os = N} + = S) + when is_binary(Bin) -> + send(N, Bin, S), + S#transport{os = (N + 1) rem OS}. + +%% send/3 + +%% Messages have to be sent from the controlling process, which is +%% probably a bug. Sending from here causes an inet_reply, Sock, +%% Status} message to be sent to the controlling process while +%% gen_sctp:send/4 here hangs. +send(StreamId, Bin, #transport{assoc_id = AId, + mode = {accept, LPid}}) -> + LPid ! {send, AId, StreamId, Bin}; + +send(StreamId, Bin, #transport{socket = Sock, + assoc_id = AId}) -> + send(Sock, AId, StreamId, Bin). + +%% send/4 + +send(Sock, AssocId, Stream, Bin) -> + case gen_sctp:send(Sock, AssocId, Stream, Bin) of + ok -> + ok; + {error, Reason} -> + x({send, Reason}) + end. + +%% recv/2 + +%% Association established ... +recv({[], #sctp_assoc_change{state = comm_up, + outbound_streams = OS, + inbound_streams = IS, + assoc_id = Id}}, + #transport{assoc_id = undefined} + = S) -> + up(S#transport{assoc_id = Id, + streams = {IS, OS}}); + +%% ... or not: try the next address. +recv({[], #sctp_assoc_change{} = E}, + #transport{assoc_id = undefined, + socket = Sock, + mode = {connect = C, {[RA|RAs], RP, Es}}} + = S) -> + S#transport{mode = {C, connect(Sock, RAs, RP, [{RA,E} | Es])}}; + +%% Lost association after establishment. +recv({[], #sctp_assoc_change{}}, _) -> + stop; + +%% Inbound Diameter message. +recv({[#sctp_sndrcvinfo{stream = Id}], Bin}, #transport{parent = Pid}) + when is_binary(Bin) -> + diameter_peer:recv(Pid, #diameter_packet{transport_data = {stream, Id}, + bin = Bin}), + ok; + +recv({[], #sctp_shutdown_event{assoc_id = Id}}, + #transport{assoc_id = Id}) -> + stop. + +%% up/1 + +up(#transport{parent = Pid, + mode = {connect = C, {[RA | _], RP, _}}} + = S) -> + diameter_peer:up(Pid, {RA,RP}), + S#transport{mode = C}; + +up(#transport{parent = Pid, + mode = {accept, _}} + = S) -> + diameter_peer:up(Pid), + S. + +%% find/2 + +find({[#sctp_sndrcvinfo{assoc_id = Id}], _} + = Data, + #listener{tmap = T} + = S) -> + f(ets:lookup(T, Id), Data, S); + +find({_, Rec} = Data, #listener{tmap = T} = S) -> + f(ets:lookup(T, assoc_id(Rec)), Data, S). + +%% New association and a transport waiting for one: use it. +f([], + {_, #sctp_assoc_change{state = comm_up, + assoc_id = Id}}, + #listener{tmap = T, + pending = [TPid | {_,_} = Q]} + = S) -> + [{TPid, MRef}] = ets:lookup(T, TPid), + ets:insert(T, [{MRef, Id}, {Id, TPid}]), + ets:delete(T, TPid), + {TPid, S#listener{pending = Q}}; + +%% New association and no transport start yet: spawn one and place it +%% in the queue. +f([], + {_, #sctp_assoc_change{state = comm_up, + assoc_id = Id}}, + #listener{ref = Ref, + socket = Sock, + tmap = T, + pending = {N,Q}} + = S) -> + Arg = {accept, Ref, self(), Sock, Id}, + {ok, TPid} = diameter_sctp_sup:start_child(Arg), + MRef = erlang:monitor(process, TPid), + ets:insert(T, [{MRef, Id}, {Id, TPid}]), + ets:insert(Q, {TPid, now()}), + {TPid, S#listener{pending = {N+1, Q}}}; + +%% Known association ... +f([{_, TPid}], _, S) -> + {TPid, S}; + +%% ... or not: discard. +f([], _, _) -> + false. + +%% assoc_id/1 + +assoc_id(#sctp_shutdown_event{assoc_id = Id}) -> %% undocumented + Id; +assoc_id(#sctp_assoc_change{assoc_id = Id}) -> + Id; +assoc_id(#sctp_sndrcvinfo{assoc_id = Id}) -> + Id; +assoc_id(#sctp_paddr_change{assoc_id = Id}) -> + Id; +assoc_id(#sctp_adaptation_event{assoc_id = Id}) -> + Id. + +%% connect/4 + +connect(_, [], _, Reasons) -> + x({connect, lists:reverse(Reasons)}); + +connect(Sock, [Addr | AT] = As, Port, Reasons) -> + case gen_sctp:connect_init(Sock, Addr, Port, []) of + ok -> + {As, Port, Reasons}; + {error, _} = E -> + connect(Sock, AT, Port, [{Addr, E} | Reasons]) + end. + +%% setopts/1 + +setopts(Sock) -> + case inet:setopts(Sock, [{active, once}]) of + ok -> ok; + X -> x({setopts, Sock, X}) %% possibly on peer disconnect + end. diff --git a/lib/diameter/src/transport/diameter_sctp_sup.erl b/lib/diameter/src/transport/diameter_sctp_sup.erl new file mode 100644 index 0000000000..3bdae02d68 --- /dev/null +++ b/lib/diameter/src/transport/diameter_sctp_sup.erl @@ -0,0 +1,74 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_sctp_sup). + +-behaviour(supervisor). + +%% interface +-export([start/0, + start_child/1]). + +%% internal exports +-export([start_link/1, + init/1]). + +%% Start multiple supervisors only because a child can't start another +%% child before supervisor:start_child/2 has returned. +-define(TRANSPORT_SUP, diameter_sctp_transport_sup). +-define(LISTENER_SUP, diameter_sctp_listener_sup). + +%% start/0 +%% +%% Start the TCP-specific supervisors. + +start() -> + diameter_transport_sup:start_child(?TRANSPORT_SUP, ?MODULE), + diameter_transport_sup:start_child(?LISTENER_SUP, ?MODULE). + +%% start_child/1 +%% +%% Start a worker under one of the child supervisors. + +start_child(T) -> + SupRef = case element(1,T) of + connect -> ?TRANSPORT_SUP; + accept -> ?TRANSPORT_SUP; + listen -> ?LISTENER_SUP + end, + supervisor:start_child(SupRef, [T]). + +%% start_link/1 +%% +%% Callback from diameter_transport_sup as a result of start/0. +%% Starts a child supervisor under the transport supervisor. + +start_link(Name) -> + supervisor:start_link({local, Name}, ?MODULE, []). + +init([]) -> + Mod = diameter_sctp, + Flags = {simple_one_for_one, 0, 1}, + ChildSpec = {Mod, + {Mod, start_link, []}, + temporary, + 1000, + worker, + [Mod]}, + {ok, {Flags, [ChildSpec]}}. diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl new file mode 100644 index 0000000000..653c114471 --- /dev/null +++ b/lib/diameter/src/transport/diameter_tcp.erl @@ -0,0 +1,531 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_tcp). + +-behaviour(gen_server). + +%% interface +-export([start/3]). + +%% child start from supervisor +-export([start_link/1]). + +%% child start from here +-export([init/1]). + +%% gen_server callbacks +-export([handle_call/3, + handle_cast/2, + handle_info/2, + code_change/3, + terminate/2]). + +-include_lib("diameter/include/diameter.hrl"). + +-define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})). + +-define(DEFAULT_PORT, 3868). %% RFC 3588, ch 2.1 +-define(LISTENER_TIMEOUT, 30000). +-define(FRAGMENT_TIMEOUT, 1000). + +%% The same gen_server implementation supports three different kinds +%% of processes: an actual transport process, one that will club it to +%% death should the parent die before a connection is established, and +%% a process owning the listening port. + +%% Listener process state. +-record(listener, {socket :: inet:socket(), + count = 1 :: non_neg_integer(), + tref :: reference()}). + +%% Monitor process state. +-record(monitor, + {parent :: pid(), + transport = self() :: pid()}). + +-type tref() :: reference(). %% timer reference +-type length() :: 0..16#FFFFFF. %% message length from Diameter header +-type size() :: non_neg_integer(). %% accumulated binary size +-type frag() :: {length(), size(), binary(), list(binary())} + | binary(). + +%% Accepting/connecting transport process state. +-record(transport, + {socket :: inet:socket(), %% accept or connect socket + parent :: pid(), %% of process that started us + module :: module(), %% gen_tcp-like module + frag = <<>> :: binary() | {tref(), frag()}}). %% message fragment + +%% The usual transport using gen_tcp can be replaced by anything +%% sufficiently gen_tcp-like by passing a 'module' option as the first +%% (for simplicity) transport option. The transport_module diameter_etcp +%% uses this to set itself as the module to call, its start/3 just +%% calling start/3 here with the option set. + +%% --------------------------------------------------------------------------- +%% # start/3 +%% --------------------------------------------------------------------------- + +start({T, Ref}, #diameter_service{capabilities = Caps}, Opts) -> + diameter_tcp_sup:start(), %% start tcp supervisors on demand + {Mod, Rest} = split(Opts), + Addrs = Caps#diameter_caps.host_ip_address, + Arg = {T, Ref, Mod, self(), Rest, Addrs}, + diameter_tcp_sup:start_child(Arg). + +split([{module, M} | Opts]) -> + {M, Opts}; +split(Opts) -> + {gen_tcp, Opts}. + +%% start_link/1 + +start_link(T) -> + proc_lib:start_link(?MODULE, + init, + [T], + infinity, + diameter_lib:spawn_opts(server, [])). + +%% --------------------------------------------------------------------------- +%% # init/1 +%% --------------------------------------------------------------------------- + +init(T) -> + gen_server:enter_loop(?MODULE, [], i(T)). + +%% i/1 + +%% A transport process. +i({T, Ref, Mod, Pid, Opts, Addrs}) + when T == accept; + T == connect -> + erlang:monitor(process, Pid), + %% Since accept/connect might block indefinitely, spawn a process + %% that does nothing but kill us with the parent until call + %% returns. + {ok, MPid} = diameter_tcp_sup:start_child(#monitor{parent = Pid}), + Sock = i(T, Ref, Mod, Pid, Opts, Addrs), + MPid ! {stop, self()}, %% tell the monitor to die + setopts(Mod, Sock), + #transport{parent = Pid, + module = Mod, + socket = Sock}; + +%% A monitor process to kill the transport if the parent dies. +i(#monitor{parent = Pid, transport = TPid} = S) -> + proc_lib:init_ack({ok, self()}), + erlang:monitor(process, Pid), + erlang:monitor(process, TPid), + S; +%% In principle a link between the transport and killer processes +%% could do the same thing: have the accepting/connecting process be +%% killed when the killer process dies as a consequence of parent +%% death. However, a link can be unlinked and this is exactly what +%% gen_tcp seems to so. Links should be left to supervisors. + +i({listen, LRef, APid, {Mod, Opts, Addrs}}) -> + {[LA, LP], Rest} = proplists:split(Opts, [ip, port]), + LAddr = get_addr(LA, Addrs), + LPort = get_port(LP), + {ok, LSock} = Mod:listen(LPort, gen_opts(LAddr, Rest)), + proc_lib:init_ack({ok, self(), {LAddr, LSock}}), + erlang:monitor(process, APid), + true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}), + start_timer(#listener{socket = LSock}). + +%% i/6 + +i(accept, Ref, Mod, Pid, Opts, Addrs) -> + {LAddr, LSock} = listener(Ref, {Mod, Opts, Addrs}), + proc_lib:init_ack({ok, self(), [LAddr]}), + Sock = ok(accept(Mod, LSock)), + diameter_peer:up(Pid), + Sock; + +i(connect, _, Mod, Pid, Opts, Addrs) -> + {[LA, RA, RP], Rest} = proplists:split(Opts, [ip, raddr, rport]), + LAddr = get_addr(LA, Addrs), + RAddr = get_addr(RA, []), + RPort = get_port(RP), + proc_lib:init_ack({ok, self(), [LAddr]}), + Sock = ok(connect(Mod, RAddr, RPort, gen_opts(LAddr, Rest))), + diameter_peer:up(Pid, {RAddr, RPort}), + Sock. + +ok({ok, T}) -> + T; +ok(No) -> + x(No). + +x(Reason) -> + exit({shutdown, Reason}). + +%% listener/2 + +listener(LRef, T) -> + l(diameter_reg:match({?MODULE, listener, {LRef, '_'}}), LRef, T). + +%% Existing process with the listening socket ... +l([{{?MODULE, listener, {_, AS}}, LPid}], _, _) -> + LPid ! {accept, self()}, + AS; + +%% ... or not: start one. +l([], LRef, T) -> + {ok, _, AS} = diameter_tcp_sup:start_child({listen, LRef, self(), T}), + AS. + +%% get_addr/2 + +get_addr(As, Def) -> + diameter_lib:ipaddr(addr(As, Def)). + +%% Take the first address from the service if several are unspecified. +addr([], [Addr | _]) -> + Addr; +addr([{_, Addr}], _) -> + Addr; +addr(As, Addrs) -> + ?ERROR({invalid_addrs, As, Addrs}). + +%% get_port/1 + +get_port([{_, Port}]) -> + Port; +get_port([]) -> + ?DEFAULT_PORT; +get_port(Ps) -> + ?ERROR({invalid_ports, Ps}). + +%% gen_opts/2 + +gen_opts(LAddr, Opts) -> + {L,_} = proplists:split(Opts, [binary, packet, active]), + [[],[],[]] == L orelse ?ERROR({reserved_options, Opts}), + [binary, + {packet, 0}, + {active, once}, + {ip, LAddr} + | Opts]. + +%% --------------------------------------------------------------------------- +%% # handle_call/3 +%% --------------------------------------------------------------------------- + +handle_call(_, _, State) -> + {reply, nok, State}. + +%% --------------------------------------------------------------------------- +%% # handle_cast/2 +%% --------------------------------------------------------------------------- + +handle_cast(_, State) -> + {noreply, State}. + +%% --------------------------------------------------------------------------- +%% # handle_info/2 +%% --------------------------------------------------------------------------- + +handle_info(T, #transport{} = S) -> + {noreply, #transport{} = t(T,S)}; + +handle_info(T, #listener{} = S) -> + {noreply, #listener{} = l(T,S)}; + +handle_info(T, #monitor{} = S) -> + m(T,S), + x(T). + +%% --------------------------------------------------------------------------- +%% # code_change/3 +%% --------------------------------------------------------------------------- + +code_change(_, State, _) -> + {ok, State}. + +%% --------------------------------------------------------------------------- +%% # terminate/2 +%% --------------------------------------------------------------------------- + +terminate(_, _) -> + ok. + +%% --------------------------------------------------------------------------- + +%% start_timer/1 + +start_timer(#listener{count = 0} = S) -> + S#listener{tref = erlang:start_timer(?LISTENER_TIMEOUT, self(), close)}; +start_timer(S) -> + S. + +%% m/2 +%% +%% Transition monitor state. + +%% Transport is telling us to die. +m({stop, TPid}, #monitor{transport = TPid}) -> + ok; + +%% Transport has died. +m({'DOWN', _, process, TPid, _}, #monitor{transport = TPid}) -> + ok; + +%% Transport parent has died. +m({'DOWN', _, process, Pid, _}, #monitor{parent = Pid, + transport = TPid}) -> + exit(TPid, {shutdown, parent}). + +%% l/2 +%% +%% Transition listener state. + +%% Another accept transport is attaching. +l({accept, TPid}, #listener{count = N} = S) -> + erlang:monitor(process, TPid), + S#listener{count = N+1}; + +%% Accepting process has died. +l({'DOWN', _, process, _, _}, #listener{count = N} = S) -> + start_timer(S#listener{count = N-1}); + +%% Timeout after the last accepting process has died. +l({timeout, TRef, close = T}, #listener{tref = TRef, + count = 0}) -> + x(T); +l({timeout, _, close}, #listener{} = S) -> + S. + +%% t/2 +%% +%% Transition transport state. + +t(T,S) -> + case transition(T,S) of + ok -> + S; + #transport{} = NS -> + NS; + {stop, Reason} -> + x(Reason); + stop -> + x(T) + end. + +%% transition/2 + +%% Incoming message. +transition({tcp, Sock, Data}, #transport{socket = Sock, + module = M} + = S) -> + setopts(M, Sock), + recv(Data, S); + +transition({tcp_closed, Sock}, #transport{socket = Sock}) -> + stop; + +transition({tcp_error, Sock, _Reason} = T, #transport{socket = Sock} = S) -> + ?ERROR({T,S}); + +%% Outgoing message. +transition({diameter, {send, Bin}}, #transport{socket = Sock, + module = M}) -> + case send(M, Sock, Bin) of + ok -> + ok; + {error, Reason} -> + {stop, {send, Reason}} + end; + +%% Request to close the transport connection. +transition({diameter, {close, Pid}}, #transport{parent = Pid, + socket = Sock, + module = M}) -> + M:close(Sock), + stop; + +%% Timeout for reception of outstanding packets. +transition({timeout, TRef, flush}, S) -> + flush(TRef, S); + +%% Request for the local port number. +transition({resolve_port, RPid}, #transport{socket = Sock, + module = M}) + when is_pid(RPid) -> + RPid ! lport(M, Sock), + ok; + +%% Parent process has died. +transition({'DOWN', _, process, Pid, _}, #transport{parent = Pid}) -> + stop. + +%% Crash on anything unexpected. + +%% recv/2 +%% +%% Reassemble fragmented messages and extract multple message sent +%% using Nagle. + +recv(Bin, #transport{parent = Pid, frag = Head} = S) -> + S#transport{frag = recv(Pid, Head, Bin)}. + +%% recv/3 + +%% No previous fragment. +recv(Pid, <<>>, Bin) -> + rcv(Pid, Bin); + +recv(Pid, {TRef, Head}, Bin) -> + erlang:cancel_timer(TRef), + rcv(Pid, Head, Bin). + +%% rcv/3 + +%% Not even the first four bytes of the header. +rcv(Pid, Head, Bin) + when is_binary(Head) -> + rcv(Pid, <<Head/binary, Bin/binary>>); + +%% Or enough to know how many bytes to extract. +rcv(Pid, {Len, N, Head, Acc}, Bin) -> + rcv(Pid, Len, N + size(Bin), Head, [Bin | Acc]). + +%% rcv/5 + +%% Extract a message for which we have all bytes. +rcv(Pid, Len, N, Head, Acc) + when Len =< N -> + rcv(Pid, rcv1(Pid, Len, bin(Head, Acc))); + +%% Wait for more packets. +rcv(_, Len, N, Head, Acc) -> + {start_timer(), {Len, N, Head, Acc}}. + +%% rcv/2 + +%% Nothing left. +rcv(_, <<>> = Bin) -> + Bin; + +%% Well, this isn't good. Chances are things will go south from here +%% but if we're lucky then the bytes we have extend to an intended +%% message boundary and we can recover by simply discarding them, +%% which is the result of receiving them. +rcv(Pid, <<_:1/binary, Len:24, _/binary>> = Bin) + when Len < 20 -> + diameter_peer:recv(Pid, Bin), + <<>>; + +%% Enough bytes to extract a message. +rcv(Pid, <<_:1/binary, Len:24, _/binary>> = Bin) + when Len =< size(Bin) -> + rcv(Pid, rcv1(Pid, Len, Bin)); + +%% Or not: wait for more packets. +rcv(_, <<_:1/binary, Len:24, _/binary>> = Head) -> + {start_timer(), {Len, size(Head), Head, []}}; + +%% Not even 4 bytes yet. +rcv(_, Head) -> + {start_timer(), Head}. + +%% rcv1/3 + +rcv1(Pid, Len, Bin) -> + <<Msg:Len/binary, Rest/binary>> = Bin, + diameter_peer:recv(Pid, Msg), + Rest. + +%% bin/[12] + +bin(Head, Acc) -> + list_to_binary([Head | lists:reverse(Acc)]). + +bin({_, _, Head, Acc}) -> + bin(Head, Acc); +bin(Bin) + when is_binary(Bin) -> + Bin. + +%% start_timer/0 + +%% An erroneously large message length may leave us with a fragment +%% that lingers if the peer doesn't have anything more to send. Start +%% a timer to force reception if an incoming message doesn't arrive +%% first. This won't stop a peer from sending a large bogus value and +%% following it up however but such a state of affairs can only go on +%% for so long since an unanswered DWR will eventually be the result. +%% +%% An erroneously small message length causes problems as well but +%% since all messages with length problems are discarded this should +%% also eventually lead to watchdog failover. + +start_timer() -> + erlang:start_timer(?FRAGMENT_TIMEOUT, self(), flush). + +flush(TRef, #transport{parent = Pid, frag = {TRef, Head}} = S) -> + diameter_peer:recv(Pid, bin(Head)), + S#transport{frag = <<>>}; +flush(_, S) -> + S. + +%% accept/2 + +accept(gen_tcp, LSock) -> + gen_tcp:accept(LSock); +accept(Mod, LSock) -> + Mod:accept(LSock). + +%% connect/4 + +connect(gen_tcp, Host, Port, Opts) -> + gen_tcp:connect(Host, Port, Opts); +connect(Mod, Host, Port, Opts) -> + Mod:connect(Host, Port, Opts). + +%% send/3 + +send(gen_tcp, Sock, Bin) -> + gen_tcp:send(Sock, Bin); +send(M, Sock, Bin) -> + M:send(Sock, Bin). + +%% setopts/3 + +setopts(gen_tcp, Sock, Opts) -> + inet:setopts(Sock, Opts); +setopts(M, Sock, Opts) -> + M:setopts(Sock, Opts). + +%% setopts/2 + +setopts(M, Sock) -> + case setopts(M, Sock, [{active, once}]) of + ok -> ok; + X -> x({setopts, M, Sock, X}) %% possibly on peer disconnect + end. + +%% lport/2 + +lport(gen_tcp, Sock) -> + inet:port(Sock); +lport(M, Sock) -> + M:port(Sock). diff --git a/lib/diameter/src/transport/diameter_tcp_sup.erl b/lib/diameter/src/transport/diameter_tcp_sup.erl new file mode 100644 index 0000000000..1016fa2d9b --- /dev/null +++ b/lib/diameter/src/transport/diameter_tcp_sup.erl @@ -0,0 +1,78 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(diameter_tcp_sup). + +-behaviour(supervisor). + +%% interface +-export([start/0, + start_child/1]). + +%% internal exports +-export([start_link/1, + init/1]). + +%% Start multiple supervisors only because a child can't start another +%% child before supervisor:start_child/2 has returned, although two is +%% really sufficient (listeners and monitors can be under the same). +-define(TRANSPORT_SUP, diameter_tcp_transport_sup). +-define(LISTENER_SUP, diameter_tcp_listener_sup). +-define(MONITOR_SUP, diameter_tcp_monitor_sup). + +%% start/0 +%% +%% Start the TCP-specific supervisors. + +start() -> + diameter_transport_sup:start_child(?TRANSPORT_SUP, ?MODULE), + diameter_transport_sup:start_child(?LISTENER_SUP, ?MODULE), + diameter_transport_sup:start_child(?MONITOR_SUP, ?MODULE). + +%% start_child/1 +%% +%% Start a worker under one of the child supervisors. + +start_child(T) -> + SupRef = case element(1,T) of + accept -> ?TRANSPORT_SUP; + connect -> ?TRANSPORT_SUP; + listen -> ?LISTENER_SUP; + monitor -> ?MONITOR_SUP + end, + supervisor:start_child(SupRef, [T]). + +%% start_link/1 +%% +%% Callback from diameter_transport_sup as a result of start/0. +%% Starts a child supervisor under the transport supervisor. + +start_link(Name) -> + supervisor:start_link({local, Name}, ?MODULE, []). + +init([]) -> + Mod = diameter_tcp, + Flags = {simple_one_for_one, 0, 1}, + ChildSpec = {Mod, + {Mod, start_link, []}, + temporary, + 1000, + worker, + [Mod]}, + {ok, {Flags, [ChildSpec]}}. diff --git a/lib/diameter/src/transport/diameter_transport_sup.erl b/lib/diameter/src/transport/diameter_transport_sup.erl new file mode 100644 index 0000000000..6457ab78b0 --- /dev/null +++ b/lib/diameter/src/transport/diameter_transport_sup.erl @@ -0,0 +1,68 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%% Top supervisor for transport processes. +%% + +-module(diameter_transport_sup). + +-behaviour(supervisor). + +-export([start_link/0, %% supervisor start + start_child/2]). + +%% supervisor callback +-export([init/1]). + +%% --------------------------------------------------------------------------- + +%% start_link/0 +%% +%% Start the transport top supervisor. This is started as a child at +%% at application start, from diameter_sup.erl. Protocol-specific +%% supervisors are started as children of this supervisor dynamically +%% by calling start_child/2. (Eg. diameter_tcp_sup:start/0, which +%% is called from diameter_tcp:start/3 to start supervisors the +%% first time a TCP transport process is started.) + +start_link() -> + SupName = {local, ?MODULE}, + supervisor:start_link(SupName, ?MODULE, []). + +%% start_child/2 +%% +%% Start a protocol-specific supervisor under the top supervisor. + +start_child(Name, Module) -> + Spec = {Name, + {Module, start_link, [Name]}, + permanent, + 1000, + supervisor, + [Module]}, + supervisor:start_child(?MODULE, Spec). + +%% --------------------------------------------------------------------------- + +%% Top supervisor callback. +init([]) -> + Flags = {one_for_one, 0, 1}, + Workers = [], %% Each protocol starts its supervisor on demand. + {ok, {Flags, Workers}}. diff --git a/lib/diameter/src/transport/modules.mk b/lib/diameter/src/transport/modules.mk new file mode 100644 index 0000000000..a0dc3cf2c0 --- /dev/null +++ b/lib/diameter/src/transport/modules.mk @@ -0,0 +1,29 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +MODULES = \ + diameter_etcp \ + diameter_etcp_sup \ + diameter_tcp \ + diameter_tcp_sup \ + diameter_sctp \ + diameter_sctp_sup \ + diameter_transport_sup + +HRL_FILES = diff --git a/lib/diameter/subdirs.mk b/lib/diameter/subdirs.mk new file mode 100644 index 0000000000..d80c97d57a --- /dev/null +++ b/lib/diameter/subdirs.mk @@ -0,0 +1,20 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +SUB_DIRS = src doc/src diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile new file mode 100644 index 0000000000..823e2f0311 --- /dev/null +++ b/lib/diameter/test/Makefile @@ -0,0 +1,408 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk +else +include $(DIAMETER_TOP)/make/target.mk +include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk +endif + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(DIAMETER_VSN) + + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/diameter_test + +ifeq ($(findstring win32,$(TARGET)),win32) + +MAKEFILE_SRC = Makefile.win32.src + +else + +MAKEFILE_SRC = Makefile.src + +endif + +ifeq ($(TT_DIR),) +TT_DIR = /tmp +endif + + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +include modules.mk + +EBIN = . + +HRL_FILES = diameter_test_lib.hrl + +ERL_FILES = $(MODULES:%=%.erl) + +SOURCE = $(HRL_FILES) $(ERL_FILES) + +TARGET_FILES = $(MODULES:%=%.$(EMULATOR)) + +APP_CASES = app appup + +TRANSPORT_CASES = tcp + +ALL_CASES = \ + $(APP_CASES) \ + compiler conf sync session stats reg peer \ + $(TRANSPORT_CASES) + + +EMAKEFILE = Emakefile +ifneq ($(ERL_TOP),) +MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile) +else +MAKE_EMAKE = $(wildcard $(DIAMETER_TOP)/make/make_emakefile) +endif + +ifeq ($(MAKE_EMAKE),) +BUILDTARGET = $(TARGET_FILES) +RELTEST_FILES = $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) $(SOURCE) +else +BUILDTARGET = emakebuild +RELTEST_FILES = $(EMAKEFILE) $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) $(SOURCE) +endif + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +include ../src/app/diameter.mk + +ifeq ($(USE_DIAMETER_TEST_CODE),true) +ERL_COMPILE_FLAGS += -DDIAMETER_TEST_CODE=mona_lisa_spelar_doom +endif + +ifeq ($(USE_DIAMETER_HIPE),true) +ERL_COMPILE_FLAGS += +native -DDIAMETER_hipe_special=true +endif + +ifneq ($(ERL_TOP),) +ERL_COMPILE_FLAGS += \ + $(DIAMETER_ERL_COMPILE_FLAGS) \ + -pa $(ERL_TOP)/lib/test_server/ebin \ + -I$(ERL_TOP)/lib/test_server/include +else +ERL_COMPILE_FLAGS += \ + $(DIAMETER_ERL_COMPILE_FLAGS) \ + -pa $(TEST_SERVER_DIR)/ebin \ + -I$(TEST_SERVER_DIR)/include +endif + +ERL_PATH = \ + -pa ../../$(APPLICATION)/ebin \ + -pa ../../et/ebin + +ifndef SUITE +SUITE = diameter_SUITE +endif + +ESTOP = -s init stop + +ifeq ($(DONT_STOP),true) +MAYBE_ESTOP = +else +MAYBE_ESTOP = $(ESTOP) +endif + +ETVIEW = -s et_viewer +ifeq ($(USE_ET_VIEWER),true) +MAYBE_ETVIEW = +else +MAYBE_ETVIEW = $(ETVIEW) +endif + +ifeq ($(MERL),) +MERL = $(ERL) +endif + +ARGS += -noshell + +ifeq ($(DISABLE_TC_TIMEOUT),true) +ARGS += -diameter_test_timeout +endif + + +DIAMETER_TEST_SERVER = diameter_test_server + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +tests debug opt: $(BUILDTARGET) + +targets: $(TARGET_FILES) + +.PHONY: emakebuild + +emakebuild: $(EMAKEFILE) + +$(EMAKEFILE): + $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' | grep -v Warning > $(EMAKEFILE) + $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) | grep -v Warning >> $(EMAKEFILE) + +clean: + rm -f $(EMAKEFILE) + rm -f $(TARGET_FILES) + rm -f errs core *~ + +docs: + +info: + @echo "MAKE_EMAKE = $(MAKE_EMAKE)" + @echo "EMAKEFILE = $(EMAKEFILE)" + @echo "BUILDTARGET = $(BUILDTARGET)" + @echo "" + @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" + @echo "ERL = $(ERL)" + @echo "ERLC = $(ERLC)" + @echo "MERL = $(MERL)" + @echo "" + @echo "ARGS = $(ARGS)" + @echo "" + @echo "HRL_FILES = $(HRL_FILES)" + @echo "ERL_FILES = $(ERL_FILES)" + @echo "TARGET_FILES = $(TARGET_FILES)" + @echo "" + +help: + @echo "" + @echo "This Makefile controls the test of the $(APPLICATION) application. " + @echo "" + @echo "There are two separate ways to perform the test of $(APPLICATION)." + @echo "" + @echo " a) Run the official OTP test-server (which we do not describe here)" + @echo "" + @echo " b) Run the test-server provided with this application. " + @echo " There are a number of targets to run the entire or parts" + @echo " of this applications ($(APPLICATION)) test-suite" + @echo "" + @echo "Targets:" + @echo "" + @echo " help" + @echo " Print this info" + @echo "" + @echo " info" + @echo " Prints various environment variables. " + @echo " May be useful when debugging the Makefile. " + @echo "" + @echo " tests | debug | opt " + @echo " Compile all test-code. " + @echo "" + @echo " clean " + @echo " Remove all targets. " + @echo "" + @echo " test" + @echo " Run the entire $(APPLICATION) test-suite. " + @echo "" + @echo " app" + @echo " Run the $(APPLICATION) application sub-test-suite. " + @echo "" + @echo " appup" + @echo " Run the $(APPLICATION) application upgrade (appup) sub-test-suite. " + @echo "" + @echo " compiler" + @echo " Run the $(APPLICATION) compiler sub-test-suite(s). " + @echo "" + @echo " conf" + @echo " Run the $(APPLICATION) config sub-test-suite. " + @echo " Checks various aspects of the $(APPLICATION) configuration. " + @echo "" + @echo " sync" + @echo " Run the $(APPLICATION) sync sub-test-suite. " + @echo "" + @echo " session" + @echo " Run the $(APPLICATION) session sub-test-suite. " + @echo "" + @echo " stats" + @echo " Run the $(APPLICATION) stats sub-test-suite. " + @echo "" + @echo " reg" + @echo " Run the $(APPLICATION) reg sub-test-suite. " + @echo "" + @echo " peer" + @echo " Run the $(APPLICATION) peer sub-test-suite" + @echo "" + @echo " ptab" + @echo " Run the $(APPLICATION) persistent-table sub-test-suite" + @echo "" + @echo " tcp" + @echo " Run the $(APPLICATION) tcp sub-test-suite" + @echo "" + @echo "" + + +# ---------------------------------------------------- +# Special Targets +# ---------------------------------------------------- + +all: make + @echo "make sure epmd is new" + @epmd -kill > /dev/null + @echo "Running all sub-suites separatelly" + @for i in $(ALL_CASES); do \ + echo "SUITE: $$i"; \ + clearmake -V $$i > $$i.log; \ + done + +aall: make + @echo "make sure epmd is new" + @epmd -kill > /dev/null + @echo "Running all app sub-suites separatelly" + @for i in $(APP_CASES); do \ + echo "SUITE: $$i"; \ + clearmake -V $$i > $$i.log; \ + done + echo "done" + +tall: make + @echo "make sure epmd is new" + @epmd -kill > /dev/null + @echo "Running all transport sub-suites separatelly" + @for i in $(TRANSPORT_CASES); do \ + echo "SUITE: $$i"; \ + clearmake -V $$i > $$i.log; \ + done + +make: targets + +test: make + $(MERL) $(ARGS) -sname diameter_test $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t $(SUITE) \ + $(MAYBE_ESTOP) + +utest: make + $(MERL) $(ARGS) -sname diameter_utest $(ERL_PATH) \ + $(MAYBE_ETVIEW) \ + -s $(DIAMETER_TEST_SERVER) t $(SUITE) \ + $(ESTOP) + +# ftest: make +# $(MERL) $(ARGS) -sname diameter_ftest $(ERL_PATH) \ +# -s diameter_filter \ +# -s $(DIAMETER_TEST_SERVER) t $(SUITE) \ +# $(ESTOP) +# + +########################## + +# tickets: make +# $(MERL) $(ARGS) -sname diameter_tickets $(ERL_PATH) \ +# -s $(DIAMETER_TEST_SERVER) tickets $(SUITE) \ +# $(ESTOP) +# + +app: make + $(MERL) $(ARGS) -sname diameter_app $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_app_test \ + $(ESTOP) + +appup: make + $(MERL) $(ARGS) -sname diameter_appup $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_appup_test \ + $(ESTOP) + +compiler: make + $(MERL) $(ARGS) -sname diameter_compiler $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_compiler_test \ + $(ESTOP) + +conf: make + $(MERL) $(ARGS) -sname diameter_config $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_config_test \ + $(ESTOP) + +sync: make + $(MERL) $(ARGS) -sname diameter_sync $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_sync_test \ + $(ESTOP) + +session: make + $(MERL) $(ARGS) -sname diameter_session $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_session_test \ + $(ESTOP) + +stats: make + $(MERL) $(ARGS) -sname diameter_stats $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_stats_test \ + $(ESTOP) + +reg: make + $(MERL) $(ARGS) -sname diameter_reg $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_reg_test \ + $(ESTOP) + +peer: make + $(MERL) $(ARGS) -sname diameter_peer $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_peer_test \ + $(ESTOP) + +ptab: make + $(MERL) $(ARGS) -sname diameter_persistent_table $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_persistent_table_test \ + $(ESTOP) + +tcp: make + $(MERL) $(ARGS) -sname diameter_tcp $(ERL_PATH) \ + -s $(DIAMETER_TEST_SERVER) t diameter_tcp_test \ + $(ESTOP) + + +node: + $(MERL) -sname diameter $(ERL_PATH) + + +# ---------------------------------------------------- +# Release Targets +# ---------------------------------------------------- + +ifneq ($(ERL_TOP),) +include $(ERL_TOP)/make/otp_release_targets.mk +else +include $(DIAMETER_TOP)/make/release_targets.mk +endif + +release_spec: + +release_docs_spec: + +release_tests_spec: tests + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(RELTEST_FILES) $(RELSYSDIR) +# $(INSTALL_DATA) $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) \ +# $(HRL_FILES) $(ERL_FILES) \ +# $(RELSYSDIR) +# + chmod -f -R u+w $(RELSYSDIR) + diff --git a/lib/diameter/test/diameter.cover b/lib/diameter/test/diameter.cover new file mode 100644 index 0000000000..5fde6c7d01 --- /dev/null +++ b/lib/diameter/test/diameter.cover @@ -0,0 +1,6 @@ +%% -*- erlang -*- +{exclude, + [ + ] +}. + diff --git a/lib/diameter/test/diameter.spec b/lib/diameter/test/diameter.spec new file mode 100644 index 0000000000..a6e71762eb --- /dev/null +++ b/lib/diameter/test/diameter.spec @@ -0,0 +1,9 @@ +{suites, "../diameter_test", all}. +%%{skip, {diameter_compiler_test, all, "Not yet implemented"}}. +%%{skip, {diameter_config_test, all, "Not yet implemented"}}. +%%{skip, {diameter_peer_test, all, "Not yet implemented"}}. +%%{skip, {diameter_reg_test, all, "Not yet implemented"}}. +%%{skip, {diameter_session_test, all, "Not yet implemented"}}. +%%{skip, {diameter_stats_test, all, "Not yet implemented"}}. +%%{skip, {diameter_sync_test, all, "Not yet implemented"}}. +%%{skip, {diameter_tcp_test, all, "Not yet implemented"}}. diff --git a/lib/diameter/test/diameter_SUITE.erl b/lib/diameter/test/diameter_SUITE.erl new file mode 100644 index 0000000000..443cf90e92 --- /dev/null +++ b/lib/diameter/test/diameter_SUITE.erl @@ -0,0 +1,108 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Test application config +%%---------------------------------------------------------------------- + +-module(diameter_SUITE). + +-export([ + suite/0, + all/0, + groups/0, + + init_per_testcase/2, + fin_per_testcase/2, + + init_per_suite/1, + end_per_suite/1, + + init_per_group/2, + end_per_group/2, + + init/0 + ]). + +-export([t/0, t/1]). + + +-include("diameter_test_lib.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + +init() -> + process_flag(trap_exit, true), + ?FLUSH(). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Top test case + +suite() -> + [{ct_hooks, [{ts_install_cth, [{nodenames,1}]}]}]. + +all() -> + [ + {group, app}, + {group, appup}, + {group, compiler}, + {group, config}, + {group, sync}, + {group, session}, + {group, stats}, + {group, reg}, + {group, peer}, + {group, tcp} + ]. + +groups() -> + [{app, [], [{diameter_app_test, all}]}, + {appup, [], [{diameter_appup_test, all}]}, + {compiler, [], [{diameter_compiler_test, all}]}, + {config, [], [{diameter_config_test, all}]}, + {sync, [], [{diameter_sync_test, all}]}, + {session, [], [{diameter_session_test, all}]}, + {stats, [], [{diameter_stats_test, all}]}, + {reg, [], [{diameter_reg_test, all}]}, + {peer, [], [{diameter_peer_test, all}]}, + {tcp, [], [{diameter_tcp_test, all}]}]. + + +init_per_suite(Config) -> + Config. + +end_per_suite(_Config) -> + ok. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. diff --git a/lib/diameter/test/diameter_app_test.erl b/lib/diameter/test/diameter_app_test.erl new file mode 100644 index 0000000000..7173c39caf --- /dev/null +++ b/lib/diameter/test/diameter_app_test.erl @@ -0,0 +1,393 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the application specifics of the Diameter application +%%---------------------------------------------------------------------- +-module(diameter_app_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2, + + fields/1, + modules/1, + exportall/1, + app_depend/1, + undef_funcs/1 + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(undef_funcs = Case, Config) -> + NewConfig = [{tc_timeout, ?MINUTES(10)} | Config], + diameter_test_server:init_per_testcase(Case, NewConfig); +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + [ + fields, + modules, + exportall, + app_depend, + undef_funcs + ]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + io:format("~w:init_per_suite -> entry with" + "~n Config: ~p" + "~n", [?MODULE, Config]), + case is_app(diameter) of + {ok, AppFile} -> + io:format("AppFile: ~n~p~n", [AppFile]), + %% diameter:print_version_info(), + [{app_file, AppFile}|Config]; + {error, Reason} -> + ?FAIL(Reason) + end. + +is_app(App) -> + LibDir = code:lib_dir(App), + File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]), + case file:consult(File) of + {ok, [{application, App, AppFile}]} -> + {ok, AppFile}; + Error -> + {error, {invalid_format, Error}} + end. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +fields(suite) -> + []; +fields(doc) -> + []; +fields(Config) when is_list(Config) -> + AppFile = ?KEY1SEARCH(app_file, Config), + Fields = [vsn, description, modules, registered, applications], + case check_fields(Fields, AppFile, []) of + [] -> + ok; + Missing -> + ?FAIL({missing_fields, Missing}) + end. + +check_fields([], _AppFile, Missing) -> + Missing; +check_fields([Field|Fields], AppFile, Missing) -> + check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)). + +check_field(Name, AppFile, Missing) -> + io:format("checking field: ~p~n", [Name]), + case lists:keymember(Name, 1, AppFile) of + true -> + Missing; + false -> + [Name|Missing] + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +modules(suite) -> + []; +modules(doc) -> + []; +modules(Config) when is_list(Config) -> + AppFile = ?KEY1SEARCH(app_file, Config), + Mods = ?KEY1SEARCH(modules, AppFile), + EbinList = get_ebin_mods(diameter), + case missing_modules(Mods, EbinList, []) of + [] -> + ok; + Missing -> + throw({error, {missing_modules, Missing}}) + end, + Allowed = [diameter_codegen, + diameter_make, + diameter_spec_scan, + diameter_spec_util], + case extra_modules(Mods, EbinList, Allowed, []) of + [] -> + ok; + Extra -> + throw({error, {extra_modules, Extra}}) + end, + {ok, Mods}. + +get_ebin_mods(App) -> + LibDir = code:lib_dir(App), + EbinDir = filename:join([LibDir,"ebin"]), + {ok, Files0} = file:list_dir(EbinDir), + Files1 = [lists:reverse(File) || File <- Files0], + [list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1]. + + +missing_modules([], _Ebins, Missing) -> + Missing; +missing_modules([Mod|Mods], Ebins, Missing) -> + case lists:member(Mod, Ebins) of + true -> + missing_modules(Mods, Ebins, Missing); + false -> + io:format("missing module: ~p~n", [Mod]), + missing_modules(Mods, Ebins, [Mod|Missing]) + end. + + +extra_modules(_Mods, [], Allowed, Extra) -> + Extra--Allowed; +extra_modules(Mods, [Mod|Ebins], Allowed, Extra) -> + case lists:member(Mod, Mods) of + true -> + extra_modules(Mods, Ebins, Allowed, Extra); + false -> + io:format("supefluous module: ~p~n", [Mod]), + extra_modules(Mods, Ebins, Allowed, [Mod|Extra]) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +exportall(suite) -> + []; +exportall(doc) -> + []; +exportall(Config) when is_list(Config) -> + AppFile = ?KEY1SEARCH(app_file, Config), + Mods = ?KEY1SEARCH(modules, AppFile), + check_export_all(Mods). + + +check_export_all([]) -> + ok; +check_export_all([Mod|Mods]) -> + case (catch apply(Mod, module_info, [compile])) of + {'EXIT', {undef, _}} -> + check_export_all(Mods); + O -> + case lists:keysearch(options, 1, O) of + false -> + check_export_all(Mods); + {value, {options, List}} -> + case lists:member(export_all, List) of + true -> + throw({error, {export_all, Mod}}); + false -> + check_export_all(Mods) + end + end + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +app_depend(suite) -> + []; +app_depend(doc) -> + []; +app_depend(Config) when is_list(Config) -> + AppFile = ?KEY1SEARCH(app_file, Config), + Apps = ?KEY1SEARCH(applications, AppFile), + check_apps(Apps). + + +check_apps([]) -> + ok; +check_apps([App|Apps]) -> + case is_app(App) of + {ok, _} -> + check_apps(Apps); + Error -> + throw({error, {missing_app, {App, Error}}}) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +undef_funcs(suite) -> + []; +undef_funcs(doc) -> + []; +undef_funcs(Config) when is_list(Config) -> + ?SKIP(diameter_not_known_by_xref), + App = diameter, + AppFile = ?KEY1SEARCH(app_file, Config), + Mods = ?KEY1SEARCH(modules, AppFile), + Root = code:root_dir(), + LibDir = code:lib_dir(App), + EbinDir = filename:join([LibDir,"ebin"]), + XRefTestName = undef_funcs_make_name(App, xref_test_name), + try + begin + XRef = xref_start(XRefTestName), + xref_set_defaults(XRef, [{verbose,false},{warnings,false}]), + XRefName = undef_funcs_make_name(App, xref_name), + XRefName = xref_add_release(XRef, Root, XRefName), + xref_replace_application(XRef, App, EbinDir), + Undefs = xref_analyze(XRef), + xref_stop(XRef), + analyze_undefined_function_calls(Undefs, Mods, []) + end + catch + throw:{error, Reason} -> + ?FAIL(Reason) + end. + + +xref_start(XRefTestName) -> + case (catch xref:start(XRefTestName)) of + {ok, XRef} -> + XRef; + {error, Reason} -> + throw({error, {failed_starting_xref, Reason}}); + Error -> + throw({error, {failed_starting_xref, Error}}) + end. + +xref_set_defaults(XRef, Defs) -> + case (catch xref:set_default(XRef, Defs)) of + ok -> + ok; + Error -> + throw({error, {failed_setting_defaults, Defs, Error}}) + end. + +xref_add_release(XRef, Root, Name) -> + case (catch xref:add_release(XRef, Root, {name, Name})) of + {ok, XRefName} -> + XRefName; + {error, Reason} -> + throw({error, {failed_adding_release, Reason}}); + Error -> + throw({error, {failed_adding_release, Error}}) + end. + +xref_replace_application(XRef, App, EbinDir) -> + case (catch xref:replace_application(XRef, App, EbinDir)) of + {ok, App} -> + ok; + {error, XRefMod, Reason} -> + throw({error, {failed_replacing_app, XRefMod, Reason}}); + Error -> + throw({error, {failed_replacing_app, Error}}) + end. + +xref_analyze(XRef) -> + case (catch xref:analyze(XRef, undefined_function_calls)) of + {ok, Undefs} -> + Undefs; + {error, Reason} -> + throw({error, {failed_detecting_func_calls, Reason}}); + Error -> + throw({error, {failed_detecting_func_calls, Error}}) + end. + +xref_stop(XRef) -> + xref:stop(XRef). + +analyze_undefined_function_calls([], _, []) -> + ok; +analyze_undefined_function_calls([], _, AppUndefs) -> + exit({suite_failed, {undefined_function_calls, AppUndefs}}); +analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs], + AppModules, AppUndefs) -> + %% Check that this module is our's + case lists:member(Mod,AppModules) of + true -> + {Calling,Called} = AppUndef, + {Mod1,Func1,Ar1} = Calling, + {Mod2,Func2,Ar2} = Called, + io:format("undefined function call: " + "~n ~w:~w/~w calls ~w:~w/~w~n", + [Mod1,Func1,Ar1,Mod2,Func2,Ar2]), + analyze_undefined_function_calls(Undefs, AppModules, + [AppUndef|AppUndefs]); + false -> + io:format("dropping ~p~n", [Mod]), + analyze_undefined_function_calls(Undefs, AppModules, AppUndefs) + end. + +%% This function is used simply to avoid cut-and-paste errors later... +undef_funcs_make_name(App, PostFix) -> + list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + +%% fail(Reason) -> +%% exit({suite_failed, Reason}). + +%% ?KEY1SEARCH(Key, L) -> +%% case lists:keysearch(Key, 1, L) of +%% undefined -> +%% fail({not_found, Key, L}); +%% {value, {Key, Value}} -> +%% Value +%% end. diff --git a/lib/diameter/test/diameter_appup_test.erl b/lib/diameter/test/diameter_appup_test.erl new file mode 100644 index 0000000000..97a089e01a --- /dev/null +++ b/lib/diameter/test/diameter_appup_test.erl @@ -0,0 +1,539 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the application specifics of the Diameter application +%%---------------------------------------------------------------------- +-module(diameter_appup_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2, + + appup/1 + ]). + +-export([t/0, t/1]). + +-compile({no_auto_import,[error/1]}). + +-include("diameter_test_lib.hrl"). + +-define(APPLICATION, diameter). + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + [appup]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + AppFile = file_name(?APPLICATION, ".app"), + AppupFile = file_name(?APPLICATION, ".appup"), + [{app_file, AppFile}, {appup_file, AppupFile}|Config]. + + +file_name(App, Ext) -> + LibDir = code:lib_dir(App), + filename:join([LibDir, "ebin", atom_to_list(App) ++ Ext]). + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +appup(suite) -> + []; +appup(doc) -> + "perform a simple check of the appup file"; +appup(Config) when is_list(Config) -> + AppupFile = key1search(appup_file, Config), + AppFile = key1search(app_file, Config), + Modules = modules(AppFile), + check_appup(AppupFile, Modules). + +modules(File) -> + case file:consult(File) of + {ok, [{application,diameter,Info}]} -> + case lists:keysearch(modules,1,Info) of + {value, {modules, Modules}} -> + Modules; + false -> + fail({bad_appinfo, Info}) + end; + Error -> + fail({bad_appfile, Error}) + end. + + +check_appup(AppupFile, Modules) -> + case file:consult(AppupFile) of + {ok, [{V, UpFrom, DownTo}]} -> + check_appup(V, UpFrom, DownTo, Modules); + Else -> + fail({bad_appupfile, Else}) + end. + + +check_appup(V, UpFrom, DownTo, Modules) -> + check_version(V), + check_depends(up, UpFrom, Modules), + check_depends(down, DownTo, Modules), + check_module_subset(UpFrom), + check_module_subset(DownTo), + ok. + + +check_depends(_, [], _) -> + ok; +check_depends(UpDown, [Dep|Deps], Modules) -> + check_depend(UpDown, Dep, Modules), + check_depends(UpDown, Deps, Modules). + + +check_depend(up = UpDown, {add_application, ?APPLICATION} = Instr, Modules) -> + d("check_instructions(~w) -> entry with" + "~n Instruction: ~p" + "~n Modules: ~p", [UpDown, Instr, Modules]), + ok; +check_depend(down = UpDown, {remove_application, ?APPLICATION} = Instr, + Modules) -> + d("check_instructions(~w) -> entry with" + "~n Instruction: ~p" + "~n Modules: ~p", [UpDown, Instr, Modules]), + ok; +check_depend(UpDown, {V, Instructions}, Modules) -> + d("check_instructions(~w) -> entry with" + "~n V: ~p" + "~n Modules: ~p", [UpDown, V, Modules]), + check_version(V), + case check_instructions(UpDown, + Instructions, Instructions, [], [], Modules) of + {_Good, []} -> + ok; + {_, Bad} -> + fail({bad_instructions, Bad, UpDown}) + end. + + +check_instructions(_, [], _, Good, Bad, _) -> + {lists:reverse(Good), lists:reverse(Bad)}; +check_instructions(UpDown, [Instr|Instrs], AllInstr, Good, Bad, Modules) -> + d("check_instructions(~w) -> entry with" + "~n Instr: ~p", [UpDown,Instr]), + case (catch check_instruction(UpDown, Instr, AllInstr, Modules)) of + ok -> + check_instructions(UpDown, Instrs, AllInstr, + [Instr|Good], Bad, Modules); + {error, Reason} -> + d("check_instructions(~w) -> bad instruction: " + "~n Reason: ~p", [UpDown,Reason]), + check_instructions(UpDown, Instrs, AllInstr, Good, + [{Instr, Reason}|Bad], Modules) + end. + +%% A new module is added +check_instruction(up, {add_module, Module}, _, Modules) + when is_atom(Module) -> + d("check_instruction -> entry when up-add_module instruction with" + "~n Module: ~p", [Module]), + check_module(Module, Modules); + +%% An old module is re-added +check_instruction(down, {add_module, Module}, _, Modules) + when is_atom(Module) -> + d("check_instruction -> entry when down-add_module instruction with" + "~n Module: ~p", [Module]), + case (catch check_module(Module, Modules)) of + {error, {unknown_module, Module, Modules}} -> + ok; + ok -> + error({existing_readded_module, Module}) + end; + +%% Removing a module on upgrade: +%% - the module has been removed from the app-file. +%% - check that no module depends on this (removed) module +check_instruction(up, {remove, {Module, Pre, Post}}, _, Modules) + when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) -> + d("check_instruction -> entry when up-remove instruction with" + "~n Module: ~p" + "~n Pre: ~p" + "~n Post: ~p", [Module, Pre, Post]), + case (catch check_module(Module, Modules)) of + {error, {unknown_module, Module, Modules}} -> + check_purge(Pre), + check_purge(Post); + ok -> + error({existing_removed_module, Module}) + end; + +%% Removing a module on downgrade: the module exist +%% in the app-file. +check_instruction(down, {remove, {Module, Pre, Post}}, AllInstr, Modules) + when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) -> + d("check_instruction -> entry when down-remove instruction with" + "~n Module: ~p" + "~n Pre: ~p" + "~n Post: ~p", [Module, Pre, Post]), + case (catch check_module(Module, Modules)) of + ok -> + check_purge(Pre), + check_purge(Post), + check_no_remove_depends(Module, AllInstr); + {error, {unknown_module, Module, Modules}} -> + error({nonexisting_removed_module, Module}) + end; + +check_instruction(_, {load_module, Module, Pre, Post, Depend}, + AllInstr, Modules) + when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) -> + d("check_instruction -> entry when load_module instruction with" + "~n Module: ~p" + "~n Pre: ~p" + "~n Post: ~p" + "~n Depend: ~p", [Module, Pre, Post, Depend]), + check_module(Module, Modules), + check_module_depend(Module, Depend, Modules), + check_module_depend(Module, Depend, updated_modules(AllInstr, [])), + check_purge(Pre), + check_purge(Post); + +check_instruction(_, {update, Module, Change, Pre, Post, Depend}, + AllInstr, Modules) + when is_atom(Module) andalso is_atom(Pre) andalso is_atom(Post) andalso is_list(Depend) -> + d("check_instruction -> entry when update instruction with" + "~n Module: ~p" + "~n Change: ~p" + "~n Pre: ~p" + "~n Post: ~p" + "~n Depend: ~p", [Module, Change, Pre, Post, Depend]), + check_module(Module, Modules), + check_module_depend(Module, Depend, Modules), + check_module_depend(Module, Depend, updated_modules(AllInstr, [])), + check_change(Change), + check_purge(Pre), + check_purge(Post); + +check_instruction(_, {update, Module, supervisor}, _, Modules) + when is_atom(Module) -> + check_module(Module, Modules); + +check_instruction(_, {apply, {Module, Function, Args}}, _, Modules) + when is_atom(Module) andalso is_atom(Function) andalso is_list(Args) -> + d("check_instruction -> entry when down-apply instruction with" + "~n Module: ~p" + "~n Function: ~p" + "~n Args: ~p", [Module, Function, Args]), + check_module(Module, Modules), + check_apply(Module, Function, Args); + +check_instruction(_, {restart_application, ?APPLICATION}, _AllInstr, _Modules) -> + ok; + +check_instruction(_, Instr, _AllInstr, _Modules) -> + d("check_instruction -> entry when unknown instruction with" + "~n Instr: ~p", [Instr]), + error({error, {unknown_instruction, Instr}}). + + +%% If Module X depends on Module Y, then module Y must have an update +%% instruction of some sort (otherwise the depend is faulty). +updated_modules([], Modules) -> + d("update_modules -> entry when done with" + "~n Modules: ~p", [Modules]), + Modules; +updated_modules([Instr|Instrs], Modules) -> + d("update_modules -> entry with" + "~n Instr: ~p" + "~n Modules: ~p", [Instr,Modules]), + Module = instruction_module(Instr), + d("update_modules -> Module: ~p", [Module]), + updated_modules(Instrs, [Module|Modules]). + +instruction_module({add_module, Module}) -> + Module; +instruction_module({remove, {Module, _, _}}) -> + Module; +instruction_module({load_module, Module, _, _, _}) -> + Module; +instruction_module({update, Module, _, _, _, _}) -> + Module; +instruction_module({apply, {Module, _, _}}) -> + Module; +instruction_module(Instr) -> + d("instruction_module -> entry when unknown instruction with" + "~n Instr: ~p", [Instr]), + error({error, {unknown_instruction, Instr}}). + + +%% Check that the modules handled in an instruction set for version X +%% is a subset of the instruction set for version X-1. +check_module_subset(Instructions) -> + do_check_module_subset(modules_of(Instructions)). + +do_check_module_subset([]) -> + ok; +do_check_module_subset([_]) -> + ok; +do_check_module_subset([{_V1, Mods1}|T]) -> + {V2, Mods2} = hd(T), + %% Check that the modules in V1 is a subset of V2 + case do_check_module_subset2(Mods1, Mods2) of + ok -> + do_check_module_subset(T); + {error, Modules} -> + fail({subset_missing_instructions, V2, Modules}) + end. + +do_check_module_subset2(Mods1, Mods2) -> + do_check_module_subset2(Mods1, Mods2, []). + +do_check_module_subset2([], _, []) -> + ok; +do_check_module_subset2([], _, Acc) -> + {error, lists:reverse(Acc)}; +do_check_module_subset2([Mod|Mods], Mods2, Acc) -> + case lists:member(Mod, Mods2) of + true -> + do_check_module_subset2(Mods, Mods2, Acc); + false -> + do_check_module_subset2(Mods, Mods2, [Mod|Acc]) + end. + + +modules_of(Instructions) -> + modules_of(Instructions, []). + +modules_of([], Acc) -> + lists:reverse(Acc); +modules_of([{V,Instructions}|T], Acc) -> + Mods = modules_of2(Instructions, []), + modules_of(T, [{V, Mods}|Acc]). + +modules_of2([], Acc) -> + lists:reverse(Acc); +modules_of2([Instr|Instructions], Acc) -> + case module_of(Instr) of + {value, Mod} -> + modules_of2(Instructions, [Mod|Acc]); + false -> + modules_of2(Instructions, Acc) + end. + +module_of({add_module, Module}) -> + {value, Module}; +module_of({remove, {Module, _Pre, _Post}}) -> + {value, Module}; +module_of({load_module, Module, _Pre, _Post, _Depend}) -> + {value, Module}; +module_of({update, Module, _Change, _Pre, _Post, _Depend}) -> + {value, Module}; +module_of(_) -> + false. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% The version is a string consting of numbers separated by dots: "." +%% Example: "3.3.3" +%% +check_version(V) when is_list(V) -> + case do_check_version(string:tokens(V, [$.])) of + ok -> + ok; + {error, BadVersionPart} -> + throw({error, {bad_version, V, BadVersionPart}}) + end; +check_version(V) -> + error({bad_version, V}). + +do_check_version([]) -> + ok; +do_check_version([H|T]) -> + case (catch list_to_integer(H)) of + I when is_integer(I) -> + do_check_version(T); + _ -> + {error, H} + end. + +check_module(M, Modules) when is_atom(M) -> + case lists:member(M,Modules) of + true -> + ok; + false -> + error({unknown_module, M, Modules}) + end; +check_module(M, _) -> + error({bad_module, M}). + + +check_module_depend(M, [], _) when is_atom(M) -> + d("check_module_depend -> entry with" + "~n M: ~p", [M]), + ok; +check_module_depend(M, Deps, Modules) when is_atom(M) andalso is_list(Deps) -> + d("check_module_depend -> entry with" + "~n M: ~p" + "~n Deps: ~p" + "~n Modules: ~p", [M, Deps, Modules]), + case [Dep || Dep <- Deps, lists:member(Dep, Modules) == false] of + [] -> + ok; + Unknown -> + error({unknown_depend_modules, Unknown}) + end; +check_module_depend(_M, D, _Modules) -> + d("check_module_depend -> entry when bad depend with" + "~n D: ~p", [D]), + error({bad_depend, D}). + + +check_no_remove_depends(_Module, []) -> + ok; +check_no_remove_depends(Module, [Instr|Instrs]) -> + check_no_remove_depend(Module, Instr), + check_no_remove_depends(Module, Instrs). + +check_no_remove_depend(Module, {load_module, Mod, _Pre, _Post, Depend}) -> + case lists:member(Module, Depend) of + true -> + error({removed_module_in_depend, load_module, Mod, Module}); + false -> + ok + end; +check_no_remove_depend(Module, {update, Mod, _Change, _Pre, _Post, Depend}) -> + case lists:member(Module, Depend) of + true -> + error({removed_module_in_depend, update, Mod, Module}); + false -> + ok + end; +check_no_remove_depend(_, _) -> + ok. + + +check_change(soft) -> + ok; +check_change({advanced, _Something}) -> + ok; +check_change(Change) -> + error({bad_change, Change}). + + +check_purge(soft_purge) -> + ok; +check_purge(brutal_purge) -> + ok; +check_purge(Purge) -> + error({bad_purge, Purge}). + + +check_apply(Module, Function, Args) -> + case (catch Module:module_info()) of + Info when is_list(Info) -> + check_exported(Function, Args, Info); + {'EXIT', {undef, _}} -> + error({not_existing_module, Module}) + end. + +check_exported(Function, Args, Info) -> + case lists:keysearch(exports, 1, Info) of + {value, {exports, FuncList}} -> + Arity = length(Args), + Arities = [A || {F, A} <- FuncList, F == Function], + case lists:member(Arity, Arities) of + true -> + ok; + false -> + error({not_exported_function, Function, Arity}) + end; + _ -> + error({bad_export, Info}) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +error(Reason) -> + throw({error, Reason}). + +fail(Reason) -> + exit({suite_failed, Reason}). + +key1search(Key, L) -> + case lists:keysearch(Key, 1, L) of + undefined -> + fail({not_found, Key, L}); + {value, {Key, Value}} -> + Value + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +d(F, A) -> + d(false, F, A). + +d(true, F, A) -> + io:format(F ++ "~n", A); +d(_, _, _) -> + ok. + + diff --git a/lib/diameter/test/diameter_compiler_test.erl b/lib/diameter/test/diameter_compiler_test.erl new file mode 100644 index 0000000000..ae4c9c668d --- /dev/null +++ b/lib/diameter/test/diameter_compiler_test.erl @@ -0,0 +1,104 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the dia compiler of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_compiler_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2 + + %% foo/1 + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + []. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + Config. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case example +%% + +%% foo(suite) -> +%% []; +%% foo(doc) -> +%% []; +%% foo(Config) when is_list(Config) -> +%% ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + diff --git a/lib/diameter/test/diameter_config_test.erl b/lib/diameter/test/diameter_config_test.erl new file mode 100644 index 0000000000..c44fb654ab --- /dev/null +++ b/lib/diameter/test/diameter_config_test.erl @@ -0,0 +1,105 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the config server of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_config_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2 + + %% foo/1 + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + []. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + Config. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case example +%% + +%% foo(suite) -> +%% []; +%% foo(doc) -> +%% []; +%% foo(Config) when is_list(Config) -> +%% ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + diff --git a/lib/diameter/test/diameter_etcp_test.beam b/lib/diameter/test/diameter_etcp_test.beam Binary files differnew file mode 100644 index 0000000000..efaaec69d5 --- /dev/null +++ b/lib/diameter/test/diameter_etcp_test.beam diff --git a/lib/diameter/test/diameter_peer_test.erl b/lib/diameter/test/diameter_peer_test.erl new file mode 100644 index 0000000000..27e75e26ef --- /dev/null +++ b/lib/diameter/test/diameter_peer_test.erl @@ -0,0 +1,104 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the peer component of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_peer_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2 + + %% foo/1 + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + []. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + Config. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case example +%% + +%% foo(suite) -> +%% []; +%% foo(doc) -> +%% []; +%% foo(Config) when is_list(Config) -> +%% ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + diff --git a/lib/diameter/test/diameter_reg_test.erl b/lib/diameter/test/diameter_reg_test.erl new file mode 100644 index 0000000000..a2638d6712 --- /dev/null +++ b/lib/diameter/test/diameter_reg_test.erl @@ -0,0 +1,104 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011_2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the reg component of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_reg_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2 + + %% foo/1 + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + []. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + Config. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case example +%% + +%% foo(suite) -> +%% []; +%% foo(doc) -> +%% []; +%% foo(Config) when is_list(Config) -> +%% ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + diff --git a/lib/diameter/test/diameter_session_test.erl b/lib/diameter/test/diameter_session_test.erl new file mode 100644 index 0000000000..a32647d83d --- /dev/null +++ b/lib/diameter/test/diameter_session_test.erl @@ -0,0 +1,104 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the session component of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_session_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2 + + %% foo/1 + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + []. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + Config. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case example +%% + +%% foo(suite) -> +%% []; +%% foo(doc) -> +%% []; +%% foo(Config) when is_list(Config) -> +%% ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + diff --git a/lib/diameter/test/diameter_stats_test.erl b/lib/diameter/test/diameter_stats_test.erl new file mode 100644 index 0000000000..8b666edf50 --- /dev/null +++ b/lib/diameter/test/diameter_stats_test.erl @@ -0,0 +1,104 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the stats component of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_stats_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2 + + %% foo/1 + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + []. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + Config. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case example +%% + +%% foo(suite) -> +%% []; +%% foo(doc) -> +%% []; +%% foo(Config) when is_list(Config) -> +%% ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + diff --git a/lib/diameter/test/diameter_sync_test.erl b/lib/diameter/test/diameter_sync_test.erl new file mode 100644 index 0000000000..618fa5021b --- /dev/null +++ b/lib/diameter/test/diameter_sync_test.erl @@ -0,0 +1,104 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the sync component of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_sync_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2 + + %% foo/1 + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + []. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + Config. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case example +%% + +%% foo(suite) -> +%% []; +%% foo(doc) -> +%% []; +%% foo(Config) when is_list(Config) -> +%% ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + diff --git a/lib/diameter/test/diameter_tcp_test.erl b/lib/diameter/test/diameter_tcp_test.erl new file mode 100644 index 0000000000..b002a3d289 --- /dev/null +++ b/lib/diameter/test/diameter_tcp_test.erl @@ -0,0 +1,482 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the tcp transport component of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_tcp_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/0, + groups/0, + init_per_suite/1, end_per_suite/1, + suite_init/1, suite_fin/1, + init_per_group/2, end_per_group/2, + + start_and_stop_transport_plain/1, + start_and_listen/1, + simple_connect/1, + simple_send_and_recv/1 + + ]). + +-export([t/0, t/1]). + +%% diameter_peer (internal) callback API +-export([up/1, up/3, recv/2]). + +-include("diameter_test_lib.hrl"). +-include_lib("diameter/include/diameter.hrl"). +%% -include_lib("diameter/src/tcp/diameter_tcp.hrl"). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all() -> + [ + {group, start}, + {group, simple} + ]. + +groups() -> + [ + {start, [], [start_and_stop_transport_plain, start_and_listen]}, + {simple, [], [simple_connect, simple_send_and_recv]} + ]. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(X) -> init_per_suite(X). + +init_per_suite(suite) -> []; +init_per_suite(doc) -> []; +init_per_suite(Config) when is_list(Config) -> + Config. + + +suite_fin(X) -> end_per_suite(X). + +end_per_suite(suite) -> []; +end_per_suite(doc) -> []; +end_per_suite(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case(s) +%% + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Plain start and stop of TCP transport +%% + +start_and_stop_transport_plain(suite) -> + []; +start_and_stop_transport_plain(doc) -> + []; +start_and_stop_transport_plain(Config) when is_list(Config) -> + + ?SKIP(not_yet_implemented), + + %% This has been changed *a lot* since it was written... + + process_flag(trap_exit, true), + Transport = ensure_transport_started(), + TcpTransport = ensure_tcp_transport_started(), + ensure_tcp_transport_stopped(TcpTransport), + ensure_transport_stopped(Transport), + i("done"), + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Start TCP transport and then create a listen socket +%% + +start_and_listen(suite) -> + []; +start_and_listen(doc) -> + []; +start_and_listen(Config) when is_list(Config) -> + + ?SKIP(not_yet_implemented), + + %% This has been changed *a lot* since it was written... + + process_flag(trap_exit, true), + Transport = ensure_transport_started(), + TcpTransport = ensure_tcp_transport_started(), + + case listen([{port, 0}]) of + {ok, Acceptor} when is_pid(Acceptor) -> + Ref = erlang:monitor(process, Acceptor), + [{Acceptor, Info}] = diameter_tcp:which_listeners(), + case lists:keysearch(socket, 1, Info) of + {value, {_, Listen}} -> + i("Listen socket: ~p" + "~n Opts: ~p" + "~n Stats: ~p" + "~n Name: ~p", + [Listen, + ok(inet:getopts(Listen, [keepalive, delay_send])), + ok(inet:getstat(Listen)), + ok(inet:sockname(Listen)) + ]), + ok; + _ -> + ?FAIL({bad_listener_info, Acceptor, Info}) + end, + Crash = simulate_crash, + exit(Acceptor, Crash), + receive + {'DOWN', Ref, process, Acceptor, Crash} -> + ?SLEEP(1000), + case diameter_tcp:which_listeners() of + [{NewAcceptor, _NewInfo}] -> + diameter_tcp_accept:stop(NewAcceptor), + ?SLEEP(1000), + case diameter_tcp:which_listeners() of + [] -> + ok; + UnexpectedListeners -> + ?FAIL({unexpected_listeners, empty, UnexpectedListeners}) + end; + UnexpectedListeners -> + ?FAIL({unexpected_listeners, non_empty, UnexpectedListeners}) + end + after 5000 -> + ?FAIL({failed_killing, Acceptor}) + end; + Error -> + ?FAIL({failed_creating_acceptor, Error}) + end, + ensure_tcp_transport_stopped(TcpTransport), + ensure_transport_stopped(Transport), + i("done"), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% TCP transport connecting +%% + +simple_connect(suite) -> + []; +simple_connect(doc) -> + []; +simple_connect(Config) when is_list(Config) -> + + ?SKIP(not_yet_implemented), + + %% This has been changed *a lot* since it was written... + + process_flag(trap_exit, true), + Transport = ensure_transport_started(), + TcpTransport = ensure_tcp_transport_started(), + {_Acceptor, Port} = ensure_tcp_listener(), + + {ok, Hostname} = inet:gethostname(), + + i("try connect"), + Opts = [{host, Hostname}, {port, Port}, {module, ?MODULE}], + Conn = case connect(Opts) of + {ok, C} -> + C; + Error -> + ?FAIL({failed_connecting, Error}) + end, + i("connected: ~p", [Conn]), + + %% Up for connect + receive + {diameter, {up, Host, Port}} -> + i("Received expected connect up (~p:~p)", [Host, Port]), + ok + after 5000 -> + ?FAIL(connect_up_confirmation_timeout) + end, + + %% Up for accept + receive + {diameter, {up, _ConnPid}} -> + i("Received expected accept up"), + ok + after 5000 -> + ?FAIL(acceptor_up_confirmation_timeout) + end, + + i("try disconnect"), + diameter_tcp:disconnect(Conn), + ensure_tcp_transport_stopped(TcpTransport), + ensure_transport_stopped(Transport), + i("done"), + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Plain start and stop of TCP transport +%% + +simple_send_and_recv(suite) -> + []; +simple_send_and_recv(doc) -> + []; +simple_send_and_recv(Config) when is_list(Config) -> + + ?SKIP(not_yet_implemented), + + %% This has been changed *a lot* since it was written... + + process_flag(trap_exit, true), + %% -------------------------------------------------- + %% Start the TCP transport sub-system + %% + + Transport = ensure_transport_started(), + TcpTransport = ensure_tcp_transport_started(), + + {_Acceptor, Port} = ensure_tcp_listener(), + + {ok, Hostname} = inet:gethostname(), + + i("try connect"), + Opts = [{host, Hostname}, {port, Port}, {module, ?MODULE}], + Conn = case connect(Opts) of + {ok, C1} -> + C1; + Error -> + ?FAIL({failed_connecting, Error}) + end, + i("connected: ~p", [Conn]), + + %% Up for connect + receive + {diameter, {up, Host, Port}} -> + i("Received expected connect up (~p:~p)", [Host, Port]), + ok + after 5000 -> + ?FAIL(connect_up_confirmation_timeout) + end, + + %% Up for accept + APid = + receive + {diameter, {up, C2}} -> + i("Received expected accept up"), + C2 + after 5000 -> + ?FAIL(acceptor_up_confirmation_timeout) + end, + + %% -------------------------------------------------- + %% Start some stuff needed for the codec to run + %% + + i("start persistent table"), + {ok, _Pers} = diameter_persistent_table:start_link(), + + i("start session"), + {ok, _Session} = diameter_session:start_link(), + + i("try decode a (DWR) message"), + Base = diameter_gen_base_rfc3588, + DWR = ['DWR', + {'Origin-Host', Hostname}, + {'Origin-Realm', "whatever-realm"}, + {'Origin-State-Id', [10]}], + + #diameter_packet{msg = Msg} = diameter_codec:encode(Base, DWR), + + + %% -------------------------------------------------- + %% Now try to send the message + %% + %% This is not the codec-test suite, so we dont really care what we + %% send, as long as it encoded/decodes correctly in the transport + %% + + i("try send from connect side"), + ok = diameter_tcp:send_message(Conn, Msg), + + %% Wait for data on Accept side + APkt = + receive + {diameter, {recv, A}} -> + i("[accept] Received expected data message: ~p", [A]), + A + after 5000 -> + ?FAIL(acceptor_up_confirmation_timeout) + end, + + %% Send the same message back, just to have something to send... + i("try send (\"reply\") from accept side"), + ok = diameter_tcp:send_message(APid, APkt), + + %% Wait for data on Connect side + receive + {diameter, {recv, B}} -> + i("[connect] Received expected data message: ~p", [B]), + ok + after 5000 -> + ?FAIL(acceptor_up_confirmation_timeout) + end, + + i("we are done - now close shop"), + diameter_session:stop(), + diameter_persistent_table:stop(), + + ensure_tcp_transport_stopped(TcpTransport), + ensure_transport_stopped(Transport), + i("done"), + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +ensure_transport_started() -> +%% i("start diameter transport (top) supervisor"), + case diameter_transport_sup:start_link() of + {ok, TransportSup} -> + TransportSup; + Error -> + ?FAIL({failed_starting_transport_sup, Error}) + end. + +ensure_transport_stopped(Pid) when is_pid(Pid) -> +%% i("stop diameter transport (top) supervisor"), + Stop = fun(P) -> exit(P, kill) end, + ensure_stopped(Pid, Stop, failed_stopping_transport_sup). + +ensure_tcp_transport_started() -> +%% i("start diameter TCP transport"), + case diameter_tcp:start_transport() of + {ok, TcpTransport} when is_pid(TcpTransport) -> + TcpTransport; + Error -> + ?FAIL({failed_starting_transport, Error}) + end. + +ensure_tcp_transport_stopped(Pid) when is_pid(Pid) -> +%% i("stop diameter TCP transport supervisor"), + Stop = fun(P) -> diameter_tcp:stop_transport(P) end, + ensure_stopped(Pid, Stop, failed_stopping_tcp_transport). + + +ensure_tcp_listener() -> +%% i("create diameter TCP transport listen socket"), + case listen([{port, 0}]) of + {ok, Acceptor} -> + [{Acceptor, Info}] = diameter_tcp:which_listeners(), + case lists:keysearch(socket, 1, Info) of + {value, {_, Listen}} -> + {ok, Port} = inet:port(Listen), + {Acceptor, Port}; + _ -> + ?FAIL({failed_retrieving_listen_socket, Info}) + end; + Error -> + ?FAIL({failed_creating_listen_socket, Error}) + end. + + +ensure_stopped(Pid, Stop, ReasonTag) when is_pid(Pid) -> +%% i("ensure_stopped -> create monitor to ~p", [Pid]), + Ref = erlang:monitor(process, Pid), +%% i("ensure_stopped -> try stop"), + Stop(Pid), +%% i("ensure_stopped -> await DOWN message"), + receive + {'DOWN', Ref, process, Pid, _} -> +%% i("ensure_stopped -> received DOWN message"), + ok + after 5000 -> +%% i("ensure_stopped -> timeout"), + ?FAIL({ReasonTag, Pid}) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +listen(Opts) -> + diameter_tcp:listen([{module, ?MODULE} | Opts]). + +connect(Opts) -> + diameter_tcp:connect([{module, ?MODULE} | Opts]). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +up(Pid, Host, Port) -> + Pid ! {diameter, {up, Host, Port}}, + ok. + +up(Pid) -> + Pid ! {diameter, {up, self()}}, + ok. + +recv(Pid, Pkt) -> + Pid ! {diameter, {recv, Pkt}}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +i(F) -> + i(F, []). + +i(F, A) -> + io:format(F ++ "~n", A). + + +ok({ok, Whatever}) -> + Whatever; +ok(Crap) -> + Crap. + + diff --git a/lib/diameter/test/diameter_test_lib.erl b/lib/diameter/test/diameter_test_lib.erl new file mode 100644 index 0000000000..3d46236526 --- /dev/null +++ b/lib/diameter/test/diameter_test_lib.erl @@ -0,0 +1,478 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Lightweight test server +%%---------------------------------------------------------------------- +%% + +-module(diameter_test_lib). + +-export([ + sleep/1, + + hours/1, + minutes/1, + seconds/1, + + key1search/2, + + non_pc_tc_maybe_skip/4, + os_based_skip/1, + + fail/3, + skip/3, + fatal_skip/3, + + log/4, + error/3, + + flush/0, + + proxy_start/1, proxy_start/2, + proxy_init/2, + + still_alive/1, + + prepare_test_case/5, + lookup_config/2, + + mk_nodes/2, start_nodes/3, + + display_system_info/1, display_system_info/2, display_system_info/3, + display_alloc_info/0, + alloc_info/0, + + report_event/3 + + ]). + +-include("diameter_test_lib.hrl"). + +-record('REASON', {mod, line, desc}). + + +%% ---------------------------------------------------------------- +%% Time related function +%% + +sleep(infinity) -> + receive + after infinity -> + ok + end; +sleep(MSecs) -> + receive + after trunc(MSecs) -> + ok + end, + ok. + + +hours(N) -> trunc(N * 1000 * 60 * 60). +minutes(N) -> trunc(N * 1000 * 60). +seconds(N) -> trunc(N * 1000). + + +%% ---------------------------------------------------------------- + +key1search(Key, L) -> + case lists:keysearch(Key, 1, L) of + undefined -> + fail({not_found, Key, L}, ?MODULE, ?LINE); + {value, {Key, Value}} -> + Value + end. + + +%% ---------------------------------------------------------------- +%% Conditional skip of testcases +%% + +non_pc_tc_maybe_skip(Config, Condition, File, Line) + when is_list(Config) andalso is_function(Condition) -> + %% Check if we shall skip the skip + case os:getenv("TS_OS_BASED_SKIP") of + "false" -> + ok; + _ -> + case lists:keysearch(ts, 1, Config) of + {value, {ts, megaco}} -> + %% Always run the testcase if we are using our own + %% test-server... + ok; + _ -> + case (catch Condition()) of + true -> + skip(non_pc_testcase, File, Line); + _ -> + ok + end + end + end. + + +os_based_skip(any) -> + true; +os_based_skip(Skippable) when is_list(Skippable) -> + {OsFam, OsName} = + case os:type() of + {_Fam, _Name} = FamAndName -> + FamAndName; + Fam -> + {Fam, undefined} + end, + case lists:member(OsFam, Skippable) of + true -> + true; + false -> + case lists:keysearch(OsFam, 1, Skippable) of + {value, {OsFam, OsName}} -> + true; + {value, {OsFam, OsNames}} when is_list(OsNames) -> + lists:member(OsName, OsNames); + _ -> + false + end + end; +os_based_skip(_) -> + false. + + +%%---------------------------------------------------------------------- + +error(Actual, Mod, Line) -> + global:send(megaco_global_logger, {failed, Mod, Line}), + log("<ERROR> Bad result: ~p~n", [Actual], Mod, Line), + Label = lists:concat([Mod, "(", Line, ") unexpected result"]), + report_event(60, Label, [{line, Mod, Line}, {error, Actual}]), + case global:whereis_name(megaco_test_case_sup) of + undefined -> + ignore; + Pid -> + Fail = #'REASON'{mod = Mod, line = Line, desc = Actual}, + Pid ! {fail, self(), Fail} + end, + Actual. + +log(Format, Args, Mod, Line) -> + case global:whereis_name(megaco_global_logger) of + undefined -> + io:format(user, "~p~p(~p): " ++ Format, + [self(), Mod, Line] ++ Args); + Pid -> + io:format(Pid, "~p~p(~p): " ++ Format, + [self(), Mod, Line] ++ Args) + end. + +skip(Actual, File, Line) -> + log("Skipping test case~n", [], File, Line), + String = lists:flatten(io_lib:format("Skipping test case ~p(~p): ~p~n", + [File, Line, Actual])), + exit({skipped, String}). + +fatal_skip(Actual, File, Line) -> + error(Actual, File, Line), + exit(shutdown). + + +fail(Actual, File, Line) -> + log("Test case failing~n", [], File, Line), + String = lists:flatten(io_lib:format("Test case failing ~p (~p): ~p~n", + [File, Line, Actual])), + exit({suite_failed, String}). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Flush the message queue and return its messages + +flush() -> + receive + Msg -> + [Msg | flush()] + after 1000 -> + [] + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% The proxy process + +proxy_start(ProxyId) -> + spawn_link(?MODULE, proxy_init, [ProxyId, self()]). + +proxy_start(Node, ProxyId) -> + spawn_link(Node, ?MODULE, proxy_init, [ProxyId, self()]). + +proxy_init(ProxyId, Controller) -> + process_flag(trap_exit, true), + ?LOG("[~p] proxy started by ~p~n",[ProxyId, Controller]), + proxy_loop(ProxyId, Controller). + +proxy_loop(OwnId, Controller) -> + receive + {'EXIT', Controller, Reason} -> + p("proxy_loop -> received exit from controller" + "~n Reason: ~p" + "~n", [Reason]), + exit(Reason); + {apply, Fun} -> + p("proxy_loop -> received apply request~n", []), + Res = Fun(), + p("proxy_loop -> apply result: " + "~n ~p" + "~n", [Res]), + Controller ! {res, OwnId, Res}, + proxy_loop(OwnId, Controller); + OtherMsg -> + p("proxy_loop -> received unknown message: " + "~n OtherMsg: ~p" + "~n", [OtherMsg]), + Controller ! {msg, OwnId, OtherMsg}, + proxy_loop(OwnId, Controller) + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Check if process is alive and kicking +still_alive(Pid) -> + case catch erlang:is_process_alive(Pid) of % New BIF in Erlang/OTP R5 + true -> + true; + false -> + false; + {'EXIT', _} -> % Pre R5 backward compatibility + case process_info(Pid, message_queue_len) of + undefined -> false; + _ -> true + end + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +mk_nodes(0, Nodes) -> + Nodes; +mk_nodes(N, []) -> + mk_nodes(N - 1, [node()]); +mk_nodes(N, Nodes) when N > 0 -> + Head = hd(Nodes), + [Name, Host] = node_to_name_and_host(Head), + Nodes ++ [mk_node(I, Name, Host) || I <- lists:seq(1, N)]. + +mk_node(N, Name, Host) -> + list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). + +%% Returns [Name, Host] +node_to_name_and_host(Node) -> + string:tokens(atom_to_list(Node), [$@]). + +start_nodes([Node | Nodes], File, Line) -> + case net_adm:ping(Node) of + pong -> + start_nodes(Nodes, File, Line); + pang -> + [Name, Host] = node_to_name_and_host(Node), + case slave:start_link(Host, Name) of + {ok, NewNode} when NewNode =:= Node -> + Path = code:get_path(), + {ok, Cwd} = file:get_cwd(), + true = rpc:call(Node, code, set_path, [Path]), + ok = rpc:call(Node, file, set_cwd, [Cwd]), + true = rpc:call(Node, code, set_path, [Path]), + {_, []} = rpc:multicall(global, sync, []), + start_nodes(Nodes, File, Line); + Other -> + fatal_skip({cannot_start_node, Node, Other}, File, Line) + end + end; +start_nodes([], _File, _Line) -> + ok. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +display_alloc_info() -> + io:format("Allocator memory information:~n", []), + AllocInfo = alloc_info(), + display_alloc_info(AllocInfo). + +display_alloc_info([]) -> + ok; +display_alloc_info([{Alloc, Mem}|AllocInfo]) -> + io:format(" ~15w: ~10w~n", [Alloc, Mem]), + display_alloc_info(AllocInfo). + +alloc_info() -> + case erlang:system_info(allocator) of + {_Allocator, _Version, Features, _Settings} -> + alloc_info(Features); + _ -> + [] + end. + +alloc_info(Allocators) -> + Allocs = [temp_alloc, sl_alloc, std_alloc, ll_alloc, eheap_alloc, + ets_alloc, binary_alloc, driver_alloc], + alloc_info(Allocators, Allocs, []). + +alloc_info([], _, Acc) -> + lists:reverse(Acc); +alloc_info([Allocator | Allocators], Allocs, Acc) -> + case lists:member(Allocator, Allocs) of + true -> + Instances0 = erlang:system_info({allocator, Allocator}), + Instances = + if + is_list(Instances0) -> + [Instance || Instance <- Instances0, + element(1, Instance) =:= instance]; + true -> + [] + end, + AllocatorMem = alloc_mem_info(Instances), + alloc_info(Allocators, Allocs, [{Allocator, AllocatorMem} | Acc]); + + false -> + alloc_info(Allocators, Allocs, Acc) + end. + +alloc_mem_info(Instances) -> + alloc_mem_info(Instances, []). + +alloc_mem_info([], Acc) -> + lists:sum([Mem || {instance, _, Mem} <- Acc]); +alloc_mem_info([{instance, N, Info}|Instances], Acc) -> + InstanceMemInfo = alloc_instance_mem_info(Info), + alloc_mem_info(Instances, [{instance, N, InstanceMemInfo} | Acc]). + +alloc_instance_mem_info(InstanceInfo) -> + MBCS = alloc_instance_mem_info(mbcs, InstanceInfo), + SBCS = alloc_instance_mem_info(sbcs, InstanceInfo), + MBCS + SBCS. + +alloc_instance_mem_info(Key, InstanceInfo) -> + case lists:keysearch(Key, 1, InstanceInfo) of + {value, {Key, Info}} -> + case lists:keysearch(blocks_size, 1, Info) of + {value, {blocks_size, Mem, _, _}} -> + Mem; + _ -> + 0 + end; + _ -> + 0 + end. + + +display_system_info(WhenStr) -> + display_system_info(WhenStr, undefined, undefined). + +display_system_info(WhenStr, undefined, undefined) -> + display_system_info(WhenStr, ""); +display_system_info(WhenStr, Mod, Func) -> + ModFuncStr = lists:flatten(io_lib:format(" ~w:~w", [Mod, Func])), + display_system_info(WhenStr, ModFuncStr). + +display_system_info(WhenStr, ModFuncStr) -> + Fun = fun(F) -> case (catch F()) of + {'EXIT', _} -> + undefined; + Res -> + Res + end + end, + ProcCount = Fun(fun() -> erlang:system_info(process_count) end), + ProcLimit = Fun(fun() -> erlang:system_info(process_limit) end), + ProcMemAlloc = Fun(fun() -> erlang:memory(processes) end), + ProcMemUsed = Fun(fun() -> erlang:memory(processes_used) end), + ProcMemBin = Fun(fun() -> erlang:memory(binary) end), + ProcMemTot = Fun(fun() -> erlang:memory(total) end), + %% error_logger:info_msg( + io:format("~n" + "~n*********************************************" + "~n" + "System info ~s~s => " + "~n Process count: ~w" + "~n Process limit: ~w" + "~n Process memory alloc: ~w" + "~n Process memory used: ~w" + "~n Memory for binaries: ~w" + "~n Memory total: ~w" + "~n" + "~n*********************************************" + "~n" + "~n", [WhenStr, ModFuncStr, + ProcCount, ProcLimit, ProcMemAlloc, ProcMemUsed, + ProcMemBin, ProcMemTot]), + ok. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +prepare_test_case(Actions, N, Config, File, Line) -> + OrigNodes = lookup_config(nodes, Config), + TestNodes = lookup_config(nodenames, Config), %% For testserver + This = node(), + SomeNodes = OrigNodes ++ (TestNodes -- OrigNodes), + AllNodes = [This | (SomeNodes -- [This])], + Nodes = pick_n_nodes(N, AllNodes, File, Line), + start_nodes(Nodes, File, Line), + do_prepare_test_case(Actions, Nodes, Config, File, Line). + +do_prepare_test_case([init | Actions], Nodes, Config, File, Line) -> + process_flag(trap_exit, true), + megaco_test_lib:flush(), + do_prepare_test_case(Actions, Nodes, Config, File, Line); +do_prepare_test_case([{stop_app, App} | Actions], Nodes, Config, File, Line) -> + _Res = rpc:multicall(Nodes, application, stop, [App]), + do_prepare_test_case(Actions, Nodes, Config, File, Line); +do_prepare_test_case([], Nodes, _Config, _File, _Line) -> + Nodes. + +pick_n_nodes(all, AllNodes, _File, _Line) -> + AllNodes; +pick_n_nodes(N, AllNodes, _File, _Line) + when is_integer(N) andalso (length(AllNodes) >= N) -> + AllNodes -- lists:nthtail(N, AllNodes); +pick_n_nodes(N, AllNodes, File, Line) -> + fatal_skip({too_few_nodes, N, AllNodes}, File, Line). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +lookup_config(Key, Config) -> + case lists:keysearch(Key, 1, Config) of + {value, {Key, Val}} -> + Val; + _ -> + [] + end. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +report_event(_Severity, _Label, _Content) -> + %% diameter:report_event(Severity, Label, Content). + hopefully_traced. + + +p(F,A) -> + io:format("~p" ++ F ++ "~n", [self()|A]). diff --git a/lib/diameter/test/diameter_test_lib.hrl b/lib/diameter/test/diameter_test_lib.hrl new file mode 100644 index 0000000000..0b86f38de7 --- /dev/null +++ b/lib/diameter/test/diameter_test_lib.hrl @@ -0,0 +1,106 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Define common macros for testing +%%---------------------------------------------------------------------- +%% + +-define(FLUSH(), diameter_test_lib:flush()). + +-define(SLEEP(MSEC), diameter_test_lib:sleep(MSEC)). +-define(M(), diameter_test_lib:millis()). +-define(MDIFF(A,B), diameter_test_lib:millis_diff(A,B)). + +-define(HOURS(T), diameter_test_lib:hours(T)). +-define(MINUTES(T), diameter_test_lib:minutes(T)). +-define(SECONDS(T), diameter_test_lib:seconds(T)). + +-define(KEY1SEARCH(Key, L), diameter_test_lib:key1search(Key, L)). + + +-define(APPLY(Proxy, Fun), + Proxy ! {apply, Fun}). + +-define(LOG(Format, Args), + diameter_test_lib:log(Format, Args, ?MODULE, ?LINE)). + +-define(ERROR(Reason), + diameter_test_lib:error(Reason, ?MODULE, ?LINE)). + +-define(OS_BASED_SKIP(Skippable), + diameter_test_lib:os_based_skip(Skippable)). + +-define(NON_PC_TC_MAYBE_SKIP(Config, Condition), + diameter_test_lib:non_pc_tc_maybe_skip(Config, Condition, ?MODULE, ?LINE)). + +-define(FAIL(Reason), + diameter_test_lib:fail(Reason, ?MODULE, ?LINE)). + +-define(SKIP(Reason), + diameter_test_lib:skip(Reason, ?MODULE, ?LINE)). + +-define(VERIFYL(Expected, Expr), + fun(A,B) when list(A), list(B) -> + A1 = lists:sort(A), + B1 = lists:sort(B), + case A1 of + B1 -> ?LOG("Ok, ~p~n", [B]); + _ -> ?ERROR(B) + end, + B; + (A,A) -> + ?LOG("Ok, ~p~n", [A]), + A; + (A,B) -> + ?ERROR(B), + B + end(Expected, (catch Expr))). + +-define(VERIFY(Expected, Expr), + fun() -> + AcTuAlReS = (catch (Expr)), + case AcTuAlReS of + Expected -> ?LOG("Ok, ~p~n", [AcTuAlReS]); + _ -> ?ERROR(AcTuAlReS) + end, + AcTuAlReS + end()). + +-define(RECEIVE(Expected), + ?VERIFY(Expected, ?FLUSH())). + +-define(MULTI_RECEIVE(Expected), + ?VERIFY(lists:sort(Expected), lists:sort(?FLUSH()))). + +-define(ACQUIRE_NODES(N, Config), + diameter_test_lib:prepare_test_case([init, {stop_app, diameter}], + N, Config, ?FILE, ?LINE)). + + +-define(REPORT_IMPORTANT(Label, Content), ?REPORT_EVENT(20, Label, Content)). +-define(REPORT_VERBOSE(Label, Content), ?REPORT_EVENT(40, Label, Content)). +-define(REPORT_DEBUG(Label, Content), ?REPORT_EVENT(60, Label, Content)). +-define(REPORT_TRACE(Label, Content), ?REPORT_EVENT(80, Label, Content)). + +-define(REPORT_EVENT(Severity, Label, Content), + diameter_test_lib:report_event(Severity, Label, + [{line, ?MODULE, ?LINE} | Content])). + diff --git a/lib/diameter/test/diameter_test_server.erl b/lib/diameter/test/diameter_test_server.erl new file mode 100644 index 0000000000..e2ff73fb8e --- /dev/null +++ b/lib/diameter/test/diameter_test_server.erl @@ -0,0 +1,551 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Lightweight test server +%%---------------------------------------------------------------------- + +-module(diameter_test_server). + +-export([ + t/1, t/2, + + init_per_testcase/2, + fin_per_testcase/2 + ]). + +-include("diameter_test_lib.hrl"). + + +-define(GLOGGER, diameter_global_logger). + + +%% ---------------------------------------------------------------- +%% + +t([Case]) when is_atom(Case) -> + t(Case); +t(Case) -> + process_flag(trap_exit, true), + MEM = fun() -> case (catch erlang:memory()) of + {'EXIT', _} -> + []; + Res -> + Res + end + end, + Alloc1 = diameter_test_lib:alloc_info(), + Mem1 = MEM(), + Res = lists:flatten(t(Case, default_config())), + Alloc2 = diameter_test_lib:alloc_info(), + Mem2 = MEM(), + %% io:format("Res: ~p~n", [Res]), + display_result(Res, Alloc1, Mem1, Alloc2, Mem2), + Res. + + +groups(Mod) when is_atom(Mod) -> + try Mod:groups() of + Groups when is_list(Groups) -> + Groups; + BadGroups -> + exit({bad_groups, Mod, BadGroups}) + catch + _:_ -> + [] + end. + +init_suite(Mod, Config) -> + io:format("~w:init_suite -> entry with" + "~n Mod: ~p" + "~n Config: ~p" + "~n", [?MODULE, Mod, Config]), + Mod:init_per_suite(Config). + +end_suite(Mod, Config) -> + Mod:end_per_suite(Config). + +init_group(Mod, Group, Config) -> + Mod:init_per_group(Group, Config). + +end_group(Mod, Group, Config) -> + Mod:init_per_group(Group, Config). + +%% This is for sub-SUITEs +t({_Mod, {NewMod, all}, _Groups}, _Config) when is_atom(NewMod) -> + io:format("~w:t(all) -> entry with" + "~n NewMod: ~p" + "~n", [?MODULE, NewMod]), + t(NewMod); +t({Mod, {group, Name} = Group, Groups}, Config) + when is_atom(Mod) andalso is_atom(Name) andalso is_list(Groups) -> + io:format("~w:t(group) -> entry with" + "~n Mod: ~p" + "~n Name: ~p" + "~n Groups: ~p" + "~n Config: ~p" + "~n", [?MODULE, Mod, Name, Groups, Config]), + case lists:keysearch(Name, 1, Groups) of + {value, {Name, _Props, GroupsAndCases}} -> + try init_group(Mod, Name, Config) of + Config2 when is_list(Config2) -> + Res = [t({Mod, Case, Groups}, Config2) || + Case <- GroupsAndCases], + (catch end_group(Mod, Name, Config2)), + Res; + Error -> + io:format(" => group (~w) init failed: ~p~n", + [Name, Error]), + [{failed, {Mod, Group}, Error}] + catch + exit:{skipped, SkipReason} -> + io:format(" => skipping group: ~p~n", [SkipReason]), + [{skipped, {Mod, Group}, SkipReason, 0}]; + exit:{undef, _} -> + [t({Mod, Case, Groups}, Config) || + Case <- GroupsAndCases]; + T:E -> + [{failed, {Mod, Group}, {T,E}, 0}] + end; + false -> + exit({unknown_group, Mod, Name, Groups}) + end; +t({Mod, Fun, _}, Config) + when is_atom(Mod) andalso is_atom(Fun) -> + io:format("~w:t -> entry with" + "~n Mod: ~p" + "~n Fun: ~p" + "~n Config: ~p" + "~n", [?MODULE, Mod, Fun, Config]), + case catch apply(Mod, Fun, [suite]) of + [] -> + io:format("Eval: ~p:", [{Mod, Fun}]), + Res = eval(Mod, Fun, Config), + {R, _, _, _} = Res, + io:format(" ~p~n", [R]), + Res; + + Cases when is_list(Cases) -> + io:format("Expand: ~p ...~n", [{Mod, Fun}]), + Map = fun(Case) when is_atom(Case) -> {Mod, Case}; + (Case) -> Case + end, + t(lists:map(Map, Cases), Config); + + {'EXIT', {undef, _}} -> + io:format("Undefined: ~p~n", [{Mod, Fun}]), + [{nyi, {Mod, Fun}, ok, 0}]; + + Error -> + io:format("Ignoring: ~p: ~p~n", [{Mod, Fun}, Error]), + [{failed, {Mod, Fun}, Error, 0}] + end; +t(Mod, Config) when is_atom(Mod) -> + io:format("~w:t -> entry with" + "~n Mod: ~p" + "~n Config: ~p" + "~n", [?MODULE, Mod, Config]), + %% This is assumed to be a test suite, so we start by calling + %% the top test suite function(s) (all/0 and groups/0). + case (catch Mod:all()) of + Cases when is_list(Cases) -> + %% The list may contain atoms (actual test cases) and + %% group-tuples (a tuple naming a group of test cases). + %% A group is defined by the (optional) groups/0 function. + io:format("~w:t -> suite all ok" + "~n Cases: ~p" + "~n", [?MODULE, Cases]), + Groups = groups(Mod), + io:format("~w:t -> " + "~n Groups: ~p" + "~n", [?MODULE, Groups]), + try init_suite(Mod, Config) of + Config2 when is_list(Config2) -> + io:format("~w:t -> suite init ok" + "~n Config2: ~p" + "~n", [?MODULE, Config2]), + Res = [t({Mod, Case, Groups}, Config2) || Case <- Cases], + (catch end_suite(Mod, Config2)), + Res; + Error -> + io:format(" => suite init failed: ~p~n", [Error]), + [{failed, {Mod, init_per_suite}, Error}] + catch + exit:{skipped, SkipReason} -> + io:format(" => skipping suite: ~p~n", [SkipReason]), + [{skipped, {Mod, init_per_suite}, SkipReason, 0}]; + exit:{undef, _} -> + io:format("~w:t -> suite init failed. exit undef(1)~n", [?MODULE]), + [t({Mod, Case, Groups}, Config) || Case <- Cases]; + exit:undef -> + io:format("~w:t -> suite init failed. exit undef(2)~n", [?MODULE]), + [t({Mod, Case, Groups}, Config) || Case <- Cases]; + T:E -> + io:format("~w:t -> suite init failed. " + "~n T: ~p" + "~n E: ~p" + "~n", [?MODULE, T,E]), + [{failed, {Mod, init_per_suite}, {T,E}, 0}] + end; + {'EXIT', {undef, _}} -> + io:format("Undefined: ~p~n", [{Mod, all}]), + [{nyi, {Mod, all}, ok, 0}]; + + Crap -> + io:format("~w:t -> suite all failed: " + "~n Crap: ~p" + "~n", [?MODULE, Crap]), + Crap + end; +t(Bad, _Config) -> + io:format("~w:t -> entry with" + "~n Bad: ~p" + "~n", [?MODULE, Bad]), + [{badarg, Bad, ok, 0}]. + +eval(Mod, Fun, Config) -> + TestCase = {?MODULE, Mod, Fun}, + Label = lists:concat(["TEST CASE: ", Fun]), + ?REPORT_VERBOSE(Label ++ " started", [TestCase, Config]), + global:register_name(diameter_test_case_sup, self()), + Flag = process_flag(trap_exit, true), + put(diameter_test_server, true), + Config2 = Mod:init_per_testcase(Fun, Config), + Self = self(), + Pid = spawn_link(fun() -> do_eval(Self, Mod, Fun, Config2) end), + R = wait_for_evaluator(Pid, Mod, Fun, Config2, []), + Mod:fin_per_testcase(Fun, Config2), + erase(diameter_test_server), + global:unregister_name(diameter_test_case_sup), + process_flag(trap_exit, Flag), + R. + +wait_for_evaluator(Pid, Mod, Fun, Config, Errors) -> + wait_for_evaluator(Pid, Mod, Fun, Config, Errors, 0). +wait_for_evaluator(Pid, Mod, Fun, Config, Errors, AccTime) -> + TestCase = {?MODULE, Mod, Fun}, + Label = lists:concat(["TEST CASE: ", Fun]), + receive + {done, Pid, ok, Time} when Errors =:= [] -> + ?REPORT_VERBOSE(Label ++ " ok", + [{test_case, TestCase}, {config, Config}]), + {ok, {Mod, Fun}, Errors, Time}; + {done, Pid, ok, Time} -> + ?REPORT_VERBOSE(Label ++ " failed", + [{test_case, TestCase}, {config, Config}]), + {failed, {Mod, Fun}, Errors, Time}; + {done, Pid, {ok, _}, Time} when Errors =:= [] -> + ?REPORT_VERBOSE(Label ++ " ok", + [{test_case, TestCase}, {config, Config}]), + {ok, {Mod, Fun}, Errors, Time}; + {done, Pid, {ok, _}, Time} -> + ?REPORT_VERBOSE(Label ++ " failed", + [{test_case, TestCase}, {config, Config}]), + {failed, {Mod, Fun}, Errors, Time}; + {done, Pid, Fail, Time} -> + ?REPORT_IMPORTANT(Label ++ " failed", + [{test_case, TestCase}, + {config, Config}, + {return, Fail}, + {errors, Errors}]), + {failed, {Mod, Fun}, Fail, Time}; + {'EXIT', Pid, {skipped, Reason}, Time} -> + ?REPORT_IMPORTANT(Label ++ " skipped", + [{test_case, TestCase}, + {config, Config}, + {skipped, Reason}]), + {skipped, {Mod, Fun}, Errors, Time}; + {'EXIT', Pid, Reason, Time} -> + ?REPORT_IMPORTANT(Label ++ " crashed", + [{test_case, TestCase}, + {config, Config}, + {'EXIT', Reason}]), + {crashed, {Mod, Fun}, [{'EXIT', Reason} | Errors], Time}; + {fail, Pid, Reason, Time} -> + wait_for_evaluator(Pid, Mod, Fun, Config, + Errors ++ [Reason], AccTime + Time) + end. + +do_eval(ReplyTo, Mod, Fun, Config) -> + diameter_test_lib:display_system_info("before", Mod, Fun), + case timer:tc(Mod, Fun, [Config]) of + {Time, {'EXIT', {skipped, Reason}}} -> + display_tc_time(Time), + diameter_test_lib:display_system_info("after (skipped)", Mod, Fun), + ReplyTo ! {'EXIT', self(), {skipped, Reason}, Time}; + {Time, {'EXIT', Reason}} -> + display_tc_time(Time), + diameter_test_lib:display_system_info("after (crashed)", Mod, Fun), + ReplyTo ! {'EXIT', self(), Reason, Time}; + {Time, Other} -> + display_tc_time(Time), + diameter_test_lib:display_system_info("after", Mod, Fun), + ReplyTo ! {done, self(), Other, Time} + end, + unlink(ReplyTo), + exit(shutdown). + + +display_tc_time(Time) -> + io:format("~n" + "~n*********************************************" + "~n" + "~nTest case completion time: ~.3f sec (~w)" + "~n", [(Time / 1000000), Time]), + ok. + + +display_result(Res, Alloc1, Mem1, Alloc2, Mem2) -> + io:format("~nAllocator info: ~n", []), + display_alloc(Alloc1, Alloc2), + io:format("~nMemory info: ~n", []), + display_memory(Mem1, Mem2), + display_result(Res). + +display_alloc([], []) -> + io:format("-~n", []), + ok; +display_alloc(A1, A2) -> + do_display_alloc(A1, A2). + +do_display_alloc([], _) -> + ok; +do_display_alloc([{Alloc, Mem1}|AllocInfo1], AllocInfo2) -> + Mem2 = + case lists:keysearch(Alloc, 1, AllocInfo2) of + {value, {_, Val}} -> + Val; + false -> + undefined + end, + io:format("~15w: ~10w -> ~w~n", [Alloc, Mem1, Mem2]), + do_display_alloc(AllocInfo1, AllocInfo2). + +display_memory([], []) -> + io:format("-~n", []), + ok; +display_memory(Mem1, Mem2) -> + do_display_memory(Mem1, Mem2). + + +do_display_memory([], _) -> + ok; +do_display_memory([{Key, Mem1}|MemInfo1], MemInfo2) -> + Mem2 = + case lists:keysearch(Key, 1, MemInfo2) of + {value, {_, Val}} -> + Val; + false -> + undefined + end, + io:format("~15w: ~10w -> ~w~n", [Key, Mem1, Mem2]), + do_display_memory(MemInfo1, MemInfo2). + +display_result([]) -> + io:format("OK~n", []); +display_result(Res) when is_list(Res) -> + Ok = [{MF, Time} || {ok, MF, _, Time} <- Res], + Nyi = [MF || {nyi, MF, _, _Time} <- Res], + Skipped = [{MF, Reason} || {skipped, MF, Reason, _Time} <- Res], + Failed = [{MF, Reason} || {failed, MF, Reason, _Time} <- Res], + Crashed = [{MF, Reason} || {crashed, MF, Reason, _Time} <- Res], + display_summery(Ok, Nyi, Skipped, Failed, Crashed), + display_ok(Ok), + display_skipped(Skipped), + display_failed(Failed), + display_crashed(Crashed). + +display_summery(Ok, Nyi, Skipped, Failed, Crashed) -> + io:format("~nTest case summery:~n", []), + display_summery(Ok, "successfull"), + display_summery(Nyi, "not yet implemented"), + display_summery(Skipped, "skipped"), + display_summery(Failed, "failed"), + display_summery(Crashed, "crashed"), + io:format("~n", []). + +display_summery(Res, Info) -> + io:format(" ~w test cases ~s~n", [length(Res), Info]). + +display_ok([]) -> + ok; +display_ok(Ok) -> + io:format("Ok test cases:~n", []), + F = fun({{M, F}, Time}) -> + io:format(" ~w : ~w => ~.2f sec~n", [M, F, Time / 1000000]) + end, + lists:foreach(F, Ok), + io:format("~n", []). + +display_skipped([]) -> + ok; +display_skipped(Skipped) -> + io:format("Skipped test cases:~n", []), + F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, + lists:foreach(F, Skipped), + io:format("~n", []). + + +display_failed([]) -> + ok; +display_failed(Failed) -> + io:format("Failed test cases:~n", []), + F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, + lists:foreach(F, Failed), + io:format("~n", []). + +display_crashed([]) -> + ok; +display_crashed(Crashed) -> + io:format("Crashed test cases:~n", []), + F = fun({MF, Reason}) -> io:format(" ~p => ~p~n", [MF, Reason]) end, + lists:foreach(F, Crashed), + io:format("~n", []). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Test server callbacks +init_per_testcase(_Case, Config) -> + Pid = group_leader(), + Name = ?GLOGGER, + case global:whereis_name(Name) of + undefined -> + global:register_name(?GLOGGER, Pid); + Pid -> + io:format("~w:init_per_testcase -> " + "already registered to ~p~n", [?MODULE, Pid]), + ok; + OtherPid when is_pid(OtherPid) -> + io:format("~w:init_per_testcase -> " + "already registered to other ~p (~p)~n", + [?MODULE, OtherPid, Pid]), + exit({already_registered, {?GLOGGER, OtherPid, Pid}}) + end, + set_kill_timer(Config). + +fin_per_testcase(_Case, Config) -> + Name = ?GLOGGER, + case global:whereis_name(Name) of + undefined -> + io:format("~w:fin_per_testcase -> already un-registered~n", + [?MODULE]), + ok; + Pid when is_pid(Pid) -> + global:unregister_name(?GLOGGER), + ok + end, + reset_kill_timer(Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Set kill timer + +set_kill_timer(Config) -> + case init:get_argument(diameter_test_timeout) of + {ok, _} -> + Config; + _ -> + Time = + case lookup_config(tc_timeout, Config) of + [] -> + timer:minutes(5); + ConfigTime when is_integer(ConfigTime) -> + ConfigTime + end, + Dog = + case get(diameter_test_server) of + true -> + Self = self(), + spawn_link(fun() -> watchdog(Self, Time) end); + _ -> + test_server:timetrap(Time) + end, + [{kill_timer, Dog}|Config] + + + end. + +reset_kill_timer(Config) -> + DogKiller = + case get(diameter_test_server) of + true -> + fun(P) when is_pid(P) -> P ! stop; + (_) -> ok + end; + _ -> + fun(Ref) -> test_server:timetrap_cancel(Ref) end + end, + case lists:keysearch(kill_timer, 1, Config) of + {value, {kill_timer, Dog}} -> + DogKiller(Dog), + lists:keydelete(kill_timer, 1, Config); + _ -> + Config + end. + +watchdog(Pid, Time) -> + erlang:now(), + receive + stop -> + ok + after Time -> + case (catch process_info(Pid)) of + undefined -> + ok; + Info -> + ?LOG("<ERROR> Watchdog in test case timed out " + "for ~p after ~p min" + "~n~p" + "~n", + [Pid, Time div (1000*60), Info]), + exit(Pid, kill) + end + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +lookup_config(Key, Config) -> + diameter_test_lib:lookup_config(Key, Config). + +default_config() -> + [{nodes, default_nodes()}, {ts, diameter}]. + +default_nodes() -> + mk_nodes(2, []). + +mk_nodes(0, Nodes) -> + Nodes; +mk_nodes(N, []) -> + mk_nodes(N - 1, [node()]); +mk_nodes(N, Nodes) when N > 0 -> + Head = hd(Nodes), + [Name, Host] = node_to_name_and_host(Head), + Nodes ++ [mk_node(I, Name, Host) || I <- lists:seq(1, N)]. + +mk_node(N, Name, Host) -> + list_to_atom(lists:concat([Name ++ integer_to_list(N) ++ "@" ++ Host])). + +%% Returns [Name, Host] +node_to_name_and_host(Node) -> + string:tokens(atom_to_list(Node), [$@]). + + + + diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk new file mode 100644 index 0000000000..ddc720d0c1 --- /dev/null +++ b/lib/diameter/test/modules.mk @@ -0,0 +1,47 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +TEST_SPEC_FILE = diameter.spec + +COVER_SPEC_FILE = diameter.cover + +BEHAVIOUR_MODULES = + +MODULES = \ + $(BEHAVIOUR_MODULES) \ + diameter_SUITE \ + diameter_app_test \ + diameter_appup_test \ + diameter_compiler_test \ + diameter_config_test \ + diameter_peer_test \ + diameter_reg_test \ + diameter_session_test \ + diameter_stats_test \ + diameter_sync_test \ + diameter_tcp_test \ + diameter_test_lib \ + diameter_test_server + + +INTERNAL_HRL_FILES = \ + diameter_test_lib.hrl + + + diff --git a/lib/diameter/test/slask/diameter_persistent_table_test.erl b/lib/diameter/test/slask/diameter_persistent_table_test.erl new file mode 100644 index 0000000000..bb907a5777 --- /dev/null +++ b/lib/diameter/test/slask/diameter_persistent_table_test.erl @@ -0,0 +1,495 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +%% Purpose: Verify the persistent-table component of the Diameter application +%%---------------------------------------------------------------------- +%% +-module(diameter_persistent_table_test). + +-export([ + init_per_testcase/2, fin_per_testcase/2, + + all/1, + suite_init/1, suite_fin/1, + + simple_start_and_stop/1, + table_create_and_delete/1 + + ]). + +-export([t/0, t/1]). + +-include("diameter_test_lib.hrl"). + +-record(command, {id, desc, cmd, verify}). + + +t() -> diameter_test_server:t(?MODULE). +t(Case) -> diameter_test_server:t({?MODULE, Case}). + + +%% Test server callbacks +init_per_testcase(Case, Config) -> + diameter_test_server:init_per_testcase(Case, Config). + +fin_per_testcase(Case, Config) -> + diameter_test_server:fin_per_testcase(Case, Config). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +all(suite) -> + Cases = + [ + simple_start_and_stop, + table_create_and_delete + ], + {req, [], {conf, suite_init, Cases, suite_fin}}. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +suite_init(suite) -> []; +suite_init(doc) -> []; +suite_init(Config) when is_list(Config) -> + Config. + + +suite_fin(suite) -> []; +suite_fin(doc) -> []; +suite_fin(Config) when is_list(Config) -> + Config. + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% Test case(s) +%% + +simple_start_and_stop(suite) -> + []; +simple_start_and_stop(doc) -> + []; +simple_start_and_stop(Config) when is_list(Config) -> + diameter:enable_trace(100, io), + case diameter_persistent_table:start_link() of + {ok, Pid} -> + unlink(Pid); + {error, Reason} -> + exit({failed_starting, Reason}) + end, + + ok = diameter_persistent_table:stop(), + ok. + + +table_create_and_delete(suite) -> + []; +table_create_and_delete(doc) -> + []; +table_create_and_delete(Config) when is_list(Config) -> + process_flag(trap_exit, true), + + %% Command range values + Initial = 100, + ClientCreation = 200, + Nice = 300, + Evil = 400, + End = 500, + + Verbosity = min, + %% Verbosity = max, + + Data01 = lists:sort([{a, 10}, {b, 20}, {c, 30}]), + Data02 = lists:sort([{x, 100}, {y, 200}, {z, 300}]), + + Commands = + [ + %% Initial commands + initial_command( Initial + 0, + "enable trace", + fun() -> diameter:enable_trace(Verbosity, io) end, + ok), + initial_command( Initial + 1, + "start persistent-table process", + fun() -> + case diameter_persistent_table:start_link() of + {ok, Pid} when is_pid(Pid) -> + ok; + Error -> + Error + end + end, + ok), + + client_create_command( ClientCreation + 1, + "1", + client01), + + client_create_command( ClientCreation + 2, + "2", + client02), + + nice_command( Nice + 1, + "client 1 create table 1", + fun() -> + create_table(client01, tab01, []), + diameter_persistent_table:which_tables() + end, + fun([tab01] = Tabs) -> + {ok, Tabs}; + (Unexpected) -> + {error, {bad_tables, Unexpected}} + end), + + nice_command( Nice + 2, + "client 1 create table 2", + fun() -> + create_table(client01, tab02, []), + diameter_persistent_table:which_tables() + end, + fun([tab01, tab02] = Tabs) -> + {ok, Tabs}; + ([tab02, tab01] = Tabs) -> + {ok, Tabs}; + (Unexpected) -> + {error, {bad_tables, Unexpected}} + end), + + nice_command( Nice + 3, + "client 2 create table 1", + fun() -> + create_table(client02, tab03, []), + diameter_persistent_table:which_tables(whereis(client02)) + end, + fun([tab03] = Tabs) -> + {ok, Tabs}; + (Unexpected) -> + {error, {bad_tables, Unexpected}} + end), + + nice_command( Nice + 4, + "client 1 delete table 1", + fun() -> + delete_table(client01, tab01), + diameter_persistent_table:which_tables(whereis(client01)) + end, + fun([tab02] = Tabs) -> + {ok, Tabs}; + (Unexpected) -> + {error, {bad_tables, Unexpected}} + end), + + nice_command( Nice + 5, + "client 1 fill in some data in tab02", + fun() -> + populate_table(client01, tab02, Data01), + lists:sort(ets:tab2list(tab02)) + end, + fun(Data) when Data =:= Data01 -> + {ok, Data}; + (Unexpected) -> + {error, {bad_data, Unexpected}} + end), + + nice_command( Nice + 6, + "client 2 fill in some data in tab03", + fun() -> + populate_table(client02, tab03, Data02), + lists:sort(ets:tab2list(tab03)) + end, + fun(Data) when Data =:= Data02 -> + {ok, Data}; + (Unexpected) -> + {error, {bad_data, Unexpected}} + end), + + nice_command( Nice + 7, + "simulate client 1 crash", + fun() -> + simulate_crash(client01) + end, + fun(ok) -> + {ok, crashed}; + (Unexpected) -> + {error, {bad_simulation_result, Unexpected}} + end), + + client_create_command( Nice + 8, + "1 restarted", + client01), + + nice_command( Nice + 9, + "client 1 create tab02 - verify data", + fun() -> + create_table(client01, tab02, []), + lists:sort(ets:tab2list(tab02)) + end, + fun(Data) when Data =:= Data01 -> + {ok, Data}; + (Unexpected) -> + {error, {bad_data, Unexpected}} + end), + + evil_command( Evil + 1, + "try (and fail) to delete the non-existing table tab04", + fun() -> + delete_table(client02, tab04) + end, + fun({error, {unknown_table, tab04}}) -> + {ok, tab04}; + (X) -> + {error, {bad_result, X}} + end), + + evil_command( Evil + 2, + "try (and fail) to delete a not owned table tab02", + fun() -> + delete_table(client02, tab02) + end, + fun({error, {not_owner, tab02}}) -> + {ok, tab02}; + (X) -> + {error, {bad_result, X}} + end), + + evil_command( Evil + 3, + "try (and fail) to create an already existing *and* owned table - tab03", + fun() -> + create_table(client02, tab03, []) + end, + fun({error, {already_owner, tab03}}) -> + {ok, tab03}; + (X) -> + {error, {bad_result, X}} + end), + + evil_command( Evil + 4, + "try (and fail) to create an already existing not owned table - tab02", + fun() -> + create_table(client02, tab02, []) + end, + fun({error, {not_owner, _Owner, tab02}}) -> + {ok, tab02}; + (X) -> + {error, {bad_result, X}} + end), + + end_command( End + 1, + "stop client01", + fun() -> stop_client(client01) end), + + end_command( End + 2, + "stop client02", + fun() -> stop_client(client02) end), + + end_command( End + 2, + "stop persistent-table", + fun() -> diameter_persistent_table:stop() end), + + evil_command( Evil + 5, + "try (and fail) to stop a not running persistent-table process", + fun() -> + diameter_persistent_table:stop() + end, + fun({'EXIT', {noproc, _}}) -> + {ok, not_running}; + (X) -> + {error, {bad_result, X}} + end) + + ], + + exec(Commands). + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%% +%% Command engine +%% + +exec([]) -> + ok; +exec([#command{id = No, + desc = Desc, + cmd = Cmd, + verify = Verify}|Commands]) -> + io:format("Executing command ~2w: ~s: ", [No, Desc]), + case (catch Verify((catch Cmd()))) of + {ok, OK} -> + io:format("ok => ~p~n", [OK]), + exec(Commands); + {error, Reason} -> + io:format("error => ~p~n", [Reason]), + {error, {bad_result, No, Reason}}; + Error -> + io:format("exit => ~p~n", [Error]), + {error, {unexpected_result, No, Error}} + end. + +initial_command(No, Desc0, Cmd, VerifyVal) when is_function(Cmd) -> + Desc = lists:flatten(io_lib:format("Initial - ~s", [Desc0])), + command(No, Desc, Cmd, VerifyVal). + +client_create_command(No, Desc0, Name) -> + Desc = lists:flatten(io_lib:format("Client create - ~s", [Desc0])), + Self = self(), + Cmd = fun() -> start_client(Self, Name) end, + command(No, Desc, Cmd, ok). + +nice_command(No, Desc0, Cmd, Verify) + when is_function(Cmd) andalso is_function(Verify) -> + Desc = lists:flatten(io_lib:format("Nice - ~s", [Desc0])), + command(No, Desc, Cmd, Verify). + +evil_command(No, Desc0, Cmd, Verify) + when is_function(Cmd) andalso is_function(Verify) -> + Desc = lists:flatten(io_lib:format("Evil - ~s", [Desc0])), + command(No, Desc, Cmd, Verify). + +end_command(No, Desc0, Cmd) when is_function(Cmd) -> + Desc = lists:flatten(io_lib:format("End - ~s", [Desc0])), + command(No, Desc, Cmd, ok). + +command(No, Desc, Cmd, Verify) + when (is_integer(No) andalso + is_list(Desc) andalso + is_function(Cmd) andalso + is_function(Verify)) -> + #command{id = No, + desc = Desc, + cmd = Cmd, + verify = Verify}; +command(No, Desc, Cmd, VerifyVal) + when (is_integer(No) andalso + is_list(Desc) andalso + is_function(Cmd)) -> + Verify = + fun(Val) -> + case Val of + VerifyVal -> + {ok, Val}; + _ -> + {error, Val} + end + end, + #command{id = No, + desc = Desc, + cmd = Cmd, + verify = Verify}. + + +start_client(Parent, Name) -> + ClientPid = spawn_link(fun() -> client_init(Parent, Name) end), + receive + {ClientPid, started} -> + ClientPid, + ok; + {'EXIT', ClientPid, Reason} -> + {error, {failed_starting_client, Reason}} + end. + +stop_client(Client) -> + Pid = whereis(Client), + Pid ! stop, + receive + {'EXIT', Pid, normal} -> + ok + end. + +create_table(Client, Tab, Opts) -> + Self = self(), + Pid = whereis(Client), + Pid ! {create_table, Tab, Opts, Self}, + receive + {Pid, created} -> + ok; + {Pid, {create_failed, Error}} -> + Error + end. + +delete_table(Client, Tab) -> + Self = self(), + Pid = whereis(Client), + Pid ! {delete_table, Tab, Self}, + receive + {Pid, deleted} -> + ok; + {Pid, {delete_failed, Error}} -> + Error + end. + +populate_table(Client, Tab, Data) -> + Self = self(), + Pid = whereis(Client), + Pid ! {populate_table, Tab, Data, Self}, + receive + {Pid, populated} -> + ok + end. + +simulate_crash(Client) -> + Pid = whereis(Client), + Pid ! simulate_crash, + receive + {'EXIT', Pid, simulated_crash} -> + ok + end. + +client_init(Parent, Name) -> + erlang:register(Name, self()), + process_flag(trap_exit, true), + Parent ! {self(), started}, + client_loop(). + +client_loop() -> + receive + stop -> + exit(normal); + + {create_table, T, Opts, From} when is_atom(T) andalso is_list(Opts) -> + case diameter_persistent_table:create(T, Opts) of + ok -> + From ! {self(), created}; + Error -> + From ! {self(), {create_failed, Error}} + end, + client_loop(); + + {delete_table, T, From} -> + case diameter_persistent_table:delete(T) of + ok -> + From ! {self(), deleted}; + Error -> + From ! {self(), {delete_failed, Error}} + end, + client_loop(); + + {populate_table, Tab, Data, From} -> + ets:insert(Tab, Data), + From ! {self(), populated}, + client_loop(); + + simulate_crash -> + exit(simulated_crash) + end. + diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk new file mode 100644 index 0000000000..9f822e4e85 --- /dev/null +++ b/lib/diameter/vsn.mk @@ -0,0 +1,25 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +APPLICATION = diameter +DIAMETER_VSN = 0.9 +PRE_VSN = +APP_VSN = "$(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)" + +TICKETS = diff --git a/lib/erl_interface/src/epmd/epmd_port.c b/lib/erl_interface/src/epmd/epmd_port.c index 698c75c217..a433815eb7 100644 --- a/lib/erl_interface/src/epmd/epmd_port.c +++ b/lib/erl_interface/src/epmd/epmd_port.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2010. All Rights Reserved. + * Copyright Ericsson AB 1998-2011. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -228,11 +228,8 @@ int ei_epmd_port (struct in_addr *addr, const char *alive, int *dist) return ei_epmd_port_tmo (addr, alive, dist, 0); } -int ei_epmd_port_tmo (struct in_addr *addr, const char *alive, int *dist, - unsigned ms) +int ei_epmd_port_tmo (struct in_addr *addr, const char *alive, int *dist, unsigned ms) { - int i; - - return ei_epmd_r4_port(addr,alive,dist,ms); + return ei_epmd_r4_port(addr,alive,dist,ms); } diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl index c009164f4c..0b47c7b6e1 100644 --- a/lib/hipe/cerl/erl_bif_types.erl +++ b/lib/hipe/cerl/erl_bif_types.erl @@ -154,7 +154,7 @@ type(binary, bin_to_list, Arity, Xs) when 1 =< Arity, Arity =< 3 -> fun(_) -> t_list(t_integer()) end); type(binary, compile_pattern, 1, Xs) -> strict(arg_types(binary, compile_pattern, 1), Xs, - fun(_) -> t_tuple([t_atom(bm),t_binary()]) end); + fun(_) -> t_binary_compiled_pattern() end); type(binary, copy, Arity, Xs) when Arity =:= 1; Arity =:= 2 -> strict(arg_types(binary, copy, Arity), Xs, fun(_) -> t_binary() end); @@ -4469,27 +4469,6 @@ t_endian() -> t_sup(t_atom('big'), t_atom('little')). %% ===================================================================== -%% Types for the binary module -%% ===================================================================== - -t_binary_part() -> - t_tuple([t_non_neg_integer(), t_integer()]). - -t_binary_canonical_part() -> - t_tuple([t_non_neg_integer(), t_non_neg_integer()]). - -t_binary_pattern() -> - t_sup([t_binary(), - t_list(t_binary()), - t_binary_compiled_pattern()]). - -t_binary_compiled_pattern() -> - t_tuple([t_atom('cp'), t_binary()]). - -t_binary_options() -> - t_list(t_tuple([t_atom('scope'), t_binary_part()])). - -%% ===================================================================== %% HTTP types documented in R12B-4 %% ===================================================================== @@ -4544,7 +4523,28 @@ t_HttpFieldAtom() -> 'Keep-Alive', 'Proxy-Connection']). t_HttpString() -> - t_sup(t_string(),t_binary()). + t_sup(t_string(), t_binary()). + +%% ===================================================================== +%% These are used for the built-in functions of 'binary' +%% ===================================================================== + +t_binary_part() -> + t_tuple([t_non_neg_integer(), t_integer()]). + +t_binary_canonical_part() -> + t_tuple([t_non_neg_integer(), t_non_neg_integer()]). + +t_binary_pattern() -> + t_sup([t_binary(), + t_list(t_binary()), + t_binary_compiled_pattern()]). + +t_binary_compiled_pattern() -> + t_tuple([t_sup(t_atom('bm'), t_atom('ac')), t_binary()]). + +t_binary_options() -> + t_list(t_tuple([t_atom('scope'), t_binary_part()])). %% ===================================================================== %% These are used for the built-in functions of 'code' @@ -4565,11 +4565,6 @@ t_code_load_error_rsn() -> % also used in erlang:load_module/2 t_atom('on_load'), t_atom('sticky_directory')]). % only for the 'code' functions -t_code_loaded_fname_or_status() -> - t_sup([t_string(), % filename - t_atom('preloaded'), - t_atom('cover_compiled')]). - %% ===================================================================== %% These are used for the built-in functions of 'erlang' %% ===================================================================== @@ -4734,7 +4729,6 @@ t_scheduler_bind_type_results() -> t_atom('thread_no_node_processor_spread'), t_atom('unbound')]). - t_system_monitor_settings() -> t_sup([t_atom('undefined'), t_tuple([t_pid(), t_system_monitor_options()])]). @@ -4814,13 +4808,6 @@ t_ets_info_items() -> t_atom('type')]). %% ===================================================================== -%% These are used for the built-in functions of 'prim_file' -%% ===================================================================== - -t_prim_file_name() -> - t_sup(t_unicode_string(), t_binary()). - -%% ===================================================================== %% These are used for the built-in functions of 'gen_tcp' %% ===================================================================== @@ -5014,6 +5001,13 @@ t_re_CapturedData() -> t_sup([t_tuple([t_integer(), t_integer()]), t_string(), t_binary()]). %% ===================================================================== +%% These are used for the built-in functions of 'prim_file' +%% ===================================================================== + +t_prim_file_name() -> + t_sup(t_unicode_string(), t_binary()). + +%% ===================================================================== %% These are used for the built-in functions of 'unicode' %% ===================================================================== diff --git a/lib/inets/doc/src/http_server.xml b/lib/inets/doc/src/http_server.xml index 959386e471..599a939913 100644 --- a/lib/inets/doc/src/http_server.xml +++ b/lib/inets/doc/src/http_server.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2004</year><year>2010</year> + <year>2004</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/doc/src/inets.xml b/lib/inets/doc/src/inets.xml index a2bf42320f..079f60779d 100644 --- a/lib/inets/doc/src/inets.xml +++ b/lib/inets/doc/src/inets.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2007</year><year>2010</year> + <year>2007</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl index b70b16f57f..6ffa5e8ba5 100644 --- a/lib/inets/src/http_client/httpc.erl +++ b/lib/inets/src/http_client/httpc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2009-2010. All Rights Reserved. +%% Copyright Ericsson AB 2009-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl index 8cabfe3c71..01b51d531a 100644 --- a/lib/inets/src/http_lib/http_transport.erl +++ b/lib/inets/src/http_lib/http_transport.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl index 5e6b69ac5e..5511ed388d 100644 --- a/lib/inets/src/http_lib/http_util.erl +++ b/lib/inets/src/http_lib/http_util.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/inets/src/http_server/httpd_sup.erl b/lib/inets/src/http_server/httpd_sup.erl index d028a19bf0..264dc9f006 100644 --- a/lib/inets/src/http_server/httpd_sup.erl +++ b/lib/inets/src/http_server/httpd_sup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl index c1aff65d5e..c051422529 100644 --- a/lib/inets/src/http_server/httpd_util.erl +++ b/lib/inets/src/http_server/httpd_util.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/inets/test/inets_app_test.erl b/lib/inets/test/inets_app_test.erl index 49ea18501f..9d7202e087 100644 --- a/lib/inets/test/inets_app_test.erl +++ b/lib/inets/test/inets_app_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2010. All Rights Reserved. +%% Copyright Ericsson AB 2002-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl index c837326bb5..6cedaf9638 100644 --- a/lib/inets/test/inets_test_lib.erl +++ b/lib/inets/test/inets_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/inets/test/inets_test_lib.hrl b/lib/inets/test/inets_test_lib.hrl index cc83a309b5..4dd81093a2 100644 --- a/lib/inets/test/inets_test_lib.hrl +++ b/lib/inets/test/inets_test_lib.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2001-2010. All Rights Reserved. +%% Copyright Ericsson AB 2001-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl index d5a8a2f134..2276ddcd08 100644 --- a/lib/kernel/src/inet_res.erl +++ b/lib/kernel/src/inet_res.erl @@ -872,7 +872,7 @@ query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, end end. -query_udp(_S, _Id, _Buffer, _IP, _Port, 0, Verbose) -> +query_udp(_S, _Id, _Buffer, _IP, _Port, 0, _Verbose) -> timeout; query_udp(S, Id, Buffer, IP, Port, Timeout, Verbose) -> ?verbose(Verbose, "Try UDP server : ~p:~p (timeout=~w)\n", @@ -908,7 +908,7 @@ query_udp(S, Id, Buffer, IP, Port, Timeout, Verbose) -> {error,econnrefused} end. -query_tcp(0, _Id, _Buffer, _IP, _Port, Verbose) -> +query_tcp(0, _Id, _Buffer, _IP, _Port, _Verbose) -> timeout; query_tcp(Timeout, Id, Buffer, IP, Port, Verbose) -> ?verbose(Verbose, "Try TCP server : ~p:~p (timeout=~w)\n", diff --git a/lib/kernel/test/Makefile b/lib/kernel/test/Makefile index 95517ffd6a..82bc3fc6d1 100644 --- a/lib/kernel/test/Makefile +++ b/lib/kernel/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2010. All Rights Reserved. +# Copyright Ericsson AB 1997-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl index 2f73394c4e..fdab2eb02b 100644 --- a/lib/kernel/test/file_SUITE.erl +++ b/lib/kernel/test/file_SUITE.erl @@ -360,41 +360,50 @@ make_del_dir(Config) when is_list(Config) -> ?line {error, eexist} = ?FILE_MODULE:make_dir(NewDir), ?line ok = ?FILE_MODULE:del_dir(NewDir), ?line {error, enoent} = ?FILE_MODULE:del_dir(NewDir), - - %% Check that we get an error when trying to create... - %% a deep directory - ?line NewDir2 = filename:join(RootDir, - atom_to_list(?MODULE) - ++"_mk-dir/foo"), - ?line {error, enoent} = ?FILE_MODULE:make_dir(NewDir2), - %% a nameless directory - ?line {error, enoent} = ?FILE_MODULE:make_dir(""), - %% a directory with illegal name - ?line {error, badarg} = ?FILE_MODULE:make_dir({1,2,3}), - - %% a directory with illegal name, even if it's a (bad) list - ?line {error, badarg} = ?FILE_MODULE:make_dir([1,2,3,{}]), - - %% Maybe this isn't an error, exactly, but worth mentioning anyway: - %% ok = ?FILE_MODULE:make_dir([$f,$o,$o,0,$b,$a,$r])), - %% The above line works, and created a directory "./foo" - %% More elegant would maybe have been to fail, or to really create - %% a directory, but with a name that incorporates the "bar" part of - %% the list, so that [$f,$o,$o,0,$f,$o,$o] wouldn't refer to the same - %% dir. But this would slow it down. - - %% Try deleting some bad directories - %% Deleting the parent directory to the current, sounds dangerous, huh? - %% Don't worry ;-) the parent directory should never be empty, right? - case ?FILE_MODULE:del_dir('..') of - {error, eexist} -> ok; - {error, einval} -> ok %FreeBSD + % Make sure we are not in a directory directly under test_server + % as that would result in eacess errors when trying to delere '..', + % because there are processes having that directory as current. + ?line ok = ?FILE_MODULE:make_dir(NewDir), + ?line {ok,CurrentDir} = file:get_cwd(), + ?line ok = ?FILE_MODULE:set_cwd(NewDir), + try + %% Check that we get an error when trying to create... + %% a deep directory + ?line NewDir2 = filename:join(RootDir, + atom_to_list(?MODULE) + ++"_mk-dir-noexist/foo"), + ?line {error, enoent} = ?FILE_MODULE:make_dir(NewDir2), + %% a nameless directory + ?line {error, enoent} = ?FILE_MODULE:make_dir(""), + %% a directory with illegal name + ?line {error, badarg} = ?FILE_MODULE:make_dir({1,2,3}), + + %% a directory with illegal name, even if it's a (bad) list + ?line {error, badarg} = ?FILE_MODULE:make_dir([1,2,3,{}]), + + %% Maybe this isn't an error, exactly, but worth mentioning anyway: + %% ok = ?FILE_MODULE:make_dir([$f,$o,$o,0,$b,$a,$r])), + %% The above line works, and created a directory "./foo" + %% More elegant would maybe have been to fail, or to really create + %% a directory, but with a name that incorporates the "bar" part of + %% the list, so that [$f,$o,$o,0,$f,$o,$o] wouldn't refer to the same + %% dir. But this would slow it down. + + %% Try deleting some bad directories + %% Deleting the parent directory to the current, sounds dangerous, huh? + %% Don't worry ;-) the parent directory should never be empty, right? + ?line case ?FILE_MODULE:del_dir('..') of + {error, eexist} -> ok; + {error, einval} -> ok %FreeBSD + end, + ?line {error, enoent} = ?FILE_MODULE:del_dir(""), + ?line {error, badarg} = ?FILE_MODULE:del_dir([3,2,1,{}]), + + ?line [] = flush(), + ?line test_server:timetrap_cancel(Dog) + after + ?FILE_MODULE:set_cwd(CurrentDir) end, - ?line {error, enoent} = ?FILE_MODULE:del_dir(""), - ?line {error, badarg} = ?FILE_MODULE:del_dir([3,2,1,{}]), - - ?line [] = flush(), - ?line test_server:timetrap_cancel(Dog), ok. cur_dir_0(suite) -> []; diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl index a04ea3cdcd..00eda6292f 100644 --- a/lib/kernel/test/prim_file_SUITE.erl +++ b/lib/kernel/test/prim_file_SUITE.erl @@ -250,39 +250,49 @@ make_del_dir(Config, Handle, Suffix) -> ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [NewDir]), - %% Check that we get an error when trying to create... - %% a deep directory - ?line NewDir2 = filename:join(RootDir, - atom_to_list(?MODULE) - ++"_mk-dir/foo"), - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]), - %% a nameless directory - ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]), - %% a directory with illegal name - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']), - - %% a directory with illegal name, even if it's a (bad) list - ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]), - - %% Maybe this isn't an error, exactly, but worth mentioning anyway: - %% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])), - %% The above line works, and created a directory "./foo" - %% More elegant would maybe have been to fail, or to really create - %% a directory, but with a name that incorporates the "bar" part of - %% the list, so that [$f,$o,$o,0,$f,$o,$o] wouldn't refer to the same - %% dir. But this would slow it down. - - %% Try deleting some bad directories - %% Deleting the parent directory to the current, sounds dangerous, huh? - %% Don't worry ;-) the parent directory should never be empty, right? - case ?PRIM_FILE_call(del_dir, Handle, [".."]) of - {error, eexist} -> ok; - {error, einval} -> ok %FreeBSD + % Make sure we are not in a directory directly under test_server + % as that would result in eacess errors when trying to delere '..', + % because there are processes having that directory as current. + ?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]), + ?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []), + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]), + try + %% Check that we get an error when trying to create... + %% a deep directory + ?line NewDir2 = filename:join(RootDir, + atom_to_list(?MODULE) + ++"_mk-dir-noexist/foo"), + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [NewDir2]), + %% a nameless directory + ?line {error, enoent} = ?PRIM_FILE_call(make_dir, Handle, [""]), + %% a directory with illegal name + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, ['mk-dir']), + + %% a directory with illegal name, even if it's a (bad) list + ?line {error, badarg} = ?PRIM_FILE_call(make_dir, Handle, [[1,2,3,{}]]), + + %% Maybe this isn't an error, exactly, but worth mentioning anyway: + %% ok = ?PRIM_FILE:make_dir([$f,$o,$o,0,$b,$a,$r])), + %% The above line works, and created a directory "./foo" + %% More elegant would maybe have been to fail, or to really create + %% a directory, but with a name that incorporates the "bar" part of + %% the list, so that [$f,$o,$o,0,$f,$o,$o] wouldn't refer to the same + %% dir. But this would slow it down. + + %% Try deleting some bad directories + %% Deleting the parent directory to the current, sounds dangerous, huh? + %% Don't worry ;-) the parent directory should never be empty, right? + ?line case ?PRIM_FILE_call(del_dir, Handle, [".."]) of + {error, eexist} -> ok; + {error, einval} -> ok %FreeBSD + end, + ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), + ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), + + ?line test_server:timetrap_cancel(Dog) + after + ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir]) end, - ?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]), - ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]), - - ?line test_server:timetrap_cancel(Dog), ok. cur_dir_0a(suite) -> []; diff --git a/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc b/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc index 21174340d1..ae41a216f4 100644 --- a/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc +++ b/lib/mnesia/doc/src/Mnesia_chap7.xmlsrc @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/mnesia/doc/src/mnesia.xml b/lib/mnesia/doc/src/mnesia.xml index 2a2c7d3a9f..7a8f796cee 100644 --- a/lib/mnesia/doc/src/mnesia.xml +++ b/lib/mnesia/doc/src/mnesia.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>1996</year><year>2010</year> + <year>1996</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src index 7bad6c4ea6..3691aa249a 100644 --- a/lib/mnesia/src/mnesia.appup.src +++ b/lib/mnesia/src/mnesia.appup.src @@ -1,33 +1,13 @@ %% -*- erlang -*- {"%VSN%", [ - {"4.4.17",[ - {update, mnesia_controller, soft, soft_purge, soft_purge, []} - ]}, - {"4.4.16",[ - {update, mnesia_controller, soft, soft_purge, soft_purge, []}, - {update, mnesia_frag, soft, soft_purge, soft_purge, []}, - {update, mnesia_schema, soft, soft_purge, soft_purge, []} - ]}, - {"4.4.15",[ - {update, mnesia_controller, soft, soft_purge, soft_purge, []}, - {update, mnesia_frag, soft, soft_purge, soft_purge, []}, - {update, mnesia, soft, soft_purge, soft_purge, []}, - {update, mnesia_dumper, soft, soft_purge, soft_purge, []} - ]} + {"4.4.18", [{restart_application, mnesia}]}, + {"4.4.17", [{restart_application, mnesia}]}, + {"4.4.16", [{restart_application, mnesia}]} ], - {"4.4.17",[ - {update, mnesia_controller, soft, soft_purge, soft_purge, []} - ]}, - {"4.4.16",[ - {update, mnesia_controller, soft, soft_purge, soft_purge, []}, - {update, mnesia_frag, soft, soft_purge, soft_purge, []}, - {update, mnesia_schema, soft, soft_purge, soft_purge, []} - ]}, - {"4.4.15",[ - {update, mnesia_controller, soft, soft_purge, soft_purge, []}, - {update, mnesia_frag, soft, soft_purge, soft_purge, []}, - {update, mnesia, soft, soft_purge, soft_purge, []}, - {update, mnesia_dumper, soft, soft_purge, soft_purge, []} - ]} + [ + {"4.4.18", [{restart_application, mnesia}]}, + {"4.4.17", [{restart_application, mnesia}]}, + {"4.4.16", [{restart_application, mnesia}]} + ] }. diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl index 26537815a3..2375b72d59 100644 --- a/lib/mnesia/src/mnesia.hrl +++ b/lib/mnesia/src/mnesia.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/mnesia/src/mnesia_text.erl b/lib/mnesia/src/mnesia_text.erl index ab1362f6b6..0906d18da9 100644 --- a/lib/mnesia/src/mnesia_text.erl +++ b/lib/mnesia/src/mnesia_text.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -181,9 +181,6 @@ read_term_from_stream(Stream, File, Line) -> Str = Mod:format_error(What), io:format("Error in line:~p of:~p ~s\n", [NewLine, File, Str]), - error; - T -> - io:format("Error2 **~p~n",[T]), error end; {eof,_EndLine} -> diff --git a/lib/mnesia/test/mnesia_SUITE.erl b/lib/mnesia/test/mnesia_SUITE.erl index dc8f216c1c..2267a94164 100644 --- a/lib/mnesia/test/mnesia_SUITE.erl +++ b/lib/mnesia/test/mnesia_SUITE.erl @@ -78,12 +78,14 @@ groups() -> [{group, install}, {group, atomicity}, {group, isolation}, {group, durability}, {group, recovery}, {group, consistency}, + {group, majority}, {group, mnesia_frag_test, medium}]}, {atomicity, [], [{mnesia_atomicity_test, all}]}, {isolation, [], [{mnesia_isolation_test, all}]}, {durability, [], [{mnesia_durability_test, all}]}, {recovery, [], [{mnesia_recovery_test, all}]}, {consistency, [], [{mnesia_consistency_test, all}]}, + {majority, [], [{mnesia_majority_test, all}]}, %% The 'heavy' test suite runs some resource consuming tests and %% benchmarks {heavy, [], [{group, measure}]}, @@ -142,105 +144,6 @@ silly() -> mnesia_install_test:silly(). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -light(doc) -> - ["The 'light' test suite runs a selected set of test suites and is", - "intended to be the smallest test suite that is meaningful", - "to run. It starts with an installation test (which in essence is the", - "'silly' test case) and then it covers all functions in the API in", - "various depths. All configuration parameters and examples are also", - "covered."]; -light(suite) -> - [ - install, - nice, - evil, - {mnesia_frag_test, light}, - qlc, - registry, - config, - examples - ]. - -install(suite) -> - [{mnesia_install_test, all}]. - -nice(suite) -> - [{mnesia_nice_coverage_test, all}]. - -evil(suite) -> - [{mnesia_evil_coverage_test, all}]. - -qlc(suite) -> - [{mnesia_qlc_test, all}]. - -registry(suite) -> - [{mnesia_registry_test, all}]. - -config(suite) -> - [{mnesia_config_test, all}]. - -examples(suite) -> - [{mnesia_examples_test, all}]. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -medium(doc) -> - ["The 'medium' test suite verfies the ACID (atomicity, consistency", - "isolation and durability) properties and various recovery scenarios", - "These tests may take quite while to run."]; -medium(suite) -> - [ - install, - atomicity, - isolation, - durability, - recovery, - consistency, - majority, - {mnesia_frag_test, medium} - ]. - -atomicity(suite) -> - [{mnesia_atomicity_test, all}]. - -isolation(suite) -> - [{mnesia_isolation_test, all}]. - -durability(suite) -> - [{mnesia_durability_test, all}]. - -recovery(suite) -> - [{mnesia_recovery_test, all}]. - -consistency(suite) -> - [{mnesia_consistency_test, all}]. - -majority(suite) -> - [{mnesia_majority_test, all}]. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -heavy(doc) -> - ["The 'heavy' test suite runs some resource consuming tests and", - "benchmarks"]; -heavy(suite) -> - [measure]. - -measure(suite) -> - [{mnesia_measure_test, all}]. - -prediction(suite) -> - [{mnesia_measure_test, prediction}]. - -fairness(suite) -> - [{mnesia_measure_test, fairness}]. - -benchmarks(suite) -> - [{mnesia_measure_test, benchmarks}]. - -consumption(suite) -> - [{mnesia_measure_test, consumption}]. - -scalability(suite) -> - [{mnesia_measure_test, scalability}]. clean_up_suite(doc) -> ["Not a test case only kills mnesia and nodes, that where" "started during the tests"]; diff --git a/lib/mnesia/test/mnesia_majority_test.erl b/lib/mnesia/test/mnesia_majority_test.erl index 17d1d8bcdd..41ba0fd601 100644 --- a/lib/mnesia/test/mnesia_majority_test.erl +++ b/lib/mnesia/test/mnesia_majority_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -26,13 +26,11 @@ init_per_testcase(Func, Conf) -> mnesia_test_lib:init_per_testcase(Func, Conf). -fin_per_testcase(Func, Conf) -> - mnesia_test_lib:fin_per_testcase(Func, Conf). +end_per_testcase(Func, Conf) -> + mnesia_test_lib:end_per_testcase(Func, Conf). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -all(doc) -> - ["Verify that majority checking works"]; -all(suite) -> +all() -> [ write , wread @@ -45,7 +43,7 @@ all(suite) -> write(suite) -> []; write(Config) when is_list(Config) -> - [N1, N2, N3] = Nodes = ?acquire_nodes(3, Config), + [N1, N2, N3] = ?acquire_nodes(3, Config), Tab = t, Schema = [{name, Tab}, {ram_copies, [N1,N2,N3]}, {majority,true}], ?match({atomic, ok}, mnesia:create_table(Schema)), @@ -62,7 +60,7 @@ write(Config) when is_list(Config) -> wread(suite) -> []; wread(Config) when is_list(Config) -> - [N1, N2] = Nodes = ?acquire_nodes(2, Config), + [N1, N2] = ?acquire_nodes(2, Config), Tab = t, Schema = [{name, Tab}, {ram_copies, [N1,N2]}, {majority,true}], ?match({atomic, ok}, mnesia:create_table(Schema)), @@ -76,7 +74,7 @@ wread(Config) when is_list(Config) -> delete(suite) -> []; delete(Config) when is_list(Config) -> - [N1, N2] = Nodes = ?acquire_nodes(2, Config), + [N1, N2] = ?acquire_nodes(2, Config), Tab = t, Schema = [{name, Tab}, {ram_copies, [N1,N2]}, {majority,true}], ?match({atomic, ok}, mnesia:create_table(Schema)), @@ -100,7 +98,7 @@ delete(Config) when is_list(Config) -> clear_table(suite) -> []; clear_table(Config) when is_list(Config) -> - [N1, N2] = Nodes = ?acquire_nodes(2, Config), + [N1, N2] = ?acquire_nodes(2, Config), Tab = t, Schema = [{name, Tab}, {ram_copies, [N1,N2]}, {majority,true}], ?match({atomic, ok}, mnesia:create_table(Schema)), @@ -122,7 +120,7 @@ clear_table(Config) when is_list(Config) -> frag(suite) -> []; frag(Config) when is_list(Config) -> - [N1] = Nodes = ?acquire_nodes(1, Config), + [N1] = ?acquire_nodes(1, Config), Tab = t, Schema = [ {name, Tab}, {ram_copies, [N1]}, @@ -135,7 +133,7 @@ frag(Config) when is_list(Config) -> change_majority(suite) -> []; change_majority(Config) when is_list(Config) -> - [N1,N2] = Nodes = ?acquire_nodes(2, Config), + [N1,N2] = ?acquire_nodes(2, Config), Tab = t, Schema = [ {name, Tab}, {ram_copies, [N1,N2]}, @@ -158,7 +156,7 @@ change_majority(Config) when is_list(Config) -> frag_change_majority(suite) -> []; frag_change_majority(Config) when is_list(Config) -> - [N1,N2] = Nodes = ?acquire_nodes(2, Config), + [N1,N2] = ?acquire_nodes(2, Config), Tab = t, Schema = [ {name, Tab}, {ram_copies, [N1,N2]}, diff --git a/lib/mnesia/test/mt.erl b/lib/mnesia/test/mt.erl index 322bd52130..f1152a7bc4 100644 --- a/lib/mnesia/test/mt.erl +++ b/lib/mnesia/test/mt.erl @@ -57,6 +57,7 @@ alias(heavy) -> {mnesia_SUITE, heavy}; alias(install) -> mnesia_install_test; alias(isolation) -> mnesia_isolation_test; alias(light) -> {mnesia_SUITE, light}; +alias(majority) -> mnesia_majority_test; alias(measure) -> mnesia_measure_test; alias(medium) -> {mnesia_SUITE, medium}; alias(nice) -> mnesia_nice_coverage_test; diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk index 38e1a94545..2fa629d064 100644 --- a/lib/mnesia/vsn.mk +++ b/lib/mnesia/vsn.mk @@ -1 +1 @@ -MNESIA_VSN = 4.4.18 +MNESIA_VSN = 4.4.19 diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl index 6e9d4727ec..d1c65f97e8 100644 --- a/lib/observer/test/crashdump_helper.erl +++ b/lib/observer/test/crashdump_helper.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/orber/doc/src/notes.xml b/lib/orber/doc/src/notes.xml index 589123ef73..231872f958 100644 --- a/lib/orber/doc/src/notes.xml +++ b/lib/orber/doc/src/notes.xml @@ -33,6 +33,22 @@ </header> <section> + <title>Orber 3.6.21</title> + + <section> + <title>Improvements and New Features</title> + <list type="bulleted"> + <item> + <p> + Eliminated Dialyzer warnings.</p> + <p> + Own Id: OTP-9326 Aux Id:</p> + </item> + </list> + </section> + </section> + + <section> <title>Orber 3.6.20</title> <section> diff --git a/lib/orber/src/orber.erl b/lib/orber/src/orber.erl index 665b3cb383..386c07d227 100644 --- a/lib/orber/src/orber.erl +++ b/lib/orber/src/orber.erl @@ -245,7 +245,7 @@ create_nodes(Host, N, Port, Options, Errors, NodeData) -> create_node(Host, Port, Options) -> - case slave:start_link(Host, Port) of + case slave:start_link(Host, list_to_atom(integer_to_list(Port))) of {ok, NewNode} -> case net_adm:ping(NewNode) of pong -> diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk index 5f17cda229..35aabd51cd 100644 --- a/lib/orber/vsn.mk +++ b/lib/orber/vsn.mk @@ -1,3 +1,3 @@ -ORBER_VSN = 3.6.20 +ORBER_VSN = 3.6.21 diff --git a/lib/os_mon/src/disksup.erl b/lib/os_mon/src/disksup.erl index 3ee1df759f..308cd1b7fa 100644 --- a/lib/os_mon/src/disksup.erl +++ b/lib/os_mon/src/disksup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl index cc4941ee7d..ba07a529bc 100644 --- a/lib/os_mon/src/memsup.erl +++ b/lib/os_mon/src/memsup.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/sasl/src/sasl.erl b/lib/sasl/src/sasl.erl index aed5f0da1f..989f99dc82 100644 --- a/lib/sasl/src/sasl.erl +++ b/lib/sasl/src/sasl.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/doc/src/snmp_agent_netif.xml b/lib/snmp/doc/src/snmp_agent_netif.xml index d751740a82..8f1d860d58 100644 --- a/lib/snmp/doc/src/snmp_agent_netif.xml +++ b/lib/snmp/doc/src/snmp_agent_netif.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>1997</year><year>2009</year> + <year>1997</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -119,7 +119,8 @@ Pid ! {snmp_response_received, Vsn, Pdu, From} <list type="bulleted"> <item><c>Pid</c> is the Process that waits for the response for the request. The Pid was specified in the - <c>send_pdu_req</c> message <seealso marker="#message">(see below)</seealso>. + <c>send_pdu_req</c> message + <seealso marker="#im_send_pdu_req">(see below)</seealso>. </item> <item><c>Vsn</c> is either <c>'version-1'</c>, <c>'version-2'</c>, or <c>'version-3'</c>. diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml index 72849b9c9e..b527d171b0 100644 --- a/lib/snmp/doc/src/snmpm.xml +++ b/lib/snmp/doc/src/snmpm.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2004</year><year>2010</year> + <year>2004</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/snmp/src/agent/snmp_community_mib.erl b/lib/snmp/src/agent/snmp_community_mib.erl index 3debe0a30e..77307aa7ad 100644 --- a/lib/snmp/src/agent/snmp_community_mib.erl +++ b/lib/snmp/src/agent/snmp_community_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1999-2010. All Rights Reserved. +%% Copyright Ericsson AB 1999-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmp_notification_mib.erl b/lib/snmp/src/agent/snmp_notification_mib.erl index 3da5766b44..720ac749b8 100644 --- a/lib/snmp/src/agent/snmp_notification_mib.erl +++ b/lib/snmp/src/agent/snmp_notification_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl index b2f2417b02..77910541a2 100644 --- a/lib/snmp/src/agent/snmp_target_mib.erl +++ b/lib/snmp/src/agent/snmp_target_mib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1998-2010. All Rights Reserved. +%% Copyright Ericsson AB 1998-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl index b2e4f253ab..50b169e4e7 100644 --- a/lib/snmp/src/agent/snmpa.erl +++ b/lib/snmp/src/agent/snmpa.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_acm.erl b/lib/snmp/src/agent/snmpa_acm.erl index 30bd34a205..42a0d4d6a3 100644 --- a/lib/snmp/src/agent/snmpa_acm.erl +++ b/lib/snmp/src/agent/snmpa_acm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl index e4cfeddb6a..82a7ec647b 100644 --- a/lib/snmp/src/agent/snmpa_agent.erl +++ b/lib/snmp/src/agent/snmpa_agent.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_authentication_service.erl b/lib/snmp/src/agent/snmpa_authentication_service.erl index d406c58ee4..b5ff8460c6 100644 --- a/lib/snmp/src/agent/snmpa_authentication_service.erl +++ b/lib/snmp/src/agent/snmpa_authentication_service.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl index 4e5aab5319..4b88eb69f7 100644 --- a/lib/snmp/src/agent/snmpa_conf.erl +++ b/lib/snmp/src/agent/snmpa_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl index a91f30a4a6..a490a78f84 100644 --- a/lib/snmp/src/agent/snmpa_internal.hrl +++ b/lib/snmp/src/agent/snmpa_internal.hrl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl index 39a4246d26..14f62b12f3 100644 --- a/lib/snmp/src/agent/snmpa_mpd.erl +++ b/lib/snmp/src/agent/snmpa_mpd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl index bbc5568cde..79c85a6e4e 100644 --- a/lib/snmp/src/agent/snmpa_net_if.erl +++ b/lib/snmp/src/agent/snmpa_net_if.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl index 3c7ae804a5..567de020c0 100644 --- a/lib/snmp/src/agent/snmpa_trap.erl +++ b/lib/snmp/src/agent/snmpa_trap.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl index e457d3b47a..0d084332de 100644 --- a/lib/snmp/src/manager/snmpm.erl +++ b/lib/snmp/src/manager/snmpm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl index 3d248fff57..a116c9f26b 100644 --- a/lib/snmp/src/manager/snmpm_net_if.erl +++ b/lib/snmp/src/manager/snmpm_net_if.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl index b8d7cf6375..58a58507d6 100644 --- a/lib/snmp/src/manager/snmpm_server.erl +++ b/lib/snmp/src/manager/snmpm_server.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/manager/snmpm_usm.erl b/lib/snmp/src/manager/snmpm_usm.erl index ef2070a90e..497d6d6102 100644 --- a/lib/snmp/src/manager/snmpm_usm.erl +++ b/lib/snmp/src/manager/snmpm_usm.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/misc/snmp_conf.erl b/lib/snmp/src/misc/snmp_conf.erl index cb5b3bbfbd..20f4455d10 100644 --- a/lib/snmp/src/misc/snmp_conf.erl +++ b/lib/snmp/src/misc/snmp_conf.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl index 813942225e..fcbc6a88c9 100644 --- a/lib/snmp/src/misc/snmp_config.erl +++ b/lib/snmp/src/misc/snmp_config.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl index 7930e37c66..2c781810ef 100644 --- a/lib/snmp/src/misc/snmp_log.erl +++ b/lib/snmp/src/misc/snmp_log.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/misc/snmp_misc.erl b/lib/snmp/src/misc/snmp_misc.erl index 6adef06ab9..a061dcd97c 100644 --- a/lib/snmp/src/misc/snmp_misc.erl +++ b/lib/snmp/src/misc/snmp_misc.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/src/misc/snmp_pdus.erl b/lib/snmp/src/misc/snmp_pdus.erl index 82618a0b86..0788d86b2d 100644 --- a/lib/snmp/src/misc/snmp_pdus.erl +++ b/lib/snmp/src/misc/snmp_pdus.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2010. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile index 0e9c73081d..5530805bc1 100644 --- a/lib/snmp/test/Makefile +++ b/lib/snmp/test/Makefile @@ -2,7 +2,7 @@ # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2009. All Rights Reserved. +# Copyright Ericsson AB 1997-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl index acf62f5646..468280db02 100644 --- a/lib/snmp/test/snmp_agent_test.erl +++ b/lib/snmp/test/snmp_agent_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl index 3ae2409997..a18d9f3201 100644 --- a/lib/snmp/test/snmp_agent_test_lib.erl +++ b/lib/snmp/test/snmp_agent_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl index 6bd62df655..0b536748fb 100644 --- a/lib/snmp/test/snmp_manager_test.erl +++ b/lib/snmp/test/snmp_manager_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/test/snmp_manager_user.erl b/lib/snmp/test/snmp_manager_user.erl index 30b5dd1fc7..1b62b04960 100644 --- a/lib/snmp/test/snmp_manager_user.erl +++ b/lib/snmp/test/snmp_manager_user.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2005-2010. All Rights Reserved. +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/snmp/test/snmp_pdus_test.erl b/lib/snmp/test/snmp_pdus_test.erl index 197797c816..07b6d6b657 100644 --- a/lib/snmp/test/snmp_pdus_test.erl +++ b/lib/snmp/test/snmp_pdus_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml index 4f546a37ed..71f3941577 100644 --- a/lib/ssh/doc/src/notes.xml +++ b/lib/ssh/doc/src/notes.xml @@ -29,6 +29,20 @@ <file>notes.xml</file> </header> +<section><title>Ssh 2.0.7</title> + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + An unexpected message would crash the ssh_connection_handler and close + the connection. Now an error message is generated instead.</p> + <p> + Own Id: OTP-9273</p> + </item> + </list> + </section> +</section> + <section><title>Ssh 2.0.6</title> <section><title>Fixed Bugs and Malfunctions</title> <list> diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index 37f24e2463..974145836c 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -19,10 +19,12 @@ {"%VSN%", [ + {"2.0.6", [{load_module, ssh_userreg, soft_purge, soft_purge, []}]}, {"2.0.5", [{load_module, ssh_userreg, soft_purge, soft_purge, []}, {load_module, ssh_connection_handler, soft_purge, soft_purge, [ssh_userreg]}]} ], [ + {"2.0.6", [{load_module, ssh_userreg, soft_purge, soft_purge, []}]}, {"2.0.5", [{load_module, ssh_userreg, soft_purge, soft_purge, []}, {load_module, ssh_connection_handler, soft_purge, soft_purge, [ssh_userreg]}]} ] diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 3193be2510..00b30e5434 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -569,7 +569,19 @@ handle_info({CloseTag, _Socket}, _StateName, #state{transport_close_tag = CloseTag, %%manager = Pid, ssh_params = #ssh{role = _Role, opts = _Opts}} = State) -> %%ok = ssh_connection_manager:delivered(Pid), - {stop, normal, State}. + {stop, normal, State}; +handle_info(UnexpectedMessage, StateName, #state{ssh_params = SshParams} = State) -> + Msg = lists:flatten(io_lib:format( + "Unexpected message '~p' received in state '~p'\n" + "Role: ~p\n" + "Peer: ~p\n" + "Local Address: ~p\n", [UnexpectedMessage, StateName, + SshParams#ssh.role, SshParams#ssh.peer, + proplists:get_value(address, SshParams#ssh.opts)])), + error_logger:info_report(Msg), + {next_state, StateName, State}. + + %%-------------------------------------------------------------------- %% Function: terminate(Reason, StateName, State) -> void() %% Description:This function is called by a gen_fsm when it is about diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile new file mode 100644 index 0000000000..5a2a6de24a --- /dev/null +++ b/lib/ssh/test/Makefile @@ -0,0 +1,121 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2004-2011. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# + +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../vsn.mk +VSN=$(GS_VSN) + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- + +MODULES= \ + ssh_test_lib \ + ssh_SUITE \ + ssh_basic_SUITE \ + ssh_to_openssh_SUITE \ + ssh_sftp_SUITE \ + ssh_sftpd_SUITE \ + ssh_sftpd_erlclient_SUITE + +HRL_FILES_NEEDED_IN_TEST= \ + $(ERL_TOP)/lib/ssh/src/ssh.hrl \ + $(ERL_TOP)/lib/ssh/src/ssh_xfer.hrl + +ERL_FILES= $(MODULES:%=%.erl) + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) + +DATA_DIRS = $(MODULES:%=%_data) + +INCLUDES = -I$(ERL_TOP)/lib/test_server/include \ + -I$(ERL_TOP)/lib/ssh/src \ + +EMAKEFILE=Emakefile +MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile) + +ifeq ($(MAKE_EMAKE),) +BUILDTARGET = $(TARGET_FILES) +RELTEST_FILES = $(INETS_SPECS) $(SOURCE) +else +BUILDTARGET = emakebuild +RELTEST_FILES = $(EMAKEFILE) $(INETS_SPECS) $(SOURCE) +endif + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/ssh_test + +# ---------------------------------------------------- +# FLAGS +# The path to the test_server ebin dir is needed when +# running the target "targets". +# ---------------------------------------------------- +ERL_COMPILE_FLAGS += -pa ../../../internal_tools/test_server/ebin \ + $(INCLUDES) + +EBIN = . + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- +tests debug opt: $(BUILDTARGET) + +targets: $(TARGET_FILES) + +.PHONY: emakebuild + +emakebuild: $(EMAKEFILE) + +$(EMAKEFILE): + $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' | grep -v Warning > $(EMAKEFILE) + $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) | grep -v Warning >> $(EMAKEFILE) + +clean: + rm -f $(EMAKEFILE) + rm -f $(TARGET_FILES) + rm -f core +docs: + +info: + @echo "TARGET_FILES = $(TARGET_FILES)" + @echo "DATA_DIRS = $(DATA_DIRS)" + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + +release_tests_spec: opt + $(INSTALL_DIR) $(RELSYSDIR) + $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR) + $(INSTALL_DATA) ssh.spec ssh.cover $(RELSYSDIR) + $(INSTALL_DATA) $(HRL_FILES_NEEDED_IN_TEST) $(RELSYSDIR) + chmod -f -R u+w $(RELSYSDIR) + @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -) + +release_docs_spec: diff --git a/lib/ssh/test/ssh.cover b/lib/ssh/test/ssh.cover new file mode 100644 index 0000000000..a4221fbbbe --- /dev/null +++ b/lib/ssh/test/ssh.cover @@ -0,0 +1,2 @@ +{incl_app,ssh,details}. + diff --git a/lib/ssh/test/ssh.spec b/lib/ssh/test/ssh.spec new file mode 100644 index 0000000000..8de0fe44e4 --- /dev/null +++ b/lib/ssh/test/ssh.spec @@ -0,0 +1,7 @@ +{suites,"../ssh_test",all}. +{skip_cases,"../ssh_test",ssh_ssh_SUITE, + [ssh], + "Current implementation is timingdependent and\nhence will succeed/fail on a whim"}. +{skip_cases,"../ssh_test",ssh_ssh_SUITE, + [ssh_compressed], + "Current implementation is timingdependent hence will succeed/fail on a whim"}. diff --git a/lib/ssh/test/ssh.spec.vxworks b/lib/ssh/test/ssh.spec.vxworks new file mode 100644 index 0000000000..81f665283c --- /dev/null +++ b/lib/ssh/test/ssh.spec.vxworks @@ -0,0 +1,3 @@ +{topcase, {dir, "../ssh_test"}}. +{require_nodenames, 1}. +%{skip, {M, F, "Not yet implemented"}}. diff --git a/lib/ssh/test/ssh_SUITE.erl b/lib/ssh/test/ssh_SUITE.erl new file mode 100644 index 0000000000..953c9080f9 --- /dev/null +++ b/lib/ssh/test/ssh_SUITE.erl @@ -0,0 +1,72 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%%---------------------------------------------------------------- +%%% Purpose:ssh application test suite. +%%%----------------------------------------------------------------- +-module(ssh_SUITE). +-include_lib("common_test/include/ct.hrl"). +-include("test_server_line.hrl"). + +% Default timetrap timeout (set in init_per_testcase). +-define(default_timeout, ?t:minutes(1)). +-define(application, ssh). + +% Test server specific exports +-export([all/0,groups/0,init_per_group/2,end_per_group/2]). +-export([init_per_testcase/2, end_per_testcase/2]). + +% Test cases must be exported. +-export([app_test/1]). +-define(cases, [app_test]). + +%% +%% all/1 +%% +all() -> + [app_test]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +init_per_testcase(_Case, Config) -> + Dog=test_server:timetrap(?default_timeout), + [{watchdog, Dog}|Config]. +end_per_testcase(_Case, Config) -> + Dog=?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. +% +% Test cases starts here. +% +app_test(suite) -> + []; +app_test(doc) -> + ["Application consistency test."]; +app_test(Config) when is_list(Config) -> + ?t:app_test(?application), + ok. diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl new file mode 100644 index 0000000000..5ea0d98980 --- /dev/null +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -0,0 +1,389 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +-module(ssh_basic_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include("test_server_line.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-define(NEWLINE, <<"\r\n">>). + +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + case catch crypto:start() of + ok -> + Dir = ?config(priv_dir, Config), + {ok, _} = ssh_test_lib:get_id_keys(Dir), + ssh_test_lib:make_dsa_files(Config), + Config; + _Else -> + {skip, "Crypto could not be started!"} + end. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(Config) -> + Dir = ?config(priv_dir, Config), + crypto:stop(), + ssh_test_lib:remove_id_keys(Dir), + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config) -> + ssh_test_lib:known_hosts(backup), + ssh:start(), + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, _Config) -> + ssh:stop(), + ssh_test_lib:known_hosts(restore), + ok. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all() -> + [exec, exec_compressed, shell, daemon_already_started, + server_password_option, server_userpassword_option, + known_hosts]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +%% Test cases starts here. +%%-------------------------------------------------------------------- +sign_and_verify_rsa(doc) -> + ["Test api function ssh:sign_data and ssh:verify_data"]; + +sign_and_verify_rsa(suite) -> + []; +sign_and_verify_rsa(Config) when is_list(Config) -> + Data = ssh:sign_data(<<"correct data">>, "ssh-rsa"), + ok = ssh:verify_data(<<"correct data">>, Data, "ssh-rsa"), + {error,invalid_signature} = ssh:verify_data(<<"incorrect data">>, Data,"ssh-rsa"). + + +exec(doc) -> + ["Test api function ssh_connection:exec"]; + +exec(suite) -> + []; + +exec(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = ?config(data_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_interaction, false}]), + {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId0, + "1+1.", infinity), + Data0 = {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"2\n">>}}, + case ssh_test_lib:receive_exec_result(Data0) of + expected -> + ok; + Other0 -> + test_server:fail(Other0) + end, + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0), + + %% Test that it is possible to start a new channel and + %% run an other exec on the same connection. + {ok, ChannelId1} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId1, + "2+2.", infinity), + Data1 = {ssh_cm, ConnectionRef, {data, ChannelId1, 0, <<"4\n">>}}, + case ssh_test_lib:receive_exec_result(Data1) of + expected -> + ok; + Other1 -> + test_server:fail(Other1) + end, + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +exec_compressed(doc) -> + ["Test that compression option works"]; + +exec_compressed(suite) -> + []; + +exec_compressed(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = ?config(data_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {compression, zlib}, + {failfun, fun ssh_test_lib:failfun/2}]), + + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user_interaction, false}]), + {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId, + "1+1.", infinity), + Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"2\n">>}}, + case ssh_test_lib:receive_exec_result(Data) of + expected -> + ok; + Other -> + test_server:fail(Other) + end, + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- + +shell(doc) -> + ["Test that ssh:shell/2 works"]; + +shell(suite) -> + []; + +shell(Config) when is_list(Config) -> + process_flag(trap_exit, true), + SystemDir = ?config(data_dir, Config), + {_Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + test_server:sleep(500), + + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(Port, IO), + receive + ErlShellStart -> + test_server:format("Erlang shell start: ~p~n", [ErlShellStart]) + end, + receive + ErlPrompt0 -> + test_server:format("Erlang prompt: ~p~n", [ErlPrompt0]) + end, + IO ! {input, self(), "1+1.\r\n"}, + receive + Echo0 -> + test_server:format("Echo: ~p ~n", [Echo0]) + end, + receive + ?NEWLINE -> + ok + end, + receive + Result0 = <<"2">> -> + test_server:format("Result: ~p~n", [Result0]) + end, + receive + ?NEWLINE -> + ok + end, + receive + ErlPrompt1 -> + test_server:format("Erlang prompt: ~p~n", [ErlPrompt1]) + end, + exit(Shell, kill), + %% Does not seem to work in the testserver! + %% IO ! {input, self(), "q().\r\n"}, + %% receive + %% ?NEWLINE -> + %% ok + %% end, + %% receive + %% Echo1 -> + %% test_server:format("Echo: ~p ~n", [Echo1]) + %% end, + %% receive + %% ?NEWLINE -> + %% ok + %% end, + %% receive + %% Result1 -> + %% test_server:format("Result: ~p~n", [Result1]) + %% end, + receive + {'EXIT', Shell, killed} -> + ok + end. + +%%-------------------------------------------------------------------- +daemon_already_started(doc) -> + ["Test that get correct error message if you try to start a daemon", + "on an adress that already runs a daemon see also seq10667" ]; + +daemon_already_started(suite) -> + []; + +daemon_already_started(Config) when is_list(Config) -> + SystemDir = ?config(data_dir, Config), + {Pid, _Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + {error, eaddrinuse} = ssh_test_lib:daemon(Port, [{system_dir, SystemDir}, + {failfun, + fun ssh_test_lib:failfun/2}]), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +server_password_option(doc) -> + ["validate to server that uses the 'password' option"]; +server_password_option(suite) -> + []; +server_password_option(Config) when is_list(Config) -> + UserDir = ?config(data_dir, Config), % to make sure we don't use + SysDir = ?config(data_dir, Config), % public-key-auth + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {password, "morot"}]), + + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + {error, Reason} = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "vego"}, + {password, "foo"}, + {user_interaction, false}, + {user_dir, UserDir}]), + + test_server:format("Test of wrong password: Error msg: ~p ~n", [Reason]), + + ssh:close(ConnectionRef), + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- + +server_userpassword_option(doc) -> + ["validate to server that uses the 'password' option"]; +server_userpassword_option(suite) -> + []; +server_userpassword_option(Config) when is_list(Config) -> + UserDir = ?config(data_dir, Config), % to make sure we don't use + SysDir = ?config(data_dir, Config), % public-key-auth + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SysDir}, + {user_passwords, [{"vego", "morot"}]}]), + + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "vego"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + ssh:close(ConnectionRef), + + {error, Reason0} = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + + test_server:format("Test of user foo that does not exist. " + "Error msg: ~p ~n", [Reason0]), + + {error, Reason1} = + ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true}, + {user, "vego"}, + {password, "foo"}, + {user_interaction, false}, + {user_dir, UserDir}]), + test_server:format("Test of wrong Password. " + "Error msg: ~p ~n", [Reason1]), + + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +known_hosts(doc) -> + ["check that known_hosts is updated correctly"]; +known_hosts(suite) -> + []; +known_hosts(Config) when is_list(Config) -> + SystemDir = ?config(data_dir, Config), + UserDir = ?config(priv_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + + KnownHosts = filename:join(UserDir, "known_hosts"), + file:delete(KnownHosts), + {error, enoent} = file:read_file(KnownHosts), + ConnectionRef = + ssh_test_lib:connect(Host, Port, [{user_dir, UserDir}, + {user_interaction, false}, + silently_accept_hosts]), + {ok, _Channel} = ssh_connection:session_channel(ConnectionRef, infinity), + ok = ssh:close(ConnectionRef), + {ok, Binary} = file:read_file(KnownHosts), + Lines = string:tokens(binary_to_list(Binary), "\n"), + [Line] = Lines, + [HostAndIp, Alg, _KeyData] = string:tokens(Line, " "), + [Host, _Ip] = string:tokens(HostAndIp, ","), + "ssh-" ++ _ = Alg, + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +%% Internal functions +%%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl new file mode 100644 index 0000000000..c96b6de3ea --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE.erl @@ -0,0 +1,543 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssh_sftp_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include("test_server_line.hrl"). + +-include_lib("kernel/include/file.hrl"). + +% Default timetrap timeout +-define(default_timeout, ?t:minutes(1)). + +-define(SFPD_PORT, 9999). +-define(USER, "Alladin"). +-define(PASSWD, "Sesame"). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initiation before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + case {catch crypto:start(),catch ssh:start()} of + {ok,ok} -> + Dir = ?config(priv_dir, Config), + {ok, _} = ssh_test_lib:get_id_keys(Dir), + ssh_test_lib:make_dsa_files(Config), + Config; + {ok,_} -> + {skip,"Could not start ssh!"}; + {_,ok} -> + {skip,"Could not start crypto!"}; + {_,_} -> + {skip,"Could not start crypto and ssh!"} + end. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(Config) -> + crypto:stop(), + Dir = ?config(priv_dir, Config), + ssh_test_lib:remove_id_keys(Dir), + Config. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initiation before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initiation before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_Case, Config) -> + prep(Config), + TmpConfig0 = lists:keydelete(watchdog, 1, Config), + TmpConfig = lists:keydelete(sftp, 1, TmpConfig0), + Dog = test_server:timetrap(?default_timeout), + Dir = ?config(priv_dir, Config), + SysDir = ?config(data_dir, Config), + Host = ssh_test_lib:hostname(), + + Sftp = case (catch ssh_sftp:start_channel(Host, + [{user_dir, Dir}, + {user_interaction, false}, + {silently_accept_hosts, true}])) of + {ok, ChannelPid, Connection} -> + {ChannelPid, Connection}; + _Error -> + {_Sftpd, _Host, _Port} = + ssh_test_lib:daemon(Host, ?SFPD_PORT, + [{system_dir, SysDir}, + {user_passwords, + [{?USER, ?PASSWD}]}, + {failfun, + fun ssh_test_lib:failfun/2}]), + Result = (catch ssh_sftp:start_channel(Host, ?SFPD_PORT, + [{user, ?USER}, + {password, ?PASSWD}, + {user_interaction, false}, + {silently_accept_hosts, true}])), + {ok, ChannelPid, Connection} = Result, + {ChannelPid, Connection} + end, + + [{sftp, Sftp}, {watchdog, Dog} | TmpConfig]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_Case, Config) -> + {Sftp, Connection} = ?config(sftp, Config), + ssh_sftp:stop_channel(Sftp), + ssh:close(Connection), + Dog = ?config(watchdog, Config), + test_server:timetrap_cancel(Dog), + ok. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all() -> + [open_close_file, open_close_dir, read_file, read_dir, + write_file, rename_file, mk_rm_dir, remove_file, links, + retrieve_attributes, set_attributes, async_read, + async_write, position, pos_read, pos_write]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%% Test cases starts here. +%%-------------------------------------------------------------------- +open_close_file(doc) -> + ["Test API functions open/3 and close/2"]; +open_close_file(suite) -> + []; +open_close_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + + {Sftp, _} = ?config(sftp, Config), + + ok = open_close_file(Sftp, FileName, [read]), + ok = open_close_file(Sftp, FileName, [write]), + ok = open_close_file(Sftp, FileName, [write, creat]), + ok = open_close_file(Sftp, FileName, [write, trunc]), + ok = open_close_file(Sftp, FileName, [append]), + ok = open_close_file(Sftp, FileName, [read, binary]), + + ok. + +open_close_file(Server, File, Mode) -> + {ok, Handle} = ssh_sftp:open(Server, File, Mode), + ok = ssh_sftp:close(Server, Handle), + ok. + + +%%-------------------------------------------------------------------- +open_close_dir(doc) -> + ["Test API functions opendir/2 and close/2"]; +open_close_dir(suite) -> + []; +open_close_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Sftp, _} = ?config(sftp, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + + {ok, Handle} = ssh_sftp:opendir(Sftp, PrivDir), + ok = ssh_sftp:close(Sftp, Handle), + {error, _} = ssh_sftp:opendir(Sftp, FileName), + + ok. +%%-------------------------------------------------------------------- +read_file(doc) -> + ["Test API funtion read_file/2"]; +read_file(suite) -> + []; +read_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + + {Sftp, _} = ?config(sftp, Config), + + {ok, Data} = ssh_sftp:read_file(Sftp, FileName), + + {ok, Data} = file:read_file(FileName), + + ok. +%%-------------------------------------------------------------------- +read_dir(doc) -> + ["Test API function list_dir/2"]; +read_dir(suite) -> + []; +read_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Sftp, _} = ?config(sftp, Config), + {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), + test_server:format("sftp list dir: ~p~n", [Files]), + ok. + +%%-------------------------------------------------------------------- +write_file(doc) -> + ["Test API function write_file/2"]; +write_file(suite) -> + []; +write_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + + {Sftp, _} = ?config(sftp, Config), + + Data = list_to_binary("Hej hopp!"), + + ssh_sftp:write_file(Sftp, FileName, [Data]), + + {ok, Data} = file:read_file(FileName), + + ok. + +%%-------------------------------------------------------------------- +remove_file(doc) -> + ["Test API function delete/2"]; +remove_file(suite) -> + []; +remove_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + + {Sftp, _} = ?config(sftp, Config), + + {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), + + true = lists:member(filename:basename(FileName), Files), + + ok = ssh_sftp:delete(Sftp, FileName), + + {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir), + + false = lists:member(filename:basename(FileName), NewFiles), + + {error, _} = ssh_sftp:delete(Sftp, FileName), + + ok. + +%%-------------------------------------------------------------------- +rename_file(doc) -> + ["Test API function rename_file/2"]; +rename_file(suite) -> + []; +rename_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + NewFileName = filename:join(PrivDir, "test.txt"), + + {Sftp, _} = ?config(sftp, Config), + + {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir), + + test_server:format("FileName: ~p, Files: ~p~n", [FileName, Files]), + + true = lists:member(filename:basename(FileName), Files), + false = lists:member(filename:basename(NewFileName), Files), + + ok = ssh_sftp:rename(Sftp, FileName, NewFileName), + + {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir), + + test_server:format("FileName: ~p, Files: ~p~n", [FileName, NewFiles]), + + false = lists:member(filename:basename(FileName), NewFiles), + true = lists:member(filename:basename(NewFileName), NewFiles), + + ok. + +%%-------------------------------------------------------------------- +mk_rm_dir(doc) -> + ["Test API functions make_dir/2, del_dir/2"]; +mk_rm_dir(suite) -> + []; +mk_rm_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Sftp, _} = ?config(sftp, Config), + DirName = filename:join(PrivDir, "test"), + + ok = ssh_sftp:make_dir(Sftp, DirName), + ok = ssh_sftp:del_dir(Sftp, DirName), + + NewDirName = filename:join(PrivDir, "foo/bar"), + + {error, _} = ssh_sftp:make_dir(Sftp, NewDirName), + {error, _} = ssh_sftp:del_dir(Sftp, PrivDir), + + ok. + +%%-------------------------------------------------------------------- +links(doc) -> + ["Tests API function make_symlink/3"]; +links(suite) -> + []; +links(Config) when is_list(Config) -> + case test_server:os_type() of + {win32, _} -> + {skip, "Links are not fully supported by windows"}; + _ -> + {Sftp, _} = ?config(sftp, Config), + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + LinkFileName = filename:join(PrivDir, "link_test.txt"), + + ok = ssh_sftp:make_symlink(Sftp, FileName, LinkFileName), + {ok, FileName} = ssh_sftp:read_link(Sftp, LinkFileName), + ok + end. + +%%-------------------------------------------------------------------- +retrieve_attributes(doc) -> + ["Test API function read_file_info/3"]; +retrieve_attributes(suite) -> + []; +retrieve_attributes(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + {Sftp, _} = ?config(sftp, Config), + + {ok, FileInfo} = ssh_sftp:read_file_info(Sftp, FileName), + + {ok, NewFileInfo} = file:read_file_info(FileName), + + %% TODO comparison. There are some differences now is that ok? + test_server:format("SFTP: ~p FILE: ~p~n", [FileInfo, NewFileInfo]), + ok. + +%%-------------------------------------------------------------------- +set_attributes(doc) -> + ["Test API function write_file_info/3"]; +set_attributes(suite) -> + []; +set_attributes(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + {Sftp, _} = ?config(sftp, Config), + + {ok,Fd} = file:open(FileName, write), + io:put_chars(Fd,"foo"), + + ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#400}), + {error, eacces} = file:write_file(FileName, "hello again"), + ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#600}), + ok = file:write_file(FileName, "hello again"), + + ok. + +%%-------------------------------------------------------------------- + +async_read(doc) -> + ["Test API aread/3"]; +async_read(suite) -> + []; +async_read(Config) when is_list(Config) -> + {Sftp, _} = ?config(sftp, Config), + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "sftp.txt"), + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]), + {async, Ref} = ssh_sftp:aread(Sftp, Handle, 20), + + receive + {async_reply, Ref, {ok, Data}} -> + test_server:format("Data: ~p~n", [Data]), + ok; + Msg -> + test_server:fail(Msg) + end, + ok. +%%-------------------------------------------------------------------- +async_write(doc) -> + ["Test API awrite/3"]; +async_write(suite) -> + []; +async_write(Config) when is_list(Config) -> + {Sftp, _} = ?config(sftp, Config), + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]), + Data = list_to_binary("foobar"), + {async, Ref} = ssh_sftp:awrite(Sftp, Handle, Data), + + receive + {async_reply, Ref, ok} -> + {ok, Data} = file:read_file(FileName); + Msg -> + test_server:fail(Msg) + end, + ok. + +%%-------------------------------------------------------------------- + +position(doc) -> + ["Test API functions position/3"]; +position(suite) -> + []; +position(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + {Sftp, _} = ?config(sftp, Config), + + Data = list_to_binary("1234567890"), + ssh_sftp:write_file(Sftp, FileName, [Data]), + + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]), + + {ok, 3} = ssh_sftp:position(Sftp, Handle, {bof, 3}), + {ok, "4"} = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 10} = ssh_sftp:position(Sftp, Handle, eof), + eof = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 6} = ssh_sftp:position(Sftp, Handle, {bof, 6}), + {ok, "7"} = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 9} = ssh_sftp:position(Sftp, Handle, {cur, 2}), + {ok, "0"} = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 0} = ssh_sftp:position(Sftp, Handle, bof), + {ok, "1"} = ssh_sftp:read(Sftp, Handle, 1), + + {ok, 1} = ssh_sftp:position(Sftp, Handle, cur), + {ok, "2"} = ssh_sftp:read(Sftp, Handle, 1), + + ok. + +%%-------------------------------------------------------------------- +pos_read(doc) -> + ["Test API functions pread/3 and apread/3"]; +pos_read(suite) -> + []; +pos_read(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + {Sftp, _} = ?config(sftp, Config), + Data = list_to_binary("Hej hopp!"), + ssh_sftp:write_file(Sftp, FileName, [Data]), + + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]), + + {async, Ref} = ssh_sftp:apread(Sftp, Handle, {bof, 5}, 4), + + NewData = "opp!", + + receive + {async_reply, Ref, {ok, NewData}} -> + ok; + Msg -> + test_server:fail(Msg) + end, + + NewData1 = "hopp", + + {ok, NewData1} = ssh_sftp:pread(Sftp, Handle, {bof, 4}, 4), + + ok. +%%-------------------------------------------------------------------- +pos_write(doc) -> + ["Test API functions pwrite/4 and apwrite/4"]; +pos_write(suite) -> + []; +pos_write(Config) when is_list(Config) -> + + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + {Sftp, _} = ?config(sftp, Config), + + {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]), + + Data = list_to_binary("Bye,"), + ssh_sftp:write_file(Sftp, FileName, [Data]), + + NewData = list_to_binary(" see you tomorrow"), + {async, Ref} = ssh_sftp:apwrite(Sftp, Handle, {bof, 4}, NewData), + receive + {async_reply, Ref, ok} -> + ok; + Msg -> + test_server:fail(Msg) + end, + + ok = ssh_sftp:pwrite(Sftp, Handle, eof, list_to_binary("!")), + + NewData1 = list_to_binary("Bye, see you tomorrow!"), + {ok, NewData1} = ssh_sftp:read_file(Sftp, FileName), + + ok. + +%% Internal functions +%%-------------------------------------------------------------------- +prep(Config) -> + PrivDir = ?config(priv_dir, Config), + TestFile = filename:join(PrivDir, "sftp.txt"), + TestFile1 = filename:join(PrivDir, "test.txt"), + TestLink = filename:join(PrivDir, "link_test.txt"), + + file:delete(TestFile), + file:delete(TestFile1), + file:delete(TestLink), + + %% Initial config + DataDir = ?config(data_dir, Config), + FileName = filename:join(DataDir, "sftp.txt"), + file:copy(FileName, TestFile), + Mode = 8#00400 bor 8#00200 bor 8#00040, % read & write owner, read group + {ok, FileInfo} = file:read_file_info(TestFile), + ok = file:write_file_info(TestFile, + FileInfo#file_info{mode = Mode}). diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa new file mode 100644 index 0000000000..7e3f885f5d --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICWwIBAAKBgQDLKYTdRnGzphcN+pF8UuI3sYB7rxZUHbOT87K3vh8XOLkDOsS3 +8VREtNS8Wb3uYXsRtyDoUvrLIDnyllOfJSDupWLr4ibckUZd/nhFAaC6WryVmH6k +GlQLLp9KU+vcn2DwYeo14gbwHYDB3pmv4CWAlnO1m/BkX4aLz1zC314OkQIBIwKB +gD/Z2UzboBPjvhpWEHeHw3CW3zzQoJ4X9pw2peH57IOkHOPCA0/A3/hWFvleCH4e +owWRU3w3ViKVGYbBh/7RJ5rllN+ENUmVn536srJTxLKUtvb5jRGj3W6EWgAGHSUB +hm83Kt9Lb5hprL7dPrNGvSseBm/LQSfBQ4vUUyiVRKGPAkEA/rPxWoLdBBP+FZtE +fGzz9izPM6Fe6o8ZGNZIlRBProOhgEvvIqdgzQWObgLVVrw+M/YApPpiYS3PEmWj +b2b+jwJBAMwyYeL6coKTl8swDu8HvLnshgUFJFTtHhOTXsKtXQNI1b24xhUrB3Sb +X8fmoByyRNRpOfvg4Jdqi3Z6KfIcsN8CQQDEfC83McBw3DkJWoVKCugVrYnmACSm +USH9N5cT6AL0VupNB2C0VTwL37cEaJXyc/V4ipLIaWHV8CNl9qKmZWVJAkEAurG4 +lQI8zyfbPW3EgsU+1d+QeZ5NGnJkpC73jWtNudwxIn0M4CdXRgpmMxwAGjyWs5No +Nr75OfsDKn5SPHIAywJAKrtONlOizgDiG3EvAXZlwFtOb+HkQ7lrFwczrQu9m7yi +brSAcnTrLKI6CrR33b/QJLvb9C/HTEZojFABGq8M7A== +-----END RSA PRIVATE KEY----- diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub new file mode 100644 index 0000000000..77f57de4af --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAyymE3UZxs6YXDfqRfFLiN7GAe68WVB2zk/Oyt74fFzi5AzrEt/FURLTUvFm97mF7Ebcg6FL6yyA58pZTnyUg7qVi6+Im3JFGXf54RQGgulq8lZh+pBpUCy6fSlPr3J9g8GHqNeIG8B2Awd6Zr+AlgJZztZvwZF+Gi89cwt9eDpE= jakob@balin diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp.txt new file mode 100644 index 0000000000..2a878ae255 --- /dev/null +++ b/lib/ssh/test/ssh_sftp_SUITE_data/sftp.txt @@ -0,0 +1,252 @@ +There are 5 KeySyms per KeyCode; KeyCodes range from 8 to 254. + + KeyCode Keysym (Keysym) ... + Value Value (Name) ... + + 8 + 9 + 10 + 11 0x0041 (A) + 12 0x0042 (B) + 13 0x0043 (C) + 14 0x0044 (D) + 15 0x0065 (e) 0x0045 (E) 0x20ac (EuroSign) + 16 0x0046 (F) + 17 0x0047 (G) + 18 0x0048 (H) + 19 0x0049 (I) + 20 0x004a (J) + 21 0x004b (K) + 22 0x004c (L) + 23 0x004d (M) + 24 0x004e (N) + 25 0x004f (O) + 26 0x0050 (P) + 27 0x0051 (Q) + 28 0x0052 (R) + 29 0x0053 (S) + 30 0x0054 (T) + 31 0x0055 (U) + 32 0x0056 (V) + 33 0x0057 (W) + 34 0x0058 (X) + 35 0x0059 (Y) + 36 0x005a (Z) + 37 0x0031 (1) 0x0021 (exclam) + 38 0x0032 (2) 0x0022 (quotedbl) 0x0040 (at) + 39 0x0033 (3) 0x0023 (numbersign) 0x00a3 (sterling) + 40 0x0034 (4) 0x00a4 (currency) 0x0024 (dollar) + 41 0x0035 (5) 0x0025 (percent) + 42 0x0036 (6) 0x0026 (ampersand) + 43 0x0037 (7) 0x002f (slash) 0x007b (braceleft) + 44 0x0038 (8) 0x0028 (parenleft) 0x005b (bracketleft) + 45 0x0039 (9) 0x0029 (parenright) 0x005d (bracketright) + 46 0x0030 (0) 0x003d (equal) 0x007d (braceright) + 47 0xff0d (Return) + 48 0xff1b (Escape) + 49 0xff08 (BackSpace) + 50 0xff09 (Tab) + 51 0x0020 (space) + 52 0x002b (plus) 0x003f (question) 0x005c (backslash) + 53 0x1005ff03 (SunFA_Acute) 0x1005ff00 (SunFA_Grave) + 54 0x00c5 (Aring) + 55 0x1005ff04 (SunFA_Diaeresis) 0x005e (asciicircum) 0x007e (asciitilde) + 56 + 57 0x0027 (apostrophe) 0x002a (asterisk) 0x0060 (grave) + 58 0x00d6 (Odiaeresis) + 59 0x00c4 (Adiaeresis) + 60 0x00a7 (section) 0x00bd (onehalf) + 61 0x002c (comma) 0x003b (semicolon) + 62 0x002e (period) 0x003a (colon) + 63 0x002d (minus) 0x005f (underscore) + 64 0xffe5 (Caps_Lock) + 65 0xffbe (F1) + 66 0xffbf (F2) + 67 0xffc0 (F3) + 68 0xffc1 (F4) + 69 0xffc2 (F5) + 70 0xffc3 (F6) + 71 0xffc4 (F7) + 72 0xffc5 (F8) + 73 0xffc6 (F9) + 74 0xffc7 (F10) + 75 0x1005ff10 (SunF36) + 76 0x1005ff11 (SunF37) + 77 0xffd3 (F22) 0xffd3 (F22) 0xff61 (Print) 0x1005ff60 (SunSys_Req) + 78 0xffd4 (F23) 0xffd4 (F23) 0xff14 (Scroll_Lock) + 79 0xffd2 (F21) 0xffd2 (F21) 0xff13 (Pause) 0xff6b (Break) + 80 0xff63 (Insert) + 81 0xff50 (Home) + 82 0xff55 (Prior) + 83 0xffff (Delete) + 84 0xff57 (End) + 85 0xff56 (Next) + 86 0xff53 (Right) + 87 0xff51 (Left) + 88 0xff54 (Down) + 89 0xff52 (Up) + 90 0xff7f (Num_Lock) + 91 0xffd6 (F25) 0xffd6 (F25) 0xffaf (KP_Divide) + 92 0xffd7 (F26) 0xffd7 (F26) 0xffaa (KP_Multiply) + 93 0xffd5 (F24) 0xffd5 (F24) 0xffad (KP_Subtract) + 94 0xffab (KP_Add) + 95 0xff8d (KP_Enter) + 96 0xffde (F33) 0xffde (F33) 0xffb1 (KP_1) 0xff57 (End) + 97 0xff54 (Down) 0xffdf (F34) 0xffb2 (KP_2) + 98 0xffe0 (F35) 0xffe0 (F35) 0xffb3 (KP_3) 0xff56 (Next) + 99 0xff51 (Left) 0xffdb (F30) 0xffb4 (KP_4) + 100 0xffdc (F31) 0xffdc (F31) 0xffb5 (KP_5) + 101 0xff53 (Right) 0xffdd (F32) 0xffb6 (KP_6) + 102 0xffd8 (F27) 0xffd8 (F27) 0xffb7 (KP_7) 0xff50 (Home) + 103 0xff52 (Up) 0xffd9 (F28) 0xffb8 (KP_8) + 104 0xffda (F29) 0xffda (F29) 0xffb9 (KP_9) 0xff55 (Prior) + 105 0xff9e (KP_Insert) 0xff9e (KP_Insert) 0xffb0 (KP_0) + 106 0xffff (Delete) 0xffff (Delete) 0xffac (KP_Separator) + 107 0x003c (less) 0x003e (greater) 0x007c (bar) + 108 0xff20 (Multi_key) + 109 0x1005ff76 (SunPowerSwitch) 0x1005ff7d (SunPowerSwitchShift) + 110 + 111 + 112 + 113 + 114 + 115 + 116 + 117 + 118 + 119 + 120 + 121 + 122 + 123 0xffce (F17) 0xffce (F17) 0x1005ff73 (SunOpen) + 124 0xff6a (Help) + 125 0xffca (F13) 0xffca (F13) 0x1005ff70 (SunProps) + 126 0xffcc (F15) 0xffcc (F15) 0x1005ff71 (SunFront) + 127 0xffc8 (F11) 0xffc8 (F11) 0xff69 (Cancel) + 128 0xffc9 (F12) 0xffc9 (F12) 0xff66 (Redo) + 129 0xffcb (F14) 0xffcb (F14) 0xff65 (Undo) + 130 0xffd1 (F20) 0xffd1 (F20) 0x1005ff75 (SunCut) + 131 0xffcd (F16) 0xffcd (F16) 0x1005ff72 (SunCopy) + 132 0xffcf (F18) 0xffcf (F18) 0x1005ff74 (SunPaste) + 133 0xffd0 (F19) 0xffd0 (F19) 0xff68 (Find) + 134 0x1005ff78 (SunAudioMute) 0x1005ff7a (SunVideoDegauss) + 135 0x1005ff79 (SunAudioRaiseVolume) 0x1005ff7c (SunVideoRaiseBrightness) + 136 0x1005ff77 (SunAudioLowerVolume) 0x1005ff7b (SunVideoLowerBrightness) + 137 + 138 + 139 + 140 + 141 + 142 + 143 + 144 + 145 + 146 + 147 + 148 + 149 + 150 + 151 + 152 + 153 + 154 + 155 + 156 + 157 + 158 + 159 + 160 + 161 + 162 + 163 + 164 + 165 + 166 + 167 + 168 + 169 + 170 + 171 + 172 + 173 + 174 + 175 + 176 + 177 + 178 + 179 + 180 + 181 + 182 + 183 + 184 + 185 + 186 + 187 + 188 + 189 + 190 + 191 + 192 + 193 + 194 + 195 + 196 + 197 + 198 + 199 + 200 + 201 + 202 + 203 + 204 + 205 + 206 + 207 + 208 + 209 + 210 + 211 + 212 + 213 + 214 + 215 + 216 + 217 + 218 + 219 + 220 + 221 + 222 + 223 + 224 + 225 + 226 + 227 + 228 + 229 + 230 + 231 0xffe3 (Control_L) + 232 0xffe1 (Shift_L) + 233 0xffe9 (Alt_L) + 234 0xffe7 (Meta_L) + 235 + 236 0xffe2 (Shift_R) + 237 0xff7e (Mode_switch) + 238 0xffe8 (Meta_R) + 239 + 240 + 241 + 242 + 243 + 244 + 245 + 246 + 247 + 248 + 249 + 250 + 251 + 252 + 253 + 254 diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl new file mode 100644 index 0000000000..bfe54a3e75 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_SUITE.erl @@ -0,0 +1,934 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssh_sftpd_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include("test_server_line.hrl"). +-include("ssh_xfer.hrl"). +-include("ssh.hrl"). + +-include_lib("kernel/include/file.hrl"). + +-define(SFPD_PORT, 9999). +-define(USER, "Alladin"). +-define(PASSWD, "Sesame"). +-define(XFER_PACKET_SIZE, 32768). +-define(XFER_WINDOW_SIZE, 4*?XFER_PACKET_SIZE). +-define(TIMEOUT, 10000). +-define(REG_ATTERS, <<0,0,0,0,1>>). +-define(UNIX_EPOCH, 62167219200). + +-define(is_set(F, Bits), + ((F) band (Bits)) == (F)). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initiation before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + case {catch ssh:stop(),catch crypto:start()} of + {ok,ok} -> + ssh_test_lib:make_dsa_files(Config), + Config; + {ok,_} -> + {skip,"Could not start ssh!"}; + {_,ok} -> + {skip,"Could not start crypto!"}; + {_,_} -> + {skip,"Could not start crypto and ssh!"} + end. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + crypto:stop(), + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initiation before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initiation before each test case +%%-------------------------------------------------------------------- +init_per_testcase(TestCase, Config) -> + ssh:start(), + prep(Config), + SysDir = ?config(data_dir, Config), + {ok, Sftpd} = + ssh_sftpd:listen(?SFPD_PORT, [{system_dir, SysDir}, + {user_passwords,[{?USER, ?PASSWD}]}, + {pwdfun, fun(_,_) -> true end}]), + + Cm = ssh_test_lib:connect(?SFPD_PORT, + [{system_dir, SysDir}, + {user_dir, SysDir}, + {user, ?USER}, {password, ?PASSWD}, + {user_interaction, false}, + {silently_accept_hosts, true}, + {pwdfun, fun(_,_) -> true end}]), + {ok, Channel} = + ssh_connection:session_channel(Cm, ?XFER_WINDOW_SIZE, + ?XFER_PACKET_SIZE, ?TIMEOUT), + + success = ssh_connection:subsystem(Cm, Channel, "sftp", ?TIMEOUT), + + ProtocolVer = case atom_to_list(TestCase) of + "ver3_" ++ _ -> + 3; + _ -> + ?SSH_SFTP_PROTOCOL_VERSION + end, + + Data = <<?UINT32(ProtocolVer)>> , + + Size = 1 + size(Data), + + ssh_connection:send(Cm, Channel, << ?UINT32(Size), + ?SSH_FXP_INIT, Data/binary >>), + + {ok, <<?SSH_FXP_VERSION, ?UINT32(Version), _Ext/binary>>, _} + = reply(Cm, Channel), + + test_server:format("Client: ~p Server ~p~n", [ProtocolVer, Version]), + + [{sftp, {Cm, Channel}}, {sftpd, Sftpd }| Config]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, Config) -> + ssh_sftpd:stop(?config(sftpd, Config)), + {Cm, Channel} = ?config(sftp, Config), + ssh_connection:close(Cm, Channel), + ssh:close(Cm), + ssh:stop(), + ok. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all() -> + [open_close_file, open_close_dir, read_file, read_dir, + write_file, rename_file, mk_rm_dir, remove_file, + real_path, retrieve_attributes, set_attributes, links, + ver3_rename_OTP_6352, seq10670, sshd_read_file]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + + +%% Test cases starts here. +%%-------------------------------------------------------------------- +open_close_file(doc) -> + ["Test SSH_FXP_OPEN and SSH_FXP_CLOSE commands"]; +open_close_file(suite) -> + []; +open_close_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + {Cm, Channel} = ?config(sftp, Config), + ReqId = 0, + + {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), Handle/binary>>, _} = + open_file(FileName, Cm, Channel, ReqId, + ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, + ?SSH_FXF_OPEN_EXISTING), + + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = close(Handle, ReqId, + Cm, Channel), + NewReqId = ReqId + 1, + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_INVALID_HANDLE), _/binary>>, _} = + close(Handle, ReqId, Cm, Channel), + + NewReqId1 = NewReqId + 1, + %% {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), % Ver 6 we have 5 + %% ?UINT32(?SSH_FX_FILE_IS_A_DIRECTORY), _/binary>>, _} = + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId1), + ?UINT32(?SSH_FX_FAILURE), _/binary>>, _} = + open_file(PrivDir, Cm, Channel, NewReqId1, + ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, + ?SSH_FXF_OPEN_EXISTING), + + ok. + +%%-------------------------------------------------------------------- +open_close_dir(doc) -> + ["Test SSH_FXP_OPENDIR and SSH_FXP_CLOSE commands"]; +open_close_dir(suite) -> + []; +open_close_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Cm, Channel} = ?config(sftp, Config), + FileName = filename:join(PrivDir, "test.txt"), + ReqId = 0, + + {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), Handle/binary>>, _} = + open_dir(PrivDir, Cm, Channel, ReqId), + + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = close(Handle, ReqId, + Cm, Channel), + + NewReqId = 1, + case open_dir(FileName, Cm, Channel, NewReqId) of + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), + ?UINT32(?SSH_FX_NOT_A_DIRECTORY), _/binary>>, _} -> + %% Only if server is using vsn > 5. + ok; + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), + ?UINT32(?SSH_FX_FAILURE), _/binary>>, _} -> + ok + end. + +%%-------------------------------------------------------------------- +read_file(doc) -> + ["Test SSH_FXP_READ command"]; +read_file(suite) -> + []; +read_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), Handle/binary>>, _} = + open_file(FileName, Cm, Channel, ReqId, + ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, + ?SSH_FXF_OPEN_EXISTING), + + NewReqId = 1, + + {ok, <<?SSH_FXP_DATA, ?UINT32(NewReqId), ?UINT32(_Length), + Data/binary>>, _} = + read_file(Handle, 100, 0, Cm, Channel, NewReqId), + + {ok, Data} = file:read_file(FileName), + + ok. +%%-------------------------------------------------------------------- +read_dir(doc) -> + ["Test SSH_FXP_READDIR command"]; +read_dir(suite) -> + []; +read_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Cm, Channel} = ?config(sftp, Config), + ReqId = 0, + {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), Handle/binary>>, _} = + open_dir(PrivDir, Cm, Channel, ReqId), + ok = read_dir(Handle, Cm, Channel, ReqId), + ok. + +%%-------------------------------------------------------------------- +write_file(doc) -> + ["Test SSH_FXP_WRITE command"]; +write_file(suite) -> + []; +write_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), Handle/binary>>, _} = + open_file(FileName, Cm, Channel, ReqId, + ?ACE4_WRITE_DATA bor ?ACE4_WRITE_ATTRIBUTES, + ?SSH_FXF_OPEN_EXISTING), + + NewReqId = 1, + Data = list_to_binary("Write file test"), + + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), ?UINT32(?SSH_FX_OK), + _/binary>>, _} + = write_file(Handle, Data, 0, Cm, Channel, NewReqId), + + {ok, Data} = file:read_file(FileName), + + ok. + +%%-------------------------------------------------------------------- +remove_file(doc) -> + ["Test SSH_FXP_REMOVE command"]; +remove_file(suite) -> + []; +remove_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = + remove(FileName, Cm, Channel, ReqId), + + NewReqId = 1, + %% {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), % ver 6 we have 5 + %% ?UINT32(?SSH_FX_FILE_IS_A_DIRECTORY ), _/binary>>, _} = + + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), + ?UINT32(?SSH_FX_FAILURE), _/binary>>, _} = + remove(PrivDir, Cm, Channel, NewReqId), + + ok. + +%%-------------------------------------------------------------------- +rename_file(doc) -> + ["Test SSH_FXP_RENAME command"]; +rename_file(suite) -> + []; +rename_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + NewFileName = filename:join(PrivDir, "test1.txt"), + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = + rename(FileName, NewFileName, Cm, Channel, ReqId, 6, 0), + + NewReqId = ReqId + 1, + + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = + rename(NewFileName, FileName, Cm, Channel, NewReqId, 6, + ?SSH_FXP_RENAME_OVERWRITE), + + NewReqId1 = NewReqId + 1, + file:copy(FileName, NewFileName), + + %% No owerwrite + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId1), + ?UINT32(?SSH_FX_FILE_ALREADY_EXISTS), _/binary>>, _} = + rename(FileName, NewFileName, Cm, Channel, NewReqId1, 6, + ?SSH_FXP_RENAME_NATIVE), + + NewReqId2 = NewReqId1 + 1, + + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId2), + ?UINT32(?SSH_FX_OP_UNSUPPORTED), _/binary>>, _} = + rename(FileName, NewFileName, Cm, Channel, NewReqId2, 6, + ?SSH_FXP_RENAME_ATOMIC), + + ok. + +%%-------------------------------------------------------------------- +mk_rm_dir(doc) -> + ["Test SSH_FXP_MKDIR and SSH_FXP_RMDIR command"]; +mk_rm_dir(suite) -> + []; +mk_rm_dir(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + {Cm, Channel} = ?config(sftp, Config), + DirName = filename:join(PrivDir, "test"), + ReqId = 0, + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), ?UINT32(?SSH_FX_OK), + _/binary>>, _} = mkdir(DirName, Cm, Channel, ReqId), + + NewReqId = 1, + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId), ?UINT32(?SSH_FX_FAILURE), + _/binary>>, _} = mkdir(DirName, Cm, Channel, NewReqId), + + NewReqId1 = 2, + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId1), ?UINT32(?SSH_FX_OK), + _/binary>>, _} = rmdir(DirName, Cm, Channel, NewReqId1), + + NewReqId2 = 3, + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId2), ?UINT32(?SSH_FX_NO_SUCH_FILE), + _/binary>>, _} = rmdir(DirName, Cm, Channel, NewReqId2), + + ok. +%%-------------------------------------------------------------------- +real_path(doc) -> + ["Test SSH_FXP_REALPATH command"]; +real_path(suite) -> + []; +real_path(Config) when is_list(Config) -> + case test_server:os_type() of + {win32, _} -> + {skip, "Not a relevant test on windows"}; + _ -> + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + PrivDir = ?config(priv_dir, Config), + TestDir = filename:join(PrivDir, "ssh_test"), + ok = file:make_dir(TestDir), + + OrigPath = filename:join(TestDir, ".."), + + {ok, <<?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(_), ?UINT32(Len), + Path:Len/binary, _/binary>>, _} + = real_path(OrigPath, Cm, Channel, ReqId), + + RealPath = filename:absname(binary_to_list(Path)), + AbsPrivDir = filename:absname(PrivDir), + + test_server:format("Path: ~p PrivDir: ~p~n", [RealPath, AbsPrivDir]), + + true = RealPath == AbsPrivDir, + + ok + end. + +%%-------------------------------------------------------------------- +links(doc) -> + []; +links(suite) -> + []; +links(Config) when is_list(Config) -> + case test_server:os_type() of + {win32, _} -> + {skip, "Links are not fully supported by windows"}; + _ -> + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + LinkFileName = filename:join(PrivDir, "link_test.txt"), + + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = + create_link(LinkFileName, FileName, Cm, Channel, ReqId), + + NewReqId = 1, + {ok, <<?SSH_FXP_NAME, ?UINT32(NewReqId), ?UINT32(_), ?UINT32(Len), + Path:Len/binary, _/binary>>, _} + = read_link(LinkFileName, Cm, Channel, NewReqId), + + + true = binary_to_list(Path) == FileName, + + test_server:format("Path: ~p~n", [binary_to_list(Path)]), + ok + end. + +%%-------------------------------------------------------------------- +retrieve_attributes(doc) -> + ["Test SSH_FXP_STAT, SSH_FXP_LSTAT AND SSH_FXP_FSTAT commands"]; +retrieve_attributes(suite) -> + []; +retrieve_attributes(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + {ok, FileInfo} = file:read_file_info(FileName), + + AttrValues = + retrive_attributes(FileName, Cm, Channel, ReqId), + + Type = encode_file_type(FileInfo#file_info.type), + Size = FileInfo#file_info.size, + Owner = FileInfo#file_info.uid, + Group = FileInfo#file_info.gid, + Permissions = FileInfo#file_info.mode, + Atime = calendar:datetime_to_gregorian_seconds( + erlang:localtime_to_universaltime(FileInfo#file_info.atime)) + - ?UNIX_EPOCH, + Mtime = calendar:datetime_to_gregorian_seconds( + erlang:localtime_to_universaltime(FileInfo#file_info.mtime)) + - ?UNIX_EPOCH, + Ctime = calendar:datetime_to_gregorian_seconds( + erlang:localtime_to_universaltime(FileInfo#file_info.ctime)) + - ?UNIX_EPOCH, + + lists:foreach(fun(Value) -> + <<?UINT32(Flags), _/binary>> = Value, + true = ?is_set(?SSH_FILEXFER_ATTR_SIZE, + Flags), + true = ?is_set(?SSH_FILEXFER_ATTR_PERMISSIONS, + Flags), + true = ?is_set(?SSH_FILEXFER_ATTR_ACCESSTIME, + Flags), + true = ?is_set(?SSH_FILEXFER_ATTR_CREATETIME, + Flags), + true = ?is_set(?SSH_FILEXFER_ATTR_MODIFYTIME, + Flags), + true = ?is_set(?SSH_FILEXFER_ATTR_OWNERGROUP, + Flags), + false = ?is_set(?SSH_FILEXFER_ATTR_ACL, + Flags), + false = ?is_set(?SSH_FILEXFER_ATTR_SUBSECOND_TIMES, + Flags), + false = ?is_set(?SSH_FILEXFER_ATTR_BITS, + Flags), + false = ?is_set(?SSH_FILEXFER_ATTR_EXTENDED, + Flags), + + <<?UINT32(_Flags), ?BYTE(Type), + ?UINT64(Size), + ?UINT32(OwnerLen), BinOwner:OwnerLen/binary, + ?UINT32(GroupLen), BinGroup:GroupLen/binary, + ?UINT32(Permissions), + ?UINT64(Atime), + ?UINT64(Ctime), + ?UINT64(Mtime)>> = Value, + + Owner = list_to_integer(binary_to_list(BinOwner)), + Group = list_to_integer(binary_to_list(BinGroup)) + end, AttrValues), + + ok. +%%-------------------------------------------------------------------- +set_attributes(doc) -> + ["Test SSH_FXP_SETSTAT AND SSH_FXP_FSETSTAT commands"]; +set_attributes(suite) -> + []; +set_attributes(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + {ok, FileInfo} = file:read_file_info(FileName), + + OrigPermissions = FileInfo#file_info.mode, + Permissions = 8#400, %% User read-only + + Flags = ?SSH_FILEXFER_ATTR_PERMISSIONS, + + Atters = [?uint32(Flags), ?byte(?SSH_FILEXFER_TYPE_REGULAR), + ?uint32(Permissions)], + + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = + set_attributes_file(FileName, Atters, Cm, Channel, ReqId), + + {ok, NewFileInfo} = file:read_file_info(FileName), + NewPermissions = NewFileInfo#file_info.mode, + + %% Can not test that NewPermissions = Permissions as + %% on Unix platforms, other bits than those listed in the + %% API may be set. + test_server:format("Org: ~p New: ~p~n", [OrigPermissions, NewPermissions]), + true = OrigPermissions =/= NewPermissions, + + test_server:format("Try to open the file"), + NewReqId = 2, + {ok, <<?SSH_FXP_HANDLE, ?UINT32(NewReqId), Handle/binary>>, _} = + open_file(FileName, Cm, Channel, NewReqId, + ?ACE4_READ_DATA bor ?ACE4_WRITE_ATTRIBUTES, + ?SSH_FXF_OPEN_EXISTING), + + NewAtters = [?uint32(Flags), ?byte(?SSH_FILEXFER_TYPE_REGULAR), + ?uint32(OrigPermissions)], + + NewReqId1 = 3, + + test_server:format("Set original permissions on the now open file"), + + {ok, <<?SSH_FXP_STATUS, ?UINT32(NewReqId1), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = + set_attributes_open_file(Handle, NewAtters, Cm, Channel, NewReqId1), + + {ok, NewFileInfo1} = file:read_file_info(FileName), + OrigPermissions = NewFileInfo1#file_info.mode, + + ok. + +%%-------------------------------------------------------------------- +ver3_rename_OTP_6352(doc) -> + ["Test that ver3 rename message is handled"]; + +ver3_rename_OTP_6352(suite) -> + []; + +ver3_rename_OTP_6352(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + NewFileName = filename:join(PrivDir, "test1.txt"), + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_OK), _/binary>>, _} = + rename(FileName, NewFileName, Cm, Channel, ReqId, 3, 0), + + ok. + +%%-------------------------------------------------------------------- +seq10670(doc) -> + ["Check that realpath works ok"]; + +seq10670(suite) -> + []; + +seq10670(Config) when is_list(Config) -> + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + case test_server:os_type() of + {win32, _} -> + {skip, "Not a relevant test on windows"}; + _ -> + {ok, <<?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(_), ?UINT32(Len), + Root:Len/binary, _/binary>>, _} + = real_path("/..", Cm, Channel, ReqId), + + <<"/">> = Root, + + {ok, <<?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(_), ?UINT32(Len), + Path:Len/binary, _/binary>>, _} + = real_path("/usr/bin/../..", Cm, Channel, ReqId), + + Root = Path + end. + +%% Internal functions +%%-------------------------------------------------------------------- +prep(Config) -> + PrivDir = ?config(priv_dir, Config), + TestFile = filename:join(PrivDir, "test.txt"), + TestFile1 = filename:join(PrivDir, "test1.txt"), + + file:delete(TestFile), + file:delete(TestFile1), + + %% Initial config + DataDir = ?config(data_dir, Config), + FileName = filename:join(DataDir, "test.txt"), + file:copy(FileName, TestFile), + Mode = 8#00400 bor 8#00200 bor 8#00040, % read & write owner, read group + {ok, FileInfo} = file:read_file_info(TestFile), + ok = file:write_file_info(TestFile, + FileInfo#file_info{mode = Mode}). + +reply(Cm, Channel) -> + reply(Cm, Channel,<<>>). + +reply(Cm, Channel, RBuf) -> + receive + {ssh_cm, Cm, {data, Channel, 0, Data}} -> + case <<RBuf/binary, Data/binary>> of + <<?UINT32(Len),Reply:Len/binary,Rest/binary>> -> + {ok, Reply, Rest}; + RBuf2 -> + reply(Cm, Channel, RBuf2) + end; + {ssh_cm, Cm, {eof, Channel}} -> + eof; + {ssh_cm, Cm, {closed, Channel}} -> + closed; + {ssh_cm, Cm, Msg} -> + test_server:fail(Msg) + end. + + +open_file(File, Cm, Channel, ReqId, Access, Flags) -> + + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(File)), + ?uint32(Access), + ?uint32(Flags), + ?REG_ATTERS]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_OPEN, Data/binary>>), + reply(Cm, Channel). + + + +close(Handle, ReqId, Cm , Channel) -> + Data = list_to_binary([?uint32(ReqId), Handle]), + + Size = 1 + size(Data), + + ssh_connection:send(Cm, Channel, <<?UINT32(Size), ?SSH_FXP_CLOSE, + Data/binary>>), + + reply(Cm, Channel). + + + +open_dir(Dir, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(Dir))]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_OPENDIR, Data/binary>>), + reply(Cm, Channel). + + +rename(OldName, NewName, Cm, Channel, ReqId, Version, Flags) -> + Data = + case Version of + 3 -> + list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(OldName)), + ?binary(list_to_binary(NewName))]); + _ -> + list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(OldName)), + ?binary(list_to_binary(NewName)), + ?uint32(Flags)]) + end, + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_RENAME, Data/binary>>), + reply(Cm, Channel). + + +mkdir(Dir, Cm, Channel, ReqId)-> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(Dir)), + ?REG_ATTERS]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_MKDIR, Data/binary>>), + reply(Cm, Channel). + + +rmdir(Dir, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(Dir))]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_RMDIR, Data/binary>>), + reply(Cm, Channel). + +remove(File, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(File))]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_REMOVE, Data/binary>>), + reply(Cm, Channel). + + +read_dir(Handle, Cm, Channel, ReqId) -> + + Data = list_to_binary([?uint32(ReqId), Handle]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_READDIR, Data/binary>>), + case reply(Cm, Channel) of + {ok, <<?SSH_FXP_NAME, ?UINT32(ReqId), ?UINT32(Count), + ?UINT32(Len), Listing:Len/binary, _/binary>>, _} -> + test_server:format("Count: ~p Listing: ~p~n", + [Count, binary_to_list(Listing)]), + read_dir(Handle, Cm, Channel, ReqId); + {ok, <<?SSH_FXP_STATUS, ?UINT32(ReqId), + ?UINT32(?SSH_FX_EOF), _/binary>>, _} -> + ok + end. + +read_file(Handle, MaxLength, OffSet, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), Handle, + ?uint64(OffSet), + ?uint32(MaxLength)]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_READ, Data/binary>>), + reply(Cm, Channel). + + +write_file(Handle, FileData, OffSet, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), Handle, + ?uint64(OffSet), + ?binary(FileData)]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_WRITE, Data/binary>>), + reply(Cm, Channel). + + +real_path(OrigPath, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(OrigPath))]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_REALPATH, Data/binary>>), + reply(Cm, Channel). + +create_link(LinkPath, Path, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(LinkPath)), + ?binary(list_to_binary(Path))]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_SYMLINK, Data/binary>>), + reply(Cm, Channel). + + +read_link(Link, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(Link))]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_READLINK, Data/binary>>), + reply(Cm, Channel). + +retrive_attributes_file(FilePath, Flags, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(FilePath)), + ?uint32(Flags)]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_STAT, Data/binary>>), + reply(Cm, Channel). + +retrive_attributes_file_or_link(FilePath, Flags, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(FilePath)), + ?uint32(Flags)]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_LSTAT, Data/binary>>), + reply(Cm, Channel). + +retrive_attributes_open_file(Handle, Flags, Cm, Channel, ReqId) -> + + Data = list_to_binary([?uint32(ReqId), + Handle, + ?uint32(Flags)]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_FSTAT, Data/binary>>), + reply(Cm, Channel). + +retrive_attributes(FileName, Cm, Channel, ReqId) -> + + Attr = ?SSH_FILEXFER_ATTR_SIZE, + + {ok, <<?SSH_FXP_ATTRS, ?UINT32(ReqId), Value/binary>>, _} + = retrive_attributes_file(FileName, Attr, + Cm, Channel, ReqId), + + NewReqId = ReqId + 1, + {ok, <<?SSH_FXP_ATTRS, ?UINT32(NewReqId), Value1/binary>>, _} + = retrive_attributes_file_or_link(FileName, + Attr, Cm, Channel, NewReqId), + + NewReqId1 = NewReqId + 1, + {ok, <<?SSH_FXP_HANDLE, ?UINT32(NewReqId1), Handle/binary>>, _} = + open_file(FileName, Cm, Channel, NewReqId1, + ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, + ?SSH_FXF_OPEN_EXISTING), + + NewReqId2 = NewReqId1 + 1, + {ok, <<?SSH_FXP_ATTRS, ?UINT32(NewReqId2), Value2/binary>>, _} + = retrive_attributes_open_file(Handle, Attr, Cm, Channel, NewReqId2), + + [Value, Value1, Value2]. + +set_attributes_file(FilePath, Atters, Cm, Channel, ReqId) -> + Data = list_to_binary([?uint32(ReqId), + ?binary(list_to_binary(FilePath)), + Atters]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_SETSTAT, Data/binary>>), + reply(Cm, Channel). + + +set_attributes_open_file(Handle, Atters, Cm, Channel, ReqId) -> + + Data = list_to_binary([?uint32(ReqId), + Handle, + Atters]), + Size = 1 + size(Data), + ssh_connection:send(Cm, Channel, <<?UINT32(Size), + ?SSH_FXP_FSETSTAT, Data/binary>>), + reply(Cm, Channel). + + +encode_file_type(Type) -> + case Type of + regular -> ?SSH_FILEXFER_TYPE_REGULAR; + directory -> ?SSH_FILEXFER_TYPE_DIRECTORY; + symlink -> ?SSH_FILEXFER_TYPE_SYMLINK; + special -> ?SSH_FILEXFER_TYPE_SPECIAL; + unknown -> ?SSH_FILEXFER_TYPE_UNKNOWN; + other -> ?SSH_FILEXFER_TYPE_UNKNOWN; + socket -> ?SSH_FILEXFER_TYPE_SOCKET; + char_device -> ?SSH_FILEXFER_TYPE_CHAR_DEVICE; + block_device -> ?SSH_FILEXFER_TYPE_BLOCK_DEVICE; + fifo -> ?SSH_FILEXFER_TYPE_FIFO; + undefined -> ?SSH_FILEXFER_TYPE_UNKNOWN + end. + +%%-------------------------------------------------------------------- +sshd_read_file(doc) -> + ["Test SSH_FXP_READ command, using sshd-server"]; +sshd_read_file(suite) -> + []; +sshd_read_file(Config) when is_list(Config) -> + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(PrivDir, "test.txt"), + + ReqId = 0, + {Cm, Channel} = ?config(sftp, Config), + + {ok, <<?SSH_FXP_HANDLE, ?UINT32(ReqId), Handle/binary>>, _} = + open_file(FileName, Cm, Channel, ReqId, + ?ACE4_READ_DATA bor ?ACE4_READ_ATTRIBUTES, + ?SSH_FXF_OPEN_EXISTING), + + NewReqId = 1, + + {ok, <<?SSH_FXP_DATA, ?UINT32(NewReqId), ?UINT32(_Length), + Data/binary>>, _} = + read_file(Handle, 100, 0, Cm, Channel, NewReqId), + + {ok, Data} = file:read_file(FileName), + + ok. diff --git a/lib/ssh/test/ssh_sftpd_SUITE_data/test.txt b/lib/ssh/test/ssh_sftpd_SUITE_data/test.txt new file mode 100644 index 0000000000..681bff80a0 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_SUITE_data/test.txt @@ -0,0 +1 @@ +Sftp test file.
\ No newline at end of file diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl new file mode 100644 index 0000000000..2209af05d5 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl @@ -0,0 +1,328 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssh_sftpd_erlclient_SUITE). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include("test_server_line.hrl"). + +-include_lib("kernel/include/file.hrl"). + +-define(SSHD_PORT, 9999). +-define(USER, "Alladin"). +-define(PASSWD, "Sesame"). +-define(SSH_MAX_PACKET_SIZE, 32768). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initiation before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + catch ssh:stop(), + case catch crypto:start() of + ok -> + DataDir = ?config(data_dir, Config), + FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), + c:c(FileAlt), + FileName = filename:join(DataDir, "test.txt"), + {ok, FileInfo} = file:read_file_info(FileName), + ok = file:write_file_info(FileName, + FileInfo#file_info{mode = 8#400}), + ssh_test_lib:make_dsa_files(Config), + Config; + _Else -> + {skip,"Could not start ssh!"} + end. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + crypto:stop(), + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initiation before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initiation before each test case +%%-------------------------------------------------------------------- +init_per_testcase(TestCase, Config) -> + ssh:start(), + DataDir = ?config(data_dir, Config), + + Options = + case atom_to_list(TestCase) of + "file_cb" ++ _ -> + Spec = + ssh_sftpd:subsystem_spec([{file_handler, + ssh_sftpd_file_alt}]), + [{user_passwords,[{?USER, ?PASSWD}]}, + {pwdfun, fun(_,_) -> true end}, + {system_dir, DataDir}, + {user_dir, DataDir}, + {subsystems, [Spec]}]; + "root_dir" -> + Privdir = ?config(priv_dir, Config), + Root = filename:join(Privdir, root), + file:make_dir(Root), + Spec = ssh_sftpd:subsystem_spec([{root,Root}]), + [{user_passwords,[{?USER, ?PASSWD}]}, + {pwdfun, fun(_,_) -> true end}, + {system_dir, DataDir}, + {user_dir, DataDir}, + {subsystems, [Spec]}]; + "list_dir_limited" -> + Spec = + ssh_sftpd:subsystem_spec([{max_files,1}]), + [{user_passwords,[{?USER, ?PASSWD}]}, + {pwdfun, fun(_,_) -> true end}, + {system_dir, DataDir}, + {user_dir, DataDir}, + {subsystems, [Spec]}]; + + _ -> + [{user_passwords,[{?USER, ?PASSWD}]}, + {pwdfun, fun(_,_) -> true end}, + {user_dir, DataDir}, + {system_dir, DataDir}] + end, + + {Sftpd, Host, _Port} = ssh_test_lib:daemon(any, ?SSHD_PORT, Options), + + {ok, ChannelPid, Connection} = + ssh_sftp:start_channel(Host, ?SSHD_PORT, + [{silently_accept_hosts, true}, + {user, ?USER}, {password, ?PASSWD}, + {pwdfun, fun(_,_) -> true end}, + {system_dir, DataDir}, + {user_dir, DataDir}, + {timeout, 30000}]), + TmpConfig = lists:keydelete(sftp, 1, Config), + NewConfig = lists:keydelete(sftpd, 1, TmpConfig), + [{sftp, {ChannelPid, Connection}}, {sftpd, Sftpd} | NewConfig]. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, Config) -> + catch ssh_sftpd:stop(?config(sftpd, Config)), + {Sftp, Connection} = ?config(sftp, Config), + catch ssh_sftp:stop_channel(Sftp), + catch ssh:close(Connection), + ssh:stop(), + ok. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all() -> + [close_file_OTP_6350, quit_OTP_6349, file_cb_OTP_6356, + root_dir, list_dir_limited]. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +%% Test cases starts here. +%%-------------------------------------------------------------------- +close_file_OTP_6350(doc) -> + ["Test that sftpd closes its fildescriptors after compleating the " + "transfer"]; + +close_file_OTP_6350(suite) -> + []; + +close_file_OTP_6350(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + FileName = filename:join(DataDir, "test.txt"), + + {Sftp, _} = ?config(sftp, Config), + + NumOfPorts = length(erlang:ports()), + + test_server:format("Number of open ports: ~p~n", [NumOfPorts]), + + {ok, <<_/binary>>} = ssh_sftp:read_file(Sftp, FileName), + + NumOfPorts = length(erlang:ports()), + + test_server:format("Number of open ports: ~p~n", + [length(erlang:ports())]), + + ok. + +%%-------------------------------------------------------------------- + +quit_OTP_6349(doc) -> + [" When the sftp client ends the session the " + "server will now behave correctly and not leave the " + "client hanging."]; + +quit_OTP_6349(suite) -> + []; + +quit_OTP_6349(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + FileName = filename:join(DataDir, "test.txt"), + + {Sftp, _} = ?config(sftp, Config), + + {ok, <<_/binary>>} = ssh_sftp:read_file(Sftp, FileName), + + ok = ssh_sftp:stop_channel(Sftp), + + Host = ssh_test_lib:hostname(), + + timer:sleep(5000), + {ok, NewSftp, _Conn} = ssh_sftp:start_channel(Host, ?SSHD_PORT, + [{silently_accept_hosts, true}, + {pwdfun, fun(_,_) -> true end}, + {system_dir, DataDir}, + {user_dir, DataDir}, + {user, ?USER}, {password, ?PASSWD}]), + + {ok, <<_/binary>>} = ssh_sftp:read_file(NewSftp, FileName), + + ok = ssh_sftp:stop_channel(NewSftp), + ok. + +%%-------------------------------------------------------------------- + +file_cb_OTP_6356(doc) -> + ["Test that it is possible to change the callback module for" + " the sftpds filehandling."]; + +file_cb_OTP_6356(suite) -> + []; + +file_cb_OTP_6356(Config) when is_list(Config) -> + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + FileName = filename:join(DataDir, "test.txt"), + + register(sftpd_file_alt_tester, self()), + + {Sftp, _} = ?config(sftp, Config), + + {ok, Bin} = ssh_sftp:read_file(Sftp, FileName), + alt_file_handler_check(alt_open), + alt_file_handler_check(alt_read_file_info), + alt_file_handler_check(alt_position), + alt_file_handler_check(alt_read), + alt_file_handler_check(alt_position), + alt_file_handler_check(alt_read), + alt_file_handler_check(alt_close), + + + NewFileName = filename:join(PrivDir, "test.txt"), + ok = ssh_sftp:write_file(Sftp, NewFileName, Bin), + alt_file_handler_check(alt_open), + alt_file_handler_check(alt_read_file_info), + alt_file_handler_check(alt_position), + alt_file_handler_check(alt_write), + alt_file_handler_check(alt_close), + + ReFileName = filename:join(PrivDir, "test1.txt"), + ok = ssh_sftp:rename(Sftp, NewFileName, ReFileName), + alt_file_handler_check(alt_rename), + + ok = ssh_sftp:delete(Sftp, ReFileName), + alt_file_handler_check(alt_delete), + + NewDir = filename:join(PrivDir, "testdir"), + ok = ssh_sftp:make_dir(Sftp, NewDir), + alt_file_handler_check(alt_make_dir), + + ok = ssh_sftp:del_dir(Sftp, NewDir), + alt_file_handler_check(alt_read_link_info), + alt_file_handler_check(alt_write_file_info), + alt_file_handler_check(alt_del_dir), + ok. + +root_dir(doc) -> + [""]; +root_dir(suite) -> + []; +root_dir(Config) when is_list(Config) -> + {Sftp, _} = ?config(sftp, Config), + FileName = "test.txt", + Bin = <<"Test file for root dir option">>, + ok = ssh_sftp:write_file(Sftp, FileName, Bin), + {ok, Bin} = ssh_sftp:read_file(Sftp, FileName), + {ok, Listing} = + ssh_sftp:list_dir(Sftp, "."), + test_server:format("Listing: ~p~n", [Listing]), + ok. + +list_dir_limited(doc) -> + [""]; +list_dir_limited(suite) -> + []; +list_dir_limited(Config) when is_list(Config) -> + {Sftp, _} = ?config(sftp, Config), + {ok, Listing} = + ssh_sftp:list_dir(Sftp, "."), + test_server:format("Listing: ~p~n", [Listing]), + ok. + +alt_file_handler_check(Msg) -> + receive + Msg -> + ok; + Other -> + test_server:fail({Msg, Other}) + after 10000 -> + test_server:fail("Not alt file handler") + end. diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl new file mode 100644 index 0000000000..9e119c4929 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl @@ -0,0 +1,100 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2010. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% + +%%% Description: Dummy Callback module for ssh_sftpd to test +%%% the possibility to switch file handling implementation. + +-module(ssh_sftpd_file_alt). + +-behaviour(ssh_sftpd_file_api). + +%% API +-export([close/2, delete/2, del_dir/2, get_cwd/1, is_dir/2, list_dir/2, + make_dir/2, make_symlink/3, open/3, position/3, read/3, + read_file_info/2, read_link/2, read_link_info/2, rename/3, + write/3, write_file_info/3]). + +close(IoDevice, State) -> + sftpd_file_alt_tester ! alt_close, + {file:close(IoDevice), State}. + +delete(Path, State) -> + sftpd_file_alt_tester ! alt_delete, + {file:delete(Path), State}. + +del_dir(Path, State) -> + sftpd_file_alt_tester ! alt_del_dir, + {file:del_dir(Path), State}. + +get_cwd(State) -> + {file:get_cwd(), State}. + +is_dir(AbsPath, State) -> + sftpd_file_alt_tester ! alt_is_dir, + {filelib:is_dir(AbsPath), State}. + +list_dir(AbsPath, State) -> + sftpd_file_alt_tester ! alt_list_dir, + {file:list_dir(AbsPath), State}. + +make_dir(Dir, State) -> + sftpd_file_alt_tester ! alt_make_dir, + {file:make_dir(Dir), State}. + +make_symlink(Path2, Path, State) -> + sftpd_file_alt_tester ! alt_make_symlink, + {file:make_symlink(Path2, Path), State}. + +open(Path, Flags, State) -> + sftpd_file_alt_tester ! alt_open, + {file:open(Path, Flags), State}. + +position(IoDevice, Offs, State) -> + sftpd_file_alt_tester ! alt_position, + {file:position(IoDevice, Offs), State}. + +read(IoDevice, Len, State) -> + sftpd_file_alt_tester ! alt_read, + {file:read(IoDevice, Len), State}. + +read_link(Path, State) -> + sftpd_file_alt_tester ! alt_read_link, + {file:read_link(Path), State}. + +read_link_info(Path, State) -> + sftpd_file_alt_tester ! alt_read_link_info, + {file:read_link_info(Path), State}. + +read_file_info(Path, State) -> + sftpd_file_alt_tester ! alt_read_file_info, + {file:read_file_info(Path), State}. + +rename(Path, Path2, State) -> + sftpd_file_alt_tester ! alt_rename, + {file:rename(Path, Path2), State}. + +write(IoDevice, Data, State) -> + sftpd_file_alt_tester ! alt_write, + {file:write(IoDevice, Data), State}. + +write_file_info(Path,Info, State) -> + sftpd_file_alt_tester ! alt_write_file_info, + {file:write_file_info(Path, Info), State}. diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/test.txt b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/test.txt new file mode 100644 index 0000000000..681bff80a0 --- /dev/null +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/test.txt @@ -0,0 +1 @@ +Sftp test file.
\ No newline at end of file diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl new file mode 100644 index 0000000000..425fae22c1 --- /dev/null +++ b/lib/ssh/test/ssh_test_lib.erl @@ -0,0 +1,684 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +%%---------------------------------------------------------------------- +-module(ssh_test_lib). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-include_lib("public_key/include/public_key.hrl"). +-include("test_server.hrl"). +-include("test_server_line.hrl"). + +-define(TIMEOUT, 50000). + +connect(Options) -> + connect(hostname(), inet_port(), Options). + +connect(Port, Options) when is_integer(Port) -> + connect(hostname(), Port, Options); +connect(any, Options) -> + connect(hostname(), inet_port(), Options); +connect(Host, Options) -> + connect(Host, inet_port(), Options). + +connect(any, Port, Options) -> + connect(hostname(), Port, Options); +connect(Host, Port, Options) -> + case ssh:connect(Host, Port, Options) of + {ok, ConnectionRef} -> + ConnectionRef; + Error -> + Error + end. + +daemon(Options) -> + daemon(any, inet_port(), Options). + +daemon(Port, Options) when is_integer(Port) -> + daemon(any, Port, Options); +daemon(Host, Options) -> + daemon(Host, inet_port(), Options). + +daemon(Host, Port, Options) -> + case ssh:daemon(Host, Port, Options) of + {ok, Pid} when Host == any -> + {Pid, hostname(), Port}; + {ok, Pid} -> + {Pid, Host, Port}; + Error -> + Error + end. + + + + +start_shell(Port, IOServer) -> + spawn_link(?MODULE, init_shell, [Port, IOServer]). + +init_shell(Port, IOServer) -> + Host = hostname(), + UserDir = get_user_dir(), + Options = [{user_interaction, false}, {silently_accept_hosts, + true}] ++ UserDir, + group_leader(IOServer, self()), + loop_shell(Host, Port, Options). + +loop_shell(Host, Port, Options) -> + ssh:shell(Host, Port, Options). + +start_io_server() -> + spawn_link(?MODULE, init_io_server, [self()]). + +init_io_server(TestCase) -> + process_flag(trap_exit, true), + loop_io_server(TestCase, []). + +loop_io_server(TestCase, Buff0) -> + receive + {input, TestCase, Line} -> + %io:format("~p~n",[{input, TestCase, Line}]), + loop_io_server(TestCase, Buff0 ++ [Line]); + {io_request, From, ReplyAs, Request} -> + %io:format("request -> ~p~n",[Request]), + {ok, Reply, Buff} = io_request(Request, TestCase, From, + ReplyAs, Buff0), + %io:format("reply -> ~p~n",[Reply]), + io_reply(From, ReplyAs, Reply), + loop_io_server(TestCase, Buff); + {'EXIT',_, _} -> + erlang:display('EXIT'), + ok + end. + +io_request({put_chars, Chars}, TestCase, _, _, Buff) -> + reply(TestCase, Chars), + {ok, ok, Buff}; +io_request({put_chars, Enc, Chars}, TestCase, _, _, Buff) -> + reply(TestCase, unicode:characters_to_binary(Chars,Enc,latin1)), + {ok, ok, Buff}; + +io_request({get_line, _} = Request, _, From, ReplyAs, [] = Buff) -> + erlang:send_after(1000, self(), {io_request, From, ReplyAs, Request}), + {ok, [], Buff}; +io_request({get_line, _Enc, _Prompt} = Request, _, From, ReplyAs, [] = Buff) -> + erlang:send_after(1000, self(), {io_request, From, ReplyAs, Request}), + {ok, [], Buff}; + +io_request({get_line, _Enc,_}, _, _, _, [Line | Buff]) -> + {ok, Line, Buff}. + +io_reply(_, _, []) -> + ok; +io_reply(From, ReplyAs, Reply) -> + From ! {io_reply, ReplyAs, Reply}. + +reply(_, []) -> + ok; +reply(TestCase, Result) -> + TestCase ! Result. + +receive_exec_result(Msg) -> + test_server:format("Expect data! ~p", [Msg]), + receive + Msg -> + test_server:format("1: Collected data ~p", [Msg]), + expected; + Other -> + {unexpected_msg, Other} + end. +receive_exec_end(ConnectionRef, ChannelId) -> + Eof = {ssh_cm, ConnectionRef, {eof, ChannelId}}, + ExitStatus = {ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}}, + Closed = {ssh_cm, ConnectionRef,{closed, ChannelId}}, + case receive_exec_result(ExitStatus) of + {unexpected_msg, Eof} -> %% Open ssh seems to not allways send these messages + %% in the same order! + test_server:format("2: Collected data ~p", [Eof]), + case receive_exec_result(ExitStatus) of + expected -> + expected = receive_exec_result(Closed); + {unexpected_msg, Closed} -> + test_server:format("3: Collected data ~p", [Closed]) + end; + expected -> + test_server:format("4: Collected data ~p", [ExitStatus]), + expected = receive_exec_result(Eof), + expected = receive_exec_result(Closed); + Other -> + test_server:fail({unexpected_msg, Other}) + end. + +receive_exec_result(Data, ConnectionRef, ChannelId) -> + Eof = {ssh_cm, ConnectionRef, {eof, ChannelId}}, + Closed = {ssh_cm, ConnectionRef,{closed, ChannelId}}, + expected = receive_exec_result(Data), + expected = receive_exec_result(Eof), + expected = receive_exec_result(Closed). + + +inet_port()-> + {ok, Socket} = gen_tcp:listen(0, [{reuseaddr, true}]), + {ok, Port} = inet:port(Socket), + gen_tcp:close(Socket), + Port. + + +%% copy private keys to given dir from ~/.ssh +get_id_keys(DstDir) -> + SrcDir = filename:join(os:getenv("HOME"), ".ssh"), + RsaOk = copyfile(SrcDir, DstDir, "id_rsa"), + DsaOk = copyfile(SrcDir, DstDir, "id_dsa"), + case {RsaOk, DsaOk} of + {{ok, _}, {ok, _}} -> {ok, both}; + {{ok, _}, _} -> {ok, rsa}; + {_, {ok, _}} -> {ok, dsa}; + {Error, _} -> Error + end. + +remove_id_keys(Dir) -> + file:delete(filename:join(Dir, "id_rsa")), + file:delete(filename:join(Dir, "id_dsa")). + +copyfile(SrcDir, DstDir, Fn) -> + file:copy(filename:join(SrcDir, Fn), + filename:join(DstDir, Fn)). + +failfun(_User, {authmethod,none}) -> + ok; +failfun(User, Reason) -> + error_logger:format("~p failed XXX to login: ~p~n", [User, Reason]). + +hostname() -> + {ok,Host} = inet:gethostname(), + Host. + +known_hosts(BR) -> + KnownHosts = ssh_file:file_name(user, "known_hosts", []), + B = KnownHosts ++ "xxx", + case BR of + backup -> + file:rename(KnownHosts, B); + restore -> + file:delete(KnownHosts), + file:rename(B, KnownHosts) + end. + + +get_user_dir() -> + case os:type() of + {win32, _} -> + [{user_dir, filename:join([os:getenv("HOME"), ".ssh"])}]; + _ -> + [] + end. + + +make_dsa_cert_files(Config) -> + make_dsa_cert_files("", Config). + +make_dsa_cert_files(RoleStr, Config) -> + + CaInfo = {CaCert, _} = make_cert([{key, dsa}]), + {Cert, CertKey} = make_cert([{key, dsa}, {issuer, CaInfo}]), + CaCertFile = filename:join([?config(data_dir, Config), + RoleStr, "dsa_cacerts.pem"]), + CertFile = filename:join([?config(data_dir, Config), + RoleStr, "dsa_cert.pem"]), + KeyFile = filename:join([?config(data_dir, Config), + RoleStr, "dsa_key.pem"]), + + der_to_pem(CaCertFile, [{'Certificate', CaCert, not_encrypted}]), + der_to_pem(CertFile, [{'Certificate', Cert, not_encrypted}]), + der_to_pem(KeyFile, [CertKey]), + {CaCertFile, CertFile, KeyFile}. + +make_dsa_files(Config) -> + make_dsa_files(Config, rfc4716_public_key). +make_dsa_files(Config, Type) -> + {DSA, EncodedKey} = ssh_test_lib:gen_dsa(128, 20), + PKey = DSA#'DSAPrivateKey'.y, + P = DSA#'DSAPrivateKey'.p, + Q = DSA#'DSAPrivateKey'.q, + G = DSA#'DSAPrivateKey'.g, + Dss = #'Dss-Parms'{p=P, q=Q, g=G}, + {ok, Hostname} = inet:gethostname(), + {ok, {A, B, C, D}} = inet:getaddr(Hostname, inet), + IP = lists:concat([A, ".", B, ".", C, ".", D]), + Attributes = [], % Could be [{comment,"user@" ++ Hostname}], + HostNames = [{hostnames,[IP, IP]}], + PublicKey = [{{PKey, Dss}, Attributes}], + KnownHosts = [{{PKey, Dss}, HostNames}], + + KnownHostsEnc = public_key:ssh_encode(KnownHosts, known_hosts), + KnownHosts = public_key:ssh_decode(KnownHostsEnc, known_hosts), + + PublicKeyEnc = public_key:ssh_encode(PublicKey, Type), +% PublicKey = public_key:ssh_decode(PublicKeyEnc, Type), + + SystemTmpDir = ?config(data_dir, Config), + filelib:ensure_dir(SystemTmpDir), + file:make_dir(SystemTmpDir), + + DSAFile = filename:join(SystemTmpDir, "ssh_host_dsa_key.pub"), + file:delete(DSAFile), + + DSAPrivateFile = filename:join(SystemTmpDir, "ssh_host_dsa_key"), + file:delete(DSAPrivateFile), + + KHFile = filename:join(SystemTmpDir, "known_hosts"), + file:delete(KHFile), + + PemBin = public_key:pem_encode([EncodedKey]), + + file:write_file(DSAFile, PublicKeyEnc), + file:write_file(KHFile, KnownHostsEnc), + file:write_file(DSAPrivateFile, PemBin), + ok. + +%%-------------------------------------------------------------------- +%% Create and return a der encoded certificate +%% Option Default +%% ------------------------------------------------------- +%% digest sha1 +%% validity {date(), date() + week()} +%% version 3 +%% subject [] list of the following content +%% {name, Name} +%% {email, Email} +%% {city, City} +%% {state, State} +%% {org, Org} +%% {org_unit, OrgUnit} +%% {country, Country} +%% {serial, Serial} +%% {title, Title} +%% {dnQualifer, DnQ} +%% issuer = {Issuer, IssuerKey} true (i.e. a ca cert is created) +%% (obs IssuerKey migth be {Key, Password} +%% key = KeyFile|KeyBin|rsa|dsa Subject PublicKey rsa or dsa generates key +%% +%% +%% (OBS: The generated keys are for testing only) +%% make_cert([{::atom(), ::term()}]) -> {Cert::binary(), Key::binary()} +%%-------------------------------------------------------------------- +make_cert(Opts) -> + SubjectPrivateKey = get_key(Opts), + {TBSCert, IssuerKey} = make_tbs(SubjectPrivateKey, Opts), + Cert = public_key:pkix_sign(TBSCert, IssuerKey), + true = verify_signature(Cert, IssuerKey, undef), %% verify that the keys where ok + {Cert, encode_key(SubjectPrivateKey)}. + +%%-------------------------------------------------------------------- +%% Writes cert files in Dir with FileName and FileName ++ Suffix +%% write_cert(::string(), ::string(), {Cert,Key}) -> ok +%%-------------------------------------------------------------------- +write_cert(Dir, FileName, Suffix, {Cert, Key = {_,_,not_encrypted}}) when is_binary(Cert) -> + ok = der_to_pem(filename:join(Dir, FileName), + [{'Certificate', Cert, not_encrypted}]), + ok = der_to_pem(filename:join(Dir, FileName ++ Suffix), [Key]). + +%%-------------------------------------------------------------------- +%% Creates a rsa key (OBS: for testing only) +%% the size are in bytes +%% gen_rsa(::integer()) -> {::atom(), ::binary(), ::opaque()} +%%-------------------------------------------------------------------- +gen_rsa(Size) when is_integer(Size) -> + Key = gen_rsa2(Size), + {Key, encode_key(Key)}. + +%%-------------------------------------------------------------------- +%% Creates a dsa key (OBS: for testing only) +%% the sizes are in bytes +%% gen_dsa(::integer()) -> {::atom(), ::binary(), ::opaque()} +%%-------------------------------------------------------------------- +gen_dsa(LSize,NSize) when is_integer(LSize), is_integer(NSize) -> + Key = gen_dsa2(LSize, NSize), + {Key, encode_key(Key)}. + +%%-------------------------------------------------------------------- +%% Verifies cert signatures +%% verify_signature(::binary(), ::tuple()) -> ::boolean() +%%-------------------------------------------------------------------- +verify_signature(DerEncodedCert, DerKey, _KeyParams) -> + Key = decode_key(DerKey), + case Key of + #'RSAPrivateKey'{modulus=Mod, publicExponent=Exp} -> + public_key:pkix_verify(DerEncodedCert, + #'RSAPublicKey'{modulus=Mod, publicExponent=Exp}); + #'DSAPrivateKey'{p=P, q=Q, g=G, y=Y} -> + public_key:pkix_verify(DerEncodedCert, {Y, #'Dss-Parms'{p=P, q=Q, g=G}}) + end. + +%%%%%%%%%%%%%%%%%%%%%%%%% Implementation %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_key(Opts) -> + case proplists:get_value(key, Opts) of + undefined -> make_key(rsa, Opts); + rsa -> make_key(rsa, Opts); + dsa -> make_key(dsa, Opts); + Key -> + Password = proplists:get_value(password, Opts, no_passwd), + decode_key(Key, Password) + end. + +decode_key({Key, Pw}) -> + decode_key(Key, Pw); +decode_key(Key) -> + decode_key(Key, no_passwd). + + +decode_key(#'RSAPublicKey'{} = Key,_) -> + Key; +decode_key(#'RSAPrivateKey'{} = Key,_) -> + Key; +decode_key(#'DSAPrivateKey'{} = Key,_) -> + Key; +decode_key(PemEntry = {_,_,_}, Pw) -> + public_key:pem_entry_decode(PemEntry, Pw); +decode_key(PemBin, Pw) -> + [KeyInfo] = public_key:pem_decode(PemBin), + decode_key(KeyInfo, Pw). + +encode_key(Key = #'RSAPrivateKey'{}) -> + {ok, Der} = 'OTP-PUB-KEY':encode('RSAPrivateKey', Key), + {'RSAPrivateKey', list_to_binary(Der), not_encrypted}; +encode_key(Key = #'DSAPrivateKey'{}) -> + {ok, Der} = 'OTP-PUB-KEY':encode('DSAPrivateKey', Key), + {'DSAPrivateKey', list_to_binary(Der), not_encrypted}. + +make_tbs(SubjectKey, Opts) -> + Version = list_to_atom("v"++integer_to_list(proplists:get_value(version, Opts, 3))), + + IssuerProp = proplists:get_value(issuer, Opts, true), + {Issuer, IssuerKey} = issuer(IssuerProp, Opts, SubjectKey), + + {Algo, Parameters} = sign_algorithm(IssuerKey, Opts), + + SignAlgo = #'SignatureAlgorithm'{algorithm = Algo, + parameters = Parameters}, + Subject = case IssuerProp of + true -> %% Is a Root Ca + Issuer; + _ -> + subject(proplists:get_value(subject, Opts),false) + end, + + {#'OTPTBSCertificate'{serialNumber = trunc(random:uniform()*100000000)*10000 + 1, + signature = SignAlgo, + issuer = Issuer, + validity = validity(Opts), + subject = Subject, + subjectPublicKeyInfo = publickey(SubjectKey), + version = Version, + extensions = extensions(Opts) + }, IssuerKey}. + +issuer(true, Opts, SubjectKey) -> + %% Self signed + {subject(proplists:get_value(subject, Opts), true), SubjectKey}; +issuer({Issuer, IssuerKey}, _Opts, _SubjectKey) when is_binary(Issuer) -> + {issuer_der(Issuer), decode_key(IssuerKey)}; +issuer({File, IssuerKey}, _Opts, _SubjectKey) when is_list(File) -> + {ok, [{cert, Cert, _}|_]} = pem_to_der(File), + {issuer_der(Cert), decode_key(IssuerKey)}. + +issuer_der(Issuer) -> + Decoded = public_key:pkix_decode_cert(Issuer, otp), + #'OTPCertificate'{tbsCertificate=Tbs} = Decoded, + #'OTPTBSCertificate'{subject=Subject} = Tbs, + Subject. + +subject(undefined, IsRootCA) -> + User = if IsRootCA -> "RootCA"; true -> os:getenv("USER") end, + Opts = [{email, User ++ "@erlang.org"}, + {name, User}, + {city, "Stockholm"}, + {country, "SE"}, + {org, "erlang"}, + {org_unit, "testing dep"}], + subject(Opts); +subject(Opts, _) -> + subject(Opts). + +subject(SubjectOpts) when is_list(SubjectOpts) -> + Encode = fun(Opt) -> + {Type,Value} = subject_enc(Opt), + [#'AttributeTypeAndValue'{type=Type, value=Value}] + end, + {rdnSequence, [Encode(Opt) || Opt <- SubjectOpts]}. + +%% Fill in the blanks +subject_enc({name, Name}) -> {?'id-at-commonName', {printableString, Name}}; +subject_enc({email, Email}) -> {?'id-emailAddress', Email}; +subject_enc({city, City}) -> {?'id-at-localityName', {printableString, City}}; +subject_enc({state, State}) -> {?'id-at-stateOrProvinceName', {printableString, State}}; +subject_enc({org, Org}) -> {?'id-at-organizationName', {printableString, Org}}; +subject_enc({org_unit, OrgUnit}) -> {?'id-at-organizationalUnitName', {printableString, OrgUnit}}; +subject_enc({country, Country}) -> {?'id-at-countryName', Country}; +subject_enc({serial, Serial}) -> {?'id-at-serialNumber', Serial}; +subject_enc({title, Title}) -> {?'id-at-title', {printableString, Title}}; +subject_enc({dnQualifer, DnQ}) -> {?'id-at-dnQualifier', DnQ}; +subject_enc(Other) -> Other. + + +extensions(Opts) -> + case proplists:get_value(extensions, Opts, []) of + false -> + asn1_NOVALUE; + Exts -> + lists:flatten([extension(Ext) || Ext <- default_extensions(Exts)]) + end. + +default_extensions(Exts) -> + Def = [{key_usage,undefined}, + {subject_altname, undefined}, + {issuer_altname, undefined}, + {basic_constraints, default}, + {name_constraints, undefined}, + {policy_constraints, undefined}, + {ext_key_usage, undefined}, + {inhibit_any, undefined}, + {auth_key_id, undefined}, + {subject_key_id, undefined}, + {policy_mapping, undefined}], + Filter = fun({Key, _}, D) -> lists:keydelete(Key, 1, D) end, + Exts ++ lists:foldl(Filter, Def, Exts). + +extension({_, undefined}) -> []; +extension({basic_constraints, Data}) -> + case Data of + default -> + #'Extension'{extnID = ?'id-ce-basicConstraints', + extnValue = #'BasicConstraints'{cA=true}, + critical=true}; + false -> + []; + Len when is_integer(Len) -> + #'Extension'{extnID = ?'id-ce-basicConstraints', + extnValue = #'BasicConstraints'{cA=true, pathLenConstraint=Len}, + critical=true}; + _ -> + #'Extension'{extnID = ?'id-ce-basicConstraints', + extnValue = Data} + end; +extension({Id, Data, Critical}) -> + #'Extension'{extnID = Id, extnValue = Data, critical = Critical}. + + +publickey(#'RSAPrivateKey'{modulus=N, publicExponent=E}) -> + Public = #'RSAPublicKey'{modulus=N, publicExponent=E}, + Algo = #'PublicKeyAlgorithm'{algorithm= ?rsaEncryption, parameters='NULL'}, + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, + subjectPublicKey = Public}; +publickey(#'DSAPrivateKey'{p=P, q=Q, g=G, y=Y}) -> + Algo = #'PublicKeyAlgorithm'{algorithm= ?'id-dsa', + parameters={params, #'Dss-Parms'{p=P, q=Q, g=G}}}, + #'OTPSubjectPublicKeyInfo'{algorithm = Algo, subjectPublicKey = Y}. + +validity(Opts) -> + DefFrom0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())-1), + DefTo0 = calendar:gregorian_days_to_date(calendar:date_to_gregorian_days(date())+7), + {DefFrom, DefTo} = proplists:get_value(validity, Opts, {DefFrom0, DefTo0}), + Format = fun({Y,M,D}) -> lists:flatten(io_lib:format("~w~2..0w~2..0w000000Z",[Y,M,D])) end, + #'Validity'{notBefore={generalTime, Format(DefFrom)}, + notAfter ={generalTime, Format(DefTo)}}. + +sign_algorithm(#'RSAPrivateKey'{}, Opts) -> + Type = case proplists:get_value(digest, Opts, sha1) of + sha1 -> ?'sha1WithRSAEncryption'; + sha512 -> ?'sha512WithRSAEncryption'; + sha384 -> ?'sha384WithRSAEncryption'; + sha256 -> ?'sha256WithRSAEncryption'; + md5 -> ?'md5WithRSAEncryption'; + md2 -> ?'md2WithRSAEncryption' + end, + {Type, 'NULL'}; +sign_algorithm(#'DSAPrivateKey'{p=P, q=Q, g=G}, _Opts) -> + {?'id-dsa-with-sha1', {params,#'Dss-Parms'{p=P, q=Q, g=G}}}. + +make_key(rsa, _Opts) -> + %% (OBS: for testing only) + gen_rsa2(64); +make_key(dsa, _Opts) -> + gen_dsa2(128, 20). %% Bytes i.e. {1024, 160} + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% RSA key generation (OBS: for testing only) +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +-define(SMALL_PRIMES, [65537,97,89,83,79,73,71,67,61,59,53, + 47,43,41,37,31,29,23,19,17,13,11,7,5,3]). + +gen_rsa2(Size) -> + P = prime(Size), + Q = prime(Size), + N = P*Q, + Tot = (P - 1) * (Q - 1), + [E|_] = lists:dropwhile(fun(Candidate) -> (Tot rem Candidate) == 0 end, ?SMALL_PRIMES), + {D1,D2} = extended_gcd(E, Tot), + D = erlang:max(D1,D2), + case D < E of + true -> + gen_rsa2(Size); + false -> + {Co1,Co2} = extended_gcd(Q, P), + Co = erlang:max(Co1,Co2), + #'RSAPrivateKey'{version = 'two-prime', + modulus = N, + publicExponent = E, + privateExponent = D, + prime1 = P, + prime2 = Q, + exponent1 = D rem (P-1), + exponent2 = D rem (Q-1), + coefficient = Co + } + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% DSA key generation (OBS: for testing only) +%% See http://en.wikipedia.org/wiki/Digital_Signature_Algorithm +%% and the fips_186-3.pdf +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +gen_dsa2(LSize, NSize) -> + Q = prime(NSize), %% Choose N-bit prime Q + X0 = prime(LSize), + P0 = prime((LSize div 2) +1), + + %% Choose L-bit prime modulus P such that p-1 is a multiple of q. + case dsa_search(X0 div (2*Q*P0), P0, Q, 1000) of + error -> + gen_dsa2(LSize, NSize); + P -> + G = crypto:mod_exp(2, (P-1) div Q, P), % Choose G a number whose multiplicative order modulo p is q. + %% such that This may be done by setting g = h^(p-1)/q mod p, commonly h=2 is used. + + X = prime(20), %% Choose x by some random method, where 0 < x < q. + Y = crypto:mod_exp(G, X, P), %% Calculate y = g^x mod p. + + #'DSAPrivateKey'{version=0, p=P, q=Q, g=G, y=Y, x=X} + end. + +%% See fips_186-3.pdf +dsa_search(T, P0, Q, Iter) when Iter > 0 -> + P = 2*T*Q*P0 + 1, + case is_prime(crypto:mpint(P), 50) of + true -> P; + false -> dsa_search(T+1, P0, Q, Iter-1) + end; +dsa_search(_,_,_,_) -> + error. + + +%%%%%%% Crypto Math %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +prime(ByteSize) -> + Rand = odd_rand(ByteSize), + crypto:erlint(prime_odd(Rand, 0)). + +prime_odd(Rand, N) -> + case is_prime(Rand, 50) of + true -> + Rand; + false -> + NotPrime = crypto:erlint(Rand), + prime_odd(crypto:mpint(NotPrime+2), N+1) + end. + +%% see http://en.wikipedia.org/wiki/Fermat_primality_test +is_prime(_, 0) -> true; +is_prime(Candidate, Test) -> + CoPrime = odd_rand(<<0,0,0,4, 10000:32>>, Candidate), + case crypto:mod_exp(CoPrime, Candidate, Candidate) of + CoPrime -> is_prime(Candidate, Test-1); + _ -> false + end. + +odd_rand(Size) -> + Min = 1 bsl (Size*8-1), + Max = (1 bsl (Size*8))-1, + odd_rand(crypto:mpint(Min), crypto:mpint(Max)). + +odd_rand(Min,Max) -> + Rand = <<Sz:32, _/binary>> = crypto:rand_uniform(Min,Max), + BitSkip = (Sz+4)*8-1, + case Rand of + Odd = <<_:BitSkip, 1:1>> -> Odd; + Even = <<_:BitSkip, 0:1>> -> + crypto:mpint(crypto:erlint(Even)+1) + end. + +extended_gcd(A, B) -> + case A rem B of + 0 -> + {0, 1}; + N -> + {X, Y} = extended_gcd(B, N), + {Y, X-Y*(A div B)} + end. + +pem_to_der(File) -> + {ok, PemBin} = file:read_file(File), + public_key:pem_decode(PemBin). + +der_to_pem(File, Entries) -> + PemBin = public_key:pem_encode(Entries), + file:write_file(File, PemBin). diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl new file mode 100644 index 0000000000..f959d50484 --- /dev/null +++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl @@ -0,0 +1,458 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(ssh_to_openssh_SUITE). + +-include_lib("common_test/include/ct.hrl"). +-include("test_server_line.hrl"). + +%% Note: This directive should only be used in test suites. +-compile(export_all). + +-define(TIMEOUT, 50000). +-define(SSH_DEFAULT_PORT, 22). + +%% Test server callback functions +%%-------------------------------------------------------------------- +%% Function: init_per_suite(Config) -> Config +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Initialization before the whole suite +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%%-------------------------------------------------------------------- +init_per_suite(Config) -> + case catch crypto:start() of + ok -> + ssh_test_lib:make_dsa_files(Config), + Config; + _Else -> + {skip,"Could not start crypto!"} + end. + +%%-------------------------------------------------------------------- +%% Function: end_per_suite(Config) -> _ +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after the whole suite +%%-------------------------------------------------------------------- +end_per_suite(_Config) -> + crypto:stop(), + ok. + +%%-------------------------------------------------------------------- +%% Function: init_per_testcase(TestCase, Config) -> Config +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% +%% Description: Initialization before each test case +%% +%% Note: This function is free to add any key/value pairs to the Config +%% variable, but should NOT alter/remove any existing entries. +%% Description: Initialization before each test case +%%-------------------------------------------------------------------- +init_per_testcase(_TestCase, Config) -> + ssh:start(), + Config. + +%%-------------------------------------------------------------------- +%% Function: end_per_testcase(TestCase, Config) -> _ +%% Case - atom() +%% Name of the test case that is about to be run. +%% Config - [tuple()] +%% A list of key/value pairs, holding the test case configuration. +%% Description: Cleanup after each test case +%%-------------------------------------------------------------------- +end_per_testcase(_TestCase, _Config) -> + ssh:stop(), + ok. + +%%-------------------------------------------------------------------- +%% Function: all(Clause) -> TestCases +%% Clause - atom() - suite | doc +%% TestCases - [Case] +%% Case - atom() +%% Name of a test case. +%% Description: Returns a list of all test cases in this test suite +%%-------------------------------------------------------------------- +all() -> + case os:find_executable("ssh") of + false -> + {skip, "openSSH not installed on host"}; + _ -> + [erlang_shell_client_openssh_server, + erlang_client_openssh_server_exec, + erlang_client_openssh_server_exec_compressed, + erlang_server_openssh_client_exec, + erlang_server_openssh_client_exec_compressed, + erlang_client_openssh_server_setenv, + erlang_client_openssh_server_publickey_rsa, + erlang_client_openssh_server_publickey_dsa, + erlang_server_openssh_client_pulic_key_dsa, + erlang_client_openssh_server_password] + end. + +groups() -> + []. + +init_per_group(_GroupName, Config) -> + Config. + +end_per_group(_GroupName, Config) -> + Config. + +%% TEST cases starts here. +%%-------------------------------------------------------------------- +erlang_shell_client_openssh_server(doc) -> + ["Test that ssh:shell/2 works"]; + +erlang_shell_client_openssh_server(suite) -> + []; + +erlang_shell_client_openssh_server(Config) when is_list(Config) -> + process_flag(trap_exit, true), + IO = ssh_test_lib:start_io_server(), + Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO), + IO ! {input, self(), "echo Hej\n"}, + receive_hej(), + IO ! {input, self(), "exit\n"}, + receive + <<"logout">> -> + receive + <<"Connection closed">> -> + ok + end; + Other0 -> + test_server:fail({unexpected_msg, Other0}) + end, + receive + {'EXIT', Shell, normal} -> + ok; + Other1 -> + test_server:fail({unexpected_msg, Other1}) + end. + +%-------------------------------------------------------------------- +erlang_client_openssh_server_exec(doc) -> + ["Test api function ssh_connection:exec"]; + +erlang_client_openssh_server_exec(suite) -> + []; + +erlang_client_openssh_server_exec(Config) when is_list(Config) -> + ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true}, + {user_interaction, false}]), + {ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId0, + "echo testing", infinity), + Data0 = {ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"testing\n">>}}, + case ssh_test_lib:receive_exec_result(Data0) of + expected -> + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId0); + {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId0, 0}} + = ExitStatus0} -> + test_server:format("0: Collected data ~p", [ExitStatus0]), + ssh_test_lib:receive_exec_result(Data0, + ConnectionRef, ChannelId0); + Other0 -> + test_server:fail(Other0) + end, + + {ok, ChannelId1} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId1, + "echo testing1", infinity), + Data1 = {ssh_cm, ConnectionRef, {data, ChannelId1, 0, <<"testing1\n">>}}, + case ssh_test_lib:receive_exec_result(Data1) of + expected -> + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1); + {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId1, 0}} + = ExitStatus1} -> + test_server:format("0: Collected data ~p", [ExitStatus1]), + ssh_test_lib:receive_exec_result(Data1, + ConnectionRef, ChannelId1); + Other1 -> + test_server:fail(Other1) + end. + +%%-------------------------------------------------------------------- +erlang_client_openssh_server_exec_compressed(doc) -> + ["Test that compression option works"]; + +erlang_client_openssh_server_exec_compressed(suite) -> + []; + +erlang_client_openssh_server_exec_compressed(Config) when is_list(Config) -> + ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true}, + {user_interaction, false}, + {compression, zlib}]), + {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity), + success = ssh_connection:exec(ConnectionRef, ChannelId, + "echo testing", infinity), + Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, <<"testing\n">>}}, + case ssh_test_lib:receive_exec_result(Data) of + expected -> + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId); + {unexpected_msg,{ssh_cm, ConnectionRef, + {exit_status, ChannelId, 0}} = ExitStatus} -> + test_server:format("0: Collected data ~p", [ExitStatus]), + ssh_test_lib:receive_exec_result(Data, ConnectionRef, ChannelId); + Other -> + test_server:fail(Other) + end. + +%%-------------------------------------------------------------------- +erlang_server_openssh_client_exec(doc) -> + ["Test that exec command works."]; + +erlang_server_openssh_client_exec(suite) -> + []; + +erlang_server_openssh_client_exec(Config) when is_list(Config) -> + SystemDir = ?config(data_dir, Config), + + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {failfun, fun ssh_test_lib:failfun/2}]), + + + test_server:sleep(500), + + Cmd = "ssh -p " ++ integer_to_list(Port) ++ + " -o StrictHostKeyChecking=no "++ Host ++ " 1+1.", + SshPort = open_port({spawn, Cmd}, [binary]), + + receive + {SshPort,{data, <<"2\n">>}} -> + ok + after ?TIMEOUT -> + test_server:fail("Did not receive answer") + + end, + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +erlang_server_openssh_client_exec_compressed(doc) -> + ["Test that exec command works."]; + +erlang_server_openssh_client_exec_compressed(suite) -> + []; + +erlang_server_openssh_client_exec_compressed(Config) when is_list(Config) -> + SystemDir = ?config(data_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {compression, zlib}, + {failfun, fun ssh_test_lib:failfun/2}]), + + test_server:sleep(500), + + Cmd = "ssh -p " ++ integer_to_list(Port) ++ + " -o StrictHostKeyChecking=no -C "++ Host ++ " 1+1.", + SshPort = open_port({spawn, Cmd}, [binary]), + + receive + {SshPort,{data, <<"2\n">>}} -> + ok + after ?TIMEOUT -> + test_server:fail("Did not receive answer") + + end, + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +erlang_client_openssh_server_setenv(doc) -> + ["Test api function ssh_connection:setenv"]; + +erlang_client_openssh_server_setenv(suite) -> + []; + +erlang_client_openssh_server_setenv(Config) when is_list(Config) -> + ConnectionRef = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true}, + {user_interaction, false}]), + {ok, ChannelId} = + ssh_connection:session_channel(ConnectionRef, infinity), + Env = case ssh_connection:setenv(ConnectionRef, ChannelId, + "ENV_TEST", "testing_setenv", + infinity) of + success -> + <<"tesing_setenv\n">>; + failure -> + <<"\n">> + end, + success = ssh_connection:exec(ConnectionRef, ChannelId, + "echo $ENV_TEST", infinity), + Data = {ssh_cm, ConnectionRef, {data, ChannelId, 0, Env}}, + case ssh_test_lib:receive_exec_result(Data) of + expected -> + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId); + {unexpected_msg,{ssh_cm, ConnectionRef, + {data,0,1, UnxpectedData}}} -> + %% Some os may return things as + %% ENV_TEST: Undefined variable.\n" + test_server:format("UnxpectedData: ~p", [UnxpectedData]), + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId); + {unexpected_msg,{ssh_cm, ConnectionRef, {exit_status, ChannelId, 0}} + = ExitStatus} -> + test_server:format("0: Collected data ~p", [ExitStatus]), + ssh_test_lib:receive_exec_result(Data, + ConnectionRef, ChannelId); + Other -> + test_server:fail(Other) + end. + +%%-------------------------------------------------------------------- + +%% setenv not meaningfull on erlang ssh daemon! + +%%-------------------------------------------------------------------- +erlang_client_openssh_server_publickey_rsa(doc) -> + ["Validate using rsa publickey."]; +erlang_client_openssh_server_publickey_rsa(suite) -> + []; +erlang_client_openssh_server_publickey_rsa(Config) when is_list(Config) -> + {ok,[[Home]]} = init:get_argument(home), + SrcDir = filename:join(Home, ".ssh"), + UserDir = ?config(priv_dir, Config), + case ssh_test_lib:copyfile(SrcDir, UserDir, "id_rsa") of + {ok, _} -> + ConnectionRef = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, + [{user_dir, UserDir}, + {public_key_alg, ssh_rsa}, + {user_interaction, false}, + silently_accept_hosts]), + {ok, Channel} = + ssh_connection:session_channel(ConnectionRef, infinity), + ok = ssh_connection:close(ConnectionRef, Channel), + ok = ssh:close(ConnectionRef), + ok = file:delete(filename:join(UserDir, "id_rsa")); + {error, enoent} -> + {skip, "no ~/.ssh/id_rsa"} + end. + +%%-------------------------------------------------------------------- +erlang_client_openssh_server_publickey_dsa(doc) -> + ["Validate using dsa publickey."]; +erlang_client_openssh_server_publickey_dsa(suite) -> + []; +erlang_client_openssh_server_publickey_dsa(Config) when is_list(Config) -> + {ok,[[Home]]} = init:get_argument(home), + SrcDir = filename:join(Home, ".ssh"), + UserDir = ?config(priv_dir, Config), + case ssh_test_lib:copyfile(SrcDir, UserDir, "id_dsa") of + {ok, _} -> + ConnectionRef = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, + [{user_dir, UserDir}, + {public_key_alg, ssh_dsa}, + {user_interaction, false}, + silently_accept_hosts]), + {ok, Channel} = + ssh_connection:session_channel(ConnectionRef, infinity), + ok = ssh_connection:close(ConnectionRef, Channel), + ok = ssh:close(ConnectionRef), + ok = file:delete(filename:join(UserDir, "id_dsa")); + {error, enoent} -> + {skip, "no ~/.ssh/id_dsa"} + end. + +%%-------------------------------------------------------------------- +erlang_server_openssh_client_pulic_key_dsa(doc) -> + ["Validate using dsa publickey."]; + +erlang_server_openssh_client_pulic_key_dsa(suite) -> + []; + +erlang_server_openssh_client_pulic_key_dsa(Config) when is_list(Config) -> + SystemDir = ?config(data_dir, Config), + {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir}, + {public_key_alg, ssh_dsa}, + {failfun, fun ssh_test_lib:failfun/2}]), + + test_server:sleep(500), + + Cmd = "ssh -p " ++ integer_to_list(Port) ++ + " -o StrictHostKeyChecking=no "++ Host ++ " 1+1.", + SshPort = open_port({spawn, Cmd}, [binary]), + + receive + {SshPort,{data, <<"2\n">>}} -> + ok + after ?TIMEOUT -> + test_server:fail("Did not receive answer") + + end, + ssh:stop_daemon(Pid). + +%%-------------------------------------------------------------------- +erlang_client_openssh_server_password(doc) -> + ["Test client password option"]; + +erlang_client_openssh_server_password(suite) -> + []; + +erlang_client_openssh_server_password(Config) when is_list(Config) -> + %% to make sure we don't public-key-auth + UserDir = ?config(data_dir, Config), + {error, Reason0} = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true}, + {user, "foo"}, + {password, "morot"}, + {user_interaction, false}, + {user_dir, UserDir}]), + + test_server:format("Test of user foo that does not exist. " + "Error msg: ~p~n", [Reason0]), + + User = string:strip(os:cmd("whoami"), right, $\n), + + case length(string:tokens(User, " ")) of + 1 -> + {error, Reason1} = + ssh_test_lib:connect(?SSH_DEFAULT_PORT, + [{silently_accept_hosts, true}, + {user, User}, + {password, "foo"}, + {user_interaction, false}, + {user_dir, UserDir}]), + test_server:format("Test of wrong Pasword. " + "Error msg: ~p~n", [Reason1]); + _ -> + test_server:format("Whoami failed reason: ~n", []) + end. + +%%-------------------------------------------------------------------- +% +%% Not possible to send password with openssh without user interaction +%% +%%-------------------------------------------------------------------- +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +receive_hej() -> + receive + <<"Hej\n">> = Hej-> + test_server:format("Expected result: ~p~n", [Hej]); + Info -> + test_server:format("Extra info: ~p~n", [Info]), + receive_hej() + end. diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index d0861b3ddc..d79038df29 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 2.0.6 +SSH_VSN = 2.0.7 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/c_src/Makefile.in b/lib/ssl/c_src/Makefile.in index 49a209f2eb..6e413e7e8e 100644 --- a/lib/ssl/c_src/Makefile.in +++ b/lib/ssl/c_src/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1999-2010. All Rights Reserved. +# Copyright Ericsson AB 1999-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -28,6 +28,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk # ---------------------------------------------------- SSL_LIBDIR = @SSL_LIBDIR@ SSL_INCLUDE = @SSL_INCLUDE@ +SSL_CRYPTO_LIBNAME = @SSL_CRYPTO_LIBNAME@ +SSL_SSL_LIBNAME = @SSL_SSL_LIBNAME@ # ---------------------------------------------------- # Application version @@ -134,7 +136,7 @@ ifeq ($(findstring @,$(SSL_CC_RUNTIME_LIBRARY_PATH)),@) SSL_CC_RUNTIME_LIBRARY_PATH = $(CC_R_OPT) endif -SSL_LINK_LIB=-L$(SSL_LIBDIR) -lssl -lcrypto +SSL_LINK_LIB=-L$(SSL_LIBDIR) -l$(SSL_SSL_LIBNAME) -l$(SSL_CRYPTO_LIBNAME) else # not dynamic crypto lib (default from R11B-5) NEED_KERBEROS=@SSL_LINK_WITH_KERBEROS@ @@ -142,7 +144,7 @@ NEED_ZLIB=@SSL_LINK_WITH_ZLIB@ SSL_MAKEFILE = CC_R_OPT = SSL_CC_RUNTIME_LIBRARY_PATH= -SSL_LINK_LIB = $(SSL_LIBDIR)/libssl.a $(SSL_LIBDIR)/libcrypto.a +SSL_LINK_LIB = $(SSL_LIBDIR)/lib$(SSL_SSL_LIBNAME).a $(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a ifeq ($(NEED_KERBEROS),yes) SSL_LINK_LIB += @STATIC_KERBEROS_LIBS@ endif @@ -175,7 +177,7 @@ $(BINDIR)/ssl_esock: $(OBJS) # Win32/Cygwin $(BINDIR)/ssl_esock.exe: $(OBJS) - $(LD) $(SSL_CC_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -o $@ $^ -lwsock32 -llibeay32 -lssleay32 + $(LD) $(SSL_CC_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -o $@ $^ -lwsock32 -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME) # Unix only, and only when linking statically $(SSL_MAKEFILE): diff --git a/lib/ssl/examples/src/Makefile b/lib/ssl/examples/src/Makefile index ae5881d49b..c5f31b689c 100644 --- a/lib/ssl/examples/src/Makefile +++ b/lib/ssl/examples/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2003-2009. All Rights Reserved. +# Copyright Ericsson AB 2003-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/stdlib/doc/src/erl_eval.xml b/lib/stdlib/doc/src/erl_eval.xml index c95494bf25..d0622594d9 100644 --- a/lib/stdlib/doc/src/erl_eval.xml +++ b/lib/stdlib/doc/src/erl_eval.xml @@ -46,7 +46,7 @@ </datatype> <datatype> <name name="binding_struct"/> - <desc>A binding structure.</desc> + <desc><p>A binding structure.</p></desc> </datatype> <datatype> <name name="expression"/> diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml index 8c9e08ac3a..18867cfb68 100644 --- a/lib/stdlib/doc/src/re.xml +++ b/lib/stdlib/doc/src/re.xml @@ -94,7 +94,7 @@ <type> <v>Regexp = iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> <v>Options = [ Option ]</v> - <v>Option = unicode | anchored | caseless | dollar_endonly | dotall | extended | firstline | multiline | no_auto_capture | dupnames | ungreedy | {newline, NLSpec}| bsr_anycrlf | bsr_unicode</v> + <v>Option = <seealso marker="#type-compile_option">compile_option()</seealso></v> <v>NLSpec = <seealso marker="#type-nl_spec">nl_spec()</seealso></v> <v>MP = <seealso marker="#type-mp">mp()</seealso></v> <v>ErrSpec = {ErrString, Position}</v> @@ -170,7 +170,7 @@ This option makes it possible to include comments inside complicated patterns. N <fsummary>Match a subject against regular expression and capture subpatterns</fsummary> <type> <v>Subject = iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> - <v>RE = <seealso marker="#type-mp">mp()</seealso> | iodata() | <seealso marker="unicode#type-charlist">io:charlist()</seealso></v> + <v>RE = <seealso marker="#type-mp">mp()</seealso> | iodata()</v> <v>Captured = [ CaptureData ]</v> <v>CaptureData = {integer(),integer()}</v> </type> diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl index 46288cf467..515ea2ebb7 100644 --- a/lib/stdlib/src/erl_eval.erl +++ b/lib/stdlib/src/erl_eval.erl @@ -43,7 +43,7 @@ -type(name() :: term()). -type(value() :: term()). -type(bindings() :: [{name(), value()}]). --opaque(binding_struct() :: orddict:orddict()). +-type(binding_struct() :: orddict:orddict()). -type(lfun_value_handler() :: fun((Name :: atom(), Arguments :: [term()]) -> diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl index 02dbe60741..e08258a535 100644 --- a/lib/stdlib/src/re.erl +++ b/lib/stdlib/src/re.erl @@ -46,7 +46,7 @@ split(Subject,RE) -> -spec split(Subject, RE, Options) -> SplitList when Subject :: iodata() | unicode:charlist(), - RE :: mp() | iodata(), + RE :: mp() | iodata() | unicode:charlist(), Options :: [ Option ], Option :: anchored | global | notbol | noteol | notempty | {offset, non_neg_integer()} | {newline, nl_spec()} @@ -238,7 +238,7 @@ replace(Subject,RE,Replacement) -> -spec replace(Subject, RE, Replacement, Options) -> iodata() | unicode:charlist() when Subject :: iodata() | unicode:charlist(), - RE :: mp() | iodata(), + RE :: mp() | iodata() | unicode:charlist(), Replacement :: iodata() | unicode:charlist(), Options :: [Option], Option :: anchored | global | notbol | noteol | notempty diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl index d79ee676d9..de0179da59 100644 --- a/lib/stdlib/src/slave.erl +++ b/lib/stdlib/src/slave.erl @@ -72,7 +72,7 @@ start_pseudo(_,_,_) -> ok. %% It's already there %% This relay can be used to relay all messages directed to a process. --spec relay(Pid) -> none() when +-spec relay(Pid) -> no_return() when Pid :: pid(). relay({badrpc,Reason}) -> diff --git a/lib/test_server/src/configure.in b/lib/test_server/src/configure.in index 2bbbc18966..097853bcfc 100644 --- a/lib/test_server/src/configure.in +++ b/lib/test_server/src/configure.in @@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script for Erlang. dnl dnl %CopyrightBegin% dnl -dnl Copyright Ericsson AB 1997-2009. All Rights Reserved. +dnl Copyright Ericsson AB 1997-2011. All Rights Reserved. dnl dnl The contents of this file are subject to the Erlang Public License, dnl Version 1.1, (the "License"); you may not use this file except in @@ -136,7 +136,7 @@ case $system in fi SHLIB_EXTRACT_ALL="" ;; - NetBSD-*|FreeBSD-*|OpenBSD-*) + NetBSD-*|FreeBSD-*|OpenBSD-*|DragonFly*) # Not available on all versions: check for include file. AC_CHECK_HEADER(dlfcn.h, [ SHLIB_CFLAGS="-fpic" diff --git a/lib/test_server/src/ts_install.erl b/lib/test_server/src/ts_install.erl index 8332ccfb40..9703478f20 100644 --- a/lib/test_server/src/ts_install.erl +++ b/lib/test_server/src/ts_install.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2010. All Rights Reserved. +%% Copyright Ericsson AB 1997-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/test_server/src/ts_run.erl b/lib/test_server/src/ts_run.erl index d145290820..885a3c9b96 100644 --- a/lib/test_server/src/ts_run.erl +++ b/lib/test_server/src/ts_run.erl @@ -365,6 +365,14 @@ make_common_test_args(Args0, Options, _Vars) -> [{logdir,"../test_server"}] end, + TimeTrap = case test_server:timetrap_scale_factor() of + 1 -> + []; + Scale -> + [{multiply_timetraps, Scale}, + {scale_timetraps, true}] + end, + ConfigPath = case {os:getenv("TEST_CONFIG_PATH"), lists:keysearch(config, 1, Options)} of {false,{value, {config, Path}}} -> @@ -377,7 +385,7 @@ make_common_test_args(Args0, Options, _Vars) -> ConfigFiles = [{config,[filename:join(ConfigPath,File) || File <- get_config_files()]}], io_lib:format("~100000p",[Args0++Trace++Cover++Logdir++ - ConfigFiles++Options]). + ConfigFiles++Options++TimeTrap]). to_list(X) when is_atom(X) -> atom_to_list(X); diff --git a/lib/tools/src/make.erl b/lib/tools/src/make.erl index e78e2a43a4..5cc8d47faa 100644 --- a/lib/tools/src/make.erl +++ b/lib/tools/src/make.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1996-2009. All Rights Reserved. +%% Copyright Ericsson AB 1996-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/webtool/doc/src/webtool_chapter.xml b/lib/webtool/doc/src/webtool_chapter.xml index 305fbcb8ee..77fcaebb4b 100644 --- a/lib/webtool/doc/src/webtool_chapter.xml +++ b/lib/webtool/doc/src/webtool_chapter.xml @@ -4,7 +4,7 @@ <chapter> <header> <copyright> - <year>2001</year><year>2009</year> + <year>2001</year><year>2011</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> diff --git a/lib/wx/src/Makefile b/lib/wx/src/Makefile index 3cc668375f..46bc06271c 100644 --- a/lib/wx/src/Makefile +++ b/lib/wx/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2010. All Rights Reserved. +# Copyright Ericsson AB 2008-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in @@ -29,8 +29,7 @@ ERL_COMPILE_FLAGS += -I$(ERLINC) +warn_unused_vars ARCHIVE = wx-$(VSN).ez -ErlMods = \ - wx \ +ErlMods = wx \ wx_object \ wxe_master \ wxe_server \ @@ -44,7 +43,7 @@ GEN_FILES = $(wildcard gen/wx*.erl) \ gen/glu.erl \ gen/gl.erl -GEN_MODS = $(GEN_FILES:gen/%.erl= %,\n ) +GEN_MODS = $(GEN_FILES:gen/%.erl=%,) GEN_HRL = \ $(EGEN)/wxe_debug.hrl \ diff --git a/lib/wx/src/wx.appup.src b/lib/wx/src/wx.appup.src index c02edd2afb..1102af612e 100644 --- a/lib/wx/src/wx.appup.src +++ b/lib/wx/src/wx.appup.src @@ -2,7 +2,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -18,5 +18,6 @@ %% %CopyrightEnd% {"%VSN%", + [ ], [ ] }. diff --git a/lib/xmerl/src/xmerl_sax_parser.erl b/lib/xmerl/src/xmerl_sax_parser.erl index 571feabee0..45e2a928ac 100644 --- a/lib/xmerl/src/xmerl_sax_parser.erl +++ b/lib/xmerl/src/xmerl_sax_parser.erl @@ -1,7 +1,7 @@ %%-------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2009. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl index 22eb641a02..059c8f21b6 100644 --- a/lib/xmerl/src/xmerl_scan.erl +++ b/lib/xmerl/src/xmerl_scan.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/src/xmerl_xpath.erl b/lib/xmerl/src/xmerl_xpath.erl index c803af3631..db3d3ac2d6 100644 --- a/lib/xmerl/src/xmerl_xpath.erl +++ b/lib/xmerl/src/xmerl_xpath.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2010. All Rights Reserved. +%% Copyright Ericsson AB 2003-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl index 1f0793bc58..e56f1470c0 100644 --- a/lib/xmerl/src/xmerl_xsd.erl +++ b/lib/xmerl/src/xmerl_xsd.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/src/xmerl_xsd_type.erl b/lib/xmerl/src/xmerl_xsd_type.erl index 9352f4185d..0f46b1f9aa 100644 --- a/lib/xmerl/src/xmerl_xsd_type.erl +++ b/lib/xmerl/src/xmerl_xsd_type.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/test/Makefile b/lib/xmerl/test/Makefile index 0f8cd88c13..9715aa054a 100644 --- a/lib/xmerl/test/Makefile +++ b/lib/xmerl/test/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2004-2010. All Rights Reserved. +# Copyright Ericsson AB 2004-2011. All Rights Reserved. # # The contents of this file are subject to the Erlang Public License, # Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl index 9b65232fe7..392b2522e8 100644 --- a/lib/xmerl/test/xmerl_SUITE.erl +++ b/lib/xmerl/test/xmerl_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2010. All Rights Reserved. +%% Copyright Ericsson AB 2008-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/test/xmerl_appup_test.erl b/lib/xmerl/test/xmerl_appup_test.erl index 88d4a9bc28..80c8d8e4fd 100644 --- a/lib/xmerl/test/xmerl_appup_test.erl +++ b/lib/xmerl/test/xmerl_appup_test.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2004-2010. All Rights Reserved. +%% Copyright Ericsson AB 2004-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/test/xmerl_sax_std_SUITE.erl b/lib/xmerl/test/xmerl_sax_std_SUITE.erl index 2048cc384f..2b7b59dacf 100644 --- a/lib/xmerl/test/xmerl_sax_std_SUITE.erl +++ b/lib/xmerl/test/xmerl_sax_std_SUITE.erl @@ -2,7 +2,7 @@ %%---------------------------------------------------------------------- %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010. All Rights Reserved. +%% Copyright Ericsson AB 2010-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/test/xmerl_test_lib.erl b/lib/xmerl/test/xmerl_test_lib.erl index 16f438ca84..a83956c076 100644 --- a/lib/xmerl/test/xmerl_test_lib.erl +++ b/lib/xmerl/test/xmerl_test_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/test/xmerl_xsd_SUITE.erl b/lib/xmerl/test/xmerl_xsd_SUITE.erl index 74de42aee5..a0d3b1e667 100644 --- a/lib/xmerl/test/xmerl_xsd_SUITE.erl +++ b/lib/xmerl/test/xmerl_xsd_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in diff --git a/lib/xmerl/test/xmerl_xsd_lib.erl b/lib/xmerl/test/xmerl_xsd_lib.erl index 0b6b1ebc84..e5c2d900ba 100644 --- a/lib/xmerl/test/xmerl_xsd_lib.erl +++ b/lib/xmerl/test/xmerl_xsd_lib.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2006-2010. All Rights Reserved. +%% Copyright Ericsson AB 2006-2011. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in |