diff options
author | Harald Welte <laforge@gnumonks.org> | 2019-07-26 13:45:18 +0200 |
---|---|---|
committer | laforge <laforge@gnumonks.org> | 2019-08-18 17:14:20 +0000 |
commit | d27ab24dcb2dbd09c687cabfe1c6a48b40bc7aca (patch) | |
tree | be7dad2054f6d2effde2ab5fa3c17f0db34af3f0 | |
parent | 5aadb0ef180db606bffd4a0e0ec1270c856d0134 (diff) |
library: Add DIAMETER Templates, Emulation, CodecPort
Contrary to the DIAMETER_Types.ttcn, these files are not generated
but written by hand.
Change-Id: Iafbf55ab25bbaa40960eb1744cff36dcd7970c17
-rw-r--r-- | library/DIAMETER_CodecPort.ttcn | 81 | ||||
-rw-r--r-- | library/DIAMETER_CodecPort_CtrlFunct.ttcn | 44 | ||||
-rw-r--r-- | library/DIAMETER_CodecPort_CtrlFunctDef.cc | 56 | ||||
-rw-r--r-- | library/DIAMETER_Emulation.ttcn | 427 | ||||
-rw-r--r-- | library/DIAMETER_Templates.ttcn | 821 |
5 files changed, 1429 insertions, 0 deletions
diff --git a/library/DIAMETER_CodecPort.ttcn b/library/DIAMETER_CodecPort.ttcn new file mode 100644 index 00000000..65ae42b0 --- /dev/null +++ b/library/DIAMETER_CodecPort.ttcn @@ -0,0 +1,81 @@ +module DIAMETER_CodecPort { + +/* Simple DIAMETER Codec Port, translating between raw SCTP primitives with + * octetstring payload towards the IPL4asp provider, and DIAMETER primitives + * which carry the decoded DIAMETER data types as payload. + * + * (C) 2019 by Harald Welte <laforge@gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + + import from IPL4asp_PortType all; + import from IPL4asp_Types all; + import from DIAMETER_Types all; + + type record DIAMETER_RecvFrom { + ConnectionId connId, + HostName remName, + PortNumber remPort, + HostName locName, + PortNumber locPort, + PDU_DIAMETER msg + }; + + template DIAMETER_RecvFrom t_DIAMETER_RecvFrom(template PDU_DIAMETER msg) := { + connId := ?, + remName := ?, + remPort := ?, + locName := ?, + locPort := ?, + msg := msg + } + + type record DIAMETER_Send { + ConnectionId connId, + PDU_DIAMETER msg + } + + template DIAMETER_Send t_DIAMETER_Send(template ConnectionId connId, template PDU_DIAMETER msg) := { + connId := connId, + msg := msg + } + + private function IPL4_to_DIAMETER_RecvFrom(in ASP_RecvFrom pin, out DIAMETER_RecvFrom pout) { + pout.connId := pin.connId; + pout.remName := pin.remName; + pout.remPort := pin.remPort; + pout.locName := pin.locName; + pout.locPort := pin.locPort; + pout.msg := f_DIAMETER_Dec(pin.msg); + } with { extension "prototype(fast)" }; + + private function DIAMETER_to_IPL4_Send(in DIAMETER_Send pin, out ASP_Send pout) { + pout.connId := pin.connId; + pout.proto := { + sctp := { + sinfo_stream := omit, + sinfo_ppid := 46, /* plain text Diameter in SCTP DATA */ + remSocks := omit, + assocId := omit + } + }; + pout.msg := f_DIAMETER_Enc(pin.msg); + } with { extension "prototype(fast)" }; + + type port DIAMETER_CODEC_PT message { + out DIAMETER_Send; + in DIAMETER_RecvFrom, + ASP_ConnId_ReadyToRelease, + ASP_Event; + } with { extension "user IPL4asp_PT + out(DIAMETER_Send -> ASP_Send:function(DIAMETER_to_IPL4_Send)) + in(ASP_RecvFrom -> DIAMETER_RecvFrom: function(IPL4_to_DIAMETER_RecvFrom); + ASP_ConnId_ReadyToRelease -> ASP_ConnId_ReadyToRelease: simple; + ASP_Event -> ASP_Event: simple)" + } +} diff --git a/library/DIAMETER_CodecPort_CtrlFunct.ttcn b/library/DIAMETER_CodecPort_CtrlFunct.ttcn new file mode 100644 index 00000000..3b2230db --- /dev/null +++ b/library/DIAMETER_CodecPort_CtrlFunct.ttcn @@ -0,0 +1,44 @@ +module DIAMETER_CodecPort_CtrlFunct { + + import from DIAMETER_CodecPort all; + import from IPL4asp_Types all; + + external function f_IPL4_listen( + inout DIAMETER_CODEC_PT portRef, + in HostName locName, + in PortNumber locPort, + in ProtoTuple proto, + in OptionList options := {} + ) return Result; + + external function f_IPL4_connect( + inout DIAMETER_CODEC_PT portRef, + in HostName remName, + in PortNumber remPort, + in HostName locName, + in PortNumber locPort, + in ConnectionId connId, + in ProtoTuple proto, + in OptionList options := {} + ) return Result; + + external function f_IPL4_close( + inout DIAMETER_CODEC_PT portRef, + in ConnectionId id, + in ProtoTuple proto := { unspecified := {} } + ) return Result; + + external function f_IPL4_setUserData( + inout DIAMETER_CODEC_PT portRef, + in ConnectionId id, + in UserData userData + ) return Result; + + external function f_IPL4_getUserData( + inout DIAMETER_CODEC_PT portRef, + in ConnectionId id, + out UserData userData + ) return Result; + +} + diff --git a/library/DIAMETER_CodecPort_CtrlFunctDef.cc b/library/DIAMETER_CodecPort_CtrlFunctDef.cc new file mode 100644 index 00000000..782d176e --- /dev/null +++ b/library/DIAMETER_CodecPort_CtrlFunctDef.cc @@ -0,0 +1,56 @@ +#include "IPL4asp_PortType.hh" +#include "DIAMETER_CodecPort.hh" +#include "IPL4asp_PT.hh" + +namespace DIAMETER__CodecPort__CtrlFunct { + + IPL4asp__Types::Result f__IPL4__listen( + DIAMETER__CodecPort::DIAMETER__CODEC__PT& portRef, + const IPL4asp__Types::HostName& locName, + const IPL4asp__Types::PortNumber& locPort, + const IPL4asp__Types::ProtoTuple& proto, + const IPL4asp__Types::OptionList& options) + { + return f__IPL4__PROVIDER__listen(portRef, locName, locPort, proto, options); + } + + IPL4asp__Types::Result f__IPL4__connect( + DIAMETER__CodecPort::DIAMETER__CODEC__PT& portRef, + const IPL4asp__Types::HostName& remName, + const IPL4asp__Types::PortNumber& remPort, + const IPL4asp__Types::HostName& locName, + const IPL4asp__Types::PortNumber& locPort, + const IPL4asp__Types::ConnectionId& connId, + const IPL4asp__Types::ProtoTuple& proto, + const IPL4asp__Types::OptionList& options) + { + return f__IPL4__PROVIDER__connect(portRef, remName, remPort, + locName, locPort, connId, proto, options); + } + + IPL4asp__Types::Result f__IPL4__close( + DIAMETER__CodecPort::DIAMETER__CODEC__PT& portRef, + const IPL4asp__Types::ConnectionId& connId, + const IPL4asp__Types::ProtoTuple& proto) + { + return f__IPL4__PROVIDER__close(portRef, connId, proto); + } + + IPL4asp__Types::Result f__IPL4__setUserData( + DIAMETER__CodecPort::DIAMETER__CODEC__PT& portRef, + const IPL4asp__Types::ConnectionId& connId, + const IPL4asp__Types::UserData& userData) + { + return f__IPL4__PROVIDER__setUserData(portRef, connId, userData); + } + + IPL4asp__Types::Result f__IPL4__getUserData( + DIAMETER__CodecPort::DIAMETER__CODEC__PT& portRef, + const IPL4asp__Types::ConnectionId& connId, + IPL4asp__Types::UserData& userData) + { + return f__IPL4__PROVIDER__getUserData(portRef, connId, userData); + } + +} + diff --git a/library/DIAMETER_Emulation.ttcn b/library/DIAMETER_Emulation.ttcn new file mode 100644 index 00000000..dc7bc94e --- /dev/null +++ b/library/DIAMETER_Emulation.ttcn @@ -0,0 +1,427 @@ +module DIAMETER_Emulation { + +/* DIAMETER Emulation, runs on top of DIAMETER_CodecPort. It multiplexes/demultiplexes + * the individual IMSIs/subscribers, so there can be separate TTCN-3 components handling + * each of them. + * + * The DIAMETER_Emulation.main() function processes DIAMETER primitives from the DIAMETER + * socket via the DIAMETER_CodecPort, and dispatches them to the per-IMSI components. + * + * For each new IMSI, the DiameterOps.create_cb() is called. It can create + * or resolve a TTCN-3 component, and returns a component reference to which that IMSI + * is routed/dispatched. + * + * If a pre-existing component wants to register to handle a future inbound IMSI, it can + * do so by registering an "expect" with the expected IMSI. + * + * Inbound DIAMETER messages without IMSI (such as RESET-IND/ACK) are dispatched to + * the DiameterOps.unitdata_cb() callback, which is registered with an argument to the + * main() function below. + * + * (C) 2019 by Harald Welte <laforge@gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +import from DIAMETER_CodecPort all; +import from DIAMETER_CodecPort_CtrlFunct all; +import from DIAMETER_Types all; +import from DIAMETER_Templates all; +import from Osmocom_Types all; +import from IPL4asp_Types all; +import from DNS_Helpers all; +import from MobileL3_Types all; + +type hexstring IMSI; + +type component DIAMETER_ConnHdlr { + port DIAMETER_Conn_PT DIAMETER; + /* procedure based port to register for incoming connections */ + port DIAMETEREM_PROC_PT DIAMETER_PROC; +} + +/* port between individual per-connection components and this dispatcher */ +type port DIAMETER_Conn_PT message { + inout PDU_DIAMETER, PDU_ML3_MS_NW, PDU_ML3_NW_MS; +} with { extension "internal" }; + +/* global test port e.g. for non-imsi/conn specific messages */ +type port DIAMETER_PT message { + inout PDU_DIAMETER; +} with { extension "internal" }; + + +/* represents a single DIAMETER Association */ +type record AssociationData { + DIAMETER_ConnHdlr comp_ref, + hexstring imsi optional +}; + +type component DIAMETER_Emulation_CT { + /* Port facing to the UDP SUT */ + port DIAMETER_CODEC_PT DIAMETER; + /* All DIAMETER_ConnHdlr DIAMETER ports connect here + * DIAMETER_Emulation_CT.main needs to figure out what messages + * to send where with CLIENT.send() to vc_conn */ + port DIAMETER_Conn_PT DIAMETER_CLIENT; + /* currently tracked connections */ + var AssociationData SgsapAssociationTable[16]; + /* pending expected CRCX */ + var ExpectData DiameterExpectTable[8]; + /* procedure based port to register for incoming connections */ + port DIAMETEREM_PROC_PT DIAMETER_PROC; + /* test port for unit data messages */ + port DIAMETER_PT DIAMETER_UNIT; + + var charstring g_diameter_id; + var integer g_diameter_conn_id := -1; +} + +type function DIAMETERCreateCallback(PDU_DIAMETER msg, hexstring imsi, charstring id) +runs on DIAMETER_Emulation_CT return DIAMETER_ConnHdlr; + +type function DIAMETERUnitdataCallback(PDU_DIAMETER msg) +runs on DIAMETER_Emulation_CT return template PDU_DIAMETER; + +type record DIAMETEROps { + DIAMETERCreateCallback create_cb, + DIAMETERUnitdataCallback unitdata_cb +} + +type record DIAMETER_conn_parameters { + HostName remote_ip, + PortNumber remote_sctp_port, + HostName local_ip, + PortNumber local_sctp_port +} + +function tr_DIAMETER_RecvFrom_R(template PDU_DIAMETER msg) +runs on DIAMETER_Emulation_CT return template DIAMETER_RecvFrom { + var template DIAMETER_RecvFrom mrf := { + connId := g_diameter_conn_id, + remName := ?, + remPort := ?, + locName := ?, + locPort := ?, + msg := msg + } + return mrf; +} + +private function f_imsi_known(hexstring imsi) +runs on DIAMETER_Emulation_CT return boolean { + var integer i; + for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) { + if (SgsapAssociationTable[i].imsi == imsi) { + return true; + } + } + return false; +} + +private function f_comp_known(DIAMETER_ConnHdlr client) +runs on DIAMETER_Emulation_CT return boolean { + var integer i; + for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) { + if (SgsapAssociationTable[i].comp_ref == client) { + return true; + } + } + return false; +} + +private function f_comp_by_imsi(hexstring imsi) +runs on DIAMETER_Emulation_CT return DIAMETER_ConnHdlr { + var integer i; + for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) { + if (SgsapAssociationTable[i].imsi == imsi) { + return SgsapAssociationTable[i].comp_ref; + } + } + setverdict(fail, "DIAMETER Association Table not found by IMSI", imsi); + mtc.stop; +} + +private function f_imsi_by_comp(DIAMETER_ConnHdlr client) +runs on DIAMETER_Emulation_CT return hexstring { + var integer i; + for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) { + if (SgsapAssociationTable[i].comp_ref == client) { + return SgsapAssociationTable[i].imsi; + } + } + setverdict(fail, "DIAMETER Association Table not found by component ", client); + mtc.stop; +} + +private function f_imsi_table_add(DIAMETER_ConnHdlr comp_ref, hexstring imsi) +runs on DIAMETER_Emulation_CT { + var integer i; + for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) { + if (not isvalue(SgsapAssociationTable[i].imsi)) { + SgsapAssociationTable[i].imsi := imsi; + SgsapAssociationTable[i].comp_ref := comp_ref; + return; + } + } + testcase.stop("DIAMETER Association Table full!"); +} + +private function f_imsi_table_del(DIAMETER_ConnHdlr comp_ref, hexstring imsi) +runs on DIAMETER_Emulation_CT { + var integer i; + for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) { + if (SgsapAssociationTable[i].comp_ref == comp_ref and + SgsapAssociationTable[i].imsi == imsi) { + SgsapAssociationTable[i].imsi := omit; + SgsapAssociationTable[i].comp_ref := null; + return; + } + } + setverdict(fail, "DIAMETER Association Table: Couldn't find to-be-deleted entry!"); + mtc.stop; +} + + +private function f_imsi_table_init() +runs on DIAMETER_Emulation_CT { + for (var integer i := 0; i < sizeof(SgsapAssociationTable); i := i+1) { + SgsapAssociationTable[i].comp_ref := null; + SgsapAssociationTable[i].imsi := omit; + } +} + +function f_DIAMETER_get_avp(PDU_DIAMETER pdu, template (present) AVP_Code avp_code) +return template (omit) AVP +{ + var integer i; + + for (i := 0; i < lengthof(pdu.avps); i := i+1) { + if (not ispresent(pdu.avps[i].avp)) { + continue; + } + var AVP_Header hdr := pdu.avps[i].avp.avp_header; + if (match(hdr.avp_code, avp_code)) { + return pdu.avps[i].avp; + } + } + return omit; +} + +function f_DIAMETER_get_imsi(PDU_DIAMETER pdu) return template (omit) IMSI +{ + var template (omit) AVP imsi_avp; + + imsi_avp := f_DIAMETER_get_avp(pdu, c_AVP_Code_BASE_NONE_User_Name); + if (istemplatekind(imsi_avp, "omit")) { + return omit; + } else { + var octetstring imsi_oct := valueof(imsi_avp.avp_data.avp_BASE_NONE_User_Name); + return str2hex(oct2char(imsi_oct)); + } +} + +private template (value) SctpTuple ts_SCTP(template (omit) integer ppid := omit) := { + sinfo_stream := omit, + sinfo_ppid := ppid, + remSocks := omit, + assocId := omit +}; + +private template PortEvent tr_SctpAssocChange := { + sctpEvent := { + sctpAssocChange := ? + } +} +private template PortEvent tr_SctpPeerAddrChange := { + sctpEvent := { + sctpPeerAddrChange := ? + } +} + +private function f_diameter_xceive(template (value) PDU_DIAMETER tx, + template PDU_DIAMETER rx_t := ?) +runs on DIAMETER_Emulation_CT return PDU_DIAMETER { + timer T := 10.0; + var DIAMETER_RecvFrom mrf; + + DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, tx)); + alt { + [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(rx_t)) -> value mrf { } + [] DIAMETER.receive(tr_SctpAssocChange) { repeat; } + [] DIAMETER.receive(tr_SctpPeerAddrChange) { repeat; } + [] T.timeout { + setverdict(fail, "Timeout waiting for ", rx_t); + mtc.stop; + } + } + return mrf.msg; +} + +function main(DIAMETEROps ops, DIAMETER_conn_parameters p, charstring id) runs on DIAMETER_Emulation_CT { + var Result res; + g_diameter_id := id; + f_imsi_table_init(); + f_expect_table_init(); + + map(self:DIAMETER, system:DIAMETER_CODEC_PT); + if (p.remote_sctp_port == -1) { + res := DIAMETER_CodecPort_CtrlFunct.f_IPL4_listen(DIAMETER, p.local_ip, p.local_sctp_port, { sctp := valueof(ts_SCTP) }); + } else { + res := DIAMETER_CodecPort_CtrlFunct.f_IPL4_connect(DIAMETER, p.remote_ip, p.remote_sctp_port, + p.local_ip, p.local_sctp_port, -1, { sctp := valueof(ts_SCTP) }); + } + if (not ispresent(res.connId)) { + setverdict(fail, "Could not connect DIAMETER socket, check your configuration"); + mtc.stop; + } + g_diameter_conn_id := res.connId; + + while (true) { + var DIAMETER_ConnHdlr vc_conn; + var PDU_ML3_MS_NW l3_mo; + var PDU_ML3_NW_MS l3_mt; + var template IMSI imsi_t; + var hexstring imsi; + var DIAMETER_RecvFrom mrf; + var PDU_DIAMETER msg; + var charstring vlr_name, mme_name; + var PortEvent port_evt; + + alt { + [] DIAMETER.receive(PortEvent:{connOpened := ?}) -> value port_evt { + g_diameter_conn_id := port_evt.connOpened.connId; + } + [] DIAMETER.receive(PortEvent:?) { } + /* DIAMETER from client */ + [] DIAMETER_CLIENT.receive(PDU_DIAMETER:?) -> value msg sender vc_conn { + /* Pass message through */ + /* TODO: check which ConnectionID client has allocated + store in table? */ + DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, msg)); + } + + /* handle CER/CEA handshake */ + [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(tr_DIAMETER_R(cmd_code := Capabilities_Exchange))) -> value mrf { + var template (value) PDU_DIAMETER resp; + resp := ts_DIA_CEA(mrf.msg.hop_by_hop_id, mrf.msg.end_to_end_id); + DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, resp)); + } + + /* DIAMETER from remote peer */ + [] DIAMETER.receive(tr_DIAMETER_RecvFrom_R(?)) -> value mrf { + imsi_t := f_DIAMETER_get_imsi(mrf.msg); + if (isvalue(imsi_t)) { + imsi := valueof(imsi_t); + if (f_imsi_known(imsi)) { + vc_conn := f_comp_by_imsi(imsi); + DIAMETER_CLIENT.send(mrf.msg) to vc_conn; + } else { + vc_conn := ops.create_cb.apply(mrf.msg, imsi, id); + f_imsi_table_add(vc_conn, imsi); + DIAMETER_CLIENT.send(mrf.msg) to vc_conn; + } + } else { + /* message contained no IMSI; is not IMSI-oriented */ + var template PDU_DIAMETER resp := ops.unitdata_cb.apply(mrf.msg); + if (isvalue(resp)) { + DIAMETER.send(t_DIAMETER_Send(g_diameter_conn_id, valueof(resp))); + } + } + } + [] DIAMETER.receive(tr_SctpAssocChange) { } + [] DIAMETER.receive(tr_SctpPeerAddrChange) { } + [] DIAMETER_PROC.getcall(DIAMETEREM_register:{?,?}) -> param(imsi, vc_conn) { + f_create_expect(imsi, vc_conn); + DIAMETER_PROC.reply(DIAMETEREM_register:{imsi, vc_conn}) to vc_conn; + } + + } + + } +} + +/* "Expect" Handling */ + +type record ExpectData { + hexstring imsi optional, + DIAMETER_ConnHdlr vc_conn +} + +signature DIAMETEREM_register(in hexstring imsi, in DIAMETER_ConnHdlr hdlr); + +type port DIAMETEREM_PROC_PT procedure { + inout DIAMETEREM_register; +} with { extension "internal" }; + +/* Function that can be used as create_cb and will usse the expect table */ +function ExpectedCreateCallback(PDU_DIAMETER msg, hexstring imsi, charstring id) +runs on DIAMETER_Emulation_CT return DIAMETER_ConnHdlr { + var DIAMETER_ConnHdlr ret := null; + var integer i; + + for (i := 0; i < sizeof(DiameterExpectTable); i := i+1) { + if (not ispresent(DiameterExpectTable[i].imsi)) { + continue; + } + if (imsi == DiameterExpectTable[i].imsi) { + ret := DiameterExpectTable[i].vc_conn; + /* Release this entry */ + DiameterExpectTable[i].imsi := omit; + DiameterExpectTable[i].vc_conn := null; + log("Found Expect[", i, "] for ", msg, " handled at ", ret); + return ret; + } + } + setverdict(fail, "Couldn't find Expect for ", msg); + mtc.stop; +} + +private function f_create_expect(hexstring imsi, DIAMETER_ConnHdlr hdlr) +runs on DIAMETER_Emulation_CT { + var integer i; + + /* Check an entry like this is not already presnt */ + for (i := 0; i < sizeof(DiameterExpectTable); i := i+1) { + if (imsi == DiameterExpectTable[i].imsi) { + setverdict(fail, "IMSI already present", imsi); + mtc.stop; + } + } + for (i := 0; i < sizeof(DiameterExpectTable); i := i+1) { + if (not ispresent(DiameterExpectTable[i].imsi)) { + DiameterExpectTable[i].imsi := imsi; + DiameterExpectTable[i].vc_conn := hdlr; + log("Created Expect[", i, "] for ", imsi, " to be handled at ", hdlr); + return; + } + } + testcase.stop("No space left in DiameterExpectTable") +} + +/* client/conn_hdlr side function to use procedure port to create expect in emulation */ +function f_diameter_expect(hexstring imsi) runs on DIAMETER_ConnHdlr { + DIAMETER_PROC.call(DIAMETEREM_register:{imsi, self}) { + [] DIAMETER_PROC.getreply(DIAMETEREM_register:{?,?}) {}; + } +} + +private function f_expect_table_init() +runs on DIAMETER_Emulation_CT { + var integer i; + for (i := 0; i < sizeof(DiameterExpectTable); i := i + 1) { + DiameterExpectTable[i].imsi := omit; + } +} + +function DummyUnitdataCallback(PDU_DIAMETER msg) +runs on DIAMETER_Emulation_CT return template PDU_DIAMETER { + log("Ignoring DIAMETER ", msg); + return omit; +} + + +} diff --git a/library/DIAMETER_Templates.ttcn b/library/DIAMETER_Templates.ttcn new file mode 100644 index 00000000..27795362 --- /dev/null +++ b/library/DIAMETER_Templates.ttcn @@ -0,0 +1,821 @@ +module DIAMETER_Templates { + +/* (C) 2019 by Harald Welte <laforge@gnumonks.org> + * All rights reserved. + * + * Released under the terms of GNU General Public License, Version 2 or + * (at your option) any later version. + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +import from DIAMETER_Types all; +import from Osmocom_Types all; + +/* https://www.iana.org/assignments/aaa-parameters/aaa-parameters.xhtml#aaa-parameters-4 */ +type enumerated DIAMETER_Resultcode { + /* Informational */ + DIAMETER_MULTI_ROUND_AUTH (1001), + + /* Success */ + DIAMETER_SUCCESS (2001), + DIAMETER_LIMITED_SUCCESS (2002), + DIAMETER_FIRST_REGISTRATION (2003), + DIAMETER_SUBSEQUENT_REGISTRATION (2004), + DIAMETER_UNREGISTERED_SERVICE (2005), + DIAMETER_SUCCESS_SERVER_NAME_NOT_STORED (2006), + DIAMETER_SERVER_SELECTION (2007), + DIAMETER_SUCCESS_AUTH_SENT_SERVER_NOT_STORED (2008), + DIAMETER_SUCCESS_RELOCATE_HA (2009), + + /* 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), + DIAMETER_REALM_REDIRECT_INDICATION (3011), + + /* Transient Failures */ + DIAMETER_AUTHENTICATION_REJECTED (4001), + DIAMETER_OUT_OF_SPACE (4002), + ELECTION_LOST (4003), + DIAMETER_ERROR_MIP_REPLY_FAILURE (4005), + DIAMETER_ERROR_HA_NOT_AVAILABLE (4006), + DIAMETER_ERROR_BAD_KEY (4007), + DIAMETER_ERROR_MIP_FILTER_NOT_SUPPORTED (4008), + DIAMETER_END_USER_SERVICE_DENIED (4010), + DIAMETER_CREDIT_CONTROL_NOT_APPLICABLE (4011), + DIAMETER_CREDIT_LIMIT_REACHED (4012), + DIAMETER_USER_NAME_REQUIRED (4013), + RESOURCE_FAILURE (4014), + + DIAMETER_AUTHENTICATION_DATA_UNAVAILABLE (4181), + DIAMETER_ERROR_CAMEL_SUBSCRIPTION_PRESENT (4882), + + /* Permanent Failure */ + 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), + DIAMETER_RADIUS_AVP_UNTRANSLATABLE (5018), + DIAMETER_ERROR_NO_FOREIGN_HA_SERVICE (5024), + DIAMETER_ERROR_END_TO_END_MIP_KEY_ENCRYPTION (5025), + DIAMETER_USER_UNKNOWN (5030), + DIAMETER_RATING_FAILED (5031), + DIAMETER_ERROR_USER_UNKNOWN (5032), + DIAMETER_ERROR_IDENTITIES_DONT_MATCH (5033), + DIAMETER_ERROR_IDENTITY_NOT_REGISTERED (5034), + DIAMETER_ERROR_ROAMING_NOT_ALLOWED (5035), + DIAMETER_ERROR_IDENTITY_ALREADY_REGISTERED (5036), + DIAMETER_ERROR_AUTH_SCHEME_NOT_SUPPORTED (5037), + DIAMETER_ERROR_IN_ASSIGNMENT_TYPE (5038), + DIAMETER_ERROR_TOO_MUCH_DATA (5039), + DIAMETER_ERROR_NOT_SUPPORTED_USER_DATA (5040), + DIAMETER_ERROR_MIP6_AUTH_MODE (5041), + UNKNOWN_BINDING_TEMPLATE_NAME (5042), + BINDING_FAILURE (5043), + MAX_BINDINGS_SET_FAILURE (5044), + MAXIMUM_BINDINGS_REACHED_FOR_ENDPOINT (5045), + SESSION_EXISTS (5046), + INSUFFICIENT_CLASSIFIERS (5047), + DIAMETER_ERROR_EAP_CODE_UNKNOWN (5048) +}; + +/* 3GPP TS 29.272 Section 7.1.8 */ +const uint32_t c_DIAMETER_3GPP_S6_AID := 16777251; +const uint32_t c_DIAMETER_3GPP_S13_AID := 16777252; +const uint32_t c_DIAMETER_3GPP_S7_AID := 16777308; + +template (value) PDU_DIAMETER +ts_DIAMETER(template (value) BIT8 flags, + template (value) Command_Code cmd_code, + template (value) OCTET4 app_id := '00000000'O, + template (value) UINT32 hbh_id, + template (value) UINT32 ete_id, + template (value) AVP_list avps := {} +) := { + version := 1, + message_length := 0, /* overwritten */ + RPETxxxx := flags, + command_code := cmd_code, + application_id := app_id, + hop_by_hop_id := hbh_id, + end_to_end_id := ete_id, + avps := avps +} +template (present) PDU_DIAMETER +tr_DIAMETER(template (present) BIT8 flags := ?, + template (present) Command_Code cmd_code := ?, + template (present) OCTET4 app_id := ?, + template (present) UINT32 hbh_id := ?, + template (present) UINT32 ete_id := ?, + template (present) AVP_list avps := ?) := { + version := 1, + message_length := ?, + RPETxxxx := flags, + command_code := cmd_code, + application_id := app_id, + hop_by_hop_id := hbh_id, + end_to_end_id := ete_id, + avps := avps +} +template (present) PDU_DIAMETER +tr_DIAMETER_A( + template (present) Command_Code cmd_code := ?, + template (present) OCTET4 app_id := ?, + template (present) UINT32 hbh_id := ?, + template (present) UINT32 ete_id := ?, + template (present) AVP_list avps := ?) := + tr_DIAMETER('0???????'B, cmd_code, app_id, hbh_id, ete_id, avps); +template (present) PDU_DIAMETER +tr_DIAMETER_R( + template (present) Command_Code cmd_code := ?, + template (present) OCTET4 app_id := ?, + template (present) UINT32 hbh_id := ?, + template (present) UINT32 ete_id := ?, + template (present) AVP_list avps := ?) := + tr_DIAMETER('1???????'B, cmd_code, app_id, hbh_id, ete_id, avps); + + +template (value) AVP_Header +ts_DIA_Hdr(template (value) AVP_Code avp_code, + template (value) BIT8 flags := '01000000'B) := { + avp_code := avp_code, + VMPxxxxx := flags, + avp_length := 0, /* overwritten */ + vendor_id := omit +} +template (present) AVP_Header +tr_DIA_Hdr(template (present) AVP_Code avp_code, + template (present) BIT8 flags := '0???????'B) := { + avp_code := avp_code, + VMPxxxxx := flags, + avp_length := ?, /* overwritten */ + vendor_id := omit +} + +template (value) AVP_Header +ts_DIA_Hdr_3GPP(template (value) AVP_Code avp_code, + template (value) BIT8 flags := '11000000'B) := { + avp_code := avp_code, + VMPxxxxx := flags, + avp_length := 0, /* overwritten */ + vendor_id := vendor_id_3GPP +} +template (present) AVP_Header +tr_DIA_Hdr_3GPP(template (present) AVP_Code avp_code, + template (present) BIT8 flags := '1???????'B) := { + avp_code := avp_code, + VMPxxxxx := flags, + avp_length := ?, /* overwritten */ + vendor_id := vendor_id_3GPP +} + + +template (value) GenericAVP ts_AVP_OriginHost(template (value) charstring host) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Origin_Host), + avp_data := { + avp_BASE_NONE_Origin_Host := host + } + } +} +template (present) GenericAVP tr_AVP_OriginHost(template (present) charstring host := ?) := { + avp := { + avp_header := tr_DIA_Hdr(c_AVP_Code_BASE_NONE_Origin_Host), + avp_data := { + avp_BASE_NONE_Origin_Host := host + } + } +} + + +template (value) GenericAVP ts_AVP_OriginRealm(template (value) charstring realm) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Origin_Realm), + avp_data := { + avp_BASE_NONE_Origin_Realm := realm + } + } +} +template (present) GenericAVP tr_AVP_OriginRealm(template (present) charstring realm := ?) := { + avp := { + avp_header := tr_DIA_Hdr(c_AVP_Code_BASE_NONE_Origin_Realm), + avp_data := { + avp_BASE_NONE_Origin_Realm := realm + } + } +} + + +template (value) GenericAVP ts_AVP_OriginStateId(template (value) OCTET4 state_id) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Origin_State_Id), + avp_data := { + avp_BASE_NONE_Origin_State_Id := state_id + } + } +} + +template (value) GenericAVP ts_AVP_HostIpAddr(template (value) OCTET4 ipv4_addr) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Host_IP_Address), + avp_data := { + avp_BASE_NONE_Host_IP_Address := { + address_type := IP, + address_data := ipv4_addr + } + } + } +} + +template (value) GenericAVP ts_AVP_VendorId(Vendor_Id vendor_id) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Vendor_Id, '00000000'B), + avp_data := { + avp_BASE_NONE_Vendor_Id := int2oct(enum2int(vendor_id), 4) + } + } +} + +template (value) GenericAVP ts_AVP_ProductName(charstring name) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Product_Name, '00000000'B), + avp_data := { + avp_BASE_NONE_Product_Name := char2oct(name) + } + } +} + +template (value) GenericAVP ts_AVP_FwRevision(octetstring fw_version) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Firmware_Revision, '00000000'B), + avp_data := { + avp_BASE_NONE_Firmware_Revision := fw_version + } + } +} + +template (value) GenericAVP ts_AVP_InbSecId(template (value) OCTET4 inb_sec_id) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Inband_Security_Id), + avp_data := { + avp_BASE_NONE_Inband_Security_Id := inb_sec_id + } + } +} + +template (value) GenericAVP ts_AVP_VendorSpecAppId(Vendor_Id vendor_id, uint32_t auth_app_id) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Vendor_Specific_Application_Id), + avp_data := { + avp_BASE_NONE_Vendor_Specific_Application_Id := { + { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Vendor_Id), + avp_data := { + avp_BASE_NONE_Vendor_Id := int2oct(enum2int(vendor_id), 4) + } + } + }, { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Auth_Application_Id), + avp_data := { + avp_BASE_NONE_Auth_Application_Id := int2oct(auth_app_id, 4) + } + } + } + } + } + } +} + +template (value) GenericAVP ts_AVP_AuthAppId(template (value) OCTET4 auth_app_id) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Auth_Application_Id), + avp_data := { + avp_BASE_NONE_Auth_Application_Id := auth_app_id + } + } +} + +template (value) GenericAVP ts_AVP_SuppVendorIdRaw(uint32_t vendor_id) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Supported_Vendor_Id), + avp_data := { + avp_BASE_NONE_Supported_Vendor_Id := int2oct(vendor_id, 4) + } + } +} +template (value) GenericAVP ts_AVP_SuppVendorId(Vendor_Id vendor_id) := + ts_AVP_SuppVendorIdRaw(enum2int(vendor_id)); + +template (value) GenericAVP ts_AVP_ResultCode(DIAMETER_Resultcode res_code) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Result_Code), + avp_data := { + avp_BASE_NONE_Result_Code := int2oct(enum2int(res_code), 4) + } + } +} + +template (value) GenericAVP ts_AVP_AuthSessionState(template (value) BASE_NONE_Auth_Session_State ass := NO_STATE_MAINTAINED) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Auth_Session_State), + avp_data := { + avp_BASE_NONE_Auth_Session_State := ass + } + } +} +template (present) GenericAVP tr_AVP_AuthSessionState(template (present) BASE_NONE_Auth_Session_State ass := ?) := { + avp := { + avp_header := tr_DIA_Hdr(c_AVP_Code_BASE_NONE_Auth_Session_State), + avp_data := { + avp_BASE_NONE_Auth_Session_State := ass + } + } +} + +template (value) GenericAVP ts_AVP_SessionId(template (value) octetstring session_id) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Session_Id), + avp_data := { + avp_BASE_NONE_Session_Id := session_id + } + } +} +template (present) GenericAVP tr_AVP_SessionId(template (present) octetstring session_id := ?) := { + avp := { + avp_header := tr_DIA_Hdr(c_AVP_Code_BASE_NONE_Session_Id), + avp_data := { + avp_BASE_NONE_Session_Id := session_id + } + } +} + +/* 3.3 Destination Realm */ +template (value) GenericAVP ts_AVP_DestinationRealm(template (value) charstring dest_realm) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Destination_Realm), + avp_data := { + avp_BASE_NONE_Destination_Realm := dest_realm + } + } +} +template (present) GenericAVP tr_AVP_DestinationRealm(template (present) charstring dest_realm := ?) := { + avp := { + avp_header := tr_DIA_Hdr(c_AVP_Code_BASE_NONE_Destination_Realm), + avp_data := { + avp_BASE_NONE_Destination_Realm := dest_realm + } + } +} + +/* 8.14 User-Name */ +template (value) GenericAVP ts_AVP_UserName(template (value) octetstring uid) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_User_Name), + avp_data := { + avp_BASE_NONE_User_Name := uid + } + } +} +template (present) GenericAVP tr_AVP_UserName(template (present) octetstring uid := ?) := { + avp := { + avp_header := tr_DIA_Hdr(c_AVP_Code_BASE_NONE_User_Name), + avp_data := { + avp_BASE_NONE_User_Name := uid + } + } +} +template (value) GenericAVP ts_AVP_UserNameImsi(hexstring imsi) := ts_AVP_UserName(char2oct(hex2str(imsi))); +template (present) GenericAVP tr_AVP_UserNameImsi(hexstring imsi) := tr_AVP_UserName(char2oct(hex2str(imsi))); + + + +/* TS 29.262 7.3.53 RAND */ +template (value) GenericAVP ts_AVP_RAND(template (value) octetstring rand) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_RAND), + avp_data := { + avp_AAA_3GPP_RAND := rand + } + } +} + +/* TS 29.262 7.3.54 XRES */ +template (value) GenericAVP ts_AVP_XRES(template (value) octetstring xres) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_XRES), + avp_data := { + avp_AAA_3GPP_XRES := xres + } + } +} + +/* TS 29.262 7.3.55 XRES */ +template (value) GenericAVP ts_AVP_AUTN(template (value) octetstring autn) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_AUTN), + avp_data := { + avp_AAA_3GPP_AUTN := autn + } + } +} + +/* TS 29.262 7.3.56 KASME */ +template (value) GenericAVP ts_AVP_KASME(template (value) octetstring kasme) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_KASME), + avp_data := { + avp_AAA_3GPP_KASME := kasme + } + } +} + +/* TS 29.262 7.3.23 Item-Number */ +template (value) GenericAVP ts_AVP_ItemNumber(uint32_t num) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_KASME), + avp_data := { + avp_AAA_3GPP_Item_Number := int2oct(num, 4) + } + } +} + +/* TS 29.262 7.3.18 E-UTRAN Vector */ +template (value) GenericAVP ts_AVP_EutranVec(uint32_t item_num, octetstring rand, octetstring xres, + octetstring autn, octetstring kasme) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_E_UTRAN_Vector), + avp_data := { + avp_AAA_3GPP_E_UTRAN_Vector := { + ts_AVP_ItemNumber(item_num), + ts_AVP_RAND(rand), + ts_AVP_XRES(xres), + ts_AVP_AUTN(autn), + ts_AVP_KASME(kasme) + } + } + } +} + +/* TS 29.262 7.3.2 Subscription-Data */ +template (value) GenericAVP ts_AVP_3GPP_SubscriptionData(template (value) AVP_list content) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_Subscription_Data), + avp_data := { + avp_AAA_3GPP_Subscription_Data := content + } + } +} + + +/* TS 29.262 7.3.17 Authentication-Info */ +template (value) GenericAVP ts_AVP_3GPP_AuthInfo(template (value) AVP_list content) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_Authentication_Info), + avp_data := { + avp_AAA_3GPP_Authentication_Info := content + } + } +} + +/* TS 29.262 7.3.9 Visited-PLMN-Id */ +template (value) GenericAVP ts_AVP_3GPP_VisitedPlmnId(template (value) octetstring id) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_Visited_PLMN_Id), + avp_data := { + avp_AAA_3GPP_Visited_PLMN_Id := id + } + } +} +template (present) GenericAVP tr_AVP_3GPP_VisitedPlmnId(template (present) octetstring id := ?) := { + avp := { + avp_header := tr_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_Visited_PLMN_Id), + avp_data := { + avp_AAA_3GPP_Visited_PLMN_Id := id + } + } +} + +/* TS 29.262 7.3.13 RAT-Type */ +template (value) GenericAVP ts_AVP_3GPP_RatType(template (value) PCC_3GPP_RAT_Type rat_type) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_PCC_3GPP_RAT_Type), + avp_data := { + avp_PCC_3GPP_RAT_Type := rat_type + } + } +} +template (present) GenericAVP tr_AVP_3GPP_RatType(template (present) PCC_3GPP_RAT_Type rat_type := ?) := { + avp := { + avp_header := tr_DIA_Hdr_3GPP(c_AVP_Code_PCC_3GPP_RAT_Type), + avp_data := { + avp_PCC_3GPP_RAT_Type := rat_type + } + } +} + +/* TS 29.262 7.3.7 ULR-Flags */ +template (value) GenericAVP ts_AVP_3GPP_UlrFlags(template (value) UINT32 flags) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_ULR_Flags), + avp_data := { + avp_AAA_3GPP_ULR_Flags := flags + } + } +} +template (present) GenericAVP tr_AVP_3GPP_UlrFlags(template (present) UINT32 flags := ?) := { + avp := { + avp_header := tr_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_ULR_Flags), + avp_data := { + avp_AAA_3GPP_ULR_Flags := flags + } + } +} + +/* TS 29.262 7.3.8 ULA-Flags */ +template (value) GenericAVP ts_AVP_3GPP_UlaFlags(template (value) UINT32 flags) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_ULA_Flags), + avp_data := { + avp_AAA_3GPP_ULA_Flags := flags + } + } +} +template (present) GenericAVP tr_AVP_3GPP_UlaFlags(template (present) UINT32 flags := ?) := { + avp := { + avp_header := tr_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_ULA_Flags), + avp_data := { + avp_AAA_3GPP_ULA_Flags := flags + } + } +} + +/* TS 29.262 7.3.27 Context-Identifier */ +template (value) GenericAVP ts_AVP_3GPP_ContextId(uint32_t ctx) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_Context_Identifier), + avp_data := { + avp_AAA_3GPP_Context_Identifier := int2oct(ctx, 4) + } + } +} + +/* Ts 29.262 7.3.29 Subscriber-Status */ +template (value) GenericAVP ts_AVP_3GPP_SubscriberStatus(template (value) AAA_3GPP_Subscriber_Status sts) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_Subscriber_Status), + avp_data := { + avp_AAA_3GPP_Subscriber_Status := sts + } + } +} + +template (value) GenericAVP ts_AVP_3GPP_SubscrRauTauTmr(uint32_t tmr) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_Subscribed_Periodic_RAU_TAU_Timer), + avp_data := { + avp_AAA_3GPP_Subscribed_Periodic_RAU_TAU_Timer := int2oct(tmr, 4) + } + } +} + +/* TS 29.262 7.3.33 All-APN-Configurations-Included-Indicator */ +template (value) GenericAVP ts_AVP_3GPP_AllApnConfigsIncl(template (value) AAA_3GPP_All_APN_Configurations_Included_Indicator ind := All_APN_CONFIGURATIONS_INCLUDED) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_All_APN_Configurations_Included_Indicator), + avp_data := { + avp_AAA_3GPP_All_APN_Configurations_Included_Indicator := ind + } + } +} + +/* TS 29.262 7.3.34 APN-Configuration-Profile */ +template (value) GenericAVP ts_AVP_3GPP_ApnConfigProfile(template (value) AVP_list content) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_APN_Configuration_Profile), + avp_data := { + avp_AAA_3GPP_APN_Configuration_Profile := content + } + } +} + +/* TS 29.262 7.3.35 APN-Configuration */ +template (value) GenericAVP ts_AVP_3GPP_ApnConfig(uint32_t ctx, AAA_3GPP_PDN_Type pdn_type, + charstring apn) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_APN_Configuration_Profile), + avp_data := { + avp_AAA_3GPP_APN_Configuration := { + ts_AVP_3GPP_ContextId(ctx), + ts_AVP_3GPP_PdnType(pdn_type), + ts_AVP_3GPP_EpsSubscrQosProfile(1, 1), + ts_AVP_ServiceSelection(apn) + } + } + } +} + +/* TS 29.262 7.3.36 Service-Selection (refers to RFC 5778) */ +template (value) GenericAVP ts_AVP_ServiceSelection(charstring apn) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_MIPv6_NONE_Service_Selection), + avp_data := { + avp_MIPv6_NONE_Service_Selection := char2oct(apn) + } + } +} + +template (value) GenericAVP ts_AVP_3GPP_QosClassId(uint32_t id) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_PCC_3GPP_QoS_Class_Identifier), + avp_data := { + avp_PCC_3GPP_QoS_Class_Identifier := int2oct(id, 4) + } + } +} + +template (value) GenericAVP ts_AVP_3GPP_PriorityLevel(uint32_t prio) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_PCC_3GPP_Priority_Level), + avp_data := { + avp_PCC_3GPP_Priority_Level := int2oct(prio, 4) + } + } +} + + +template (value) GenericAVP ts_AVP_3GPP_AllocRetenPrio(uint32_t prio) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_PCC_3GPP_Allocation_Retention_Priority), + avp_data := { + avp_PCC_3GPP_Allocation_Retention_Priority := { + ts_AVP_3GPP_PriorityLevel(prio) + /* pre-emption capability */ + /* pre-emption vulnerability */ + } + } + } +} + +template (value) GenericAVP ts_AVP_3GPP_EpsSubscrQosProfile(uint32_t qos_class, uint32_t prio) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_EPS_Subscribed_QoS_Profile), + avp_data := { + avp_AAA_3GPP_EPS_Subscribed_QoS_Profile := { + ts_AVP_3GPP_QosClassId(qos_class), + ts_AVP_3GPP_AllocRetenPrio(prio) + } + } + } +} + + +/* TS 29.262 7.3.41 AMBR */ +template (value) GenericAVP ts_AVP_3GPP_AMBR(uint32_t ul, uint32_t dl) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_AMBR), + avp_data := { + avp_AAA_3GPP_AMBR := { + ts_AVP_3GPP_MaxReqBwUL(ul), + ts_AVP_3GPP_MaxReqBwDL(dl) + } + } + } +} + +template (value) GenericAVP ts_AVP_3GPP_MaxReqBwUL(uint32_t bw) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_RX_3GPP_Max_Requested_Bandwidth_UL), + avp_data := { + avp_RX_3GPP_Max_Requested_Bandwidth_UL := int2oct(bw, 4) + } + } +} + +template (value) GenericAVP ts_AVP_3GPP_MaxReqBwDL(uint32_t bw) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_RX_3GPP_Max_Requested_Bandwidth_DL), + avp_data := { + avp_RX_3GPP_Max_Requested_Bandwidth_DL := int2oct(bw, 4) + } + } +} + + + +/* TS 29.262 7.3.62 PDN-Type */ +template (value) GenericAVP ts_AVP_3GPP_PdnType(template (value) AAA_3GPP_PDN_Type pdn_type) := { + avp := { + avp_header := ts_DIA_Hdr_3GPP(c_AVP_Code_AAA_3GPP_PDN_Type), + avp_data := { + avp_AAA_3GPP_PDN_Type := pdn_type + } + } +} + + + +/* 5.3.2 Capabilities Exchange Answer */ +template (value) PDU_DIAMETER +ts_DIA_CEA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id) +:= ts_DIAMETER(flags:='00000000'B, cmd_code:=Capabilities_Exchange, hbh_id:=hbh_id, ete_id:=ete_id, + avps := { + ts_AVP_ResultCode(DIAMETER_SUCCESS), + ts_AVP_OriginHost("hss.localdomain"), + ts_AVP_OriginRealm("localdomain"), + ts_AVP_HostIpAddr('7E000004'O), + ts_AVP_VendorId(vendor_id_3GPP), + ts_AVP_ProductName("TTCN-3 Testsuite"), + ts_AVP_OriginStateId('00000001'O), + ts_AVP_SuppVendorIdRaw(5535), /* 3GPP2 */ + ts_AVP_SuppVendorId(vendor_id_3GPP), + ts_AVP_SuppVendorIdRaw(13019), /* ETSI */ + ts_AVP_AuthAppId('FFFFFFFF'O), + ts_AVP_InbSecId('00000000'O), + ts_AVP_VendorSpecAppId(vendor_id_3GPP, c_DIAMETER_3GPP_S6_AID) + }); + +template (present) PDU_DIAMETER +tr_DIA_AIR(hexstring imsi) := tr_DIAMETER(flags := '11000000'B, cmd_code:=Authentication_Information, + app_id := int2oct(c_DIAMETER_3GPP_S6_AID, 4), + avps := superset( + tr_AVP_SessionId, + tr_AVP_DestinationRealm, + tr_AVP_UserNameImsi(imsi), + tr_AVP_3GPP_VisitedPlmnId + )); + +/* TS 29.262 5.2.3.1 + 7.2.6 Authentication Information Answer */ +template (value) PDU_DIAMETER +ts_DIA_AIA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, + template (value) octetstring sess_id, + template (value) AVP_list auth_info_contents) +:= ts_DIAMETER(flags:='01000000'B, cmd_code:=Authentication_Information, + app_id := int2oct(c_DIAMETER_3GPP_S6_AID, 4), hbh_id:=hbh_id, ete_id:=ete_id, + avps := { + ts_AVP_SessionId(sess_id), + ts_AVP_ResultCode(DIAMETER_SUCCESS), + ts_AVP_AuthSessionState(NO_STATE_MAINTAINED), + ts_AVP_OriginHost("hss.localdomain"), + ts_AVP_OriginRealm("localdomain"), + ts_AVP_3GPP_AuthInfo(auth_info_contents) + }); + + +/* TS 29.262 7.2.3 Update Location Request */ +template (present) PDU_DIAMETER +tr_DIA_ULR(hexstring imsi) := tr_DIAMETER(flags:='11000000'B, cmd_code:=Update_Location, + app_id:=int2oct(c_DIAMETER_3GPP_S6_AID, 4), + avps := superset( + tr_AVP_SessionId, + tr_AVP_AuthSessionState, + tr_AVP_OriginHost, + tr_AVP_OriginRealm, + tr_AVP_DestinationRealm, + tr_AVP_UserNameImsi(imsi), + tr_AVP_3GPP_RatType(EUTRAN), + tr_AVP_3GPP_UlrFlags, + tr_AVP_3GPP_VisitedPlmnId + )); + +template (value) PDU_DIAMETER +ts_DIA_ULA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, + template (value) octetstring sess_id, + template (value) AVP_list sub_data_content) +:= ts_DIAMETER(flags:='01000000'B, cmd_code:=Update_Location, + app_id := int2oct(c_DIAMETER_3GPP_S6_AID, 4), hbh_id:=hbh_id, ete_id:=ete_id, + avps := { + ts_AVP_SessionId(sess_id), + ts_AVP_ResultCode(DIAMETER_SUCCESS), /* optional */ + ts_AVP_AuthSessionState(NO_STATE_MAINTAINED), + ts_AVP_OriginHost("hss.localdomain"), + ts_AVP_OriginRealm("localdomain"), + ts_AVP_3GPP_UlaFlags('00000002'O), + ts_AVP_3GPP_SubscriptionData(sub_data_content) + }); + + + +} |