diff options
200 files changed, 74393 insertions, 328 deletions
diff --git a/Makefile.in b/Makefile.in index b17713f182..5acd390333 100644 --- a/Makefile.in +++ b/Makefile.in @@ -502,6 +502,7 @@ ifeq ($(TARGET),win32) bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target @rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/erl.exe \ $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc.exe \ + $(BOOTSTRAP_ROOT)/bootstrap/bin/escript.exe \ $(BOOTSTRAP_ROOT)/bootstrap/bin/erl.ini \ $(BOOTSTRAP_ROOT)/bootstrap/bin/beam.dll make_bootstrap_ini.sh $(BOOTSTRAP_ROOT)/bootstrap \ @@ -510,8 +511,10 @@ bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc.exe @cp $(ERL_TOP)/bin/$(TARGET)/erl.exe \ $(BOOTSTRAP_ROOT)/bootstrap/bin/erl.exe + @cp $(ERL_TOP)/bin/$(TARGET)/escript.exe \ + $(BOOTSTRAP_ROOT)/bootstrap/bin/escript.exe else -bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target $(BOOTSTRAP_ROOT)/bootstrap/bin/erl $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc +bootstrap_setup: check_recreate_primary_bootstrap bootstrap_setup_target $(BOOTSTRAP_ROOT)/bootstrap/bin/erl $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc $(BOOTSTRAP_ROOT)/bootstrap/bin/escript $(BOOTSTRAP_ROOT)/bootstrap/bin/erl: $(ERL_TOP)/erts/etc/unix/erl.src.src $(BOOTSTRAP_ROOT)/bootstrap/target @rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/erl @@ -526,6 +529,11 @@ $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc: $(ERL_TOP)/bin/$(TARGET)/erlc $(BOOTSTRAP_ @rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc @cp $(ERL_TOP)/bin/$(TARGET)/erlc $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc @chmod 755 $(BOOTSTRAP_ROOT)/bootstrap/bin/erlc + +$(BOOTSTRAP_ROOT)/bootstrap/bin/escript: $(ERL_TOP)/bin/$(TARGET)/escript $(BOOTSTRAP_ROOT)/bootstrap/target + @rm -f $(BOOTSTRAP_ROOT)/bootstrap/bin/escript + @cp $(ERL_TOP)/bin/$(TARGET)/escript $(BOOTSTRAP_ROOT)/bootstrap/bin/escript + @chmod 755 $(BOOTSTRAP_ROOT)/bootstrap/bin/escript endif bootstrap_setup_target: diff --git a/erts/configure.in b/erts/configure.in index e4c6a7852f..fac07f8b6a 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -3524,6 +3524,8 @@ dnl use "PATH/include" and "PATH/lib". AC_SUBST(SSL_INCLUDE) AC_SUBST(SSL_ROOT) AC_SUBST(SSL_LIBDIR) +AC_SUBST(SSL_CRYPTO_LIBNAME) +AC_SUBST(SSL_SSL_LIBNAME) AC_SUBST(SSL_CC_RUNTIME_LIBRARY_PATH) AC_SUBST(SSL_LD_RUNTIME_LIBRARY_PATH) AC_SUBST(SSL_DED_LD_RUNTIME_LIBRARY_PATH) @@ -3687,19 +3689,41 @@ case "$erl_xcomp_without_sysroot-$with_ssl" in CRYPTO_APP=crypto SSH_APP=ssh - AC_MSG_CHECKING(for OpenSSL >= 0.9.7 in standard locations) + SSL_CRYPTO_LIBNAME=crypto + SSL_SSL_LIBNAME=ssl + + AC_MSG_CHECKING(for OpenSSL >= 0.9.7 in standard locations) for rdir in $extra_dir /cygdrive/c/OpenSSL $std_ssl_locations; do dir="$erl_xcomp_sysroot$rdir" if test -f "$erl_xcomp_isysroot$rdir/include/openssl/opensslv.h"; then is_real_ssl=yes SSL_ROOT="$dir" if test "x$MIXED_CYGWIN" = "xyes" ; then - if test -f "$dir/lib/VC/ssleay32.lib" || \ - test -f "$dir/lib/VC/openssl.lib"; then + if test -f "$dir/lib/VC/libeay32.lib"; then + SSL_RUNTIME_LIBDIR="$rdir/lib/VC" + SSL_LIBDIR="$dir/lib/VC" + SSL_CRYPTO_LIBNAME=libeay32 + SSL_SSL_LIBNAME=ssleay32 + elif test -f "$dir/lib/VC/openssl.lib"; then SSL_RUNTIME_LIBDIR="$rdir/lib/VC" SSL_LIBDIR="$dir/lib/VC" - elif test -f "$dir/lib/ssleay32.lib" || \ - test -f "$dir/lib/openssl.lib"; then + elif test -f $dir/lib/VC/libeay32MD.lib; then + SSL_CRYPTO_LIBNAME=libeay32MD + SSL_SSL_LIBNAME=ssleay32MD + if test "x$enable_dynamic_ssl" = "xno" && \ + test -f $dir/lib/VC/static/libeay32MD.lib; then + SSL_RUNTIME_LIBDIR="$rdir/lib/VC/static" + SSL_LIBDIR="$dir/lib/VC/static" + else + SSL_RUNTIME_LIBDIR="$rdir/lib/VC" + SSL_LIBDIR="$dir/lib/VC" + fi + elif test -f "$dir/lib/libeay32.lib"; then + SSL_RUNTIME_LIBDIR="$rdir/lib" + SSL_LIBDIR="$dir/lib" + SSL_CRYPTO_LIBNAME=libeay32 + SSL_CRYPTO_LIBNAME=ssleay32 + elif test -f "$dir/lib/openssl.lib"; then SSL_RUNTIME_LIBDIR="$rdir/lib" SSL_LIBDIR="$dir/lib" else @@ -3859,8 +3883,32 @@ dnl so it is - be adoptable AC_MSG_ERROR(Invalid path to option --with-ssl=PATH) fi SSL_ROOT="$with_ssl" + SSL_CRYPTO_LIBNAME=crypto + SSL_SSL_LIBNAME=ssl if test "x$MIXED_CYGWIN" = "xyes" && test -d "$with_ssl/lib/VC"; then - SSL_LIBDIR="$with_ssl/lib/VC" + if test -f "$with_ssl/lib/VC/libeay32.lib"; then + SSL_LIBDIR="$with_ssl/lib/VC" + SSL_CRYPTO_LIBNAME=libeay32 + SSL_SSL_LIBNAME=ssleay32 + elif test -f "$with_ssl/lib/VC/openssl.lib"; then + SSL_LIBDIR="$with_ssl/lib/VC" + elif test -f $with_ssl/lib/VC/libeay32MD.lib; then + SSL_CRYPTO_LIBNAME=libeay32MD + SSL_SSL_LIBNAME=ssleay32MD + if test "x$enable_dynamic_ssl" = "xno" && \ + test -f $with_ssl/lib/VC/static/libeay32MD.lib; then + SSL_LIBDIR="$with_ssl/lib/VC/static" + else + SSL_LIBDIR="$with_ssl/lib/VC" + fi + elif test -f "$with_ssl/lib/libeay32.lib"; then + SSL_LIBDIR="$with_ssl/lib" + SSL_CRYPTO_LIBNAME=libeay32 + SSL_CRYPTO_LIBNAME=ssleay32 + else + # This probably wont work, but that's what the user said, so... + SSL_LIBDIR="$with_ssl/lib" + fi elif test "x$ac_cv_sizeof_void_p" = "x8"; then if test -f "$with_ssl/lib64/libcrypto.a"; then SSL_LIBDIR="$with_ssl/lib64" diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index 12c7631448..a920bd2c8c 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -251,6 +251,7 @@ static int async_del(long id) erts_free(ERTS_ALC_T_ASYNC, a); return 1; } + a = a->next; } erts_mtx_unlock(&async_q[i].mtx); } diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index aec456151c..40c4a0df08 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1948,7 +1948,7 @@ static int http_response_inetdrv(void *arg, int major, int minor, tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; ErlDrvTermData spec[27]; - ErlDrvTermData caller; + ErlDrvTermData caller = ERL_DRV_NIL; if (desc->inet.active == INET_PASSIVE) { /* {inet_async,S,Ref,{ok,{http_response,Version,Status,Phrase}}} */ @@ -2041,7 +2041,7 @@ http_request_inetdrv(void* arg, const http_atom_t* meth, const char* meth_ptr, tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; ErlDrvTermData spec[43]; - ErlDrvTermData caller; + ErlDrvTermData caller = ERL_DRV_NIL; if (desc->inet.active == INET_PASSIVE) { /* {inet_async, S, Ref, {ok,{http_request,Meth,Uri,Version}}} */ @@ -2092,7 +2092,7 @@ http_header_inetdrv(void* arg, const http_atom_t* name, const char* name_ptr, tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; ErlDrvTermData spec[26]; - ErlDrvTermData caller; + ErlDrvTermData caller = ERL_DRV_NIL; if (desc->inet.active == INET_PASSIVE) { /* {inet_async,S,Ref,{ok,{http_header,Bit,Name,IValue,Value}} */ @@ -2221,7 +2221,7 @@ int ssl_tls_inetdrv(void* arg, unsigned type, unsigned major, unsigned minor, tcp_descriptor* desc = (tcp_descriptor*) arg; int i = 0; ErlDrvTermData spec[28]; - ErlDrvTermData caller; + ErlDrvTermData caller = ERL_DRV_NIL; ErlDrvBinary* bin; int ret; @@ -7980,11 +7980,11 @@ static int tcp_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf, int len, timeout = get_int32(buf); if (desc->inet.state == TCP_STATE_ACCEPTING) { - unsigned long time_left; - int oid; - ErlDrvTermData ocaller; - int oreq; - unsigned otimeout; + unsigned long time_left = 0; + int oid = 0; + ErlDrvTermData ocaller = ERL_DRV_NIL; + int oreq = 0; + unsigned otimeout = 0; ErlDrvTermData caller = driver_caller(desc->inet.port); MultiTimerData *mtd = NULL,*omtd = NULL; ErlDrvMonitor monitor, omonitor; diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index 520e3e8c76..f6cf01ce16 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -74,7 +74,8 @@ missing_callbacks/1, smp_select/1, driver_select_use/1, - thread_mseg_alloc_cache_clean/1]). + thread_mseg_alloc_cache_clean/1, + otp_9302/1]). -export([bin_prefix/2]). @@ -141,7 +142,8 @@ all() -> smaller_minor_vsn_drv, peek_non_existing_queue, otp_6879, caller, many_events, missing_callbacks, smp_select, driver_select_use, - thread_mseg_alloc_cache_clean]. + thread_mseg_alloc_cache_clean, + otp_9302]. groups() -> [{timer, [], @@ -1890,13 +1892,39 @@ thread_mseg_alloc_cache_clean_test(Port, N, CCI, Size) -> ?line ?t:format("CCC = ~p~n", [CCC]), ?line true = CCC > OCCC, ?line thread_mseg_alloc_cache_clean_test(Port, N-1, CCI, Size). - - + +otp_9302(Config) when is_list(Config) -> + ?line Path = ?config(data_dir, Config), + ?line erl_ddll:start(), + ?line ok = load_driver(Path, otp_9302_drv), + ?line Port = open_port({spawn, otp_9302_drv}, []), + ?line true = is_port(Port), + ?line port_command(Port, ""), + ?line {msg, block} = get_port_msg(Port, infinity), + ?line {msg, job} = get_port_msg(Port, infinity), + ?line case erlang:system_info(thread_pool_size) of + 0 -> + {msg, cancel} = get_port_msg(Port, infinity); + _ -> + ok + end, + ?line {msg, job} = get_port_msg(Port, infinity), + ?line {msg, end_of_jobs} = get_port_msg(Port, infinity), + ?line no_msg = get_port_msg(Port, 2000), + ?line port_close(Port), + ?line ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Utilities %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - + +get_port_msg(Port, Timeout) -> + receive + {Port, What} -> + {msg, What} + after Timeout -> + no_msg + end. wait_until(Fun) -> case Fun() of diff --git a/erts/emulator/test/driver_SUITE_data/Makefile.src b/erts/emulator/test/driver_SUITE_data/Makefile.src index 4ac7987d2f..5b3ba1557e 100644 --- a/erts/emulator/test/driver_SUITE_data/Makefile.src +++ b/erts/emulator/test/driver_SUITE_data/Makefile.src @@ -11,7 +11,8 @@ MISC_DRVS = outputv_drv@dll@ \ caller_drv@dll@ \ many_events_drv@dll@ \ missing_callback_drv@dll@ \ - thr_alloc_drv@dll@ + thr_alloc_drv@dll@ \ + otp_9302_drv@dll@ SYS_INFO_DRVS = sys_info_1_0_drv@dll@ \ sys_info_1_1_drv@dll@ \ diff --git a/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c new file mode 100644 index 0000000000..1147549135 --- /dev/null +++ b/erts/emulator/test/driver_SUITE_data/otp_9302_drv.c @@ -0,0 +1,137 @@ +/* + * %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% + */ +#ifdef __WIN32__ +#include <windows.h> +#endif +#include "erl_driver.h" + +static ErlDrvData start(ErlDrvPort port, + char *command); +static void output(ErlDrvData drv_data, + char *buf, int len); +static void ready_async(ErlDrvData drv_data, + ErlDrvThreadData thread_data); + +static ErlDrvEntry otp_9302_drv_entry = { + NULL /* init */, + start, + NULL /* stop */, + output, + NULL /* ready_input */, + NULL /* ready_output */, + "otp_9302_drv", + NULL /* finish */, + NULL /* handle */, + NULL /* control */, + NULL /* timeout */, + NULL /* outputv */, + ready_async, + NULL /* flush */, + NULL /* call */, + NULL /* event */, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + ERL_DRV_FLAG_USE_PORT_LOCKING, + NULL /* handle2 */, + NULL /* handle_monitor */ +}; + +DRIVER_INIT(otp_9302_drv) +{ + return &otp_9302_drv_entry; +} + +static ErlDrvData start(ErlDrvPort port, + char *command) +{ + return (ErlDrvData) port; +} + +typedef struct { + ErlDrvPort port; + ErlDrvTermData receiver; + int block; + int cancel; + int eoj; +} Otp9302AsyncData; + +static void async_invoke(void *data) +{ + Otp9302AsyncData *adata = (Otp9302AsyncData *) data; + char *what = (adata->block + ? "block" + : (adata->cancel + ? "cancel" + : (adata->eoj + ? "end_of_jobs" + : "job"))); + ErlDrvTermData spec[] = { + ERL_DRV_PORT, driver_mk_port(adata->port), + ERL_DRV_ATOM, driver_mk_atom(what), + ERL_DRV_TUPLE, 2 + }; + driver_send_term(adata->port, adata->receiver, + spec, sizeof(spec)/sizeof(spec[0])); + if (adata->block) { +#ifdef __WIN32__ + Sleep((DWORD) 2000); +#else + sleep(2); +#endif + } +} + +static void output(ErlDrvData drv_data, + char *buf, int len) +{ + ErlDrvPort port = (ErlDrvPort) drv_data; + ErlDrvTermData caller = driver_caller(port); + unsigned int key = (unsigned int) port; + long id[5]; + Otp9302AsyncData *ad[5]; + int i; + + for (i = 0; i < sizeof(ad)/sizeof(ad[0]); i++) { + ad[i] = driver_alloc(sizeof(Otp9302AsyncData)); + if (!ad[i]) + abort(); + + ad[i]->port = port; + ad[i]->receiver = caller; + ad[i]->block = 0; + ad[i]->eoj = 0; + ad[i]->cancel = 0; + } + ad[0]->block = 1; + ad[2]->cancel = 1; + ad[4]->eoj = 1; + for (i = 0; i < sizeof(id)/sizeof(id[0]); i++) + id[i] = driver_async(port, &key, async_invoke, ad[i], driver_free); + if (id[2] > 0) + driver_async_cancel(id[2]); +} + +static void ready_async(ErlDrvData drv_data, + ErlDrvThreadData thread_data) +{ + if ((void *) thread_data) + driver_free((void *) thread_data); +} + diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl index 72c890503d..6889ec0b34 100644 --- a/erts/epmd/test/epmd_SUITE.erl +++ b/erts/epmd/test/epmd_SUITE.erl @@ -780,42 +780,43 @@ no_nonlocal_register(suite) -> no_nonlocal_register(doc) -> ["Ensure that we cannot register throug a nonlocal connection"]; no_nonlocal_register(Config) when is_list(Config) -> + ?line case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of + {SSH,Name} when is_list(Name), is_list(SSH) -> + do_no_nonlocal_register(Config,Name); + {false,_} -> + {skip, "No ssh command found to create proxy"}; + _ -> + {skip, "No ssh_proxy_host configured in ts.config"} + end. +do_no_nonlocal_register(Config,SSHHost) when is_list(Config) -> ?line ok = epmdrun(), - ?line {ok,Ifs} = inet:getiflist(), - ?line Addr0 = [ inet:ifget(I, [addr]) || I <- Ifs ], - ?line Addr1 = [ A || {ok,[{addr,A}]} <- Addr0], - ?line Addr = lists:filter(fun({127,_,_,_}) -> - false; - (_) -> - true - end,Addr1), - %% Now we should have all non loopback interface addresses, - %% none should accept a alive2 registration. - ?line Res = lists:map(fun(Ad={A1,A2,A3,A4}) -> - try - Name = "gurka_"++ - integer_to_list(A1)++"_"++ - integer_to_list(A2)++"_"++ - integer_to_list(A3)++"_"++ - integer_to_list(A4), - Bname = list_to_binary(Name), - NameS = byte_size(Bname), - ?line Bin= <<$x:8,4747:16,$M:8,0:8,5:16, - 5:16,NameS:16,Bname/binary, - 0:16>>, - ?line S = size(Bin), - {ok, E} = connect(Ad), - gen_tcp:send(E,[<<S:16>>,Bin]), - closed = recv(E,1), - gen_tcp:close(E), - true - catch - _:_ -> - false - end - end, Addr), - erlang:display(Res), - ?line true = alltrue(Res), + ?line ProxyPort = proxy_port(), + ?line ok = ssh_proxy(SSHHost,ProxyPort), + Res = try + ?line Name = "gurka_" + %++ + %integer_to_list(A1)++"_"++ + %integer_to_list(A2)++"_"++ + %integer_to_list(A3)++"_"++ + %integer_to_list(A4) + , + ?line Bname = list_to_binary(Name), + ?line NameS = byte_size(Bname), + ?line Bin= <<$x:8,4747:16,$M:8,0:8,5:16, + 5:16,NameS:16,Bname/binary, + 0:16>>, + ?line S = size(Bin), + ?line {ok, E} = connect("localhost",ProxyPort,passive), + ?line gen_tcp:send(E,[<<S:16>>,Bin]), + ?line closed = recv(E,1), + ?line gen_tcp:close(E), + true + catch + _:_ -> + false + end, + %erlang:display(Res), + true = Res, ok. no_nonlocal_kill(suite) -> @@ -823,35 +824,34 @@ no_nonlocal_kill(suite) -> no_nonlocal_kill(doc) -> ["Ensure that we cannot kill through nonlocal connection"]; no_nonlocal_kill(Config) when is_list(Config) -> + ?line case {os:find_executable("ssh"),ct:get_config(ssh_proxy_host)} of + {SSH,Name} when is_list(Name), is_list(SSH) -> + do_no_nonlocal_kill(Config,Name); + {false,_} -> + {skip, "No ssh command found to create proxy"}; + _ -> + {skip, "No ssh_proxy_host configured in ts.config"} + end. +do_no_nonlocal_kill(Config,SSHHost) when is_list(Config) -> ?line ok = epmdrun(), - ?line {ok,Ifs} = inet:getiflist(), - ?line Addr0 = [ inet:ifget(I, [addr]) || I <- Ifs ], - ?line Addr1 = [ A || {ok,[{addr,A}]} <- Addr0], - ?line Addr = lists:filter(fun({127,_,_,_}) -> - false; - (_) -> - true - end,Addr1), - %% Now we should have all non loopback interface addresses, - %% none should accept a alive2 registration. - ?line Res = lists:map(fun(Ad) -> - try - {ok, E} = connect(Ad), - M = [?EPMD_KILL_REQ], - send(E, [size16(M), M]), - closed = recv(E,2), - gen_tcp:close(E), - sleep(?MEDIUM_PAUSE), - {ok, E2} = connect(Ad), - gen_tcp:close(E2), - true - catch - _:_ -> - false - end - end, Addr), - erlang:display(Res), - ?line true = alltrue(Res), + ?line ProxyPort = proxy_port(), + ?line ok = ssh_proxy(SSHHost,ProxyPort), + Res = try + {ok, E} = connect("localhost",ProxyPort,passive), + M = [?EPMD_KILL_REQ], + send(E, [size16(M), M]), + closed = recv(E,2), + gen_tcp:close(E), + sleep(?MEDIUM_PAUSE), + {ok, E2} = connect("localhost",ProxyPort,passive), + gen_tcp:close(E2), + true + catch + _:_ -> + false + end, + %erlang:display(Res), + true = Res, ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% no_live_killing(doc) -> @@ -896,6 +896,19 @@ cleanup() -> true end. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Start an ssh channel to simulate remote access + +proxy_port() -> + ?PORT+1. + +ssh_proxy(SSHHost,ProxyPort) -> + ?line Host = lists:nth(2,string:tokens(atom_to_list(node()),"@")), + % Requires proxy to be a unix host with the command 'read' accessible + ?line osrun("ssh -L "++integer_to_list(ProxyPort)++":"++Host++":" + ++integer_to_list(?PORT)++" "++SSHHost++" read"). + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Normal debug start of epmd 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/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in index 040adcfd09..3ace10403e 100644 --- a/lib/crypto/c_src/Makefile.in +++ b/lib/crypto/c_src/Makefile.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/doc/src/licenses.xml b/lib/crypto/doc/src/licenses.xml index bae87a373e..e851655aa5 100644 --- a/lib/crypto/doc/src/licenses.xml +++ b/lib/crypto/doc/src/licenses.xml @@ -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/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..fcefdb7679 --- /dev/null +++ b/lib/diameter/aclocal.m4 @@ -0,0 +1,65 @@ +dnl +dnl %CopyrightBegin% +dnl +dnl Copyright Ericsson AB 1998-2010. 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..70d7bdbaf2 --- /dev/null +++ b/lib/diameter/autoconf/configure.vxworks @@ -0,0 +1,147 @@ +#!/bin/sh +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. 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..f725a6f9ca --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.general @@ -0,0 +1,125 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. 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..163dd78897 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 @@ -0,0 +1,45 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-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% +# +# 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..5db28337c0 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 @@ -0,0 +1,52 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2006-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% +# +# 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..40296b8f07 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 @@ -0,0 +1,51 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2000-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% +# +# 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..2550432d1e --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall @@ -0,0 +1,51 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-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% +# +# 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..cd7c9ff797 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 @@ -0,0 +1,50 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-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% +# +# 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..6eb6f8ea92 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux @@ -0,0 +1,59 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2008-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% +# +# 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..1d7413b484 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_simso @@ -0,0 +1,64 @@ +# +# %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% +# +# 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..ae26f234d2 --- /dev/null +++ b/lib/diameter/autoconf/vxworks/sed.vxworks_sparc @@ -0,0 +1,38 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. 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..cba664bfad --- /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. 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..76b15ced9b --- /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-2010. 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/Makefile b/lib/diameter/doc/src/Makefile new file mode 100644 index 0000000000..f2a91a88b7 --- /dev/null +++ b/lib/diameter/doc/src/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 +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_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) \ + $(XML_REF1_FILES) $(XML_REF3_FILES) $(XML_REF4_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_REF1_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html) \ + $(XML_REF4_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 *~ + +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 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: + +$(HTMLDIR)/diameter_app.html: diameter_app.xml +$(HTMLDIR)/diameter_compile.html: diameter_compile.xml +$(HTMLDIR)/diameter_debug.html: diameter_debug.xml +$(HTMLDIR)/diameter_dict.html: diameter_dict.xml +$(HTMLDIR)/diameter_intro.html: diameter_intro.xml +$(HTMLDIR)/diameter_run.html: diameter_run.xml +$(HTMLDIR)/diameter.html: diameter.xml +$(HTMLDIR)/diameter_tcp.html: diameter_tcp.xml +$(HTMLDIR)/diameter_transport.html: diameter_transport.xml +$(HTMLDIR)/diameter_soc.html: diameter_soc.xml +$(HTMLDIR)/diameter_sctp.html: diameter_sctp.xml + +.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/diameter.xml b/lib/diameter/doc/src/diameter.xml new file mode 100644 index 0000000000..9774183a2a --- /dev/null +++ b/lib/diameter/doc/src/diameter.xml @@ -0,0 +1,1123 @@ +<?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> + +<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_1">service_info/1,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. +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. +Not that the function returns before a transport connection has been +established.</p> + +<p> +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) -> 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>. +The call returns either when an answer message is received from the +peer or an error occurs, unless the <c>detach</c> option has been +specified. +If <c>detach</c> is not specified then the form of an <c>Answer</c> is +as returned from a <seealso +marker="diameter_app#handle_answer">handle_answer/4</seealso> or +<seealso +marker="diameter_app#handle_error">handle_error/4</seealso> +callback.</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 not 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. +The value returned is the number of seconds since 19680120T031408Z +(the first value that can be encoded as a 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_1"/> +</desc> +</func> + +<!-- ===================================================================== --> + +<func> +<name>service_info(SvcName) -> Info</name> +<fsummary>Return information about a started service.</fsummary> +<type> +<v>SvcName = service_name()</v> +<v>Info = [{Item, Value}]</v> +</type> +<desc> +<p> +Return information about a started service. +Equivalent to <c>service_info(SvcName, all)</c>.</p> + +<marker id="service_info_2"/> +</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 specific 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. +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_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. +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_service(SvcName) -> ok | {error, Reason}</name> +<fsummary>Stops 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 from a service.</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></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..c2fecce768 --- /dev/null +++ b/lib/diameter/doc/src/diameter_app.xml @@ -0,0 +1,582 @@ +<?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 +specification 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> + +<note> +<p> +The arities of the callback functions below 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, except for peer_up, peer_down and handle_request, any extra +arguments passed to <seealso +marker="diameter#call">diameter:call/4</seealso>.</p> +</note> + +<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 communicativity 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> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<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 in the 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: 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. +Defined in diameter.hrl. +Fields should not be altered 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(Cands, Reserved, SvcName, State) + -> {ok, Peer} | {Peer, NewState} | false</name> +<fsummary>Select a target peer for an outgoing request.</fsummary> +<type> +<v>Cands = [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>.</p> +<!-- +The local candidates are those whose transport process is executing on +the local Erlang node, the remote list those that are available on +other nodes.</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.</p> + +<p> +Any returned packet() can 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. +A specified <c>message_length</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 +Packet passed to <c>prepare_retransmit/3</c> is as returned by +<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.</p> + +<p> +The decoded answer record is in the <c>msg</c> field of <c>Packet</c>, +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}</c>. +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.</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 | NoReply | Relay | {eval, Action, ContF}</v> +<v>Reply = {reply, message()} + | {protocol_error, ResultCode}</v> +<v>NoReply = discard</v> +<v>Relay = {relay, Opts}</v> +<v>Opts = list()</v> +<v>ContF = diameter:evaluable()</v> +<v>ResultCode = 3000..3999</v> +</type> +<desc> +<p> +Invoked when a request message is received from a peer.</p> + +<p> +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 Diameter request message, the selected module being the one +whose corresponding <seealso +marker="diameter_dict#MESSAGE_RECORDS">dictionary</seealso> declares +itself as defining the application in question, or the RFC 3588 relay +application if the specific application is unsupported but the relay +application has been advertised.</p> + +<p> +The packet() in which the incoming request is communicated has the +following signature.</p> + +<code> +#diameter_packet{header = #diameter_header{}, + avps = [#diameter_avp{}], + msg = record() | undefined, + errors = [integer() | {integer(), #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 non-protocol errors that were +encountered in decoding the request and can be returned in a +<c>reply</c> tuple to have diameter set the Result-Code and Failed-AVP +AVP's appropriately. +The 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. +(TODO: more.)</p> + +<taglist> + +<tag><c>{reply, Answer}</c></tag> +<item> +<p> +Send the specified answer message to the peer.</p> +</item> + +<tag><c>{relay, Opts}</c></tag> +<item> +<p> +Relay a request to another peer.</p> +</item> + +<tag><c>{protocol_error, ResultCode}</c></tag> +<item> +<p> +Send an answer message to the peer containing the specified 3xxx +protocol error.</p> + +<p> +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, ResultCode}</c> +tuple will cause the request process in question to fail.</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 the evaluable() <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 the a <c>handle_request/3</c> callback.</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..5bc3cab9e4 --- /dev/null +++ b/lib/diameter/doc/src/diameter_dict.xml @@ -0,0 +1,601 @@ +<?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.</p> + +<p> +The codec generation also results in an hrl 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. +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.</p> + +<!-- TODO: Need some reserved dictionary for agents that shouldn't --> +<!-- know about specific applications. --> + +<p> +The diameter application defines the base application of RFC 3588 in +the file diameter_gen_base_rfc3588.dia, and +this is the only application that diameter itself has any specific +knowledge of. +Other applications are callback modules configured for an application +as far as diameter is concerned.</p> + +<p> +A generated hrl also contains defines for the values of defined for +AVPs of type Enumerated.</p> + +<p> +See <seealso marker="diameter_compile">diameterc</seealso> for a +utility that transforms dictionary files into codec modules needed +at runtime.</p> + +<marker id="FILE_FORMAT"/> +</description> + +<!-- ===================================================================== --> + +<section> +<title>FILE FORMAT</title> + +<p> +A specification 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 +diameter_gen_base_rfc3588.</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.</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 diameter_app(3) <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 +infinity or '-infinity' 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 parsed by diameter.</p> + +</section> + +<!-- ===================================================================== --> +<!-- ===================================================================== --> + +<section> +<title>SEE ALSO</title> + +<p> +<seealso marker="diameter_util">diameterc(1)</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..344b237866 --- /dev/null +++ b/lib/diameter/doc/src/diameter_examples.xml @@ -0,0 +1,40 @@ +<?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> + +<!-- ===================================================================== --> + +</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..0009b2b77d --- /dev/null +++ b/lib/diameter/doc/src/diameter_intro.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>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 allowing a client to +specify the commands and AVP's to be supported and has support for +implementing all roles defined in the RFC: client, server and agent. +</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..be1bb2c56e --- /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 behaviour.</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..737a0a3941 --- /dev/null +++ b/lib/diameter/doc/src/diameter_using.xml @@ -0,0 +1,40 @@ +<?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> + +<!-- ===================================================================== --> + +</chapter> diff --git a/lib/diameter/doc/src/files.mk b/lib/diameter/doc/src/files.mk new file mode 100644 index 0000000000..23558e394f --- /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. 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..8fdb88749e --- /dev/null +++ b/lib/diameter/doc/src/notes.xml @@ -0,0 +1,47 @@ +<?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> +First OTP release.</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..b8705aedfc --- /dev/null +++ b/lib/diameter/examples/server_cb.erl @@ -0,0 +1,118 @@ +%% +%% %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 non-3xxx errors for which we must contruct a reply. +%% Returning a packet with the non-[] errors field will cause +%% diameter to add the appropriate result code and Failed-AVPs avps. +%% We just have to return the relevant answer record with any required +%% avps. +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, Pkt#diameter_packet{msg = 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..8bd1ad1e51 --- /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 diameter_service.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..479a9aded1 --- /dev/null +++ b/lib/diameter/make/release_targets.mk @@ -0,0 +1,92 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-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% +# + +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..9fd1c3b0d0 --- /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-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% + +.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..49198bbefd --- /dev/null +++ b/lib/diameter/make/subdir.mk @@ -0,0 +1,53 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 1997-2009. 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..1310a0da6b --- /dev/null +++ b/lib/diameter/src/app/.gitignore @@ -0,0 +1,5 @@ + +/diameter_gen_*.erl +/diameter_gen_*.hrl +/depend.mk + diff --git a/lib/diameter/src/app/Makefile b/lib/diameter/src/app/Makefile new file mode 100644 index 0000000000..8985ca4911 --- /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) modules.mk 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..5f2ab82475 --- /dev/null +++ b/lib/diameter/src/app/diameter.erl @@ -0,0 +1,212 @@ +%% +%% %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/1, + 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]). + +%% Backwards compatibility. +-export([add_connector/2, + add_listener/2, + remove_connector/2, + remove_listener/2]). + +-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/[12] +%%% -------------------------------------------------------------------------- + +-spec service_info(service_name(), atom() | [atom()]) + -> any(). + +service_info(SvcName, Option) -> + diameter_service:info(SvcName, Option). + +service_info(SvcName) -> + service_info(SvcName, all). + +%%% -------------------------------------------------------------------------- +%%% 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). + +add_listener(SvcName, Opts) -> + add_transport(SvcName, {listen, Opts}). + +add_connector(SvcName, Opts) -> + add_transport(SvcName, {connect, Opts}). + +%%% -------------------------------------------------------------------------- +%%% remove_transport/2 +%%% -------------------------------------------------------------------------- + +-spec remove_transport(service_name(), transport_pred()) + -> ok | {error, term()}. + +remove_transport(SvcName, Pred) -> + diameter_config:remove_transport(SvcName, Pred). + +remove_listener(SvcName, Pred) -> + remove_transport(SvcName, {listen, Pred}). + +remove_connector(SvcName, Pred) -> + remove_transport(SvcName, {connect, 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..82a8d7a994 --- /dev/null +++ b/lib/diameter/src/app/diameter_service.erl @@ -0,0 +1,2931 @@ +%% +%% %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. There are two +%% cases: a diameter_packet as argument when we're calling call/4 +%% ourselves in order to relay a request or a bare message in case the +%% call came by way of diameter:call/4. + +make_packet(Bin) + when is_binary(Bin) -> + #diameter_packet{header = diameter_codec:decode_header(Bin), + bin = Bin}; + +make_packet(#diameter_packet{msg = [#diameter_header{} | _]} = Pkt) -> + Pkt; + +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. + +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}); + +%% Simplify the handling of error cases by accepting a list consisting +%% of an answer record followed by failed AVPs to be packed into a +%% Failed-AVP field, either directly or into an AVP field. Only if +%% the message is a tuple-list or record however, not a list +%% with a list of #diameter_header{} and #diameter_avp{}. +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..8512eb515a --- /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) modules.mk 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..4125e2331c --- /dev/null +++ b/lib/diameter/src/compiler/diameter_forms.hrl @@ -0,0 +1,52 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 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% +%% + +%% +%% 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..3026224e00 --- /dev/null +++ b/lib/diameter/src/subdirs.mk @@ -0,0 +1,21 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 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% + +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..5dc1772796 --- /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) modules.mk 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..1e292d0ed1 --- /dev/null +++ b/lib/diameter/subdirs.mk @@ -0,0 +1,20 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 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% + +SUB_DIRS = src doc/src diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile new file mode 100644 index 0000000000..daae70b1e2 --- /dev/null +++ b/lib/diameter/test/Makefile @@ -0,0 +1,408 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 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% + +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..0469b833cb --- /dev/null +++ b/lib/diameter/test/diameter_reg_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 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..01b5dc5293 --- /dev/null +++ b/lib/diameter/test/diameter_tcp_test.erl @@ -0,0 +1,482 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 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% +%% + +%% +%%---------------------------------------------------------------------- +%% 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..16b3b9d216 --- /dev/null +++ b/lib/diameter/test/diameter_test_lib.erl @@ -0,0 +1,478 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. 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..8b1352f801 --- /dev/null +++ b/lib/diameter/test/diameter_test_lib.hrl @@ -0,0 +1,106 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 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% +%% + +%% +%%---------------------------------------------------------------------- +%% 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..fa8b4a8eda --- /dev/null +++ b/lib/diameter/test/modules.mk @@ -0,0 +1,47 @@ +#-*-makefile-*- ; force emacs to enter makefile-mode + +# %CopyrightBegin% +# +# Copyright Ericsson AB 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% + +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..25bbe41347 --- /dev/null +++ b/lib/diameter/test/slask/diameter_persistent_table_test.erl @@ -0,0 +1,495 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 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% +%% + +%% +%%---------------------------------------------------------------------- +%% 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..6450f285cc 100644 --- a/lib/erl_interface/src/epmd/epmd_port.c +++ b/lib/erl_interface/src/epmd/epmd_port.c @@ -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/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/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/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_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/snmp/doc/src/snmp_agent_netif.xml b/lib/snmp/doc/src/snmp_agent_netif.xml index d751740a82..14ef3630b5 100644 --- a/lib/snmp/doc/src/snmp_agent_netif.xml +++ b/lib/snmp/doc/src/snmp_agent_netif.xml @@ -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/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..da716f7c40 100644 --- a/lib/ssl/c_src/Makefile.in +++ b/lib/ssl/c_src/Makefile.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/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/test_server/src/configure.in b/lib/test_server/src/configure.in index 2bbbc18966..ff4ba1dfaf 100644 --- a/lib/test_server/src/configure.in +++ b/lib/test_server/src/configure.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_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); @@ -186,15 +186,16 @@ set_config_flags () if target_contains free_source; then CONFIG_FLAGS="$CONFIG_FLAGS --host=$TARGET" fi + # Link SSL static for all binary distributions if not overridden + # Even for win32 starting with R14B03 + XX=`echo $* | grep -v dynamic-ssl-lib` + if [ "$*" = "$XX" ]; then + CONFIG_FLAGS="--disable-dynamic-ssl-lib $CONFIG_FLAGS" + fi if target_contains win32; then - CONFIG_FLAGS="--build=$BUILDSYS build_alias=win32 --host=win32 --target=win32 $CONFIG_FLAGS" - else - # Link SSL static for all binary distributions if not overridden - XX=`echo $* | grep -v dynamic-ssl-lib` - if [ "$*" = "$XX" ]; then - CONFIG_FLAGS="--disable-dynamic-ssl-lib $CONFIG_FLAGS" - fi + CONFIG_FLAGS="--build=$BUILDSYS build_alias=win32 --host=win32 --target=win32 $CONFIG_FLAGS" fi + if [ "x$OVERRIDE_CONFIG_CACHE" = "x" ]; then CONFIG_FLAGS="$CONFIG_FLAGS --cache-file=/dev/null" else |