diff --git a/epdg/EPDG_Tests.ttcn b/epdg/EPDG_Tests.ttcn index ff026cff6..44dc80fcf 100644 --- a/epdg/EPDG_Tests.ttcn +++ b/epdg/EPDG_Tests.ttcn @@ -46,6 +46,10 @@ modulepar { integer mp_s2b_local_port := GTP2C_PORT; charstring mp_s2b_remote_ip := "127.0.0.1"; integer mp_s2b_remote_port := GTP2C_PORT; + charstring mp_s2b_dns_ipv4 := "1.2.3.4"; + charstring mp_s2b_dns_ipv6 := "::1"; + charstring mp_s2b_pcscf_ipv4 := "5.6.7.8"; + charstring mp_s2b_pcscf_ipv6 := "::2"; charstring mp_diam_realm := "localdomain"; integer mp_diam_watchdog_initial_wait_sec := 6*3; @@ -433,6 +437,45 @@ private function f_S6b_ST_success() runs on EPDG_ConnHdlr { } } +private function f_exp_tr_GTP2C_APCO_in_CreateSessionReq() + runs on EPDG_ConnHdlr return template (present) APCO { + var template ProtocolIDs_and_ContainerIDs protos, protosV4, protosV6, protosV46; + protosV4 := {tr_GTP2C_PCO_P_DNS_IPv4(''O), tr_GTP2C_PCO_P_PCSCF_IPv4(''O)}; + protosV6 := {tr_GTP2C_PCO_P_DNS_IPv6(''O), tr_GTP2C_PCO_P_PCSCF_IPv6(''O)}; + protosV46 := {tr_GTP2C_PCO_P_DNS_IPv4(''O), tr_GTP2C_PCO_P_PCSCF_IPv4(''O), + tr_GTP2C_PCO_P_DNS_IPv6(''O), tr_GTP2C_PCO_P_PCSCF_IPv6(''O)} + /* TODO: pick proto based on req_type v4, v6 or v4v6 */ + protos := protosV4; + return tr_GTP2C_APCO('0000'B, protos); +} + +private function f_GTPv2C_gen_APCO_response(APCO apco_req) runs on EPDG_ConnHdlr return template (value) APCO { + var ProtocolIDs_and_ContainerIDs proto_list_resp := {}; + + for (var integer i := 0; i < lengthof(apco_req.protocolIDs_and_ContainerIDs); i := i + 1) { + var ProtocolID_or_ContainerID proto_req := apco_req.protocolIDs_and_ContainerIDs[i]; + select (proto_req.protocolID_or_ContainerID) { + case (PCO_P_to_OCT2(PCO_P_DNS_IPv4_ADDR)) { + proto_list_resp := proto_list_resp & { valueof(ts_GTP2C_PCO_P_DNS_IPv4(f_inet_addr(mp_s2b_dns_ipv4))) }; + } + case (PCO_P_to_OCT2(PCO_P_DNS_IPv6_ADDR)) { + proto_list_resp := proto_list_resp & { valueof(ts_GTP2C_PCO_P_DNS_IPv6(f_inet_addr(mp_s2b_dns_ipv6))) }; + } + case (PCO_P_to_OCT2(PCO_P_PCSCF_IPv4_ADDR)) { + proto_list_resp := proto_list_resp & { valueof(ts_GTP2C_PCO_P_PCSCF_IPv4(f_inet_addr(mp_s2b_pcscf_ipv4))) }; + } + case (PCO_P_to_OCT2(PCO_P_PCSCF_ADDR)) { + proto_list_resp := proto_list_resp & { valueof(ts_GTP2C_PCO_P_PCSCF_IPv6(f_inet_addr(mp_s2b_pcscf_ipv6))) }; + } + case else { + log("Ignoring unknown PCO Protocol ID: ", proto_req); + } + } + } + + return ts_GTP2C_APCO(apco_req.instance, proto_list_resp); +} + /* ePDG Creates session at the PGW. PGW sends Diameter s6b AAR + AAA. */ private altstep as_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr { var PDU_GTPCv2 rx_msg; @@ -441,7 +484,7 @@ private altstep as_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr { var template (value) PDN_AddressAllocation paa; var template (value) BearerContextIEs bctx_ies; - [] GTP2.receive(tr_GTP2C_CreateSessionReq(g_pars.imsi)) -> value rx_msg { + [] GTP2.receive(tr_GTP2C_CreateSessionReq(g_pars.imsi, apco := f_exp_tr_GTP2C_APCO_in_CreateSessionReq())) -> value rx_msg { /* Parse TEIC and Bearer EBI and TEID and store it in g_pars */ g_pars.teic_remote := rx_msg.gtpcv2_pdu.createSessionRequest.fullyQualifiedTEID[0].tEID_GRE_Key; rx_bctx_ies := rx_msg.gtpcv2_pdu.createSessionRequest.bearerContextGrouped[0].bearerContextIEs; @@ -466,7 +509,8 @@ private altstep as_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr { charging_id := ts_GTP2C_ChargingID(g_pars.teic_local)); GTP2.send(ts_GTP2C_CreateSessionResp(g_pars.teic_remote, rx_msg.sequenceNumber, { fteid_c_ie }, paa, - { ts_GTP2C_BcGrouped(bctx_ies) } )); + { ts_GTP2C_BcGrouped(bctx_ies) }, + f_GTPv2C_gen_APCO_response(rx_msg.gtpcv2_pdu.createSessionRequest.aPCO) )); setverdict(pass); } [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg { @@ -605,15 +649,20 @@ private function f_GSUP_EPDGTunnel_success() runs on EPDG_ConnHdlr { GSUP.send(ts_GSUP_EPDGTunnel_REQ(g_pars.imsi, pco)); as_GTP2C_CreateSession_success(); /* Expect a positive response back to the translator; */ - var template (present) GSUP_IEs pdp_info := { + var template (present) GSUP_IEs exp_pdp_info := { tr_GSUP_IE_PDP_CONTEXT_ID(?), tr_GSUP_IE_PDP_ADDRESS(tr_GSUP_PDP_Address_IPv4(f_inet_addr(g_pars.ue_ip))), tr_GSUP_IE_APN(f_enc_dns_hostname(g_pars.apn)), tr_GSUP_IE_PDP_QOS(?), tr_GSUP_IE_Charging_Characteristics(?) }; + var template (present) PCO_DATA exp_pco := tr_PCO({ + tr_PCO_P_DNS_IPv4(f_inet_addr(mp_s2b_dns_ipv4)), + tr_PCO_P_PCSCF_IPv4(f_inet_addr(mp_s2b_pcscf_ipv4)) + }); + /* TODO: check for v6 and v4v6 types ^ */ alt { - [] GSUP.receive(tr_GSUP_EPDGTunnel_RES(g_pars.imsi, pdp_info)); + [] GSUP.receive(tr_GSUP_EPDGTunnel_RES(g_pars.imsi, exp_pdp_info)); [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup { Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup)); } diff --git a/library/GSUP_Templates.ttcn b/library/GSUP_Templates.ttcn index d8860885c..9daf9c04c 100644 --- a/library/GSUP_Templates.ttcn +++ b/library/GSUP_Templates.ttcn @@ -301,6 +301,14 @@ template (value) GSUP_IE ts_GSUP_IE_PCO(template (value) PCO_DATA pco) := { } } +template (present) GSUP_IE tr_GSUP_IE_PCO(template (present) PCO_DATA pco := ?) := { + tag := OSMO_GSUP_PCO_IE, + len := ?, + val := { + pco := pco + } +} + template GSUP_PDU tr_GSUP(template GSUP_MessageType msgt := ?, template GSUP_IEs ies := *) := { msg_type := msgt, ies := ies @@ -536,6 +544,7 @@ template (value) GSUP_PDU ts_GSUP_EPDGTunnel_RES(hexstring imsi, template (present) GSUP_PDU tr_GSUP_EPDGTunnel_RES(template (present) hexstring imsi, template (present) GSUP_IEs pdp_info, + template (present) PCO_DATA pco := ?, template (present) GSUP_Message_Class message_class := OSMO_GSUP_MESSAGE_CLASS_IPSEC_EPDG, template octetstring destination_name := omit) := tr_GSUP(OSMO_GSUP_MSGT_EPDG_TUNNEL_RESULT, @@ -543,6 +552,7 @@ template (present) GSUP_PDU tr_GSUP_EPDGTunnel_RES(template (present) hexstring pdp_info_compl := true, pdp_info := pdp_info, message_class := message_class, + pco := pco, destination_name := destination_name)); template (value) GSUP_PDU ts_GSUP_EPDGTunnel_ERR(hexstring imsi, @@ -1229,6 +1239,7 @@ private function f_gen_tr_ies(template hexstring imsi, template GSUP_CancelType cancel_type := omit, template hexstring msisdn := omit, template GSUP_IMEIResult imei_result := omit, + template PCO_DATA pco := omit, template GSUP_CnDomain cn_domain := omit, template octetstring source_name := omit, template octetstring destination_name := omit @@ -1278,6 +1289,11 @@ private function f_gen_tr_ies(template hexstring imsi, idx := idx + 1; } + if (not istemplatekind(pco, "omit")) { + ies[idx] := tr_GSUP_IE_PCO(pco); + idx := idx + 1; + } + if (not istemplatekind(source_name, "omit")) { ies[idx] := tr_GSUP_IE_Source_Name(source_name); idx := idx + 1; diff --git a/library/PCO_Types.ttcn b/library/PCO_Types.ttcn index 22b475a2c..0eaa45e49 100644 --- a/library/PCO_Types.ttcn +++ b/library/PCO_Types.ttcn @@ -48,6 +48,10 @@ type enumerated PCO_P { } with { variant "FIELDLENGTH(16)"; variant "BYTEORDER(last)" }; +function PCO_P_to_OCT2(PCO_P p) return OCT2 { + return int2oct(enum2int(p), 2); +} + /* RFC 1332 IP Control Protocol options, extensions in RFC 1877 */ type enumerated IPCP_OPT { IPCP_OPT_IPADDR (3), /* RFC 1332 3.3 */ @@ -108,15 +112,23 @@ template (present) ProtocolElement tr_PCO_P_OCTSTR(template (present) PCO_P prot template (value) ProtocolElement ts_PCO_P_DNS_IPv4(template (value) octetstring dns4 := ''O) := ts_PCO_P_OCTSTR(PCO_P_DNS_IPv4_ADDR, protoIDContents := dns4); +template (present) ProtocolElement tr_PCO_P_DNS_IPv4(template (present) octetstring dns4 := ?) := + tr_PCO_P_OCTSTR(PCO_P_DNS_IPv4_ADDR, protoIDContents := dns4); template (value) ProtocolElement ts_PCO_P_DNS_IPv6(template (value) octetstring dns6 := ''O) := ts_PCO_P_OCTSTR(PCO_P_DNS_IPv6_ADDR, protoIDContents := dns6); +template (present) ProtocolElement tr_PCO_P_DNS_IPv6(template (present) octetstring dns6 := ?) := + tr_PCO_P_OCTSTR(PCO_P_DNS_IPv6_ADDR, protoIDContents := dns6); template (value) ProtocolElement ts_PCO_P_PCSCF_IPv4(template (value) octetstring pcscf4 := ''O) := ts_PCO_P_OCTSTR(PCO_P_PCSCF_IPv4_ADDR, protoIDContents := pcscf4); +template (present) ProtocolElement tr_PCO_P_PCSCF_IPv4(template (present) octetstring pcscf4 := ?) := + tr_PCO_P_OCTSTR(PCO_P_PCSCF_IPv4_ADDR, protoIDContents := pcscf4); template (value) ProtocolElement ts_PCO_P_PCSCF_IPv6(template (value) octetstring pcscf6 := ''O) := ts_PCO_P_OCTSTR(PCO_P_PCSCF_ADDR, protoIDContents := pcscf6); +template (present) ProtocolElement tr_PCO_P_PCSCF_IPv6(template (present) octetstring pcscf6 := ?) := + tr_PCO_P_OCTSTR(PCO_P_PCSCF_ADDR, protoIDContents := pcscf6); /* PCO send base template */ template (value) PCO_DATA ts_PCO(template (value) ProtocolIDList protocols := {}) := {