diff --git a/library/DIAMETER_Templates.ttcn b/library/DIAMETER_Templates.ttcn index 450e01302..2cc298614 100644 --- a/library/DIAMETER_Templates.ttcn +++ b/library/DIAMETER_Templates.ttcn @@ -326,6 +326,51 @@ template (value) GenericAVP ts_AVP_AuthAppId(template (value) OCTET4 auth_app_id } } } +template (present) GenericAVP tr_AVP_AuthAppId(template (present) OCTET4 auth_app_id := ?) := { + avp := { + avp_header := tr_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_CcReqType(template (value) DCC_NONE_CC_Request_Type r) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_DCC_NONE_CC_Request_Type), + avp_data := { + avp_DCC_NONE_CC_Request_Type := r + } + } +} +template (present) GenericAVP tr_AVP_CcReqType(template (present) DCC_NONE_CC_Request_Type r := ?) := { + avp := { + avp_header := tr_DIA_Hdr(c_AVP_Code_DCC_NONE_CC_Request_Type), + avp_data := { + avp_DCC_NONE_CC_Request_Type := r + } + } +} + +template (value) GenericAVP ts_AVP_CcReqNum(template (value) AVP_Unsigned32 n) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_DCC_NONE_CC_Request_Number), + avp_data := { + avp_DCC_NONE_CC_Request_Number := n + } + } +} +template (present) GenericAVP tr_AVP_CcReqNum(template (present) AVP_Unsigned32 n := ?) := { + avp := { + avp_header := tr_DIA_Hdr(c_AVP_Code_DCC_NONE_CC_Request_Number), + avp_data := { + avp_DCC_NONE_CC_Request_Number := n + } + } +} + + + template (value) GenericAVP ts_AVP_SuppVendorIdRaw(uint32_t vendor_id) := { avp := { @@ -879,4 +924,43 @@ ts_DIA_ULA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, +/* RFC 4006 3.1. Credit-Control-Request (CCR) Command */ +template (present) PDU_DIAMETER +tr_DIA_CCR(template (present) DCC_NONE_CC_Request_Type req_type := INITIAL_REQUEST) +:= tr_DIAMETER(flags:='11000000'B, cmd_code:=Credit_Control, + app_id:=int2oct(c_DIAMETER_3GPP_Gx_AID, 4), + avps := superset( + tr_AVP_SessionId, + tr_AVP_OriginHost, + tr_AVP_OriginRealm, + tr_AVP_DestinationRealm, + tr_AVP_AuthAppId(int2oct(c_DIAMETER_3GPP_Gx_AID, 4)), + tr_AVP_CcReqType(req_type), + tr_AVP_CcReqNum(?) + )); + + +/* RFC 4006 3.2. Credit-Control-Answer (CCA) Command */ +template (value) PDU_DIAMETER +ts_DIA_CCA(template (value) UINT32 hbh_id, template (value) UINT32 ete_id, + template (value) octetstring sess_id, + template (value) DCC_NONE_CC_Request_Type req_type, + template (value) AVP_Unsigned32 req_num) + +:= ts_DIAMETER(flags:='01000000'B, cmd_code:=Credit_Control, + app_id:=int2oct(c_DIAMETER_3GPP_Gx_AID, 4), hbh_id:=hbh_id, ete_id:=ete_id, + avps := { + ts_AVP_SessionId(sess_id), + ts_AVP_ResultCode(DIAMETER_SUCCESS), + ts_AVP_OriginHost("pcrf.localdomain"), + ts_AVP_OriginRealm("localdomain"), + ts_AVP_AuthAppId(int2oct(c_DIAMETER_3GPP_Gx_AID, 4)), + ts_AVP_CcReqType(req_type), + ts_AVP_CcReqNum(req_num)//, + // qos + // default eps bearer qos + // supported features + // origin + }); + } diff --git a/pgw/PGW_Tests.ttcn b/pgw/PGW_Tests.ttcn index c99302c02..81e3552a5 100644 --- a/pgw/PGW_Tests.ttcn +++ b/pgw/PGW_Tests.ttcn @@ -12,22 +12,37 @@ import from UECUPS_Types all; import from DNS_Helpers all; + +import from DIAMETER_Types all; +import from DIAMETER_Templates all; +import from DIAMETER_Emulation all; + + modulepar { charstring mp_pgw_hostname := "127.0.0.3"; charstring mp_local_hostname_c := "127.0.0.1"; charstring mp_local_hostname_u := "127.0.0.1"; + charstring mp_run_prog_as_user := "laforge"; charstring mp_ping_hostname := "10.45.0.1"; + + charstring mp_pcrf_local_ip := "127.0.0.5"; + integer mp_pcrf_local_port := 3868; } /* main component, we typically have one per testcase */ type component PGW_Test_CT { var GTPv2_Emulation_CT vc_GTP2; port GTP2EM_PT TEID0; + + /* emulated PCRF */ + var DIAMETER_Emulation_CT vc_DIAMETER; + port DIAMETER_PT DIAMETER_UNIT; + port DIAMETEREM_PROC_PT DIAMETER_PROC; } /* per-session component; we typically have 1..N per testcase */ -type component PGW_Session_CT extends GTP2_ConnHdlr { +type component PGW_Session_CT extends GTP2_ConnHdlr, DIAMETER_ConnHdlr { var SessionPars g_pars; /* TEI (Data) local side */ @@ -91,6 +106,35 @@ type record BearerConfig { type function void_fn() runs on PGW_Session_CT; +friend function DiameterForwardUnitdataCallback(PDU_DIAMETER msg) +runs on DIAMETER_Emulation_CT return template PDU_DIAMETER { + DIAMETER_UNIT.send(msg); + return omit; +} + +friend function f_init_diameter(charstring id) runs on PGW_Test_CT { + var DIAMETEROps ops := { + create_cb := refers(DIAMETER_Emulation.ExpectedCreateCallback), + unitdata_cb := refers(DiameterForwardUnitdataCallback) + }; + var DIAMETER_conn_parameters pars := { + remote_ip := mp_pgw_hostname, + remote_sctp_port := -1, + local_ip := mp_pcrf_local_ip, + local_sctp_port := mp_pcrf_local_port, + origin_host := "pcrf.localdomain", + origin_realm := "localdomain", + vendor_app_id := c_DIAMETER_3GPP_Gx_AID + }; + vc_DIAMETER := DIAMETER_Emulation_CT.create(id); + map(vc_DIAMETER:DIAMETER, system:DIAMETER_CODEC_PT); + connect(vc_DIAMETER:DIAMETER_UNIT, self:DIAMETER_UNIT); + connect(vc_DIAMETER:DIAMETER_PROC, self:DIAMETER_PROC); + vc_DIAMETER.start(DIAMETER_Emulation.main(ops, pars, id)); + + f_diameter_wait_capability(DIAMETER_UNIT); +} + private function f_init() runs on PGW_Test_CT { var Gtp2EmulationCfg cfg := { gtpc_bind_ip := mp_local_hostname_c, @@ -105,6 +149,10 @@ private function f_init() runs on PGW_Test_CT { map(vc_GTP2:GTP2C, system:GTP2C); connect(vc_GTP2:TEID0, self:TEID0); vc_GTP2.start(GTPv2_Emulation.main(cfg)); + + if (mp_pcrf_local_ip != "") { + f_init_diameter(testcasename()); + } } function f_start_handler(void_fn fn, template (omit) SessionPars pars := omit) @@ -114,6 +162,12 @@ runs on PGW_Test_CT return PGW_Session_CT { vc_conn := PGW_Session_CT.create(id); connect(vc_conn:GTP2, vc_GTP2:CLIENT); connect(vc_conn:GTP2_PROC, vc_GTP2:CLIENT_PROC); + + if (isbound(vc_DIAMETER)) { + connect(vc_conn:DIAMETER, vc_DIAMETER:DIAMETER_CLIENT); + connect(vc_conn:DIAMETER_PROC, vc_DIAMETER:DIAMETER_PROC); + } + vc_conn.start(f_handler_init(fn, pars)); return vc_conn; } @@ -123,6 +177,9 @@ runs on PGW_Session_CT { if (isvalue(pars)) { g_pars := valueof(pars); } + if (DIAMETER_PROC.checkstate("Connected")) { + f_diameter_expect(g_pars.imsi); + } fn.apply(); } @@ -146,6 +203,28 @@ function f_gen_msisdn(integer suffix) return hexstring { return f_concat_pad(12, '49123'H, suffix); } +private altstep as_DIA_CCR(DCC_NONE_CC_Request_Type req_type) runs on PGW_Session_CT { + var PDU_DIAMETER rx_dia; + [] DIAMETER.receive(tr_DIA_CCR(req_type := req_type)) -> value rx_dia { + var template (omit) AVP avp; + var octetstring sess_id; + var AVP_Unsigned32 req_num; + + avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_BASE_NONE_Session_Id); + sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id); + + avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_DCC_NONE_CC_Request_Number); + req_num := valueof(avp.avp_data.avp_DCC_NONE_CC_Request_Number); + + DIAMETER.send(ts_DIA_CCA(rx_dia.hop_by_hop_id, rx_dia.end_to_end_id, sess_id, + req_type, req_num)); + } + [] DIAMETER.receive(PDU_DIAMETER:?) -> value rx_dia { + setverdict(fail, "Received unexpected DIAMETER ", rx_dia); + self.stop; + } +} + /* find TEID of given interface type (and optionally instance) */ private function f_find_teid(FullyQualifiedTEID_List list, @@ -228,6 +307,9 @@ private function f_create_session() runs on PGW_Session_CT { g2c.gtpcv2_pdu.createSessionRequest.userLocationInfo := ts_GTP2C_UserLocInfo(tai := tai, ecgi := ecgi); GTP2.send(g2c); + if (DIAMETER_PROC.checkstate("Connected")) { + as_DIA_CCR(INITIAL_REQUEST); + } alt { [] GTP2.receive(tr_GTP2C_CreateSessionResp(d_teid:=g_teic, cause:='10'O)) -> value rx { /* extract TEIDs */ @@ -283,6 +365,9 @@ private function f_delete_session(template (omit) OCT1 tx_cause := omit, teid_list := {}, bearer_id := 1); GTP2.send(g2c); + if (DIAMETER_PROC.checkstate("Connected")) { + as_DIA_CCR(TERMINATION_REQUEST); + } alt { [] GTP2.receive(tr_GTP2C_DeleteSessionResp(d_teid := exp_teid, cause := exp_cause)) { setverdict(pass); diff --git a/pgw/gen_links.sh b/pgw/gen_links.sh index 061d78c3d..a0f128114 100755 --- a/pgw/gen_links.sh +++ b/pgw/gen_links.sh @@ -44,12 +44,17 @@ DIR=$BASEDIR/osmo-uecups/ttcn3 FILES="UECUPS_CodecPort.ttcn UECUPS_CodecPort_CtrlFunct.ttcn UECUPS_CodecPort_CtrlFunctDef.cc UECUPS_Types.ttcn " gen_links $DIR $FILES +DIR=$BASEDIR/titan.ProtocolModules.DIAMETER_ProtocolModule_Generator/src +FILES="DIAMETER_EncDec.cc" +gen_links $DIR $FILES + DIR=../library FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPCP_Types.ttcn PAP_Types.ttcn " FILES+="GTP_CodecPort.ttcn GTP_CodecPort_CtrlFunct.ttcn GTP_CodecPort_CtrlFunctDef.cc GTP_Templates.ttcn " FILES+="GTPv2_PrivateExtensions.ttcn GTPv2_Templates.ttcn " FILES+="GTPv2_CodecPort.ttcn GTPv2_CodecPort_CtrlFunctDef.cc GTPv2_CodecPort_CtrlFunct.ttcn GTPv2_Emulation.ttcn " FILES+="DNS_Helpers.ttcn " +FILES+="DIAMETER_Types.ttcn DIAMETER_CodecPort.ttcn DIAMETER_CodecPort_CtrlFunct.ttcn DIAMETER_CodecPort_CtrlFunctDef.cc DIAMETER_Emulation.ttcn DIAMETER_Templates.ttcn " gen_links $DIR $FILES ignore_pp_results diff --git a/pgw/regen_makefile.sh b/pgw/regen_makefile.sh index f53150c99..adb582065 100755 --- a/pgw/regen_makefile.sh +++ b/pgw/regen_makefile.sh @@ -2,5 +2,6 @@ FILES="*.ttcn IPL4asp_PT.cc IPL4asp_discovery.cc TCCConversion.cc TCCInterface.cc GTPC_EncDec.cc GTPU_EncDec.cc GTP_CodecPort_CtrlFunctDef.cc GTPv2_CodecPort_CtrlFunctDef.cc ICMPv6_EncDec.cc IP_EncDec.cc Native_FunctionDefs.cc UDP_EncDec.cc ICMP_EncDec.cc " FILES+="UECUPS_CodecPort_CtrlFunctDef.cc " +FILES+="DIAMETER_EncDec.cc DIAMETER_CodecPort_CtrlFunctDef.cc " ../regen-makefile.sh PGW_Tests.ttcn $FILES