aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.in10
-rw-r--r--erts/configure.in60
-rw-r--r--erts/emulator/beam/erl_async.c1
-rw-r--r--erts/emulator/drivers/common/inet_drv.c18
-rw-r--r--erts/emulator/test/driver_SUITE.erl38
-rw-r--r--erts/emulator/test/driver_SUITE_data/Makefile.src3
-rw-r--r--erts/emulator/test/driver_SUITE_data/otp_9302_drv.c137
-rw-r--r--erts/epmd/test/epmd_SUITE.erl139
-rw-r--r--lib/Makefile11
-rw-r--r--lib/crypto/c_src/Makefile.in8
-rw-r--r--lib/crypto/doc/src/licenses.xml2
-rw-r--r--lib/diameter/.gitignore58
-rw-r--r--lib/diameter/AUTHORS10
-rw-r--r--lib/diameter/Makefile.in88
-rw-r--r--lib/diameter/TAR.exclude2
-rw-r--r--lib/diameter/aclocal.m465
-rwxr-xr-xlib/diameter/autoconf/config.guess1519
-rwxr-xr-xlib/diameter/autoconf/config.sub1630
-rwxr-xr-xlib/diameter/autoconf/configure.vxworks147
-rwxr-xr-xlib/diameter/autoconf/install-sh519
-rw-r--r--lib/diameter/autoconf/vxworks/sed.general125
-rw-r--r--lib/diameter/autoconf/vxworks/sed.vxworks_cpu3245
-rw-r--r--lib/diameter/autoconf/vxworks/sed.vxworks_ppc3252
-rw-r--r--lib/diameter/autoconf/vxworks/sed.vxworks_ppc60351
-rw-r--r--lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall51
-rw-r--r--lib/diameter/autoconf/vxworks/sed.vxworks_ppc86050
-rw-r--r--lib/diameter/autoconf/vxworks/sed.vxworks_simlinux59
-rw-r--r--lib/diameter/autoconf/vxworks/sed.vxworks_simso64
-rw-r--r--lib/diameter/autoconf/vxworks/sed.vxworks_sparc38
-rwxr-xr-xlib/diameter/bin/diameterc155
-rw-r--r--lib/diameter/configure.in138
-rw-r--r--lib/diameter/doc/html/.gitignore0
-rw-r--r--lib/diameter/doc/man1/.gitignore0
-rw-r--r--lib/diameter/doc/man3/.gitignore0
-rw-r--r--lib/diameter/doc/man4/.gitignore0
-rw-r--r--lib/diameter/doc/pdf/.gitignore0
-rw-r--r--lib/diameter/doc/src/Makefile199
-rw-r--r--lib/diameter/doc/src/book.xml56
-rw-r--r--lib/diameter/doc/src/diameter.xml1123
-rw-r--r--lib/diameter/doc/src/diameter_app.xml582
-rw-r--r--lib/diameter/doc/src/diameter_compile.xml124
-rw-r--r--lib/diameter/doc/src/diameter_dict.xml601
-rw-r--r--lib/diameter/doc/src/diameter_examples.xml40
-rw-r--r--lib/diameter/doc/src/diameter_intro.xml45
-rw-r--r--lib/diameter/doc/src/diameter_sctp.xml133
-rw-r--r--lib/diameter/doc/src/diameter_soc.xml110
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml110
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml203
-rw-r--r--lib/diameter/doc/src/diameter_using.xml40
-rw-r--r--lib/diameter/doc/src/files.mk52
-rw-r--r--lib/diameter/doc/src/notes.gifbin0 -> 2005 bytes
-rw-r--r--lib/diameter/doc/src/notes.xml47
-rw-r--r--lib/diameter/doc/src/ref_man.xml48
-rw-r--r--lib/diameter/doc/src/user_man.xml44
-rw-r--r--lib/diameter/doc/standard/draft-ietf-dime-capablities-update-07.txt392
-rw-r--r--lib/diameter/doc/standard/draft-ietf-dime-rfc3588bis-26.txt8681
-rw-r--r--lib/diameter/doc/standard/rfc3124.txt1235
-rw-r--r--lib/diameter/doc/standard/rfc3539.txt2299
-rw-r--r--lib/diameter/doc/standard/rfc3588.txt8235
-rw-r--r--lib/diameter/doc/standard/rfc4005.txt4763
-rw-r--r--lib/diameter/doc/standard/rfc4006.txt6387
-rw-r--r--lib/diameter/doc/standard/rfc4072.txt1851
-rw-r--r--lib/diameter/doc/standard/rfc4740.txt4035
-rw-r--r--lib/diameter/doc/standard/rfc5447.txt955
-rw-r--r--lib/diameter/ebin/.gitignore5
-rw-r--r--lib/diameter/examples/.gitignore3
-rw-r--r--lib/diameter/examples/GNUmakefile35
-rw-r--r--lib/diameter/examples/client.erl125
-rw-r--r--lib/diameter/examples/client_cb.erl103
-rw-r--r--lib/diameter/examples/peer.erl139
-rw-r--r--lib/diameter/examples/redirect.erl70
-rw-r--r--lib/diameter/examples/redirect_cb.erl63
-rw-r--r--lib/diameter/examples/relay.erl92
-rw-r--r--lib/diameter/examples/relay_cb.erl69
-rw-r--r--lib/diameter/examples/sctp.erl113
-rw-r--r--lib/diameter/examples/server.erl88
-rw-r--r--lib/diameter/examples/server_cb.erl118
-rw-r--r--lib/diameter/include/diameter.hrl130
-rw-r--r--lib/diameter/include/diameter_gen.hrl431
-rw-r--r--lib/diameter/info3
-rw-r--r--lib/diameter/make/release_targets.mk92
-rw-r--r--lib/diameter/make/rules.mk.in195
-rw-r--r--lib/diameter/make/subdir.mk53
-rw-r--r--lib/diameter/make/target.mk33
-rw-r--r--lib/diameter/src/Makefile43
-rw-r--r--lib/diameter/src/app/.gitignore5
-rw-r--r--lib/diameter/src/app/Makefile199
-rw-r--r--lib/diameter/src/app/depend.sed31
-rw-r--r--lib/diameter/src/app/diameter.app.src28
-rw-r--r--lib/diameter/src/app/diameter.appup.src27
-rw-r--r--lib/diameter/src/app/diameter.erl212
-rw-r--r--lib/diameter/src/app/diameter.mk.in47
-rw-r--r--lib/diameter/src/app/diameter_app.erl36
-rw-r--r--lib/diameter/src/app/diameter_callback.erl91
-rw-r--r--lib/diameter/src/app/diameter_capx.erl388
-rw-r--r--lib/diameter/src/app/diameter_codec.erl569
-rw-r--r--lib/diameter/src/app/diameter_config.erl681
-rw-r--r--lib/diameter/src/app/diameter_dbg.erl565
-rw-r--r--lib/diameter/src/app/diameter_dict.erl153
-rw-r--r--lib/diameter/src/app/diameter_exprecs.erl301
-rw-r--r--lib/diameter/src/app/diameter_gen_base_accounting.dia68
-rw-r--r--lib/diameter/src/app/diameter_gen_base_rfc3588.dia413
-rw-r--r--lib/diameter/src/app/diameter_gen_relay.dia24
-rw-r--r--lib/diameter/src/app/diameter_info.erl869
-rw-r--r--lib/diameter/src/app/diameter_internal.hrl95
-rw-r--r--lib/diameter/src/app/diameter_lib.erl266
-rw-r--r--lib/diameter/src/app/diameter_misc_sup.erl58
-rw-r--r--lib/diameter/src/app/diameter_peer.erl230
-rw-r--r--lib/diameter/src/app/diameter_peer_fsm.erl746
-rw-r--r--lib/diameter/src/app/diameter_peer_fsm_sup.erl63
-rw-r--r--lib/diameter/src/app/diameter_reg.erl331
-rw-r--r--lib/diameter/src/app/diameter_service.erl2931
-rw-r--r--lib/diameter/src/app/diameter_service_sup.erl64
-rw-r--r--lib/diameter/src/app/diameter_session.erl172
-rw-r--r--lib/diameter/src/app/diameter_stats.erl347
-rw-r--r--lib/diameter/src/app/diameter_sup.erl101
-rw-r--r--lib/diameter/src/app/diameter_sync.erl555
-rw-r--r--lib/diameter/src/app/diameter_types.erl537
-rw-r--r--lib/diameter/src/app/diameter_types.hrl139
-rw-r--r--lib/diameter/src/app/diameter_watchdog.erl571
-rw-r--r--lib/diameter/src/app/diameter_watchdog_sup.erl60
-rw-r--r--lib/diameter/src/app/modules.mk68
-rw-r--r--lib/diameter/src/compiler/.gitignore3
-rw-r--r--lib/diameter/src/compiler/Makefile141
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl788
-rw-r--r--lib/diameter/src/compiler/diameter_forms.hrl52
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl120
-rw-r--r--lib/diameter/src/compiler/diameter_spec_scan.erl157
-rw-r--r--lib/diameter/src/compiler/diameter_spec_util.erl1052
-rw-r--r--lib/diameter/src/compiler/modules.mk27
-rw-r--r--lib/diameter/src/subdirs.mk21
-rw-r--r--lib/diameter/src/transport/.gitignore3
-rw-r--r--lib/diameter/src/transport/Makefile141
-rw-r--r--lib/diameter/src/transport/diameter_etcp.erl311
-rw-r--r--lib/diameter/src/transport/diameter_etcp_sup.erl64
-rw-r--r--lib/diameter/src/transport/diameter_sctp.erl624
-rw-r--r--lib/diameter/src/transport/diameter_sctp_sup.erl74
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl531
-rw-r--r--lib/diameter/src/transport/diameter_tcp_sup.erl78
-rw-r--r--lib/diameter/src/transport/diameter_transport_sup.erl68
-rw-r--r--lib/diameter/src/transport/modules.mk29
-rw-r--r--lib/diameter/subdirs.mk20
-rw-r--r--lib/diameter/test/Makefile408
-rw-r--r--lib/diameter/test/diameter.cover6
-rw-r--r--lib/diameter/test/diameter.spec9
-rw-r--r--lib/diameter/test/diameter_SUITE.erl108
-rw-r--r--lib/diameter/test/diameter_app_test.erl393
-rw-r--r--lib/diameter/test/diameter_appup_test.erl539
-rw-r--r--lib/diameter/test/diameter_compiler_test.erl104
-rw-r--r--lib/diameter/test/diameter_config_test.erl105
-rw-r--r--lib/diameter/test/diameter_etcp_test.beambin0 -> 1808 bytes
-rw-r--r--lib/diameter/test/diameter_peer_test.erl104
-rw-r--r--lib/diameter/test/diameter_reg_test.erl104
-rw-r--r--lib/diameter/test/diameter_session_test.erl104
-rw-r--r--lib/diameter/test/diameter_stats_test.erl104
-rw-r--r--lib/diameter/test/diameter_sync_test.erl104
-rw-r--r--lib/diameter/test/diameter_tcp_test.erl482
-rw-r--r--lib/diameter/test/diameter_test_lib.erl478
-rw-r--r--lib/diameter/test/diameter_test_lib.hrl106
-rw-r--r--lib/diameter/test/diameter_test_server.erl551
-rw-r--r--lib/diameter/test/modules.mk47
-rw-r--r--lib/diameter/test/slask/diameter_persistent_table_test.erl495
-rw-r--r--lib/diameter/vsn.mk25
-rw-r--r--lib/erl_interface/src/epmd/epmd_port.c7
-rw-r--r--lib/kernel/src/inet_res.erl4
-rw-r--r--lib/kernel/test/file_SUITE.erl77
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl74
-rw-r--r--lib/mnesia/src/mnesia.appup.src36
-rw-r--r--lib/mnesia/src/mnesia_text.erl5
-rw-r--r--lib/mnesia/test/mnesia_SUITE.erl101
-rw-r--r--lib/mnesia/test/mnesia_majority_test.erl24
-rw-r--r--lib/mnesia/test/mt.erl1
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/snmp/doc/src/snmp_agent_netif.xml3
-rw-r--r--lib/ssh/doc/src/notes.xml14
-rw-r--r--lib/ssh/src/ssh.appup.src2
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl14
-rw-r--r--lib/ssh/test/Makefile121
-rw-r--r--lib/ssh/test/ssh.cover2
-rw-r--r--lib/ssh/test/ssh.spec7
-rw-r--r--lib/ssh/test/ssh.spec.vxworks3
-rw-r--r--lib/ssh/test/ssh_SUITE.erl72
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl389
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE.erl543
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/id_rsa15
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/id_rsa.pub1
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/sftp.txt252
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE.erl934
-rw-r--r--lib/ssh/test/ssh_sftpd_SUITE_data/test.txt1
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl328
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/ssh_sftpd_file_alt.erl100
-rw-r--r--lib/ssh/test/ssh_sftpd_erlclient_SUITE_data/test.txt1
-rw-r--r--lib/ssh/test/ssh_test_lib.erl684
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl458
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/c_src/Makefile.in8
-rw-r--r--lib/stdlib/doc/src/erl_eval.xml2
-rw-r--r--lib/test_server/src/configure.in2
-rw-r--r--lib/test_server/src/ts_run.erl10
-rwxr-xr-xotp_build15
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
+ 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*)
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ 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 &plusmn; 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>&nbsp;&nbsp;&nbsp; | fun((reference(), list()) -> boolean())</v>
+<v>&nbsp;&nbsp;&nbsp; | 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 ::= &lt; Diameter Header: 287, REQ, PXY >
+ &lt; 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 ::= &lt; Diameter Header: 287, PXY >
+ &lt; 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 ::= &lt; 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 ::= &lt; 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
new file mode 100644
index 0000000000..e000cca26a
--- /dev/null
+++ b/lib/diameter/doc/src/notes.gif
Binary files differ
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
+
+
+ Glen Zorn
+ Network Zen
+ 227/358 Thanon Sanphawut
+ Bang Na, Bangkok 10260
+ Thailand
+
+ Phone: +66 (0) 87-040-4617
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
+
+
+ Jari Arkko
+ Ericsson Research
+ 02420 Jorvas
+ Finland
+
+ Phone: +358 40 5079256
+
+
+ John Loughney
+ Nokia Research Center
+ 955 Page Mill Road
+ Palo Alto, CA 94304
+ US
+
+ Phone: +1-650-283-8068
+
+
+ Glenn Zorn
+ Network Zen
+ 1310 East Thomas Street
+ Seattle, WA 98102
+ US
+
+ Phone:
+
+
+
+
+
+
+
+
+
+
+
+
+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
+
+ Web: http://nms.lcs.mit.edu/~hari/
+
+
+ Srinivasan Seshan
+ School of Computer Science
+ Carnegie Mellon University
+ 5000 Forbes Ave.
+ Pittsburgh, PA 15213
+
+ 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
+
+
+ Jonathan Wood
+ Sun Microsystems, Inc.
+ 901 San Antonio Road
+ Palo Alto, CA 94303
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
+
+ John Loughney
+ Nokia Research Center
+ Itamerenkatu 11-13
+ 00180 Helsinki
+ Finland
+
+ Phone: +358 50 483 6242
+
+ Jari Arkko
+ Ericsson
+ 02420 Jorvas
+ Finland
+
+ Phone: +358 40 5079256
+
+ Erik Guttman
+ Sun Microsystems, Inc.
+ Eichhoelzelstr. 7
+ 74915 Waibstadt
+ Germany
+
+ Phone: +49 7263 911 701
+
+ 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
+
+
+ Glen Zorn
+ Cisco Systems, Inc.
+ 500 108th Avenue N.E., Suite 500
+ Bellevue, WA 98004
+ USA
+
+ Phone: 1 425-471-4861
+
+
+ David Spence
+ 3259 Bluett Rd.
+ Ann Arbor, MI 48105
+ USA
+
+ Phone: +1 734 834 6481
+
+
+ David Mitton
+ Circular Networks
+ 733 Turnpike St #154
+ North Andover, MA 01845
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
+
+
+ Leena Mattila
+ Oy L M Ericsson Ab
+ Joukahaisenkatu 1
+ 20520 Turku
+ Finland
+
+ Phone: +358 2 265 3731
+
+
+ Juha-Pekka Koskinen
+ Nokia Networks
+ Hatanpaanvaltatie 30
+ 33100 Tampere
+ Finland
+
+ Phone: +358 7180 74027
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
+
+
+ John Loughney
+ Nokia Research Center
+ Itamerenkatu 11-13
+ 00180 Helsinki
+ Finland
+
+ Phone: +358 50 483 642
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
+
+
+
+ Tom Hiller
+ Lucent Technologies
+ 1960 Lucent Lane
+ Naperville, IL 60566
+ USA
+
+ Phone: +1 630 979 7673
+
+
+ Glen Zorn
+ Cisco Systems
+ 500 108th Avenue N.E., Suite 500
+ Bellevue, WA 98004
+ USA
+
+ Phone: +1 425 344 8113
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
+
+
+ Maria-Carmen Belinchon
+ Ericsson
+ Via de los Poblados 13
+ Madrid 28033
+ Spain
+
+ Phone: +34 91 339 3535
+
+
+ Miguel A. Pallares-Lopez
+ Ericsson
+ Via de los Poblados 13
+ Madrid 28033
+ Spain
+
+ Phone: +34 91 339 4222
+
+
+ Carolina Canales-Valenzuela
+ Ericsson
+ Via de los Poblados 13
+ Madrid 28033
+ Spain
+
+ Phone: +34 91 339 2680
+
+
+
+
+
+
+
+
+
+
+
+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
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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
+
+
+
+ Julien Bournelle
+ Orange Labs
+ 38-4O rue du general Leclerc
+ Issy-Les-Moulineaux 92794
+ France
+
+
+
+ Hannes Tschofenig
+ Nokia Siemens Networks
+ Linnoitustie 6
+ Espoo 02600
+ Finland
+
+ URI: http://www.tschofenig.priv.at
+
+
+ Charles E. Perkins
+ WiChorus Inc.
+ 3590 North First St., Suite 300
+ San Jose, CA 95134
+ US
+
+
+
+ Kuntal Chowdhury
+ Starent Networks
+ 30 International Place
+ Tewksbury, MA 01876
+ US
+
+
+
+
+
+
+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
new file mode 100644
index 0000000000..efaaec69d5
--- /dev/null
+++ b/lib/diameter/test/diameter_etcp_test.beam
Binary files differ
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);
diff --git a/otp_build b/otp_build
index 1172592415..aebb91372c 100755
--- a/otp_build
+++ b/otp_build
@@ -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