gerrit-log
Threads by month
- ----- 2026 -----
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
July 2025
- 1 participants
- 1492 discussions
[M] Change in osmo-ttcn3-hacks[master]: pgw: Move to library/ high level APIs to run commands over UECUPS
by pespin 29 Jul '25
by pespin 29 Jul '25
29 Jul '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40753?usp=email )
Change subject: pgw: Move to library/ high level APIs to run commands over UECUPS
......................................................................
pgw: Move to library/ high level APIs to run commands over UECUPS
This way the code can be reused by other testsuites more easily.
Change-Id: I49c98fd423e47e16ddfb9ae4612b18db21ca3fa4
---
M library/GTPv1U_Emulation.ttcnpp
M pgw/PGW_Tests.ttcn
2 files changed, 98 insertions(+), 62 deletions(-)
Approvals:
pespin: Looks good to me, approved
Jenkins Builder: Verified
laforge: Looks good to me, but someone else must approve
osmith: Looks good to me, but someone else must approve
diff --git a/library/GTPv1U_Emulation.ttcnpp b/library/GTPv1U_Emulation.ttcnpp
index 8b76379..aa97210 100644
--- a/library/GTPv1U_Emulation.ttcnpp
+++ b/library/GTPv1U_Emulation.ttcnpp
@@ -389,6 +389,89 @@
}
return res;
}
+
+/***********************************************************************
+ * High level APIs for user convenience
+ ***********************************************************************/
+/* start a program on the user plane side; return its PID */
+function f_gtp1u_start_prog(UECUPS_StartProgram sprog,
+ boolean redirect_output := false,
+ charstring redirect_output_path_prefix := "gtp1u_run_prog",
+ integer port_idx := 0)
+runs on GTP1U_ConnHdlr return integer
+{
+ var charstring cmd := sprog.command;
+ /* Redirect stdout/stderr to the user-specified location */
+ if (redirect_output) {
+ sprog.command := sprog.command & " 1>>" & redirect_output_path_prefix & ".prog.stdout";
+ sprog.command := sprog.command & " 2>>" & redirect_output_path_prefix & ".prog.stderr";
+ }
+
+ log("Starting a program: ", cmd);
+ var UECUPS_StartProgramRes res := f_gtp1u_start_program(sprog, port_idx := port_idx);
+ if (res.result != OK) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Unable to start program '", cmd, "'"));
+ }
+ log("Started program '", cmd, "' with PID ", res.pid);
+ return res.pid;
+}
+
+/* wait for termination of a given PID with specified exit_code */
+function f_gtp1u_wait_term(integer pid, template (present) integer exit_code := 0,
+ float tout := 10.0,
+ integer port_idx := 0) runs on GTP1U_ConnHdlr
+{
+ var UECUPS_ProgramTermInd pti;
+ timer T := tout;
+
+ T.start;
+ alt {
+ [] GTP1U[port_idx].receive(UECUPS_ProgramTermInd:{pid := pid, exit_code := exit_code}) {
+ setverdict(pass);
+ }
+ [] GTP1U[port_idx].receive(UECUPS_ProgramTermInd:?) -> value pti {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("Received unexpected ProgramTermInd := ", pti));
+ }
+ [] T.timeout {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("timeout (", tout, " seconds) waiting for user-plane program PID ", pid, " termination"));
+ }
+ }
+}
+
+/* execute a program and wait for result */
+function f_gtp1u_start_prog_wait(UECUPS_StartProgram sprog,
+ template (present) integer exit_code := 0,
+ float tout := 10.0,
+ boolean redirect_output := false,
+ charstring redirect_output_path_prefix := "gtp1u_run_prog",
+ integer port_idx := 0)
+runs on GTP1U_ConnHdlr
+{
+ var integer pid := f_gtp1u_start_prog(sprog, redirect_output, redirect_output_path_prefix, port_idx);
+ f_gtp1u_wait_term(pid, exit_code, tout, port_idx);
+}
+
+/* execute ping command and wait for result. sprog.command is filled in based on params. */
+function f_gtp1u_ping4(UECUPS_StartProgram sprog,
+ charstring host, integer interval := 1, integer count := 10,
+ template (omit) charstring src_ip := omit,
+ boolean redirect_output := false,
+ charstring redirect_output_path_prefix := "gtp1u_run_prog",
+ integer port_idx := 0) runs on GTP1U_ConnHdlr
+{
+ var charstring ping :="ping -c " & int2str(count) & " -i " & int2str(interval);
+
+ if (isvalue(src_ip)) {
+ ping := ping & " -I " & valueof(src_ip);
+ }
+ ping := ping & " " & host;
+ sprog.command := ping;
+ f_gtp1u_start_prog_wait(sprog, 0, int2float(5 + interval*count),
+ redirect_output, redirect_output_path_prefix, port_idx);
+}
#endif
}
diff --git a/pgw/PGW_Tests.ttcn b/pgw/PGW_Tests.ttcn
index 16ac9ee..c63568e 100644
--- a/pgw/PGW_Tests.ttcn
+++ b/pgw/PGW_Tests.ttcn
@@ -898,9 +898,8 @@
}
}
-/* start a program on the user plane side; return its PID */
-private function f_start_prog(charstring command, boolean redirect_output := true)
-runs on PGW_Session_CT return integer
+
+private function f_run_prog_init(charstring command) runs on PGW_Session_CT return UECUPS_StartProgram
{
var UECUPS_StartProgram sprog := {
command := command,
@@ -908,76 +907,30 @@
run_as_user := mp_run_prog_as_user,
tun_netns_name := g_pars.tun_netns_name
};
+ return sprog;
+}
+
+private function f_run_prog_unique_log_path() runs on PGW_Session_CT return charstring
+{
+ var charstring id := testcasename() & "-" & hex2str(g_pars.imsi) & "-" & int2str(g_start_prog_count);
+ var charstring prefix := mp_run_prog_log_path & "/" & id;
g_start_prog_count := g_start_prog_count + 1;
-
- /* Redirect stdout/stderr to the user-specified location */
- if (redirect_output) {
- var charstring id := testcasename() & "-" & hex2str(g_pars.imsi) & "-" & int2str(g_start_prog_count);
- var charstring prefix := mp_run_prog_log_path & "/" & id;
- sprog.command := sprog.command & " 1>>" & prefix & ".prog.stdout";
- sprog.command := sprog.command & " 2>>" & prefix & ".prog.stderr";
- }
-
- log("Starting a program: ", command);
- var UECUPS_StartProgramRes res := f_gtp1u_start_program(sprog);
- if (res.result != OK) {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
- log2str("Unable to start program '", command, "'"));
- }
- log("Started program '", command, "' with PID ", res.pid);
- return res.pid;
-}
-
-/* wait for termination of a given PID with specified exit_code */
-private function f_wait_term(integer pid, template (present) integer exit_code := 0,
- float tout := 10.0) runs on PGW_Session_CT
-{
- var UECUPS_ProgramTermInd pti;
- timer T := tout;
-
- T.start;
- alt {
- [] GTP1U[0].receive(UECUPS_ProgramTermInd:{pid := pid, exit_code := exit_code}) {
- setverdict(pass);
- }
- [] GTP1U[0].receive(UECUPS_ProgramTermInd:?) -> value pti {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
- log2str("Received unexpected ProgramTermInd := ", pti));
- }
- [] T.timeout {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
- log2str("timeout (", tout, " seconds) waiting for user-plane program PID ", pid, " termination"));
- }
- }
-}
-
-/* execute a program and wait for result */
-private function f_start_prog_wait(charstring command,
- template integer exit_code := 0,
- float tout := 10.0,
- boolean redirect_output := true)
-runs on PGW_Session_CT
-{
- var integer pid := f_start_prog(command, redirect_output);
- f_wait_term(pid, exit_code, tout);
+ return prefix;
}
/* execute ping command and wait for result */
private function f_ping4(charstring host, integer interval := 1, integer count := 10) runs on PGW_Session_CT
{
- var charstring ping :="ping -c " & int2str(count) & " -i " & int2str(interval);
-
if (not isbound(g_ip4_addr)) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "f_ping4(): g_ip4_addr is unset!");
}
- ping := ping & " -I " & f_inet_ntoa(g_ip4_addr);
- ping := ping & " " & host;
- f_start_prog_wait(ping, tout := int2float(5 + interval*count));
+ /* command will be filled in by f_gtp1u_ping4() below: */
+ var UECUPS_StartProgram sprog := f_run_prog_init("");
+ f_gtp1u_ping4(sprog, host, interval, count, f_inet_ntoa(g_ip4_addr),
+ redirect_output := true,
+ redirect_output_path_prefix := f_run_prog_unique_log_path());
}
-
-
-
/* send echo request; expect response */
testcase TC_tx_echo() runs on PGW_Test_CT {
timer T := 5.0;
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40753?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I49c98fd423e47e16ddfb9ae4612b18db21ca3fa4
Gerrit-Change-Number: 40753
Gerrit-PatchSet: 3
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
29 Jul '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40752?usp=email )
Change subject: Move ConnHdlr logic to its own file
......................................................................
Move ConnHdlr logic to its own file
Similar to what we do in other testsuites, since we start to have
considrable amount of logic.
Change-Id: If7edf8ee63c71fbf949e2d340cf3881fd8e3ba41
---
M 5gc/C5G_Tests.ttcn
A 5gc/ConnHdlr.ttcn
2 files changed, 375 insertions(+), 324 deletions(-)
Approvals:
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
laforge: Looks good to me, but someone else must approve
diff --git a/5gc/C5G_Tests.ttcn b/5gc/C5G_Tests.ttcn
index 3b84a58..f09b364 100644
--- a/5gc/C5G_Tests.ttcn
+++ b/5gc/C5G_Tests.ttcn
@@ -45,13 +45,11 @@
import from NG_NAS_Functions all;
import from NG_CryptoFunctions all;
-/* (maximum) number of emulated eNBs */
-const integer NUM_NGRAN := 1;
+import from ConnHdlr all;
/* (maximum) number of emulated UEs */
const integer NUM_UE := 1;
-
modulepar {
/* NG-C interface */
charstring mp_5gc_ngap_ip := "127.0.0.1";
@@ -68,35 +66,13 @@
charstring mp_local_gtpu_ip := "127.0.0.1";
}
-/* parameters of emulated gNB / ng-eNB */
-type record NGRANParams {
- GlobalRANNodeID global_ngran_id,
- NGRAN_CGI cell_identity,
- SupportedTAList supported_ta_list
-}
-
-/* parameters of emulated UE */
-type record UeParams {
- HEX15n imsi,
- HEX16n imeisv,
- octetstring usim_key,
- octetstring usim_opc,
- charstring ran_gtpu_ip,
- OCT4 ran_gtpu_teid,
- charstring cn_gtpu_ip optional,
- OCT4 cn_gtpu_teid optional,
- charstring ue_ip optional,
- OCT32 kausf optional,
- OCT32 kseaf optional,
- OCT32 kamf optional
-}
-
template (value) UeParams ts_UeParams(integer imsi_suffix) :=
{
imsi := f_concat_pad(lengthof(mp_imsi), substr(mp_imsi, 0, lengthof(mp_imsi) - 6), imsi_suffix),
imeisv := f_rnd_imeisv(),
usim_key := mp_usim_key,
usim_opc := mp_usim_opc,
+ apn := mp_apn,
ran_gtpu_ip := mp_local_gtpu_ip,
ran_gtpu_teid := int2oct(imsi_suffix, 4),
cn_gtpu_ip := omit,
@@ -119,21 +95,6 @@
var UeParams g_ue_pars[NUM_UE];
}
-type component ConnHdlr extends NGAP_ConnHdlr {
- var ConnHdlrPars g_pars;
-}
-
-type record ConnHdlrPars {
- /* copied over from MTC_CT on start of component */
- NGRANParams ngran_pars[NUM_NGRAN],
- /* copied over from MTC_CT on start of component */
- UeParams ue_pars,
- /* currently used 5GC (index into ngran_pars, NGAP, ...) */
- integer c5g_idx,
- /* Currently set KSI */
- NAS_KeySetIdentifier kset_id
-}
-
/* send incoming unit data messages (like reset) to global NGAP_UNIT port */
private function NGapForwardUnitdataCallback(NGAP_PDU msg)
runs on NGAP_Emulation_CT return template NGAP_PDU {
@@ -213,8 +174,6 @@
return pars;
}
-type function void_fn() runs on ConnHdlr;
-
/* start a connection handler with given parameters */
private function f_start_handler_with_pars(void_fn fn, ConnHdlrPars pars, integer ngap_idx := 0)
runs on MTC_CT return ConnHdlr {
@@ -245,44 +204,6 @@
fn.apply();
}
-private template (value) NGAP_IEs.TAI ts_ngran_NGAP_TAI(NGRANParams ngran_pars) := {
- pLMNIdentity := ngran_pars.global_ngran_id.globalGNB_ID.pLMNIdentity,
- tAC := ngran_pars.supported_ta_list[0].tAC,
- iE_Extensions := omit
-}
-
-private function f_imsi_plmn_id() runs on ConnHdlr return PLMNIdentity {
- var hexstring imsi := g_pars.ue_pars.imsi;
- var GsmMcc mcc := substr(imsi, 0, 3);
- var GsmMnc mnc := substr(imsi, 3, 2);
- return f_enc_mcc_mnc(mcc, mnc);
-}
-
-private function f_SUCI_IMSI() runs on ConnHdlr return octetstring {
- var hexstring imsi := g_pars.ue_pars.imsi;
- var PLMNIdentity plmn_id := f_imsi_plmn_id();
- var octetstring imsi_suffix := imsi_hex2oct(substr(imsi, lengthof(imsi) - 10, 10));
- return plmn_id & '21430001'O & imsi_suffix;
-}
-
-private function f_UE_SecurityCapability() runs on ConnHdlr return NG_UE_SecurityCapability {
- var template (value) NG_UE_SecurityCapability ue_sec_cap;
- ue_sec_cap := cs_NG_UE_SecurityCapabilityTLV(ngeaCap := '80'O, /* ONLY NEA0 (no encryption) for now */
- ngiaCap := '40'O /* ONLY NIA1 supported */);
- return valueof(ue_sec_cap);
-}
-
-private function f_ULI() runs on ConnHdlr return UserLocationInformation {
- var template (value) UserLocationInformation p_ueLocInf
- p_ueLocInf := m_uPTransportLayerInformation_userLocationInformationNR(
- m_userLocationInformationNR(
- g_pars.ngran_pars[g_pars.c5g_idx].cell_identity.nR_CGI,
- ts_ngran_NGAP_TAI(g_pars.ngran_pars[g_pars.c5g_idx])
-
- ));
- return valueof(p_ueLocInf);
-}
-
private function f_ngap_setup(integer idx := 0, template (omit) NGAP_IEs.Cause cause := omit) runs on MTC_CT {
var template (present) NGAP_IEs.Cause exp_cause := ?;
var boolean exp_fail := false;
@@ -323,249 +244,6 @@
}
}
-private function f_tr_ConnHdlr_kset_id() runs on ConnHdlr return template (present) NAS_KeySetIdentifier {
- /* KSI not yet set, expect whatever assignment from network: */
- if (g_pars.kset_id.nasKeySetId == tsc_NasKsi_NoKey) {
- return cr_NAS_KeySetIdentifier(?, ?);
- } else {
- /* Expect specific kset_id. Upon transmitting it UE->Network, f_attach()
- * has updated it to the expected value. */
- return g_pars.kset_id;
- }
-}
-
-/* 3GPP TS 24.501 5.4.1.3.2, 3GPP TS 33.501 6.1.3.2 */
-private altstep as_ngap_handle_auth(boolean allow_resync := true) runs on ConnHdlr {
- var NG_NAS_DL_Message_Type rx_nas;
- var template (present) NAS_KeySetIdentifier kset_id := f_tr_ConnHdlr_kset_id();
- [] NGAP.receive(cr_NG_AUTHENTICATION_REQUEST) -> value rx_nas {
- var integer ret;
- var integer my_sqn := 0; /* TODO: move to a ConnHdlr state attribute? */
- var OCT16 rand := bit2oct(rx_nas.authentication_Request.rand.randValue);
- var OCT16 autn := bit2oct(rx_nas.authentication_Request.autn.aUTN);
- var OCT2 abba := rx_nas.authentication_Request.abba.abbaValue;
- var OCT16 ik;
- var OCT16 ck;
- var OCT8 res;
- var OCT14 auts;
-
- g_pars.kset_id := rx_nas.authentication_Request.ngNasKeySetId;
-
- ret := f_milenage_check(g_pars.ue_pars.usim_key,
- g_pars.ue_pars.usim_opc,
- int2oct(my_sqn, 8),
- rand, autn, ik, ck, res, auts);
- if (ret == -1) {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
- log2str("fx_milenage_check() failed! -1"));
- }
- if (ret == -2) {
- if (not allow_resync) {
- Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
- log2str("fx_milenage_check() unexpected Resync!"));
- }
- log("Milenage: RX-SQN differs from SIM SQN: Re-Sync! AUTS=", auts);
- /* 3GPP TS 24.501 5.4.1.3.6 d) */
- NGAP.send(cs_NG_AUTHENTICATION_FAILURE(cs_GMM_GSM_Cause(omit, int2bit(21, 8)),
- cs_AuthFailParam(oct2bit(auts))));
- as_ngap_handle_auth(allow_resync := false);
- return;
- }
-
- var octetstring ssn := f_NG_NAS_ServingNetworkName_OCT(f_imsi_plmn_id(), omit);
- g_pars.ue_pars.kausf := f_kdf_kausf(ck, ik, ssn, autn);
- g_pars.ue_pars.kseaf := f_kdf_kseaf(g_pars.ue_pars.kausf, ssn);
- g_pars.ue_pars.kamf := f_kdf_kamf(g_pars.ue_pars.kseaf, char2oct(hex2str(g_pars.ue_pars.imsi)), abba);
-
- var NGAPEM_Config cfg := {
- set_nas_keys := {
- k_nas_int := f_kdf_ng_nas_int(g_pars.ue_pars.kamf, NG_NAS_ALG_IP_NIA1),
- k_nas_enc := f_kdf_ng_nas_enc(g_pars.ue_pars.kamf, NG_NAS_ALG_ENC_NEA0)
- }
- };
- NGAP.send(cfg);
-
- /* Derive (X)RES* from (X)RES, 3GPP TS 33.501 A.4 */
- var OCT16 res_star := f_kdf_xres_star(ssn, ck, ik, rand, res);
- NGAP.send(cs_NG_AUTHENTICATION_RESPONSE(cs_AuthenticationResponseParameter(oct2bit(res_star))));
- }
-}
-
-private altstep as_ngap_handle_sec_mode() runs on ConnHdlr {
- var NGAPEM_Config cfg;
- var NG_NAS_DL_Message_Type rx_nas;
- /* Make sure network selected specific algos we requested: */
- var template (present) NG_UE_SecurityCapability ue_sec_cap :=
- cr_NG_UE_SecurityCapabilityLV(ngeaCap := '80'O, /* ONLY NEA0 (no encryption) for now */
- ngiaCap := '40'O /* ONLY NIA1 supported */);
-
- [] NGAP.receive(cr_NG_SECURITY_MODE_COMMAND(p_UECap := ue_sec_cap)) -> value rx_nas {
- /* Configure integrity protection: */
- cfg := {
- set_nas_alg_int := NG_NAS_ALG_IP_NIA1
- };
- NGAP.send(cfg);
- /* Configure Ciphering: */
- cfg := {
- set_nas_alg_enc := NG_NAS_ALG_ENC_NEA0
- };
- NGAP.send(cfg);
-
- var template (value) NG_NAS_UL_Message_Type nas_ul_msg;
- var NAS_PDU nas_pdu;
- nas_ul_msg := cs_NG_REGISTRATION_REQUEST(cs_RegistrationType(tsc_NG_RegistrationInitial, '1'B),
- g_pars.kset_id.nasKeySetId,
- g_pars.kset_id.tsc,
- cs_NG_MobileIdentitySUCI('0000'B /* Type IMSI */,
- f_SUCI_IMSI()),
- p_UESecurityCap := f_UE_SecurityCapability());
- nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg));
- NGAP.send(cs_NG_SECURITY_MODE_COMPLETE(cs_NG_MobileIdentityTLV_IMEISV(hex2oct(g_pars.ue_pars.imeisv)),
- cs_ReplayedNASMessageContainerTLV(nas_pdu)));
- }
-}
-
-private altstep as_ngap_handle_configuration_update() runs on ConnHdlr {
- var NG_NAS_DL_Message_Type rx_nas;
-
- [] NGAP.receive(cr_NG_CONFIGURATION_UPDATE_COMMAND) -> value rx_nas {
- NGAP.send(cs_NG_CONFIGURATION_UPDATE_COMPLETE);
- }
-}
-
-/* Handle a PDUSessionResourceSetupRequestTransfer contained inside NGAP InitialContextSetupRequest and return a Result for InitialContextSetupResponse */
-private function f_pdu_handle_session_resource_setup_item(PDUSessionResourceSetupItemCxtReq req) runs on ConnHdlr return PDUSessionResourceSetupItemCxtRes
-{
- var PDUSessionResourceSetupItemCxtRes resp;
- var octetstring setup_trans_enc;
- var NGAP_IEs.PDUSessionResourceSetupRequestTransfer setup_req_transf;
- var NGAP_IEs.PDUSessionResourceSetupResponseTransfer setup_resp_transf;
- var template (value) UPTransportLayerInformation utla;
- var template (value) QosFlowPerTNLInformation qos;
-
- /* Parse PDUSessionResourceSetupRequestTransfer contained inside InitialContextSetupRequest's PDUSessionResourceSetup Item: */
- setup_req_transf := dec_NGAP_PDUSessionResourceSetupRequestTransfer(req.pDUSessionResourceSetupRequestTransfer);
- for (var integer i := 0; i < lengthof(setup_req_transf.protocolIEs); i := i + 1) {
- if (setup_req_transf.protocolIEs[i].id == id_UL_NGU_UP_TNLInformation) {
- var UPTransportLayerInformation utli := setup_req_transf.protocolIEs[i].value_.uPTransportLayerInformation;
- g_pars.ue_pars.cn_gtpu_ip := f_inet_ntoa(bit2oct(utli.gTPTunnel.transportLayerAddress));
- g_pars.ue_pars.cn_gtpu_teid := utli.gTPTunnel.gTP_TEID;
- }
- }
-
- /* Prepare Response for it: */
- utla := m_uPTransportLayerInformation_gTPTunnel(
- m_gTPTunnel(p_tla := oct2bit(f_inet_addr(g_pars.ue_pars.ran_gtpu_ip)),
- p_gtp_teid := g_pars.ue_pars.ran_gtpu_teid));
- qos := m_qosFlowPerTNLInformation(utla, { m_associatedQosFlowItem(1) });
- setup_resp_transf := valueof(m_pDUSessionResourceSetupResponseTransfer(qos));
- setup_trans_enc := enc_NGAP_PDUSessionResourceSetupResponseTransfer(setup_resp_transf)
- resp := valueof(m_pDUSessionResourceSetupItemCxtRes(req.pDUSessionID, setup_trans_enc));
- return resp;
-}
-
-private function f_pdu_handle_session_resource_setup_list(PDUSessionResourceSetupListCxtReq li_req) runs on ConnHdlr return PDUSessionResourceSetupListCxtRes
-{
- var PDUSessionResourceSetupListCxtRes li_resp;
- for (var integer i := 0; i < lengthof(li_req); i := i + 1) {
- var PDUSessionResourceSetupItemCxtRes it_resp;
- it_resp := f_pdu_handle_session_resource_setup_item(li_req[i]);
- if (i == 0) { /* min 1 item in list doesn't allow previously allocating an empty list */
- li_resp := { it_resp };
- } else {
- li_resp := li_resp & { it_resp };
- }
- }
- return li_resp;
-}
-
-private altstep as_ngap_handle_InitialCtxReq_withPDUSessionList() runs on ConnHdlr {
- var NGAP_PDU rx_ngap;
-
- [] NGAP.receive(mw_ngap_initMsg(mw_n2_InitialContextSetupRequest_withPDUSessionList)) -> value rx_ngap {
- var AMF_UE_NGAP_ID amf_id := valueof(f_NGAP_get_AMF_UE_NGAP_ID(rx_ngap));
- var RAN_UE_NGAP_ID ran_id := valueof(f_NGAP_get_RAN_UE_NGAP_ID(rx_ngap));
- var InitialContextSetupRequest ctx_setup_req := rx_ngap.initiatingMessage.value_.initialContextSetupRequest;
- var PDUSessionResourceSetupListCxtRes resources;
-
- for (var integer i := 0; i < lengthof(ctx_setup_req.protocolIEs); i := i + 1) {
- if (ctx_setup_req.protocolIEs[i].id != id_PDUSessionResourceSetupListCxtReq) {
- continue;
- }
- var PDUSessionResourceSetupListCxtReq li := ctx_setup_req.protocolIEs[i].value_.pDUSessionResourceSetupListCxtReq;
- resources := f_pdu_handle_session_resource_setup_list(li);
- }
- NGAP.send(m_ngap_succMsg(m_n2_InitialContextSetupResponse(amf_id, ran_id, resources)));
- }
-}
-
-private function f_pdu_sess_establish() runs on ConnHdlr {
- var template (value) NG_NAS_UL_Message_Type nas_ul_msg;
- var NAS_PDU nas_pdu;
- var NG_NAS_DL_Message_Type rx_nas, inner_nas;
-
- nas_ul_msg := cs_NG_PDU_SESSION_ESTABLISHMENT_REQUEST(cs_NG_PDU_SessionIdV('01'O), '01'O,
- p_IntegrityProtMaxDataRate := cs_IntegrityProtMaxDataRateV('FF'O, 'FF'O),
- p_PDU_SessionType := cs_PDU_SessionTypeTV('001'B), /* IPv4 */
- p_SSC_Mode := cs_SSC_ModeTV('001'B));
- nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg));
- nas_ul_msg := cs_NG_UL_NAS_TRANSPORT(cs_PayloadContainerType(tsc_PayloadContainerESMMsg),
- cs_PayloadContainerLV(nas_pdu),
- p_PDU_SessionId := cs_NG_PDU_SessionIdTV('01'O),
- p_RequestType := cs_NG_Request_TypeTV('001'B),
- p_DNN := cs_DNN_TLV(f_enc_dns_hostname(mp_apn)));
- NGAP.send(nas_ul_msg);
- as_ngap_handle_InitialCtxReq_withPDUSessionList();
-
- /* PDU Session Establishment Accept: This DL NAS arrives contained in InitialCtxReq handled above: */
- NGAP.receive(cr_NG_DL_NAS_TRANSPORT) -> value rx_nas;
- inner_nas := f_dec_NG_NAS_DL_Message_Payload_Container(rx_nas.dl_Nas_Transport.payloadContainerType.container,
- rx_nas.dl_Nas_Transport.payload.payload);
- g_pars.ue_pars.ue_ip := f_inet_ntoa(inner_nas.pdu_Session_Establishment_Accept.pduAddress.adressInfo);
- log("5GC assigned CN GTPU Address: ", g_pars.ue_pars.cn_gtpu_ip, " TEID: ", g_pars.ue_pars.cn_gtpu_teid);
- log("5GC assigned UE IP address: ", g_pars.ue_pars.ue_ip);
-}
-
-private function f_register() runs on ConnHdlr {
- var template (value) NGAP_PDU tx_pdu;
- var template (value) NG_NAS_UL_Message_Type nas_ul_msg;
- var NAS_PDU nas_pdu;
- var NG_NAS_DL_Message_Type rx_nas;
-
- nas_ul_msg := cs_NG_REGISTRATION_REQUEST(cs_RegistrationType(tsc_NG_RegistrationInitial, '1'B),
- g_pars.kset_id.nasKeySetId,
- g_pars.kset_id.tsc,
- cs_NG_MobileIdentitySUCI('0000'B /* Type IMSI */,
- f_SUCI_IMSI()),
- p_UESecurityCap := f_UE_SecurityCapability());
- nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg));
- tx_pdu := m_ngap_initMsg(m_n2_initialUeMessage(g_pars.c5g_idx,
- nas_pdu, /* Registration request */
- f_ULI(),
- mo_Signalling));
- NGAP.send(tx_pdu);
-
- /* Expect updated KSI from network following 5G Core standards
- *(open5gs.git 70310979c58fe186e9eaa06bec9d9a31f24ff7a1): */
- if (g_pars.kset_id.nasKeySetId != tsc_NasKsi_NoKey) {
- if (g_pars.kset_id.nasKeySetId == '110'B) {
- g_pars.kset_id.nasKeySetId := '000'B;
- } else {
- g_pars.kset_id.nasKeySetId := int2bit(bit2int(g_pars.kset_id.nasKeySetId) + 1, 3);
- }
- }
-
- as_ngap_handle_auth();
- as_ngap_handle_sec_mode();
-
- NGAP.receive(cr_NG_REGISTRATION_ACCEPT) -> value rx_nas;
- NGAP.send(cs_NG_REGISTRATION_COMPLETE);
-
- as_ngap_handle_configuration_update();
-
- f_pdu_sess_establish();
-}
-
/* NG Setup procedure to 5GC using a Global gNB ID containing unknown/foreign PLMN.
* Related: https://github.com/open5gs/open5gs/issues/3544 */
testcase TC_ng_setup_unknown_global_gnb_id_plmn() runs on MTC_CT {
diff --git a/5gc/ConnHdlr.ttcn b/5gc/ConnHdlr.ttcn
new file mode 100644
index 0000000..65e6c9a
--- /dev/null
+++ b/5gc/ConnHdlr.ttcn
@@ -0,0 +1,373 @@
+/* 5GC (55G Core) test suite in TTCN-3, ConnHdlr
+ * (C) 2025 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * All rights reserved.
+ * Author: Pau Espin Pedrol <pespin(a)sysmocom.de>
+ *
+ * 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
+ */
+
+module ConnHdlr {
+
+import from General_Types all;
+import from Native_Functions all;
+import from IPL4asp_Types all;
+import from Misc_Helpers all;
+
+import from Osmocom_Types all;
+import from GSM_Types all;
+
+import from DNS_Helpers all;
+
+import from Milenage_Functions all;
+
+import from NGAP_PDU_Descriptions all;
+import from NGAP_IEs all;
+import from NGAP_PDU_Contents all;
+import from NGAP_Constants all;
+
+import from NGAP_Types all;
+import from NGAP_Pixits all;
+import from NGAP_Templates all;
+import from NGAP_Functions all;
+import from NGAP_Emulation all;
+
+import from NAS_CommonTypeDefs all;
+import from NAS_CommonTemplates all;
+import from NG_NAS_Common all;
+import from NG_NAS_TypeDefs all;
+import from NG_NAS_MsgContainers all;
+import from NG_NAS_Templates all;
+
+import from NG_NAS_Osmo_Templates all;
+import from NG_NAS_Functions all;
+import from NG_CryptoFunctions all;
+
+/* (maximum) number of emulated eNBs */
+const integer NUM_NGRAN := 1;
+
+/* parameters of emulated gNB / ng-eNB */
+type record NGRANParams {
+ GlobalRANNodeID global_ngran_id,
+ NGRAN_CGI cell_identity,
+ SupportedTAList supported_ta_list
+}
+
+/* parameters of emulated UE */
+type record UeParams {
+ HEX15n imsi,
+ HEX16n imeisv,
+ octetstring usim_key,
+ octetstring usim_opc,
+ charstring apn,
+ charstring ran_gtpu_ip,
+ OCT4 ran_gtpu_teid,
+ charstring cn_gtpu_ip optional,
+ OCT4 cn_gtpu_teid optional,
+ charstring ue_ip optional,
+ OCT32 kausf optional,
+ OCT32 kseaf optional,
+ OCT32 kamf optional
+}
+
+type record ConnHdlrPars {
+ /* copied over from MTC_CT on start of component */
+ NGRANParams ngran_pars[NUM_NGRAN],
+ /* copied over from MTC_CT on start of component */
+ UeParams ue_pars,
+ /* currently used 5GC (index into ngran_pars, NGAP, ...) */
+ integer c5g_idx,
+ /* Currently set KSI */
+ NAS_KeySetIdentifier kset_id
+}
+
+type component ConnHdlr extends NGAP_ConnHdlr {
+ var ConnHdlrPars g_pars;
+}
+
+type function void_fn() runs on ConnHdlr;
+
+private template (value) NGAP_IEs.TAI ts_ngran_NGAP_TAI(NGRANParams ngran_pars) := {
+ pLMNIdentity := ngran_pars.global_ngran_id.globalGNB_ID.pLMNIdentity,
+ tAC := ngran_pars.supported_ta_list[0].tAC,
+ iE_Extensions := omit
+}
+
+private function f_imsi_plmn_id() runs on ConnHdlr return PLMNIdentity {
+ var hexstring imsi := g_pars.ue_pars.imsi;
+ var GsmMcc mcc := substr(imsi, 0, 3);
+ var GsmMnc mnc := substr(imsi, 3, 2);
+ return f_enc_mcc_mnc(mcc, mnc);
+}
+
+private function f_SUCI_IMSI() runs on ConnHdlr return octetstring {
+ var hexstring imsi := g_pars.ue_pars.imsi;
+ var PLMNIdentity plmn_id := f_imsi_plmn_id();
+ var octetstring imsi_suffix := imsi_hex2oct(substr(imsi, lengthof(imsi) - 10, 10));
+ return plmn_id & '21430001'O & imsi_suffix;
+}
+
+private function f_UE_SecurityCapability() runs on ConnHdlr return NG_UE_SecurityCapability {
+ var template (value) NG_UE_SecurityCapability ue_sec_cap;
+ ue_sec_cap := cs_NG_UE_SecurityCapabilityTLV(ngeaCap := '80'O, /* ONLY NEA0 (no encryption) for now */
+ ngiaCap := '40'O /* ONLY NIA1 supported */);
+ return valueof(ue_sec_cap);
+}
+
+private function f_ULI() runs on ConnHdlr return UserLocationInformation {
+ var template (value) UserLocationInformation p_ueLocInf
+ p_ueLocInf := m_uPTransportLayerInformation_userLocationInformationNR(
+ m_userLocationInformationNR(
+ g_pars.ngran_pars[g_pars.c5g_idx].cell_identity.nR_CGI,
+ ts_ngran_NGAP_TAI(g_pars.ngran_pars[g_pars.c5g_idx])
+
+ ));
+ return valueof(p_ueLocInf);
+}
+
+private function f_tr_ConnHdlr_kset_id() runs on ConnHdlr return template (present) NAS_KeySetIdentifier {
+ /* KSI not yet set, expect whatever assignment from network: */
+ if (g_pars.kset_id.nasKeySetId == tsc_NasKsi_NoKey) {
+ return cr_NAS_KeySetIdentifier(?, ?);
+ } else {
+ /* Expect specific kset_id. Upon transmitting it UE->Network, f_attach()
+ * has updated it to the expected value. */
+ return g_pars.kset_id;
+ }
+}
+
+/* 3GPP TS 24.501 5.4.1.3.2, 3GPP TS 33.501 6.1.3.2 */
+private altstep as_ngap_handle_auth(boolean allow_resync := true) runs on ConnHdlr {
+ var NG_NAS_DL_Message_Type rx_nas;
+ var template (present) NAS_KeySetIdentifier kset_id := f_tr_ConnHdlr_kset_id();
+ [] NGAP.receive(cr_NG_AUTHENTICATION_REQUEST) -> value rx_nas {
+ var integer ret;
+ var integer my_sqn := 0; /* TODO: move to a ConnHdlr state attribute? */
+ var OCT16 rand := bit2oct(rx_nas.authentication_Request.rand.randValue);
+ var OCT16 autn := bit2oct(rx_nas.authentication_Request.autn.aUTN);
+ var OCT2 abba := rx_nas.authentication_Request.abba.abbaValue;
+ var OCT16 ik;
+ var OCT16 ck;
+ var OCT8 res;
+ var OCT14 auts;
+
+ g_pars.kset_id := rx_nas.authentication_Request.ngNasKeySetId;
+
+ ret := f_milenage_check(g_pars.ue_pars.usim_key,
+ g_pars.ue_pars.usim_opc,
+ int2oct(my_sqn, 8),
+ rand, autn, ik, ck, res, auts);
+ if (ret == -1) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("fx_milenage_check() failed! -1"));
+ }
+ if (ret == -2) {
+ if (not allow_resync) {
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
+ log2str("fx_milenage_check() unexpected Resync!"));
+ }
+ log("Milenage: RX-SQN differs from SIM SQN: Re-Sync! AUTS=", auts);
+ /* 3GPP TS 24.501 5.4.1.3.6 d) */
+ NGAP.send(cs_NG_AUTHENTICATION_FAILURE(cs_GMM_GSM_Cause(omit, int2bit(21, 8)),
+ cs_AuthFailParam(oct2bit(auts))));
+ as_ngap_handle_auth(allow_resync := false);
+ return;
+ }
+
+ var octetstring ssn := f_NG_NAS_ServingNetworkName_OCT(f_imsi_plmn_id(), omit);
+ g_pars.ue_pars.kausf := f_kdf_kausf(ck, ik, ssn, autn);
+ g_pars.ue_pars.kseaf := f_kdf_kseaf(g_pars.ue_pars.kausf, ssn);
+ g_pars.ue_pars.kamf := f_kdf_kamf(g_pars.ue_pars.kseaf, char2oct(hex2str(g_pars.ue_pars.imsi)), abba);
+
+ var NGAPEM_Config cfg := {
+ set_nas_keys := {
+ k_nas_int := f_kdf_ng_nas_int(g_pars.ue_pars.kamf, NG_NAS_ALG_IP_NIA1),
+ k_nas_enc := f_kdf_ng_nas_enc(g_pars.ue_pars.kamf, NG_NAS_ALG_ENC_NEA0)
+ }
+ };
+ NGAP.send(cfg);
+
+ /* Derive (X)RES* from (X)RES, 3GPP TS 33.501 A.4 */
+ var OCT16 res_star := f_kdf_xres_star(ssn, ck, ik, rand, res);
+ NGAP.send(cs_NG_AUTHENTICATION_RESPONSE(cs_AuthenticationResponseParameter(oct2bit(res_star))));
+ }
+}
+
+private altstep as_ngap_handle_sec_mode() runs on ConnHdlr {
+ var NGAPEM_Config cfg;
+ var NG_NAS_DL_Message_Type rx_nas;
+ /* Make sure network selected specific algos we requested: */
+ var template (present) NG_UE_SecurityCapability ue_sec_cap :=
+ cr_NG_UE_SecurityCapabilityLV(ngeaCap := '80'O, /* ONLY NEA0 (no encryption) for now */
+ ngiaCap := '40'O /* ONLY NIA1 supported */);
+
+ [] NGAP.receive(cr_NG_SECURITY_MODE_COMMAND(p_UECap := ue_sec_cap)) -> value rx_nas {
+ /* Configure integrity protection: */
+ cfg := {
+ set_nas_alg_int := NG_NAS_ALG_IP_NIA1
+ };
+ NGAP.send(cfg);
+ /* Configure Ciphering: */
+ cfg := {
+ set_nas_alg_enc := NG_NAS_ALG_ENC_NEA0
+ };
+ NGAP.send(cfg);
+
+ var template (value) NG_NAS_UL_Message_Type nas_ul_msg;
+ var NAS_PDU nas_pdu;
+ nas_ul_msg := cs_NG_REGISTRATION_REQUEST(cs_RegistrationType(tsc_NG_RegistrationInitial, '1'B),
+ g_pars.kset_id.nasKeySetId,
+ g_pars.kset_id.tsc,
+ cs_NG_MobileIdentitySUCI('0000'B /* Type IMSI */,
+ f_SUCI_IMSI()),
+ p_UESecurityCap := f_UE_SecurityCapability());
+ nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg));
+ NGAP.send(cs_NG_SECURITY_MODE_COMPLETE(cs_NG_MobileIdentityTLV_IMEISV(hex2oct(g_pars.ue_pars.imeisv)),
+ cs_ReplayedNASMessageContainerTLV(nas_pdu)));
+ }
+}
+
+private altstep as_ngap_handle_configuration_update() runs on ConnHdlr {
+ var NG_NAS_DL_Message_Type rx_nas;
+
+ [] NGAP.receive(cr_NG_CONFIGURATION_UPDATE_COMMAND) -> value rx_nas {
+ NGAP.send(cs_NG_CONFIGURATION_UPDATE_COMPLETE);
+ }
+}
+
+/* Handle a PDUSessionResourceSetupRequestTransfer contained inside NGAP InitialContextSetupRequest and return a Result for InitialContextSetupResponse */
+private function f_pdu_handle_session_resource_setup_item(PDUSessionResourceSetupItemCxtReq req) runs on ConnHdlr return PDUSessionResourceSetupItemCxtRes
+{
+ var PDUSessionResourceSetupItemCxtRes resp;
+ var octetstring setup_trans_enc;
+ var NGAP_IEs.PDUSessionResourceSetupRequestTransfer setup_req_transf;
+ var NGAP_IEs.PDUSessionResourceSetupResponseTransfer setup_resp_transf;
+ var template (value) UPTransportLayerInformation utla;
+ var template (value) QosFlowPerTNLInformation qos;
+
+ /* Parse PDUSessionResourceSetupRequestTransfer contained inside InitialContextSetupRequest's PDUSessionResourceSetup Item: */
+ setup_req_transf := dec_NGAP_PDUSessionResourceSetupRequestTransfer(req.pDUSessionResourceSetupRequestTransfer);
+ for (var integer i := 0; i < lengthof(setup_req_transf.protocolIEs); i := i + 1) {
+ if (setup_req_transf.protocolIEs[i].id == id_UL_NGU_UP_TNLInformation) {
+ var UPTransportLayerInformation utli := setup_req_transf.protocolIEs[i].value_.uPTransportLayerInformation;
+ g_pars.ue_pars.cn_gtpu_ip := f_inet_ntoa(bit2oct(utli.gTPTunnel.transportLayerAddress));
+ g_pars.ue_pars.cn_gtpu_teid := utli.gTPTunnel.gTP_TEID;
+ }
+ }
+
+ /* Prepare Response for it: */
+ utla := m_uPTransportLayerInformation_gTPTunnel(
+ m_gTPTunnel(p_tla := oct2bit(f_inet_addr(g_pars.ue_pars.ran_gtpu_ip)),
+ p_gtp_teid := g_pars.ue_pars.ran_gtpu_teid));
+ qos := m_qosFlowPerTNLInformation(utla, { m_associatedQosFlowItem(1) });
+ setup_resp_transf := valueof(m_pDUSessionResourceSetupResponseTransfer(qos));
+ setup_trans_enc := enc_NGAP_PDUSessionResourceSetupResponseTransfer(setup_resp_transf)
+ resp := valueof(m_pDUSessionResourceSetupItemCxtRes(req.pDUSessionID, setup_trans_enc));
+ return resp;
+}
+
+private function f_pdu_handle_session_resource_setup_list(PDUSessionResourceSetupListCxtReq li_req) runs on ConnHdlr return PDUSessionResourceSetupListCxtRes
+{
+ var PDUSessionResourceSetupListCxtRes li_resp;
+ for (var integer i := 0; i < lengthof(li_req); i := i + 1) {
+ var PDUSessionResourceSetupItemCxtRes it_resp;
+ it_resp := f_pdu_handle_session_resource_setup_item(li_req[i]);
+ if (i == 0) { /* min 1 item in list doesn't allow previously allocating an empty list */
+ li_resp := { it_resp };
+ } else {
+ li_resp := li_resp & { it_resp };
+ }
+ }
+ return li_resp;
+}
+
+private altstep as_ngap_handle_InitialCtxReq_withPDUSessionList() runs on ConnHdlr {
+ var NGAP_PDU rx_ngap;
+
+ [] NGAP.receive(mw_ngap_initMsg(mw_n2_InitialContextSetupRequest_withPDUSessionList)) -> value rx_ngap {
+ var AMF_UE_NGAP_ID amf_id := valueof(f_NGAP_get_AMF_UE_NGAP_ID(rx_ngap));
+ var RAN_UE_NGAP_ID ran_id := valueof(f_NGAP_get_RAN_UE_NGAP_ID(rx_ngap));
+ var InitialContextSetupRequest ctx_setup_req := rx_ngap.initiatingMessage.value_.initialContextSetupRequest;
+ var PDUSessionResourceSetupListCxtRes resources;
+
+ for (var integer i := 0; i < lengthof(ctx_setup_req.protocolIEs); i := i + 1) {
+ if (ctx_setup_req.protocolIEs[i].id != id_PDUSessionResourceSetupListCxtReq) {
+ continue;
+ }
+ var PDUSessionResourceSetupListCxtReq li := ctx_setup_req.protocolIEs[i].value_.pDUSessionResourceSetupListCxtReq;
+ resources := f_pdu_handle_session_resource_setup_list(li);
+ }
+ NGAP.send(m_ngap_succMsg(m_n2_InitialContextSetupResponse(amf_id, ran_id, resources)));
+ }
+}
+
+private function f_pdu_sess_establish() runs on ConnHdlr {
+ var template (value) NG_NAS_UL_Message_Type nas_ul_msg;
+ var NAS_PDU nas_pdu;
+ var NG_NAS_DL_Message_Type rx_nas, inner_nas;
+
+ nas_ul_msg := cs_NG_PDU_SESSION_ESTABLISHMENT_REQUEST(cs_NG_PDU_SessionIdV('01'O), '01'O,
+ p_IntegrityProtMaxDataRate := cs_IntegrityProtMaxDataRateV('FF'O, 'FF'O),
+ p_PDU_SessionType := cs_PDU_SessionTypeTV('001'B), /* IPv4 */
+ p_SSC_Mode := cs_SSC_ModeTV('001'B));
+ nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg));
+ nas_ul_msg := cs_NG_UL_NAS_TRANSPORT(cs_PayloadContainerType(tsc_PayloadContainerESMMsg),
+ cs_PayloadContainerLV(nas_pdu),
+ p_PDU_SessionId := cs_NG_PDU_SessionIdTV('01'O),
+ p_RequestType := cs_NG_Request_TypeTV('001'B),
+ p_DNN := cs_DNN_TLV(f_enc_dns_hostname(g_pars.ue_pars.apn)));
+ NGAP.send(nas_ul_msg);
+ as_ngap_handle_InitialCtxReq_withPDUSessionList();
+
+ /* PDU Session Establishment Accept: This DL NAS arrives contained in InitialCtxReq handled above: */
+ NGAP.receive(cr_NG_DL_NAS_TRANSPORT) -> value rx_nas;
+ inner_nas := f_dec_NG_NAS_DL_Message_Payload_Container(rx_nas.dl_Nas_Transport.payloadContainerType.container,
+ rx_nas.dl_Nas_Transport.payload.payload);
+ g_pars.ue_pars.ue_ip := f_inet_ntoa(inner_nas.pdu_Session_Establishment_Accept.pduAddress.adressInfo);
+ log("5GC assigned CN GTPU Address: ", g_pars.ue_pars.cn_gtpu_ip, " TEID: ", g_pars.ue_pars.cn_gtpu_teid);
+ log("5GC assigned UE IP address: ", g_pars.ue_pars.ue_ip);
+}
+
+function f_register() runs on ConnHdlr {
+ var template (value) NGAP_PDU tx_pdu;
+ var template (value) NG_NAS_UL_Message_Type nas_ul_msg;
+ var NAS_PDU nas_pdu;
+ var NG_NAS_DL_Message_Type rx_nas;
+
+ nas_ul_msg := cs_NG_REGISTRATION_REQUEST(cs_RegistrationType(tsc_NG_RegistrationInitial, '1'B),
+ g_pars.kset_id.nasKeySetId,
+ g_pars.kset_id.tsc,
+ cs_NG_MobileIdentitySUCI('0000'B /* Type IMSI */,
+ f_SUCI_IMSI()),
+ p_UESecurityCap := f_UE_SecurityCapability());
+ nas_pdu := enc_NG_NAS_UL_Message_Type(valueof(nas_ul_msg));
+ tx_pdu := m_ngap_initMsg(m_n2_initialUeMessage(g_pars.c5g_idx,
+ nas_pdu, /* Registration request */
+ f_ULI(),
+ mo_Signalling));
+ NGAP.send(tx_pdu);
+
+ /* Expect updated KSI from network following 5G Core standards
+ *(open5gs.git 70310979c58fe186e9eaa06bec9d9a31f24ff7a1): */
+ if (g_pars.kset_id.nasKeySetId != tsc_NasKsi_NoKey) {
+ if (g_pars.kset_id.nasKeySetId == '110'B) {
+ g_pars.kset_id.nasKeySetId := '000'B;
+ } else {
+ g_pars.kset_id.nasKeySetId := int2bit(bit2int(g_pars.kset_id.nasKeySetId) + 1, 3);
+ }
+ }
+
+ as_ngap_handle_auth();
+ as_ngap_handle_sec_mode();
+
+ NGAP.receive(cr_NG_REGISTRATION_ACCEPT) -> value rx_nas;
+ NGAP.send(cs_NG_REGISTRATION_COMPLETE);
+
+ as_ngap_handle_configuration_update();
+
+ f_pdu_sess_establish();
+}
+
+}
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40752?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: If7edf8ee63c71fbf949e2d340cf3881fd8e3ba41
Gerrit-Change-Number: 40752
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[M] Change in osmo-ttcn3-hacks[master]: GTP1vU_Emulation: Make UECUPS support optional
by pespin 29 Jul '25
by pespin 29 Jul '25
29 Jul '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40745?usp=email )
Change subject: GTP1vU_Emulation: Make UECUPS support optional
......................................................................
GTP1vU_Emulation: Make UECUPS support optional
Some users may/do want to use the simple UDP/GTPU socket mode, so they
don't need to depend on all UECUPS code.
Change-Id: I3b4671d8e637f70f790b08ed8e3b5145e7a95703
---
M epdg/gen_links.sh
M epdg/regen_makefile.sh
R library/GTPv1U_Emulation.ttcnpp
M pgw/gen_links.sh
M pgw/regen_makefile.sh
5 files changed, 49 insertions(+), 18 deletions(-)
Approvals:
pespin: Looks good to me, approved
Jenkins Builder: Verified
osmith: Looks good to me, but someone else must approve
laforge: Looks good to me, but someone else must approve
diff --git a/epdg/gen_links.sh b/epdg/gen_links.sh
index d41e2e1..c3fdf61 100755
--- a/epdg/gen_links.sh
+++ b/epdg/gen_links.sh
@@ -37,10 +37,6 @@
FILES="MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn "
gen_links $DIR $FILES
-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.GTP_v13.5.0/src
FILES="GTPU_EncDec.cc GTPU_Types.ttcn "
gen_links $DIR $FILES
@@ -59,7 +55,7 @@
FILES+="IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc
IPA_Emulation.ttcnpp "
FILES+="PCO_Types.ttcn GSUP_Types.ttcn GSUP_Templates.ttcn GSUP_Emulation.ttcn "
-FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Templates.ttcn GTPv1U_Emulation.ttcn "
+FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Templates.ttcn GTPv1U_Emulation.ttcnpp "
FILES+="GTPv2_PrivateExtensions.ttcn GTPv2_Templates.ttcn "
FILES+="GTPv2_CodecPort.ttcn GTPv2_CodecPort_CtrlFunctDef.cc GTPv2_CodecPort_CtrlFunct.ttcn GTPv2_Emulation.ttcn "
FILES+="ICMP_Templates.ttcn "
diff --git a/epdg/regen_makefile.sh b/epdg/regen_makefile.sh
index 847c412..1cd2efb 100755
--- a/epdg/regen_makefile.sh
+++ b/epdg/regen_makefile.sh
@@ -17,7 +17,6 @@
TELNETasp_PT.cc
DIAMETER_EncDec.cc
DIAMETER_CodecPort_CtrlFunctDef.cc
- UECUPS_CodecPort_CtrlFunctDef.cc
GTPU_EncDec.cc
GTPv1U_CodecPort_CtrlFunctDef.cc
GTPv2_CodecPort_CtrlFunctDef.cc
diff --git a/library/GTPv1U_Emulation.ttcn b/library/GTPv1U_Emulation.ttcnpp
similarity index 91%
rename from library/GTPv1U_Emulation.ttcn
rename to library/GTPv1U_Emulation.ttcnpp
index 7c031b7..b3de2ab 100644
--- a/library/GTPv1U_Emulation.ttcn
+++ b/library/GTPv1U_Emulation.ttcnpp
@@ -15,23 +15,28 @@
import from IPL4asp_Types all;
import from General_Types all;
import from Osmocom_Types all;
+import from Misc_Helpers all;
import from GTPU_Types all;
import from GTPv1U_CodecPort all;
import from GTPv1U_CodecPort_CtrlFunct all;
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
import from SCTP_Templates all;
import from UECUPS_Types all;
import from UECUPS_CodecPort all;
import from UECUPS_CodecPort_CtrlFunct all;
+#endif
/***********************************************************************
* Main Emulation Component
***********************************************************************/
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
modulepar {
charstring mp_uecups_host := "127.0.0.1";
integer mp_uecups_port := UECUPS_SCTP_PORT;
};
+#endif
const integer GTP1U_PORT := 2152;
@@ -45,9 +50,6 @@
/* Communication with underlying GTP CodecPort */
port GTPU_PT GTP1U;
- /* Control port to GTP-U Daemon */
- port UECUPS_CODEC_PT UECUPS;
-
/* Communication with Clients */
port GTP1UEM_PT TEID0;
port GTP1UEM_PT CLIENT;
@@ -61,9 +63,13 @@
var OCT1 g_restart_ctr;
var uint16_t g_c_seq_nr;
var TidTableRec TidTable[256];
- var PidTableRec PidTable[256];
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
+ /* Control port to GTP-U Daemon */
+ port UECUPS_CODEC_PT UECUPS;
+ var PidTableRec PidTable[256];
var integer g_uecups_conn_id := -1;
+#endif
};
/* local TEID <-> ConnHdlr mapping */
@@ -72,6 +78,7 @@
GTP1U_ConnHdlr vc_conn
};
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
/* pid <-> ConnHdlr mapping (for UECUPS process termination indication) */
type record PidTableRec {
/* process ID of the running process */
@@ -79,6 +86,7 @@
/* component that started it */
GTP1U_ConnHdlr vc_conn
};
+#endif
private function f_teid_known(OCT4 teid) runs on GTPv1U_Emulation_CT return boolean {
var integer i;
@@ -101,6 +109,7 @@
mtc.stop;
}
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
private function f_comp_by_pid(integer pid) runs on GTPv1U_Emulation_CT return GTP1U_ConnHdlr {
var integer i;
for (i := 0; i < sizeof(PidTable); i := i+1) {
@@ -112,6 +121,7 @@
setverdict(fail, "No Component for PID ", pid);
mtc.stop;
}
+#endif
private function f_tid_tbl_add(OCT4 teid, GTP1U_ConnHdlr vc_conn) runs on GTPv1U_Emulation_CT {
var integer i;
@@ -125,6 +135,7 @@
testcase.stop("No Space in TidTable for ", teid);
}
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
private function f_pid_tbl_add(integer pid, GTP1U_ConnHdlr vc_conn) runs on GTPv1U_Emulation_CT {
var integer i;
for (i := 0; i < sizeof(PidTable); i := i+1) {
@@ -136,6 +147,7 @@
}
testcase.stop("No Space in PID Table for ", pid);
}
+#endif
/* allocate an unused local teid */
@@ -155,6 +167,7 @@
testcase.stop("Cannot find unused TEID after ", i, " attempts");
}
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
function tr_UECUPS_RecvFrom_R(template PDU_UECUPS msg)
runs on GTPv1U_Emulation_CT return template UECUPS_RecvFrom {
var template UECUPS_RecvFrom mrf := {
@@ -168,7 +181,6 @@
return mrf;
}
-
private function f_uecups_xceive(template (value) PDU_UECUPS tx,
template PDU_UECUPS rx_t := ?, float time_out := 10.0)
runs on GTPv1U_Emulation_CT return PDU_UECUPS {
@@ -188,6 +200,7 @@
}
return mrf.msg;
}
+#endif
private function f_init(Gtp1uEmulationCfg cfg) runs on GTPv1U_Emulation_CT {
var Result res;
@@ -197,6 +210,7 @@
g_gtp1u_cfg := cfg;
if (g_gtp1u_cfg.use_gtpu_daemon) {
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
map(self:UECUPS, system:UECUPS);
res := UECUPS_CodecPort_CtrlFunct.f_IPL4_connect(UECUPS, mp_uecups_host, mp_uecups_port, "", -1, -1,
{ sctp := valueof(ts_SctpTuple) });
@@ -209,6 +223,9 @@
f_uecups_xceive({reset_all_state := {}}, {reset_all_state_res:=?}, 30.0);
/* make sure we always pass incoming UECUPS indications whenever receiving fom the UECUPS port */
activate(as_uecups_ind());
+#else
+ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Requested UECUPS but built without UECUPS support!");
+#endif
} else if (isvalue(cfg.gtpu_bind_ip) and isvalue(cfg.gtpu_bind_port)) {
map(self:GTP1U, system:GTP1U);
res := GTPv1U_CodecPort_CtrlFunct.f_GTPU_listen(GTP1U, cfg.gtpu_bind_ip,
@@ -217,6 +234,7 @@
}
}
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
private altstep as_uecups_ind() runs on GTPv1U_Emulation_CT {
var UECUPS_RecvFrom rx;
var GTP1U_ConnHdlr vc_conn;
@@ -228,15 +246,18 @@
repeat;
}
}
+#endif
function main(Gtp1uEmulationCfg cfg) runs on GTPv1U_Emulation_CT {
var Gtp1uUnitdata g1u_ud;
var GTP1U_ConnHdlr vc_conn;
var OCT4 teid;
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
var PDU_UECUPS rx_uecups;
var UECUPS_CreateTun gtc;
var UECUPS_DestroyTun gtd;
var UECUPS_StartProgram sprog;
+#endif
f_init(cfg);
@@ -268,6 +289,7 @@
f_tid_tbl_add(t, vc_conn);
CLIENT_PROC.reply(GTP1UEM_allocate_teid:{} value t) to vc_conn;
}
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
[] CLIENT_PROC.getcall(GTP1UEM_create_tunnel:{?}) -> param(gtc) sender vc_conn {
rx_uecups := f_uecups_xceive({create_tun := gtc}, {create_tun_res:={result:=OK}});
CLIENT_PROC.reply(GTP1UEM_create_tunnel:{gtc}) to vc_conn;
@@ -284,7 +306,7 @@
}
CLIENT_PROC.reply(GTP1UEM_start_program:{sprog} value rx_uecups.start_program_res) to vc_conn;
}
-
+#endif
}
}
}
@@ -294,18 +316,27 @@
* Interaction between Main and Client Components
***********************************************************************/
type port GTP1UEM_PT message {
- inout Gtp1uUnitdata, UECUPS_ProgramTermInd;
+ inout Gtp1uUnitdata
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
+ , UECUPS_ProgramTermInd
+#endif
+ ;
} with { extension "internal" };
signature GTP1UEM_register_teid(OCT4 teid);
signature GTP1UEM_allocate_teid() return OCT4;
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
signature GTP1UEM_create_tunnel(UECUPS_CreateTun gtc);
signature GTP1UEM_destroy_tunnel(UECUPS_DestroyTun gtd);
signature GTP1UEM_start_program(UECUPS_StartProgram sprog) return UECUPS_StartProgramRes;
+#endif
type port GTP1UEM_PROC_PT procedure {
- inout GTP1UEM_register_teid, GTP1UEM_allocate_teid,
- GTP1UEM_create_tunnel, GTP1UEM_destroy_tunnel, GTP1UEM_start_program;
+ inout GTP1UEM_register_teid, GTP1UEM_allocate_teid
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
+ , GTP1UEM_create_tunnel, GTP1UEM_destroy_tunnel, GTP1UEM_start_program
+#endif
+ ;
} with { extension "internal" };
/***********************************************************************
@@ -333,6 +364,7 @@
}
}
+#ifdef GTP1U_EMULATION_HAVE_UECUPS
function f_gtp1u_create_tunnel(template (value) UECUPS_CreateTun gtc)
runs on GTP1U_ConnHdlr {
GTP1U_PROC.call(GTP1UEM_create_tunnel:{valueof(gtc)}) {
@@ -355,7 +387,6 @@
}
return res;
}
-
-
+#endif
}
diff --git a/pgw/gen_links.sh b/pgw/gen_links.sh
index fa69ee4..e1bf469 100755
--- a/pgw/gen_links.sh
+++ b/pgw/gen_links.sh
@@ -60,7 +60,7 @@
DIR=../library
FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPCP_Types.ttcn IPCP_Templates.ttcn PAP_Types.ttcn "
FILES+="GTPv1C_CodecPort.ttcn GTPv1C_CodecPort_CtrlFunct.ttcn GTPv1C_CodecPort_CtrlFunctDef.cc GTPv1C_Templates.ttcn Osmocom_Gb_Types.ttcn "
-FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Emulation.ttcn "
+FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Emulation.ttcnpp "
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 "
diff --git a/pgw/regen_makefile.sh b/pgw/regen_makefile.sh
index ec40716..2bc71d0 100755
--- a/pgw/regen_makefile.sh
+++ b/pgw/regen_makefile.sh
@@ -4,6 +4,7 @@
FILES="
*.ttcn
+ *.ttcnpp
BSSGP_EncDec.cc
DIAMETER_CodecPort_CtrlFunctDef.cc
DIAMETER_EncDec.cc
@@ -25,4 +26,8 @@
UECUPS_CodecPort_CtrlFunctDef.cc
"
+CPPFLAGS_TTCN3="
+ -DGTP1U_EMULATION_HAVE_UECUPS
+"
+
. ../_buildsystem/regen_makefile.inc.sh
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40745?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I3b4671d8e637f70f790b08ed8e3b5145e7a95703
Gerrit-Change-Number: 40745
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[S] Change in osmo-ttcn3-hacks[master]: gbproxy: Drop unneeded GTP dependencies
by pespin 29 Jul '25
by pespin 29 Jul '25
29 Jul '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40748?usp=email )
Change subject: gbproxy: Drop unneeded GTP dependencies
......................................................................
gbproxy: Drop unneeded GTP dependencies
Change-Id: Id282bf63ae4abe8f2e97d84146db1f48198dacf7
---
M gbproxy/gen_links.sh
M gbproxy/regen_makefile.sh
2 files changed, 0 insertions(+), 10 deletions(-)
Approvals:
laforge: Looks good to me, but someone else must approve
pespin: Looks good to me, approved
osmith: Looks good to me, but someone else must approve
Jenkins Builder: Verified
diff --git a/gbproxy/gen_links.sh b/gbproxy/gen_links.sh
index c71f049..aade874 100755
--- a/gbproxy/gen_links.sh
+++ b/gbproxy/gen_links.sh
@@ -49,10 +49,6 @@
FILES="MobileL3_CC_Types.ttcn MobileL3_CommonIE_Types.ttcn MobileL3_GMM_SM_Types.ttcn MobileL3_MM_Types.ttcn MobileL3_RRM_Types.ttcn MobileL3_SMS_Types.ttcn MobileL3_SS_Types.ttcn MobileL3_Types.ttcn"
gen_links $DIR $FILES
-DIR=$BASEDIR/titan.ProtocolModules.GTP_v13.5.0/src
-FILES="GTPC_EncDec.cc GTPC_Types.ttcn GTPU_EncDec.cc GTPU_Types.ttcn"
-gen_links $DIR $FILES
-
# required by M3UA_Emulation
DIR=$BASEDIR/titan.ProtocolModules.M3UA/src
FILES="M3UA_Types.ttcn"
@@ -91,8 +87,6 @@
FILES+="LLC_Templates.ttcn L3_Templates.ttcn L3_Common.ttcn "
# IPA_Emulation + dependencies
FILES+="IPA_Types.ttcn IPA_Emulation.ttcnpp IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc Native_Functions.ttcn Native_FunctionDefs.cc "
-FILES+="GTPv1C_CodecPort.ttcn GTPv1C_CodecPort_CtrlFunct.ttcn GTPv1C_CodecPort_CtrlFunctDef.cc GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTP_Emulation.ttcn
-GTPv1C_Templates.ttcn IPCP_Types.ttcn IPCP_Templates.ttcn "
gen_links $DIR $FILES
gen_links_finish
diff --git a/gbproxy/regen_makefile.sh b/gbproxy/regen_makefile.sh
index 421a8f4..ecb6cdb 100755
--- a/gbproxy/regen_makefile.sh
+++ b/gbproxy/regen_makefile.sh
@@ -8,10 +8,6 @@
AF_PACKET_PT.cc
AF_PACKET_PT.hh
BSSGP_EncDec.cc
- GTPC_EncDec.cc
- GTPU_EncDec.cc
- GTPv1C_CodecPort_CtrlFunctDef.cc
- GTPv1U_CodecPort_CtrlFunctDef.cc
IPA_CodecPort_CtrlFunctDef.cc
IPL4asp_PT.cc
IPL4asp_discovery.cc
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40748?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: Id282bf63ae4abe8f2e97d84146db1f48198dacf7
Gerrit-Change-Number: 40748
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
29 Jul '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40744?usp=email )
Change subject: Split GTPv1U out of GTPv2_Emulation
......................................................................
Split GTPv1U out of GTPv2_Emulation
GTPv1U and GTPv2C are 2 different protocols, working on 2 different
ports, on 2 different sockets.
Hence, it makes no sense to put them together, since some tests may want
to use only the control-plane, others may want to use the user-plane,
etc.
Morevoer, GTPv1U can be used together with both GTPv2C anf GTPv1C.
This commit also fixes the confusion where TEIC and TEID were not
properly separated in GTPv2_Emulation.
Change-Id: Ia45307107753294c6761cb588f0ab769821eb213
---
M epdg/EPDG_Tests.ttcn
M epdg/gen_links.sh
A library/GTPv1U_Emulation.ttcn
M library/GTPv2_Emulation.ttcn
M mme/MME_Tests.ttcn
M mme/gen_links.sh
M mme/regen_makefile.sh
M pgw/PGW_Tests.cfg
M pgw/PGW_Tests.ttcn
M pgw/gen_links.sh
10 files changed, 500 insertions(+), 262 deletions(-)
Approvals:
Jenkins Builder: Verified
pespin: Looks good to me, approved
laforge: Looks good to me, but someone else must approve
osmith: Looks good to me, but someone else must approve
diff --git a/epdg/EPDG_Tests.ttcn b/epdg/EPDG_Tests.ttcn
index 61476e2..f67fc2c 100644
--- a/epdg/EPDG_Tests.ttcn
+++ b/epdg/EPDG_Tests.ttcn
@@ -24,9 +24,10 @@
import from DIAMETER_ts29_273_Templates all;
import from DIAMETER_Emulation all;
-import from GTPv1U_CodecPort all;
import from GTPU_Types all;
+import from GTPv1U_CodecPort all;
import from GTPv1U_Templates all;
+import from GTPv1U_Emulation all;
import from GTPv2_Types all;
import from GTPv2_Templates all;
@@ -90,7 +91,10 @@
port IPA_CTRL_PT GSUP_IPA_EVENT;
var GTPv2_Emulation_CT vc_GTP2;
- port GTP2EM_PT TEID0;
+ port GTP2EM_PT TEIC0;
+
+ var GTPv1U_Emulation_CT vc_GTP1U;
+ port GTP1UEM_PT TEID0;
port Coord_PT COORD;
@@ -133,7 +137,7 @@
}
}
-type component EPDG_ConnHdlr extends DIAMETER_ConnHdlr, GSUP_ConnHdlr, GTP2_ConnHdlr {
+type component EPDG_ConnHdlr extends DIAMETER_ConnHdlr, GSUP_ConnHdlr, GTP2_ConnHdlr, GTP1U_ConnHdlr {
var EPDG_ConnHdlrPars g_pars;
port DIAMETER_Conn_PT SWx;
@@ -298,22 +302,32 @@
f_sleep(int2float(mp_diam_watchdog_initial_wait_sec));
}
-private function f_init_gtp(charstring id) runs on MTC_CT {
+private function f_init_gtp2c(charstring id) runs on MTC_CT {
var Gtp2EmulationCfg cfg := {
gtpc_bind_ip := mp_s2b_local_ip,
gtpc_bind_port := mp_s2b_local_port,
gtpc_remote_ip := mp_s2b_remote_ip,
gtpc_remote_port := mp_s2b_remote_port,
+ sgw_role := false
+ };
+
+ vc_GTP2 := GTPv2_Emulation_CT.create(id & "-GTPv2C");
+ map(vc_GTP2:GTP2C, system:GTP2C);
+ connect(vc_GTP2:TEIC0, self:TEIC0);
+ vc_GTP2.start(GTPv2_Emulation.main(cfg));
+}
+
+private function f_init_gtp1u(charstring id) runs on MTC_CT {
+ var Gtp1uEmulationCfg cfg := {
gtpu_bind_ip := mp_upf_gtpu_local_ip,
gtpu_bind_port := GTP1U_PORT,
- sgw_role := false,
use_gtpu_daemon := false /* TODO: maybe use, set to true */
};
- vc_GTP2 := GTPv2_Emulation_CT.create(id & "-GTPV2");
- map(vc_GTP2:GTP2C, system:GTP2C);
- connect(vc_GTP2:TEID0, self:TEID0);
- vc_GTP2.start(GTPv2_Emulation.main(cfg));
+ vc_GTP1U := GTPv1U_Emulation_CT.create(id & "-GTPv1U");
+ map(vc_GTP1U:GTP1U, system:GTP1U);
+ connect(vc_GTP1U:TEID0, self:TEID0);
+ vc_GTP1U.start(GTPv1U_Emulation.main(cfg));
}
private function f_init(float t_guard := 40.0) runs on MTC_CT {
@@ -323,7 +337,8 @@
f_init_gsup(testcasename());
f_init_diameter(testcasename());
- f_init_gtp(testcasename());
+ f_init_gtp2c(testcasename());
+ f_init_gtp1u(testcasename());
}
private type function void_fn(charstring id) runs on EPDG_ConnHdlr;
@@ -352,9 +367,12 @@
connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
- /* GTP2 */
+ /* GTP2C */
connect(vc_conn:GTP2, vc_GTP2:CLIENT);
connect(vc_conn:GTP2_PROC, vc_GTP2:CLIENT_PROC);
+ /* GTP1U */
+ connect(vc_conn:GTP1U, vc_GTP1U:CLIENT);
+ connect(vc_conn:GTP1U_PROC, vc_GTP1U:CLIENT_PROC);
/* SWx */
vc_conn_swx := DIAMETER_ConnHdlr_CT.create(id);
@@ -704,8 +722,8 @@
}*/
/* allocate + register TEID-C on local side */
- g_pars.teic_local := f_gtp2_allocate_teid();
- g_pars.bearer.teid_local := g_pars.teic_local;
+ g_pars.teic_local := f_gtp2_allocate_teic();
+ g_pars.bearer.teid_local := f_gtp1u_allocate_teid();
}
/* ePDG Creates session at the PGW. PGW sends Diameter s6b AAR + AAA. */
@@ -862,18 +880,18 @@
}
private function f_GTP1U_send(octetstring payload) runs on EPDG_ConnHdlr {
var Gtp1uPeer peer := valueof(ts_GtpPeerU(f_inet_addr(g_pars.bearer.gtpu_addr_remote)));
- GTP2.send(ts_GTP1U_GPDU(peer, omit /*opt_part*/, g_pars.bearer.teid_remote, payload));
+ GTP1U.send(ts_GTP1U_GPDU(peer, omit /*opt_part*/, g_pars.bearer.teid_remote, payload));
}
private function f_GTP1U_echo_ping_pong(uint16_t seq_nr := 0) runs on EPDG_ConnHdlr {
var Gtp1uPeer peer := valueof(ts_GtpPeerU(f_inet_addr(g_pars.bearer.gtpu_addr_remote)));
- GTP2.send(ts_GTPU_PING(peer, seq := seq_nr));
- GTP2.receive(tr_GTPU_PONG(peer));
+ GTP1U.send(ts_GTPU_PING(peer, seq := seq_nr));
+ GTP1U.receive(tr_GTPU_PONG(peer));
}
private altstep as_GTPU_rx_icmp4(template (present) PDU_ICMP expected := ?) runs on EPDG_ConnHdlr {
var Gtp1uUnitdata rx_msg;
var template (value) Gtp1uPeer peer := ts_GtpPeerU(f_inet_addr(g_pars.bearer.gtpu_addr_remote));
- [] GTP2.receive(tr_GTPU_GPDU(peer, g_pars.bearer.teid_local)) -> value rx_msg {
+ [] GTP1U.receive(tr_GTPU_GPDU(peer, g_pars.bearer.teid_local)) -> value rx_msg {
/*TODO: verify gtpu txseq:
if (f_verify_gtpu_txseq(ud.gtpu, use_gtpu_txseq) == false) {
setverdict(fail);
@@ -890,7 +908,7 @@
repeat;
}
}
- [] GTP2.receive(Gtp1uUnitdata:?) -> value rx_msg {
+ [] GTP1U.receive(Gtp1uUnitdata:?) -> value rx_msg {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP msg rx: ", rx_msg));
}
}
@@ -1298,7 +1316,7 @@
private function f_TC_upf_echo_req(charstring id) runs on EPDG_ConnHdlr {
f_initial_attach();
/* Dispatch Echo Resp to this component: */
- f_gtp2_register_teid('00000000'O);
+ f_gtp1u_register_teid('00000000'O);
f_GTP1U_echo_ping_pong(seq_nr := 0);
/* Send one again, to validate it works several times: */
f_GTP1U_echo_ping_pong(seq_nr := 1);
@@ -1316,7 +1334,7 @@
private function f_TC_mt_ipv4_echo_req(charstring id) runs on EPDG_ConnHdlr {
f_initial_attach();
/* Dispatch Echo Resp to this component: */
- f_gtp2_register_teid('00000000'O);
+ f_gtp1u_register_teid('00000000'O);
var octetstring echo_req := f_gen_icmpv4_echo(f_inet_addr(mp_upf_gtpu_local_ip), f_inet_addr(g_pars.ue_ip));
f_GTP1U_send(echo_req);
as_GTPU_rx_icmp4((tr_ICMPv4_ERP, tr_ICMPv4_DU));
diff --git a/epdg/gen_links.sh b/epdg/gen_links.sh
index 889cb9a..d41e2e1 100755
--- a/epdg/gen_links.sh
+++ b/epdg/gen_links.sh
@@ -59,7 +59,7 @@
FILES+="IPA_Types.ttcn IPA_CodecPort.ttcn IPA_CodecPort_CtrlFunct.ttcn IPA_CodecPort_CtrlFunctDef.cc
IPA_Emulation.ttcnpp "
FILES+="PCO_Types.ttcn GSUP_Types.ttcn GSUP_Templates.ttcn GSUP_Emulation.ttcn "
-FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Templates.ttcn "
+FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Templates.ttcn GTPv1U_Emulation.ttcn "
FILES+="GTPv2_PrivateExtensions.ttcn GTPv2_Templates.ttcn "
FILES+="GTPv2_CodecPort.ttcn GTPv2_CodecPort_CtrlFunctDef.cc GTPv2_CodecPort_CtrlFunct.ttcn GTPv2_Emulation.ttcn "
FILES+="ICMP_Templates.ttcn "
diff --git a/library/GTPv1U_Emulation.ttcn b/library/GTPv1U_Emulation.ttcn
new file mode 100644
index 0000000..7c031b7
--- /dev/null
+++ b/library/GTPv1U_Emulation.ttcn
@@ -0,0 +1,361 @@
+/* GTPv1U Emulation in TTCN-3
+ *
+ * (C) 2018-2020 Harald Welte <laforge(a)gnumonks.org>
+ * (C) 2025 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+ * 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
+ */
+
+module GTPv1U_Emulation {
+
+import from IPL4asp_Types all;
+import from General_Types all;
+import from Osmocom_Types all;
+import from GTPU_Types all;
+import from GTPv1U_CodecPort all;
+import from GTPv1U_CodecPort_CtrlFunct all;
+
+import from SCTP_Templates all;
+import from UECUPS_Types all;
+import from UECUPS_CodecPort all;
+import from UECUPS_CodecPort_CtrlFunct all;
+
+/***********************************************************************
+ * Main Emulation Component
+ ***********************************************************************/
+
+modulepar {
+ charstring mp_uecups_host := "127.0.0.1";
+ integer mp_uecups_port := UECUPS_SCTP_PORT;
+};
+
+const integer GTP1U_PORT := 2152;
+
+type record Gtp1uEmulationCfg {
+ HostName gtpu_bind_ip optional,
+ IPL4asp_Types.PortNumber gtpu_bind_port optional,
+ boolean use_gtpu_daemon
+};
+
+type component GTPv1U_Emulation_CT {
+ /* Communication with underlying GTP CodecPort */
+ port GTPU_PT GTP1U;
+
+ /* Control port to GTP-U Daemon */
+ port UECUPS_CODEC_PT UECUPS;
+
+ /* Communication with Clients */
+ port GTP1UEM_PT TEID0;
+ port GTP1UEM_PT CLIENT;
+ port GTP1UEM_PROC_PT CLIENT_PROC;
+
+ /* Configuration by the user */
+ var Gtp1uEmulationCfg g_gtp1u_cfg;
+
+ /* State */
+ var integer g_gtp1u_id := -1;
+ var OCT1 g_restart_ctr;
+ var uint16_t g_c_seq_nr;
+ var TidTableRec TidTable[256];
+ var PidTableRec PidTable[256];
+
+ var integer g_uecups_conn_id := -1;
+};
+
+/* local TEID <-> ConnHdlr mapping */
+type record TidTableRec {
+ OCT4 teid,
+ GTP1U_ConnHdlr vc_conn
+};
+
+/* pid <-> ConnHdlr mapping (for UECUPS process termination indication) */
+type record PidTableRec {
+ /* process ID of the running process */
+ integer pid,
+ /* component that started it */
+ GTP1U_ConnHdlr vc_conn
+};
+
+private function f_teid_known(OCT4 teid) runs on GTPv1U_Emulation_CT return boolean {
+ var integer i;
+ for (i := 0; i < sizeof(TidTable); i := i+1) {
+ if (isbound(TidTable[i].teid) and TidTable[i].teid == teid) {
+ return true;
+ }
+ }
+ return false;
+}
+
+private function f_comp_by_teid(OCT4 teid) runs on GTPv1U_Emulation_CT return GTP1U_ConnHdlr {
+ var integer i;
+ for (i := 0; i < sizeof(TidTable); i := i+1) {
+ if (isbound(TidTable[i].teid) and TidTable[i].teid == teid) {
+ return TidTable[i].vc_conn;
+ }
+ }
+ setverdict(fail, "No Component for TEID ", teid);
+ mtc.stop;
+}
+
+private function f_comp_by_pid(integer pid) runs on GTPv1U_Emulation_CT return GTP1U_ConnHdlr {
+ var integer i;
+ for (i := 0; i < sizeof(PidTable); i := i+1) {
+ if (isbound(PidTable[i].pid) and PidTable[i].pid == pid) {
+ /* fixme: remove */
+ return PidTable[i].vc_conn;
+ }
+ }
+ setverdict(fail, "No Component for PID ", pid);
+ mtc.stop;
+}
+
+private function f_tid_tbl_add(OCT4 teid, GTP1U_ConnHdlr vc_conn) runs on GTPv1U_Emulation_CT {
+ var integer i;
+ for (i := 0; i < sizeof(TidTable); i := i+1) {
+ if (not isbound(TidTable[i].teid)) {
+ TidTable[i].teid := teid;
+ TidTable[i].vc_conn := vc_conn;
+ return;
+ }
+ }
+ testcase.stop("No Space in TidTable for ", teid);
+}
+
+private function f_pid_tbl_add(integer pid, GTP1U_ConnHdlr vc_conn) runs on GTPv1U_Emulation_CT {
+ var integer i;
+ for (i := 0; i < sizeof(PidTable); i := i+1) {
+ if (not isbound(PidTable[i].pid)) {
+ PidTable[i].pid := pid;
+ PidTable[i].vc_conn := vc_conn;
+ return;
+ }
+ }
+ testcase.stop("No Space in PID Table for ", pid);
+}
+
+
+/* allocate an unused local teid */
+private function f_alloc_teid() runs on GTPv1U_Emulation_CT return OCT4 {
+ var OCT4 teid;
+ var integer i, j;
+ for (i := 0; i < 100; i := i+1) {
+ teid := f_rnd_octstring(4);
+ for (j := 0; j < sizeof(TidTable); j := j+1) {
+ if (isbound(TidTable) and TidTable[i].teid == teid) {
+ continue;
+ }
+ }
+ /* we iterated over all entries and found no match: great! */
+ return teid;
+ }
+ testcase.stop("Cannot find unused TEID after ", i, " attempts");
+}
+
+function tr_UECUPS_RecvFrom_R(template PDU_UECUPS msg)
+runs on GTPv1U_Emulation_CT return template UECUPS_RecvFrom {
+ var template UECUPS_RecvFrom mrf := {
+ connId := g_uecups_conn_id,
+ remName := ?,
+ remPort := ?,
+ locName := ?,
+ locPort := ?,
+ msg := msg
+ }
+ return mrf;
+}
+
+
+private function f_uecups_xceive(template (value) PDU_UECUPS tx,
+ template PDU_UECUPS rx_t := ?, float time_out := 10.0)
+runs on GTPv1U_Emulation_CT return PDU_UECUPS {
+ timer T := time_out;
+ var UECUPS_RecvFrom mrf;
+
+ UECUPS.send(t_UECUPS_Send(g_uecups_conn_id, tx));
+ T.start;
+ alt {
+ [] UECUPS.receive(tr_UECUPS_RecvFrom_R(rx_t)) -> value mrf { }
+ [] UECUPS.receive(tr_SctpAssocChange) { repeat; }
+ [] UECUPS.receive(tr_SctpPeerAddrChange) { repeat; }
+ [] T.timeout {
+ setverdict(fail, "Timeout waiting for ", rx_t);
+ mtc.stop;
+ }
+ }
+ return mrf.msg;
+}
+
+private function f_init(Gtp1uEmulationCfg cfg) runs on GTPv1U_Emulation_CT {
+ var Result res;
+
+ g_restart_ctr := f_rnd_octstring(1);
+ g_c_seq_nr := f_rnd_int(65535);
+ g_gtp1u_cfg := cfg;
+
+ if (g_gtp1u_cfg.use_gtpu_daemon) {
+ map(self:UECUPS, system:UECUPS);
+ res := UECUPS_CodecPort_CtrlFunct.f_IPL4_connect(UECUPS, mp_uecups_host, mp_uecups_port, "", -1, -1,
+ { sctp := valueof(ts_SctpTuple) });
+ if (not ispresent(res.connId)) {
+ setverdict(fail, "Could not connect UECUPS socket, check your configuration");
+ testcase.stop;
+ }
+ g_uecups_conn_id := res.connId;
+ /* clear all tunnel state in the daemon at start */
+ f_uecups_xceive({reset_all_state := {}}, {reset_all_state_res:=?}, 30.0);
+ /* make sure we always pass incoming UECUPS indications whenever receiving fom the UECUPS port */
+ activate(as_uecups_ind());
+ } else if (isvalue(cfg.gtpu_bind_ip) and isvalue(cfg.gtpu_bind_port)) {
+ map(self:GTP1U, system:GTP1U);
+ res := GTPv1U_CodecPort_CtrlFunct.f_GTPU_listen(GTP1U, cfg.gtpu_bind_ip,
+ cfg.gtpu_bind_port, {udp:={}});
+ g_gtp1u_id := res.connId;
+ }
+}
+
+private altstep as_uecups_ind() runs on GTPv1U_Emulation_CT {
+var UECUPS_RecvFrom rx;
+var GTP1U_ConnHdlr vc_conn;
+/* handle incoming program_term_ind; dispatch to whatever component started the process */
+[] UECUPS.receive(tr_UECUPS_RecvFrom_R({program_term_ind:=?})) -> value rx {
+ vc_conn := f_comp_by_pid(rx.msg.program_term_ind.pid);
+ CLIENT.send(rx.msg.program_term_ind) to vc_conn;
+ /* FIXME: remove from table */
+ repeat;
+ }
+}
+
+function main(Gtp1uEmulationCfg cfg) runs on GTPv1U_Emulation_CT {
+ var Gtp1uUnitdata g1u_ud;
+ var GTP1U_ConnHdlr vc_conn;
+ var OCT4 teid;
+ var PDU_UECUPS rx_uecups;
+ var UECUPS_CreateTun gtc;
+ var UECUPS_DestroyTun gtd;
+ var UECUPS_StartProgram sprog;
+
+ f_init(cfg);
+
+ while (true) {
+ alt {
+ [] GTP1U.receive(Gtp1uUnitdata:?) -> value g1u_ud {
+ if (f_teid_known(g1u_ud.gtpu.teid)) {
+ vc_conn := f_comp_by_teid(g1u_ud.gtpu.teid);
+ CLIENT.send(g1u_ud) to vc_conn;
+ } else if (g1u_ud.gtpu.teid == '00000000'O) {
+ TEID0.send(g1u_ud);
+ } else {
+ log("No client registered for TEID=", g1u_ud.gtpu.teid, "!");
+ }
+ }
+ [] TEID0.receive(Gtp1uUnitdata:?) -> value g1u_ud sender vc_conn {
+ GTP1U.send(g1u_ud);
+ }
+ [] CLIENT.receive(Gtp1uUnitdata:?) -> value g1u_ud sender vc_conn {
+ GTP1U.send(g1u_ud);
+ }
+
+ [] CLIENT_PROC.getcall(GTP1UEM_register_teid:{?}) -> param(teid) sender vc_conn {
+ f_tid_tbl_add(teid, vc_conn);
+ CLIENT_PROC.reply(GTP1UEM_register_teid:{teid}) to vc_conn;
+ }
+ [] CLIENT_PROC.getcall(GTP1UEM_allocate_teid:{}) -> sender vc_conn {
+ var OCT4 t := f_alloc_teid();
+ f_tid_tbl_add(t, vc_conn);
+ CLIENT_PROC.reply(GTP1UEM_allocate_teid:{} value t) to vc_conn;
+ }
+ [] CLIENT_PROC.getcall(GTP1UEM_create_tunnel:{?}) -> param(gtc) sender vc_conn {
+ rx_uecups := f_uecups_xceive({create_tun := gtc}, {create_tun_res:={result:=OK}});
+ CLIENT_PROC.reply(GTP1UEM_create_tunnel:{gtc}) to vc_conn;
+ }
+ [] CLIENT_PROC.getcall(GTP1UEM_destroy_tunnel:{?}) -> param(gtd) sender vc_conn {
+ rx_uecups := f_uecups_xceive({destroy_tun := gtd}, {destroy_tun_res:={result:=OK}});
+ CLIENT_PROC.reply(GTP1UEM_destroy_tunnel:{gtd}) to vc_conn;
+ }
+ [] CLIENT_PROC.getcall(GTP1UEM_start_program:{?}) -> param(sprog) sender vc_conn {
+ rx_uecups := f_uecups_xceive({start_program := sprog}, {start_program_res:=?});
+ /* if successful: store (pid, vc_conn) tuple so we can route program_term_ind */
+ if (rx_uecups.start_program_res.result == OK) {
+ f_pid_tbl_add(rx_uecups.start_program_res.pid, vc_conn);
+ }
+ CLIENT_PROC.reply(GTP1UEM_start_program:{sprog} value rx_uecups.start_program_res) to vc_conn;
+ }
+
+ }
+ }
+}
+
+
+/***********************************************************************
+ * Interaction between Main and Client Components
+ ***********************************************************************/
+type port GTP1UEM_PT message {
+ inout Gtp1uUnitdata, UECUPS_ProgramTermInd;
+} with { extension "internal" };
+
+signature GTP1UEM_register_teid(OCT4 teid);
+signature GTP1UEM_allocate_teid() return OCT4;
+signature GTP1UEM_create_tunnel(UECUPS_CreateTun gtc);
+signature GTP1UEM_destroy_tunnel(UECUPS_DestroyTun gtd);
+signature GTP1UEM_start_program(UECUPS_StartProgram sprog) return UECUPS_StartProgramRes;
+
+type port GTP1UEM_PROC_PT procedure {
+ inout GTP1UEM_register_teid, GTP1UEM_allocate_teid,
+ GTP1UEM_create_tunnel, GTP1UEM_destroy_tunnel, GTP1UEM_start_program;
+} with { extension "internal" };
+
+/***********************************************************************
+ * Client Component
+ ***********************************************************************/
+
+type component GTP1U_ConnHdlr {
+ port GTP1UEM_PT GTP1U;
+ port GTP1UEM_PROC_PT GTP1U_PROC;
+};
+
+
+function f_gtp1u_register_teid(OCT4 teid) runs on GTP1U_ConnHdlr {
+ GTP1U_PROC.call(GTP1UEM_register_teid:{teid}) {
+ [] GTP1U_PROC.getreply(GTP1UEM_register_teid:{teid});
+ }
+}
+
+function f_gtp1u_allocate_teid() runs on GTP1U_ConnHdlr return OCT4 {
+ var OCT4 t;
+ GTP1U_PROC.call(GTP1UEM_allocate_teid:{}) {
+ [] GTP1U_PROC.getreply(GTP1UEM_allocate_teid:{}) -> value t {
+ return t;
+ }
+ }
+}
+
+function f_gtp1u_create_tunnel(template (value) UECUPS_CreateTun gtc)
+runs on GTP1U_ConnHdlr {
+ GTP1U_PROC.call(GTP1UEM_create_tunnel:{valueof(gtc)}) {
+ [] GTP1U_PROC.getreply(GTP1UEM_create_tunnel:{gtc});
+ }
+}
+
+function f_gtp1u_destroy_tunnel(template (value) UECUPS_DestroyTun gtd)
+runs on GTP1U_ConnHdlr {
+ GTP1U_PROC.call(GTP1UEM_destroy_tunnel:{valueof(gtd)}) {
+ [] GTP1U_PROC.getreply(GTP1UEM_destroy_tunnel:{gtd});
+ }
+}
+
+function f_gtp1u_start_program(template (value) UECUPS_StartProgram sprog)
+runs on GTP1U_ConnHdlr return UECUPS_StartProgramRes {
+ var UECUPS_StartProgramRes res;
+ GTP1U_PROC.call(GTP1UEM_start_program:{valueof(sprog)}) {
+ [] GTP1U_PROC.getreply(GTP1UEM_start_program:{sprog}) -> value res;
+ }
+ return res;
+}
+
+
+
+}
diff --git a/library/GTPv2_Emulation.ttcn b/library/GTPv2_Emulation.ttcn
index 15720f9..7ef5283 100644
--- a/library/GTPv2_Emulation.ttcn
+++ b/library/GTPv2_Emulation.ttcn
@@ -14,52 +14,33 @@
import from IPL4asp_Types all;
import from General_Types all;
import from Osmocom_Types all;
-import from GTPU_Types all;
-import from GTPv1U_CodecPort all;
-import from GTPv1U_CodecPort_CtrlFunct all;
import from GTPv2_Types all;
import from GTPv2_Templates all;
import from GTPv2_CodecPort all;
import from GTPv2_CodecPort_CtrlFunct all;
-import from SCTP_Templates all;
-
-import from UECUPS_Types all;
-import from UECUPS_CodecPort all;
-import from UECUPS_CodecPort_CtrlFunct all;
/***********************************************************************
* Main Emulation Component
***********************************************************************/
-modulepar {
- charstring mp_uecups_host := "127.0.0.1";
- integer mp_uecups_port := UECUPS_SCTP_PORT;
-};
+//modulepar {};
const integer GTP2C_PORT := 2123;
-const integer GTP1U_PORT := 2152;
type record Gtp2EmulationCfg {
HostName gtpc_bind_ip,
IPL4asp_Types.PortNumber gtpc_bind_port,
HostName gtpc_remote_ip,
IPL4asp_Types.PortNumber gtpc_remote_port,
- HostName gtpu_bind_ip optional,
- IPL4asp_Types.PortNumber gtpu_bind_port optional,
- boolean sgw_role,
- boolean use_gtpu_daemon
+ boolean sgw_role
};
type component GTPv2_Emulation_CT {
/* Communication with underlying GTP CodecPort */
port GTPv2C_PT GTP2C;
- port GTPU_PT GTPU;
-
- /* Control port to GTP-U Daemon */
- port UECUPS_CODEC_PT UECUPS;
/* Communication with Clients */
- port GTP2EM_PT TEID0;
+ port GTP2EM_PT TEIC0;
port GTP2EM_PT CLIENT;
port GTP2EM_PROC_PT CLIENT_PROC;
@@ -68,7 +49,7 @@
/* State */
var Gtp2cPeer g_peer;
- var integer g_gtp2c_id, g_gtp1u_id;
+ var integer g_gtp2c_id;
var OCT1 g_restart_ctr;
var uint16_t g_c_seq_nr;
var TidTableRec TidTable[256];
@@ -76,13 +57,11 @@
var ImsiTableRec ImsiTable[256];
var UdMsgTableRec UdMsgTable[256];
var PidTableRec PidTable[256];
-
- var integer g_uecups_conn_id;
};
-/* local TEID <-> ConnHdlr mapping */
+/* local TEIC <-> ConnHdlr mapping */
type record TidTableRec {
- OCT4 teid,
+ OCT4 teic,
GTP2_ConnHdlr vc_conn
};
@@ -112,24 +91,24 @@
GTP2_ConnHdlr vc_conn
};
-private function f_teid_known(OCT4 teid) runs on GTPv2_Emulation_CT return boolean {
+private function f_teic_known(OCT4 teic) runs on GTPv2_Emulation_CT return boolean {
var integer i;
for (i := 0; i < sizeof(TidTable); i := i+1) {
- if (isbound(TidTable[i].teid) and TidTable[i].teid == teid) {
+ if (isbound(TidTable[i].teic) and TidTable[i].teic == teic) {
return true;
}
}
return false;
}
-private function f_comp_by_teid(OCT4 teid) runs on GTPv2_Emulation_CT return GTP2_ConnHdlr {
+private function f_comp_by_teic(OCT4 teic) runs on GTPv2_Emulation_CT return GTP2_ConnHdlr {
var integer i;
for (i := 0; i < sizeof(TidTable); i := i+1) {
- if (isbound(TidTable[i].teid) and TidTable[i].teid == teid) {
+ if (isbound(TidTable[i].teic) and TidTable[i].teic == teic) {
return TidTable[i].vc_conn;
}
}
- setverdict(fail, "No Component for TEID ", teid);
+ setverdict(fail, "No Component for TEIC ", teic);
mtc.stop;
}
@@ -187,16 +166,16 @@
mtc.stop;
}
-private function f_tid_tbl_add(OCT4 teid, GTP2_ConnHdlr vc_conn) runs on GTPv2_Emulation_CT {
+private function f_tid_tbl_add(OCT4 teic, GTP2_ConnHdlr vc_conn) runs on GTPv2_Emulation_CT {
var integer i;
for (i := 0; i < sizeof(TidTable); i := i+1) {
- if (not isbound(TidTable[i].teid)) {
- TidTable[i].teid := teid;
+ if (not isbound(TidTable[i].teic)) {
+ TidTable[i].teic := teic;
TidTable[i].vc_conn := vc_conn;
return;
}
}
- testcase.stop("No Space in TidTable for ", teid);
+ testcase.stop("No Space in TidTable for ", teic);
}
private function f_seq_tbl_add(OCT3 seq, GTP2_ConnHdlr vc_conn) runs on GTPv2_Emulation_CT {
@@ -260,21 +239,21 @@
}
-/* allocate an unused local teid */
-private function f_alloc_teid() runs on GTPv2_Emulation_CT return OCT4 {
- var OCT4 teid;
+/* allocate an unused local teic */
+private function f_alloc_teic() runs on GTPv2_Emulation_CT return OCT4 {
+ var OCT4 teic;
var integer i, j;
for (i := 0; i < 100; i := i+1) {
- teid := f_rnd_octstring(4);
+ teic := f_rnd_octstring(4);
for (j := 0; j < sizeof(TidTable); j := j+1) {
- if (isbound(TidTable) and TidTable[i].teid == teid) {
+ if (isbound(TidTable) and TidTable[i].teic == teic) {
continue;
}
}
/* we iterated over all entries and found no match: great! */
- return teid;
+ return teic;
}
- testcase.stop("Cannot find unused TEID after ", i, " attempts");
+ testcase.stop("Cannot find unused TEIC after ", i, " attempts");
}
/* obtain the IMSI from a GTPv2C PDU, if there is any IMSI contained. The way how the TITAN
@@ -432,40 +411,6 @@
return false;
}
-function tr_UECUPS_RecvFrom_R(template PDU_UECUPS msg)
-runs on GTPv2_Emulation_CT return template UECUPS_RecvFrom {
- var template UECUPS_RecvFrom mrf := {
- connId := g_uecups_conn_id,
- remName := ?,
- remPort := ?,
- locName := ?,
- locPort := ?,
- msg := msg
- }
- return mrf;
-}
-
-
-private function f_uecups_xceive(template (value) PDU_UECUPS tx,
- template PDU_UECUPS rx_t := ?, float time_out := 10.0)
-runs on GTPv2_Emulation_CT return PDU_UECUPS {
- timer T := time_out;
- var UECUPS_RecvFrom mrf;
-
- UECUPS.send(t_UECUPS_Send(g_uecups_conn_id, tx));
- T.start;
- alt {
- [] UECUPS.receive(tr_UECUPS_RecvFrom_R(rx_t)) -> value mrf { }
- [] UECUPS.receive(tr_SctpAssocChange) { repeat; }
- [] UECUPS.receive(tr_SctpPeerAddrChange) { repeat; }
- [] T.timeout {
- setverdict(fail, "Timeout waiting for ", rx_t);
- mtc.stop;
- }
- }
- return mrf.msg;
-}
-
private function f_init(Gtp2EmulationCfg cfg) runs on GTPv2_Emulation_CT {
var Result res;
@@ -482,41 +427,6 @@
remName := g_gtp2_cfg.gtpc_remote_ip,
remPort := g_gtp2_cfg.gtpc_remote_port
}
-
- g_uecups_conn_id := res.connId;
-
- if (g_gtp2_cfg.use_gtpu_daemon) {
- map(self:UECUPS, system:UECUPS);
- res := UECUPS_CodecPort_CtrlFunct.f_IPL4_connect(UECUPS, mp_uecups_host, mp_uecups_port, "", -1, -1,
- { sctp := valueof(ts_SctpTuple) });
- if (not ispresent(res.connId)) {
- setverdict(fail, "Could not connect UECUPS socket, check your configuration");
- testcase.stop;
- }
-
- /* clear all tunnel state in the daemon at start */
- f_uecups_xceive({reset_all_state := {}}, {reset_all_state_res:=?}, 30.0);
- } else if (isvalue(cfg.gtpu_bind_ip) and isvalue(cfg.gtpu_bind_port)) {
- map(self:GTPU, system:GTPU);
- res := GTPv1U_CodecPort_CtrlFunct.f_GTPU_listen(GTPU, cfg.gtpu_bind_ip,
- cfg.gtpu_bind_port, {udp:={}});
- g_gtp1u_id := res.connId;
- }
-
- /* make sure we always pass incoming UECUPS indications whenever receiving fom the UECUPS port */
- activate(as_uecups_ind());
-}
-
-private altstep as_uecups_ind() runs on GTPv2_Emulation_CT {
-var UECUPS_RecvFrom rx;
-var GTP2_ConnHdlr vc_conn;
-/* handle incoming program_term_ind; dispatch to whatever component started the process */
-[] UECUPS.receive(tr_UECUPS_RecvFrom_R({program_term_ind:=?})) -> value rx {
- vc_conn := f_comp_by_pid(rx.msg.program_term_ind.pid);
- CLIENT.send(rx.msg.program_term_ind) to vc_conn;
- /* FIXME: remove from table */
- repeat;
- }
}
private function SendToUdMsgTable(Gtp2cUnitdata g2c_ud) runs on GTPv2_Emulation_CT {
@@ -536,22 +446,17 @@
function main(Gtp2EmulationCfg cfg) runs on GTPv2_Emulation_CT {
var Gtp2cUnitdata g2c_ud;
- var Gtp1uUnitdata g1u_ud;
var PDU_GTPCv2 g2c;
var GTP2_ConnHdlr vc_conn;
var hexstring imsi;
var OCT1 messageType;
- var OCT4 teid;
- var PDU_UECUPS rx_uecups;
- var UECUPS_CreateTun gtc;
- var UECUPS_DestroyTun gtd;
- var UECUPS_StartProgram sprog;
+ var OCT4 teic;
f_init(cfg);
while (true) {
alt {
- /* route inbound GTP2-C based on TEID, SEQ or IMSI */
+ /* route inbound GTP2-C based on TEIC, SEQ or IMSI */
[] GTP2C.receive(Gtp2cUnitdata:?) -> value g2c_ud {
var template hexstring imsi_t := f_gtp2c_extract_imsi(g2c_ud.gtpc);
/* if this is a response, route by SEQ: */
@@ -563,17 +468,17 @@
vc_conn := f_comp_by_imsi(valueof(imsi_t));
CLIENT.send(g2c_ud.gtpc) to vc_conn;
} else if ((ispresent(g2c_ud.gtpc.tEID) and g2c_ud.gtpc.tEID != '00000000'O)
- and f_teid_known(g2c_ud.gtpc.tEID)) {
- vc_conn := f_comp_by_teid(g2c_ud.gtpc.tEID);
+ and f_teic_known(g2c_ud.gtpc.tEID)) {
+ vc_conn := f_comp_by_teic(g2c_ud.gtpc.tEID);
CLIENT.send(g2c_ud.gtpc) to vc_conn;
} else if ((not ispresent(g2c_ud.gtpc.tEID) or g2c_ud.gtpc.tEID == '00000000'O)
- and f_teid_known('00000000'O)) {
- vc_conn := f_comp_by_teid(g2c_ud.gtpc.tEID);
+ and f_teic_known('00000000'O)) {
+ vc_conn := f_comp_by_teic(g2c_ud.gtpc.tEID);
CLIENT.send(g2c_ud.gtpc) to vc_conn;
} else {
SendToUdMsgTable(g2c_ud);
if (not ispresent(g2c_ud.gtpc.tEID) or g2c_ud.gtpc.tEID == '00000000'O) {
- TEID0.send(g2c_ud.gtpc);
+ TEIC0.send(g2c_ud.gtpc);
}
}
@@ -583,18 +488,8 @@
}
}
- [] GTPU.receive(Gtp1uUnitdata:?) -> value g1u_ud {
- if (f_teid_known(g1u_ud.gtpu.teid)) {
- vc_conn := f_comp_by_teid(g1u_ud.gtpu.teid);
- CLIENT.send(g1u_ud) to vc_conn;
- } else if (g1u_ud.gtpu.teid == '00000000'O) {
- TEID0.send(g1u_ud);
- } else {
- log("No client registered for TEID=", g1u_ud.gtpu.teid, "!");
- }
- }
- [] TEID0.receive(PDU_GTPCv2:?) -> value g2c sender vc_conn {
+ [] TEIC0.receive(PDU_GTPCv2:?) -> value g2c sender vc_conn {
/* patch in the next sequence number on outbound Initial message */
if (f_gtp2c_is_initial_msg(g2c)) {
g2c.sequenceNumber := int2oct(g_c_seq_nr, 3);
@@ -607,9 +502,6 @@
f_seq_tbl_add(g2c.sequenceNumber, vc_conn);
}
}
- [] TEID0.receive(Gtp1uUnitdata:?) -> value g1u_ud sender vc_conn {
- GTPU.send(g1u_ud);
- }
[] CLIENT.receive(PDU_GTPCv2:?) -> value g2c sender vc_conn {
/* patch in the next sequence number on outbound Initial message */
@@ -624,9 +516,6 @@
f_seq_tbl_add(g2c.sequenceNumber, vc_conn);
}
}
- [] CLIENT.receive(Gtp1uUnitdata:?) -> value g1u_ud sender vc_conn {
- GTPU.send(g1u_ud);
- }
[] CLIENT_PROC.getcall(GTP2EM_register_imsi:{?}) -> param(imsi) sender vc_conn {
f_imsi_tbl_add(imsi, vc_conn);
@@ -637,32 +526,15 @@
CLIENT_PROC.reply(GTP2EM_register_udmsg:{messageType}) to vc_conn;
}
- [] CLIENT_PROC.getcall(GTP2EM_register_teid:{?}) -> param(teid) sender vc_conn {
- f_tid_tbl_add(teid, vc_conn);
- CLIENT_PROC.reply(GTP2EM_register_teid:{teid}) to vc_conn;
+ [] CLIENT_PROC.getcall(GTP2EM_register_teic:{?}) -> param(teic) sender vc_conn {
+ f_tid_tbl_add(teic, vc_conn);
+ CLIENT_PROC.reply(GTP2EM_register_teic:{teic}) to vc_conn;
}
- [] CLIENT_PROC.getcall(GTP2EM_allocate_teid:{}) -> sender vc_conn {
- var OCT4 t := f_alloc_teid();
+ [] CLIENT_PROC.getcall(GTP2EM_allocate_teic:{}) -> sender vc_conn {
+ var OCT4 t := f_alloc_teic();
f_tid_tbl_add(t, vc_conn);
- CLIENT_PROC.reply(GTP2EM_allocate_teid:{} value t) to vc_conn;
+ CLIENT_PROC.reply(GTP2EM_allocate_teic:{} value t) to vc_conn;
}
- [] CLIENT_PROC.getcall(GTP2EM_create_tunnel:{?}) -> param(gtc) sender vc_conn {
- rx_uecups := f_uecups_xceive({create_tun := gtc}, {create_tun_res:={result:=OK}});
- CLIENT_PROC.reply(GTP2EM_create_tunnel:{gtc}) to vc_conn;
- }
- [] CLIENT_PROC.getcall(GTP2EM_destroy_tunnel:{?}) -> param(gtd) sender vc_conn {
- rx_uecups := f_uecups_xceive({destroy_tun := gtd}, {destroy_tun_res:={result:=OK}});
- CLIENT_PROC.reply(GTP2EM_destroy_tunnel:{gtd}) to vc_conn;
- }
- [] CLIENT_PROC.getcall(GTP2EM_start_program:{?}) -> param(sprog) sender vc_conn {
- rx_uecups := f_uecups_xceive({start_program := sprog}, {start_program_res:=?});
- /* if successful: store (pid, vc_conn) tuple so we can route program_term_ind */
- if (rx_uecups.start_program_res.result == OK) {
- f_pid_tbl_add(rx_uecups.start_program_res.pid, vc_conn);
- }
- CLIENT_PROC.reply(GTP2EM_start_program:{sprog} value rx_uecups.start_program_res) to vc_conn;
- }
-
}
}
}
@@ -672,20 +544,17 @@
* Interaction between Main and Client Components
***********************************************************************/
type port GTP2EM_PT message {
- inout PDU_GTPCv2, Gtp1uUnitdata, UECUPS_ProgramTermInd;
+ inout PDU_GTPCv2;
} with { extension "internal" };
signature GTP2EM_register_imsi(hexstring imsi);
signature GTP2EM_register_udmsg(OCT1 messageType);
-signature GTP2EM_register_teid(OCT4 teid);
-signature GTP2EM_allocate_teid() return OCT4;
-signature GTP2EM_create_tunnel(UECUPS_CreateTun gtc);
-signature GTP2EM_destroy_tunnel(UECUPS_DestroyTun gtd);
-signature GTP2EM_start_program(UECUPS_StartProgram sprog) return UECUPS_StartProgramRes;
+signature GTP2EM_register_teic(OCT4 teic);
+signature GTP2EM_allocate_teic() return OCT4;
type port GTP2EM_PROC_PT procedure {
- inout GTP2EM_register_imsi, GTP2EM_register_udmsg, GTP2EM_register_teid, GTP2EM_allocate_teid,
- GTP2EM_create_tunnel, GTP2EM_destroy_tunnel, GTP2EM_start_program;
+ inout GTP2EM_register_imsi, GTP2EM_register_udmsg,
+ GTP2EM_register_teic, GTP2EM_allocate_teic;
} with { extension "internal" };
/***********************************************************************
@@ -713,44 +582,18 @@
}
}
-function f_gtp2_register_teid(OCT4 teid) runs on GTP2_ConnHdlr {
- GTP2_PROC.call(GTP2EM_register_teid:{teid}) {
- [] GTP2_PROC.getreply(GTP2EM_register_teid:{teid});
+function f_gtp2_register_teic(OCT4 teic) runs on GTP2_ConnHdlr {
+ GTP2_PROC.call(GTP2EM_register_teic:{teic}) {
+ [] GTP2_PROC.getreply(GTP2EM_register_teic:{teic});
}
}
-function f_gtp2_allocate_teid() runs on GTP2_ConnHdlr return OCT4 {
+function f_gtp2_allocate_teic() runs on GTP2_ConnHdlr return OCT4 {
var OCT4 t;
- GTP2_PROC.call(GTP2EM_allocate_teid:{}) {
- [] GTP2_PROC.getreply(GTP2EM_allocate_teid:{}) -> value t {
+ GTP2_PROC.call(GTP2EM_allocate_teic:{}) {
+ [] GTP2_PROC.getreply(GTP2EM_allocate_teic:{}) -> value t {
return t;
}
}
}
-
-function f_gtp2_create_tunnel(template (value) UECUPS_CreateTun gtc)
-runs on GTP2_ConnHdlr {
- GTP2_PROC.call(GTP2EM_create_tunnel:{valueof(gtc)}) {
- [] GTP2_PROC.getreply(GTP2EM_create_tunnel:{gtc});
- }
-}
-
-function f_gtp2_destroy_tunnel(template (value) UECUPS_DestroyTun gtd)
-runs on GTP2_ConnHdlr {
- GTP2_PROC.call(GTP2EM_destroy_tunnel:{valueof(gtd)}) {
- [] GTP2_PROC.getreply(GTP2EM_destroy_tunnel:{gtd});
- }
-}
-
-function f_gtp2_start_program(template (value) UECUPS_StartProgram sprog)
-runs on GTP2_ConnHdlr return UECUPS_StartProgramRes {
- var UECUPS_StartProgramRes res;
- GTP2_PROC.call(GTP2EM_start_program:{valueof(sprog)}) {
- [] GTP2_PROC.getreply(GTP2EM_start_program:{sprog}) -> value res;
- }
- return res;
-}
-
-
-
}
diff --git a/mme/MME_Tests.ttcn b/mme/MME_Tests.ttcn
index c006aa4..4885b1e 100644
--- a/mme/MME_Tests.ttcn
+++ b/mme/MME_Tests.ttcn
@@ -120,7 +120,7 @@
/* S11 interface (GTPv2C) of emulated SGW-C */
var GTPv2_Emulation_CT vc_GTP2;
- port GTP2EM_PT TEID0;
+ port GTP2EM_PT TEIC0;
var UeParams g_ue_pars[NUM_UE];
}
@@ -371,15 +371,12 @@
gtpc_bind_port := mp_s11_local_port,
gtpc_remote_ip := mp_s11_remote_ip,
gtpc_remote_port := mp_s11_remote_port,
- gtpu_bind_ip := omit, /* using gtpu daemon */
- gtpu_bind_port := omit, /* using gtpu daemon */
- sgw_role := true,
- use_gtpu_daemon := false
+ sgw_role := true
};
vc_GTP2 := GTPv2_Emulation_CT.create(id);
map(vc_GTP2:GTP2C, system:GTP2C);
- connect(vc_GTP2:TEID0, self:TEID0);
+ connect(vc_GTP2:TEIC0, self:TEIC0);
vc_GTP2.start(GTPv2_Emulation.main(cfg));
}
@@ -840,9 +837,9 @@
g_pars.ue_pars.bearer.ebi := rx_bctx_ies.ePS_Bearer_ID.ePS_Bearer_ID_Value;
/* allocate + register TEID-C on local side */
- g_pars.ue_pars.s11_teic_local := f_gtp2_allocate_teid();
+ g_pars.ue_pars.s11_teic_local := f_gtp2_allocate_teic();
g_pars.ue_pars.bearer.s11_teid_local := g_pars.ue_pars.s11_teic_local;
- g_pars.ue_pars.s5c_teic_local := f_gtp2_allocate_teid();
+ g_pars.ue_pars.s5c_teic_local := f_gtp2_allocate_teic();
g_pars.ue_pars.bearer.s5c_teid_local := g_pars.ue_pars.s5c_teic_local;
s11_fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S11_MME_GTPC, g_pars.ue_pars.s11_teic_local, 0,
diff --git a/mme/gen_links.sh b/mme/gen_links.sh
index af0355f..ea9179f 100755
--- a/mme/gen_links.sh
+++ b/mme/gen_links.sh
@@ -55,10 +55,6 @@
FILES="GTPv2_Types.ttcn"
gen_links $DIR $FILES
-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
diff --git a/mme/regen_makefile.sh b/mme/regen_makefile.sh
index 4eb0f1a..c1859da 100755
--- a/mme/regen_makefile.sh
+++ b/mme/regen_makefile.sh
@@ -26,7 +26,6 @@
TCCEncoding.cc
TCCInterface.cc
TELNETasp_PT.cc
- UECUPS_CodecPort_CtrlFunctDef.cc
"
. ../_buildsystem/regen_makefile.inc.sh
diff --git a/pgw/PGW_Tests.cfg b/pgw/PGW_Tests.cfg
index ce3076b..68688c1 100644
--- a/pgw/PGW_Tests.cfg
+++ b/pgw/PGW_Tests.cfg
@@ -20,7 +20,7 @@
PGW_Tests.mp_pcrf_local_ip:= "127.0.0.202"
PGW_Tests.mp_ocs_local_ip:= "127.0.0.202"
PGW_Tests.mp_aaa_local_ip:= "127.0.0.202"
-GTPv2_Emulation.mp_uecups_host := "127.0.0.20"
+GTPv1U_Emulation.mp_uecups_host := "127.0.0.20"
[MAIN_CONTROLLER]
diff --git a/pgw/PGW_Tests.ttcn b/pgw/PGW_Tests.ttcn
index 4a4f77f..4d225fa 100644
--- a/pgw/PGW_Tests.ttcn
+++ b/pgw/PGW_Tests.ttcn
@@ -7,6 +7,8 @@
import from Native_Functions all;
import from Misc_Helpers all;
+import from GTPv1U_Emulation all;
+
import from GTPv2_Types all;
import from GTPv2_Templates all;
import from GTPv2_Emulation all;
@@ -47,9 +49,11 @@
}
/* main component, we typically have one per testcase */
-type component PGW_Test_CT extends GTP2_ConnHdlr {
+type component PGW_Test_CT extends GTP2_ConnHdlr, GTP1U_ConnHdlr {
var GTPv2_Emulation_CT vc_GTP2;
- port GTP2EM_PT TEID0;
+ port GTP2EM_PT TEIC0;
+ var GTPv1U_Emulation_CT vc_GTP1U;
+ port GTP1UEM_PT TEID0;
/* emulated PCRF */
var DIAMETER_Emulation_CT vc_Gx;
@@ -100,7 +104,7 @@
/* 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, GTP1U_ConnHdlr {
var SessionPars g_pars;
port DIAMETER_Conn_PT Gx;
@@ -280,27 +284,44 @@
f_sleep(1.0);
}
-private function f_init(float guard_timeout := 60.0) runs on PGW_Test_CT {
- T_guard.start(guard_timeout);
- activate(as_Tguard());
-
+private function f_init_gtp2c() runs on PGW_Test_CT {
var Gtp2EmulationCfg cfg := {
gtpc_bind_ip := mp_local_hostname_c,
gtpc_bind_port := GTP2C_PORT,
gtpc_remote_ip := mp_pgw_hostname,
gtpc_remote_port := GTP2C_PORT,
- gtpu_bind_ip := omit, /* using gtpu daemon */
- gtpu_bind_port := omit, /* using gtpu daemon */
- sgw_role := true,
- use_gtpu_daemon := true
+ sgw_role := true
};
- vc_GTP2 := GTPv2_Emulation_CT.create("GTP2_EM");
+ vc_GTP2 := GTPv2_Emulation_CT.create("GTP2C_EM");
map(vc_GTP2:GTP2C, system:GTP2C);
- connect(vc_GTP2:TEID0, self:TEID0);
+ connect(vc_GTP2:TEIC0, self:TEIC0);
connect(vc_GTP2:CLIENT, self:GTP2);
connect(vc_GTP2:CLIENT_PROC, self:GTP2_PROC);
vc_GTP2.start(GTPv2_Emulation.main(cfg));
+}
+
+private function f_init_gtp1u() runs on PGW_Test_CT {
+ var Gtp1uEmulationCfg cfg := {
+ gtpu_bind_ip := omit, /* using gtpu daemon */
+ gtpu_bind_port := omit, /* using gtpu daemon */
+ use_gtpu_daemon := true
+ };
+
+ vc_GTP1U := GTPv1U_Emulation_CT.create("GTP1U_EM");
+ map(vc_GTP1U:GTP1U, system:GTP1U);
+ connect(vc_GTP1U:TEID0, self:TEID0);
+ connect(vc_GTP1U:CLIENT, self:GTP1U);
+ connect(vc_GTP1U:CLIENT_PROC, self:GTP1U_PROC);
+ vc_GTP1U.start(GTPv1U_Emulation.main(cfg));
+}
+
+private function f_init(float guard_timeout := 60.0) runs on PGW_Test_CT {
+ T_guard.start(guard_timeout);
+ activate(as_Tguard());
+
+ f_init_gtp2c();
+ f_init_gtp1u();
if (mp_pcrf_local_ip != "") {
f_init_diameter(testcasename());
@@ -323,6 +344,8 @@
vc_conn := PGW_Session_CT.create(id);
connect(vc_conn:GTP2, vc_GTP2:CLIENT);
connect(vc_conn:GTP2_PROC, vc_GTP2:CLIENT_PROC);
+ connect(vc_conn:GTP1U, vc_GTP1U:CLIENT);
+ connect(vc_conn:GTP1U_PROC, vc_GTP1U:CLIENT_PROC);
if (isbound(vc_Gx)) {
vc_conn_gx := DIAMETER_ConnHdlr_CT.create(id);
@@ -355,9 +378,9 @@
private function f_handler_init(void_fn fn, SessionPars pars)
runs on PGW_Session_CT {
g_pars := valueof(pars);
- /* allocate + register TEID-C on local side */
- g_pars.teic_local := f_gtp2_allocate_teid();
- g_pars.bearer.teid_local := g_pars.teic_local;
+ /* allocate + register TEI{C,D} on local side */
+ g_pars.teic_local := f_gtp2_allocate_teic();
+ g_pars.bearer.teid_local := f_gtp1u_allocate_teid();
fn.apply();
}
@@ -693,12 +716,12 @@
/* create tunnel in daemon */
if (isbound(g_ip4_addr)) {
uecups_create.user_addr := g_ip4_addr;
- f_gtp2_create_tunnel(uecups_create);
+ f_gtp1u_create_tunnel(uecups_create);
}
if (isbound(g_ip6_addr)) {
uecups_create.user_addr_type := IPV6;
uecups_create.user_addr := g_ip6_addr;
- f_gtp2_create_tunnel(uecups_create);
+ f_gtp1u_create_tunnel(uecups_create);
}
}
@@ -871,7 +894,7 @@
rx_teid := oct2int(g_pars.bearer.teid_local)
};
/* FIXME: what about IPv4/IPv6 differentiation? */
- f_gtp2_destroy_tunnel(uecups_destroy);
+ f_gtp1u_destroy_tunnel(uecups_destroy);
}
}
@@ -896,7 +919,7 @@
}
log("Starting a program: ", command);
- var UECUPS_StartProgramRes res := f_gtp2_start_program(sprog);
+ var UECUPS_StartProgramRes res := f_gtp1u_start_program(sprog);
if (res.result != OK) {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
log2str("Unable to start program '", command, "'"));
@@ -914,10 +937,10 @@
T.start;
alt {
- [] GTP2.receive(UECUPS_ProgramTermInd:{pid := pid, exit_code := exit_code}) {
+ [] GTP1U.receive(UECUPS_ProgramTermInd:{pid := pid, exit_code := exit_code}) {
setverdict(pass);
}
- [] GTP2.receive(UECUPS_ProgramTermInd:?) -> value pti {
+ [] GTP1U.receive(UECUPS_ProgramTermInd:?) -> value pti {
Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail,
log2str("Received unexpected ProgramTermInd := ", pti));
}
diff --git a/pgw/gen_links.sh b/pgw/gen_links.sh
index 314050e..fa69ee4 100755
--- a/pgw/gen_links.sh
+++ b/pgw/gen_links.sh
@@ -59,7 +59,8 @@
DIR=../library
FILES="Misc_Helpers.ttcn General_Types.ttcn GSM_Types.ttcn Osmocom_Types.ttcn Native_Functions.ttcn Native_FunctionDefs.cc IPCP_Types.ttcn IPCP_Templates.ttcn PAP_Types.ttcn "
-FILES+="GTPv1C_CodecPort.ttcn GTPv1C_CodecPort_CtrlFunct.ttcn GTPv1C_CodecPort_CtrlFunctDef.cc GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1C_Templates.ttcn Osmocom_Gb_Types.ttcn "
+FILES+="GTPv1C_CodecPort.ttcn GTPv1C_CodecPort_CtrlFunct.ttcn GTPv1C_CodecPort_CtrlFunctDef.cc GTPv1C_Templates.ttcn Osmocom_Gb_Types.ttcn "
+FILES+="GTPv1U_CodecPort.ttcn GTPv1U_CodecPort_CtrlFunct.ttcn GTPv1U_CodecPort_CtrlFunctDef.cc GTPv1U_Emulation.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 "
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40744?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: Ia45307107753294c6761cb588f0ab769821eb213
Gerrit-Change-Number: 40744
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[S] Change in osmo-uecups[master]: ttcn3: UECUPS_Types: Add templates for existing json commands
by pespin 29 Jul '25
by pespin 29 Jul '25
29 Jul '25
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-uecups/+/40761?usp=email )
Change subject: ttcn3: UECUPS_Types: Add templates for existing json commands
......................................................................
ttcn3: UECUPS_Types: Add templates for existing json commands
Related: SYS#7073
Change-Id: If524b0a122d1217fcd39e4633835a1a7d0620c7a
---
M ttcn3/UECUPS_Types.ttcn
1 file changed, 39 insertions(+), 0 deletions(-)
Approvals:
osmith: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/ttcn3/UECUPS_Types.ttcn b/ttcn3/UECUPS_Types.ttcn
index bbd849f..2e6686b 100644
--- a/ttcn3/UECUPS_Types.ttcn
+++ b/ttcn3/UECUPS_Types.ttcn
@@ -128,5 +128,44 @@
Port := Port
}
+template (value) UECUPS_CreateTun
+ts_UECUPS_CreateTun(template (value) uint32_t tx_teid,
+ template (value) uint32_t rx_teid,
+ template (value) UECUPS_AddrType user_addr_type,
+ template (value) OCT4_16n user_addr,
+ template (value) UECUPS_SockAddr local_gtp_ep,
+ template (value) UECUPS_SockAddr remote_gtp_ep,
+ template (value) charstring tun_dev_name := "tun",
+ template (omit) charstring tun_netns_name := omit)
+:= {
+ tx_teid := tx_teid,
+ rx_teid := rx_teid,
+ user_addr_type := user_addr_type,
+ user_addr := user_addr,
+ local_gtp_ep := local_gtp_ep,
+ remote_gtp_ep := remote_gtp_ep,
+ tun_dev_name := tun_dev_name,
+ tun_netns_name := tun_netns_name
+};
+
+template (value) UECUPS_DestroyTun
+ts_UECUPS_DestroyTun(template (value) UECUPS_SockAddr local_gtp_ep,
+ template (value) uint32_t rx_teid)
+:= {
+ local_gtp_ep := local_gtp_ep,
+ rx_teid := rx_teid
+};
+
+template (value) UECUPS_StartProgram
+ts_UECUPS_StartProgram(template (value) charstring command,
+ template (omit) charstring_list environment := omit,
+ template (value) charstring run_as_user := "root",
+ template (omit) charstring tun_netns_name := omit)
+:= {
+ command := command,
+ environment := environment,
+ run_as_user := run_as_user,
+ tun_netns_name := tun_netns_name
+};
} with { encode "JSON" };
--
To view, visit https://gerrit.osmocom.org/c/osmo-uecups/+/40761?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-uecups
Gerrit-Branch: master
Gerrit-Change-Id: If524b0a122d1217fcd39e4633835a1a7d0620c7a
Gerrit-Change-Number: 40761
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-uecups/+/40763?usp=email )
Change subject: Introduce GTPv1U QFI support
......................................................................
Introduce GTPv1U QFI support
* Allow user configuring over the json interface the Tx of PDU Session
Container with UL/DL direction and a given QFI per flow.
* Support decoding incoming GTPv1U packets containing extended headers.
* Update ttcn3/UECUPTS_Types.ttcn accordingly to be able to use the new
features.
With this patch it is now possible to use osmo-uecups against a 5GC.
Related: SYS#7073
Change-Id: I6262c3dfbf774b361aadf0aa53ce09b5fdc38da4
---
M daemon/cups_client.c
M daemon/gtp.h
M daemon/gtp_endpoint.c
M daemon/gtp_tunnel.c
M daemon/internal.h
M daemon/tun_device.c
M ttcn3/UECUPS_Types.ttcn
7 files changed, 339 insertions(+), 76 deletions(-)
Approvals:
Jenkins Builder: Verified
laforge: Looks good to me, approved
diff --git a/daemon/cups_client.c b/daemon/cups_client.c
index c9d8652..b72ebd7 100644
--- a/daemon/cups_client.c
+++ b/daemon/cups_client.c
@@ -15,6 +15,7 @@
#include <osmocom/core/exec.h>
#include "internal.h"
+#include "gtp.h"
#include <netinet/sctp.h>
@@ -202,6 +203,58 @@
return 0;
}
+static int parse_ext_hdr_pdu_session_container(struct gtp1u_exthdr_pdu_sess_container *out, json_t *jpdu_sess_cont)
+{
+ json_t *jpdu_type, *jqfi;
+ const char *str_pdu_type;
+
+ if (!json_is_object(jpdu_sess_cont))
+ return -EINVAL;
+
+ memset(out, 0, sizeof(*out));
+
+ out->enabled = true;
+
+ jpdu_type = json_object_get(jpdu_sess_cont, "pdu_type");
+ if (!json_is_string(jpdu_type))
+ return -EINVAL;
+ str_pdu_type = json_string_value(jpdu_type);
+ if (!strcmp(str_pdu_type, "ul_pdu_sess_info"))
+ out->pdu_type = GTP1_EXTHDR_PDU_TYPE_UL_PDU_SESSION_INFORMATION;
+ else if (!strcmp(str_pdu_type, "dl_pdu_sess_info"))
+ out->pdu_type = GTP1_EXTHDR_PDU_TYPE_DL_PDU_SESSION_INFORMATION;
+ else
+ return -EINVAL;
+
+ jqfi = json_object_get(jpdu_sess_cont, "qfi");
+ if (!json_is_integer(jqfi))
+ return -EINVAL;
+ out->qos_flow_identifier = json_number_value(jqfi);
+
+ return 0;
+}
+static int parse_ext_hdr(struct gtp1u_exthdrs *out, json_t *jexthdr)
+{
+ json_t *jseq_num, *jn_pdu_num, *jpdu_sess_cont;
+ int rc = 0;
+
+ if (!json_is_object(jexthdr))
+ return -EINVAL;
+
+ jseq_num = json_object_get(jexthdr, "sequence_number");
+ if (jseq_num)
+ out->seq_num_enabled = true;
+
+ jn_pdu_num = json_object_get(jexthdr, "n_pdu_number");
+ if (jn_pdu_num)
+ out->n_pdu_num_enabled = true;
+
+ jpdu_sess_cont = json_object_get(jexthdr, "pdu_session_container");
+ if (jpdu_sess_cont)
+ rc = parse_ext_hdr_pdu_session_container(&out->pdu_sess_container, jpdu_sess_cont);
+
+ return rc;
+}
static int parse_create_tun(struct gtp_tunnel_params *out, json_t *ctun)
{
@@ -209,6 +262,7 @@
json_t *jrx_teid, *jtx_teid;
json_t *jtun_dev_name, *jtun_netns_name;
json_t *juser_addr, *juser_addr_type;
+ json_t *jgtp_ext_hdr;
int rc;
/* '{"create_tun":{"tx_teid":1234,"rx_teid":5678,"user_addr_type":"IPV4","user_addr":"21222324","local_gtp_ep":{"addr_type":"IPV4","ip":"31323334","Port":2152},"remote_gtp_ep":{"addr_type":"IPV4","ip":"41424344","Port":2152},"tun_dev_name":"tun23","tun_netns_name":"foo"}}' */
@@ -257,6 +311,13 @@
out->tun_netns_name = talloc_strdup(out, json_string_value(jtun_netns_name));
}
+ jgtp_ext_hdr = json_object_get(ctun, "gtp_ext_hdr");
+ if (jgtp_ext_hdr) {
+ rc = parse_ext_hdr(&out->exthdr, jgtp_ext_hdr);
+ if (rc < 0)
+ return rc;
+ }
+
return 0;
}
diff --git a/daemon/gtp.h b/daemon/gtp.h
index f2acd36..2947d25 100644
--- a/daemon/gtp.h
+++ b/daemon/gtp.h
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0 */
#pragma once
#include <stdint.h>
+#include <osmocom/core/endian.h>
/* General GTP protocol related definitions. */
@@ -31,3 +32,60 @@
#define GTP1_F_SEQ 0x02
#define GTP1_F_EXTHDR 0x04
#define GTP1_F_MASK 0x07
+
+
+/*
+ * 5GC GTP Header (16byte)
+ * o Flags(1byte) : 0x34
+ * o Message Type(1byte) : T-PDU (0xff)
+ * o Length(2byte) : 36
+ * o TEID(4byte) : 0x00000001
+ * o Sequence Number(2byte) : 0x0000
+ * o N PDU Number(1byte) : 0x00
+ * o Next extension header type(4byte): PDU Session container(1byte) : (0x85)
+ * o Extension header(4byte)
+ * - Extension HEader Length(1byte) : 1
+ * - PDU Session Container(2byte)
+ * ; PDU Type : UL PDU SESSION INFORMATION (1)
+ * ; QoS Flow Identifier (QFI) : 1
+ * - Next extension header type : No more extension headers (0x00)
+ */
+
+#define GTP1_EXTHDR_UDP_PORT 0x40
+#define GTP1_EXTHDR_PDU_SESSION_CONTAINER 0x85
+#define GTP1_EXTHDR_PDCP_NUMBER 0xc0
+#define GTP1_EXTHDR_NO_MORE_EXTENSION_HEADERS 0x0
+
+#define GTP1_EXTHDR_PDU_TYPE_DL_PDU_SESSION_INFORMATION 0
+#define GTP1_EXTHDR_PDU_TYPE_UL_PDU_SESSION_INFORMATION 1
+
+struct gtp1_exthdr {
+ uint16_t sequence_number;
+ uint8_t n_pdu_number;
+ struct {
+#if OSMO_IS_LITTLE_ENDIAN
+ uint8_t type;
+ uint8_t len;
+ union {
+ struct { /* TODO: make sure order of fields is correct or swapped */
+ uint8_t spare1:4,
+ pdu_type:4;
+ uint8_t qos_flow_identifier:6,
+ reflective_qos_indicator:1,
+ paging_policy_presence:1;
+#elif OSMO_IS_BIG_ENDIAN
+/* auto-generated from the little endian part above (libosmocore/contrib/struct_endianness.py) */
+ uint8_t type;
+ uint8_t len;
+ union {
+ struct {
+ uint8_t spare1:4,
+ pdu_type:4;
+ uint8_t paging_policy_presence:1, reflective_qos_indicator:1, qos_flow_identifier:6;
+#endif
+ };
+ uint16_t udp_port;
+ uint16_t pdcp_number;
+ };
+ } __attribute__ ((packed)) array[8];
+} __attribute__ ((packed));
diff --git a/daemon/gtp_endpoint.c b/daemon/gtp_endpoint.c
index 4221e14..bb417da 100644
--- a/daemon/gtp_endpoint.c
+++ b/daemon/gtp_endpoint.c
@@ -27,19 +27,98 @@
* GTP Endpoint (UDP socket)
***********************************************************************/
+static void handle_gtp1u(struct gtp_endpoint *ep, const uint8_t *buffer, unsigned int nread)
+{
+ struct gtp_daemon *d = ep->d;
+ struct gtp_tunnel *t;
+ const struct gtp1_header *gtph;
+ const uint8_t *payload;
+ int rc, outfd;
+ uint32_t teid;
+ uint16_t gtp_len;
+
+ if (nread < sizeof(*gtph)) {
+ LOGEP(ep, LOGL_NOTICE, "Short read: %u < %lu\n", nread, sizeof(*gtph));
+ return;
+ }
+ gtph = (struct gtp1_header *)buffer;
+
+ /* check GTP header contents */
+ if ((gtph->flags & 0xf0) != 0x30) {
+ LOGEP(ep, LOGL_NOTICE, "Unexpected GTP Flags: 0x%02x\n", gtph->flags);
+ return;
+ }
+ if (gtph->type != GTP_TPDU) {
+ LOGEP(ep, LOGL_NOTICE, "Unexpected GTP Message Type: 0x%02x\n", gtph->type);
+ return;
+ }
+
+ gtp_len = ntohs(gtph->length);
+ if (sizeof(*gtph)+gtp_len > nread) {
+ LOGEP(ep, LOGL_NOTICE, "Short GTP Message: %lu < len=%u\n",
+ sizeof(*gtph)+gtp_len, nread);
+ return;
+ }
+ teid = ntohl(gtph->tid);
+
+ payload = buffer + sizeof(*gtph);
+ if (gtph->flags & GTP1_F_MASK) {
+ const struct gtp1_exthdr *exthdr = (const struct gtp1_exthdr *)payload;
+ if (gtp_len < 4) {
+ LOGEP(ep, LOGL_NOTICE, "Short GTP Message according to flags 0x%02x: %lu < len=%u\n",
+ gtph->flags, sizeof(*gtph) + gtp_len, nread);
+ return;
+ }
+ gtp_len -= 4;
+ payload += 4;
+ const uint8_t *it = &exthdr->array[0].type;
+ while (*it != 0) {
+ unsigned int ext_len;
+ if (gtp_len < 1) {
+ LOGEP(ep, LOGL_NOTICE, "Short GTP Message according to flags 0x%02x: %lu < len=%u\n",
+ gtph->flags, sizeof(*gtph) + gtp_len, nread);
+ return;
+ }
+ ext_len = 1 + 1 + it[1] + 1;
+ if (gtp_len < ext_len) {
+ LOGEP(ep, LOGL_NOTICE, "Short GTP Message according to flags 0x%02x: %lu < len=%u\n",
+ gtph->flags, sizeof(*gtph) + gtp_len, nread);
+ return;
+ }
+ gtp_len -= ext_len;
+ payload += ext_len;
+ it = payload - 1;
+ }
+ }
+
+ /* 2) look-up tunnel based on TEID */
+ pthread_rwlock_rdlock(&d->rwlock);
+ t = _gtp_tunnel_find_r(d, teid, ep);
+ if (!t) {
+ pthread_rwlock_unlock(&d->rwlock);
+ LOGEP(ep, LOGL_NOTICE, "Unable to find tunnel for TEID=0x%08x\n", teid);
+ return;
+ }
+ outfd = t->tun_dev->fd;
+ pthread_rwlock_unlock(&d->rwlock);
+
+ /* 3) write to TUN device */
+ rc = write(outfd, payload, gtp_len);
+ if (rc < gtp_len) {
+ LOGEP(ep, LOGL_FATAL, "Error writing to tun device %s\n", strerror(errno));
+ exit(1);
+ }
+}
+
/* one thread for reading from each GTP/UDP socket (GTP decapsulation -> tun) */
static void *gtp_endpoint_thread(void *arg)
{
struct gtp_endpoint *ep = (struct gtp_endpoint *)arg;
- struct gtp_daemon *d = ep->d;
- uint8_t buffer[MAX_UDP_PACKET+sizeof(struct gtp1_header)];
+ uint8_t buffer[sizeof(struct gtp1_header) + sizeof(struct gtp1_exthdr) + MAX_UDP_PACKET];
while (1) {
- struct gtp_tunnel *t;
- const struct gtp1_header *gtph;
- int rc, nread, outfd;
- uint32_t teid;
+ int rc;
/* 1) read GTP packet from UDP socket */
rc = recvfrom(ep->fd, buffer, sizeof(buffer), 0, (struct sockaddr *)NULL, 0);
@@ -47,46 +126,7 @@
LOGEP(ep, LOGL_FATAL, "Error reading from UDP socket: %s\n", strerror(errno));
exit(1);
}
- nread = rc;
- if (nread < sizeof(*gtph)) {
- LOGEP(ep, LOGL_NOTICE, "Short read: %d < %lu\n", nread, sizeof(*gtph));
- continue;
- }
- gtph = (struct gtp1_header *)buffer;
-
- /* check GTP heaader contents */
- if (gtph->flags != 0x30) {
- LOGEP(ep, LOGL_NOTICE, "Unexpected GTP Flags: 0x%02x\n", gtph->flags);
- continue;
- }
- if (gtph->type != GTP_TPDU) {
- LOGEP(ep, LOGL_NOTICE, "Unexpected GTP Message Type: 0x%02x\n", gtph->type);
- continue;
- }
- if (sizeof(*gtph)+ntohs(gtph->length) > nread) {
- LOGEP(ep, LOGL_NOTICE, "Shotr GTP Message: %lu < len=%d\n",
- sizeof(*gtph)+ntohs(gtph->length), nread);
- continue;
- }
- teid = ntohl(gtph->tid);
-
- /* 2) look-up tunnel based on TEID */
- pthread_rwlock_rdlock(&d->rwlock);
- t = _gtp_tunnel_find_r(d, teid, ep);
- if (!t) {
- pthread_rwlock_unlock(&d->rwlock);
- LOGEP(ep, LOGL_NOTICE, "Unable to find tunnel for TEID=0x%08x\n", teid);
- continue;
- }
- outfd = t->tun_dev->fd;
- pthread_rwlock_unlock(&d->rwlock);
-
- /* 3) write to TUN device */
- rc = write(outfd, buffer+sizeof(*gtph), ntohs(gtph->length));
- if (rc < nread-sizeof(struct gtp1_header)) {
- LOGEP(ep, LOGL_FATAL, "Error writing to tun device %s\n", strerror(errno));
- exit(1);
- }
+ handle_gtp1u(ep, buffer, rc);
}
}
diff --git a/daemon/gtp_tunnel.c b/daemon/gtp_tunnel.c
index 87d1e69..6c3e81c 100644
--- a/daemon/gtp_tunnel.c
+++ b/daemon/gtp_tunnel.c
@@ -56,6 +56,7 @@
t->rx_teid = cpars->rx_teid;
t->tx_teid = cpars->tx_teid;
+ memcpy(&t->exthdr, &cpars->exthdr, sizeof(t->exthdr));
memcpy(&t->user_addr, &cpars->user_addr, sizeof(t->user_addr));
memcpy(&t->remote_udp, &cpars->remote_udp, sizeof(t->remote_udp));
diff --git a/daemon/internal.h b/daemon/internal.h
index 25a8f91..19cf16a 100644
--- a/daemon/internal.h
+++ b/daemon/internal.h
@@ -181,6 +181,18 @@
* this is what happens when IP arrives on the tun device
*/
+struct gtp1u_exthdr_pdu_sess_container {
+ bool enabled;
+ uint8_t pdu_type; /* GTP1_EXTHDR_PDU_TYPE_* */
+ uint8_t qos_flow_identifier;
+};
+
+struct gtp1u_exthdrs {
+ bool seq_num_enabled;
+ bool n_pdu_num_enabled;
+ struct gtp1u_exthdr_pdu_sess_container pdu_sess_container;
+};
+
struct gtp_tunnel {
/* entry in global list / hash table */
struct llist_head list;
@@ -205,6 +217,9 @@
/* Remote UDP IP/Port*/
struct sockaddr_storage remote_udp;
+ /* GTP Extension Header */
+ struct gtp1u_exthdrs exthdr;
+
/* TODO: Filter */
};
@@ -219,6 +234,9 @@
uint32_t rx_teid;
uint32_t tx_teid;
+ /* GTPv1U Extension Headers: */
+ struct gtp1u_exthdrs exthdr;
+
/* end user address */
struct sockaddr_storage user_addr;
diff --git a/daemon/tun_device.c b/daemon/tun_device.c
index e9c0400..6a0d8b6 100644
--- a/daemon/tun_device.c
+++ b/daemon/tun_device.c
@@ -128,23 +128,81 @@
OSMO_ASSERT(rc == 0);
}
+/* Note: This function is called with d->rwlock locked, and it's responsible of unlocking it before returning. */
+static int tx_gtp1u_pkt(struct gtp_tunnel *t, uint8_t *base_buffer, const uint8_t *payload, unsigned int payload_len)
+{
+ struct gtp1_header *gtph;
+ unsigned int head_len = payload - base_buffer;
+ unsigned int hdr_len_needed;
+ unsigned int opt_hdr_len_needed = 0;
+ struct sockaddr_storage daddr;
+ int outfd = t->gtp_ep->fd;
+ int rc;
+ uint8_t flags;
+
+#define GTP1_F_NPDU 0x01
+#define GTP1_F_SEQ 0x02
+#define GTP1_F_EXTHDR 0x04
+#define GTP1_F_MASK 0x07
+
+ flags = 0x30; /* Version */
+
+ if (t->exthdr.seq_num_enabled)
+ flags |= GTP1_F_SEQ;
+
+ if (t->exthdr.n_pdu_num_enabled)
+ flags |= GTP1_F_NPDU;
+
+ if (t->exthdr.pdu_sess_container.enabled) {
+ flags |= GTP1_F_EXTHDR;
+ opt_hdr_len_needed += 4; /* Extra Header struct */
+ }
+
+ /* Make sure the Next Extension Header Type is counted: */
+ if (flags & GTP1_F_MASK)
+ opt_hdr_len_needed += 4;
+
+ hdr_len_needed = sizeof(struct gtp1_header) + opt_hdr_len_needed;
+ OSMO_ASSERT(hdr_len_needed < head_len);
+ gtph = (struct gtp1_header *)(payload - hdr_len_needed);
+ /* initialize the fixed part of the GTP header */
+ gtph->flags = flags;
+ gtph->type = GTP_TPDU;
+ gtph->length = htons(opt_hdr_len_needed + payload_len);
+ gtph->tid = htonl(t->tx_teid);
+
+ if (flags & GTP1_F_MASK) {
+ struct gtp1_exthdr *exthdr = (struct gtp1_exthdr *)(((uint8_t *)gtph) + sizeof(*gtph));
+ exthdr->sequence_number = htons(0); /* TODO: increment sequence_number in "t". */
+ exthdr->n_pdu_number = 0; /* TODO: increment n_pdu_number in "t". */
+ if (t->exthdr.pdu_sess_container.enabled) {
+ exthdr->array[0].type = GTP1_EXTHDR_PDU_SESSION_CONTAINER;
+ exthdr->array[0].len = 1;
+ exthdr->array[0].pdu_type = t->exthdr.pdu_sess_container.pdu_type;
+ exthdr->array[0].qos_flow_identifier = t->exthdr.pdu_sess_container.qos_flow_identifier;
+ exthdr->array[1].type = 0; /* No extension headers */
+ } else {
+ exthdr->array[0].type = 0; /* No extension headers */
+ }
+ }
+
+ memcpy(&daddr, &t->remote_udp, sizeof(daddr));
+ pthread_rwlock_unlock(&t->d->rwlock);
+
+ /* 4) write to GTP/UDP socket */
+ rc = sendto(outfd, gtph, hdr_len_needed + payload_len, 0,
+ (struct sockaddr *)&daddr, sizeof(daddr));
+ return rc;
+}
+
/* one thread for reading from each TUN device (TUN -> GTP encapsulation) */
static void *tun_device_thread(void *arg)
{
struct tun_device *tun = (struct tun_device *)arg;
struct gtp_daemon *d = tun->d;
-
- uint8_t base_buffer[MAX_UDP_PACKET+sizeof(struct gtp1_header)];
- struct gtp1_header *gtph = (struct gtp1_header *)base_buffer;
- uint8_t *buffer = base_buffer + sizeof(struct gtp1_header);
-
- struct sockaddr_storage daddr;
+ uint8_t base_buffer[sizeof(struct gtp1_header) + sizeof(struct gtp1_exthdr) + MAX_UDP_PACKET];
int old_cancelst_unused;
- /* initialize the fixed part of the GTP header */
- gtph->flags = 0x30;
- gtph->type = GTP_TPDU;
-
pthread_cleanup_push(tun_device_pthread_cleanup_routine, tun);
/* IMPORTANT!: All logging functions in this function block must be called with
* PTHREAD_CANCEL_DISABLE set, otherwise the thread could be cancelled while
@@ -154,7 +212,8 @@
while (1) {
struct gtp_tunnel *t;
struct pkt_info pinfo;
- int rc, nread, outfd;
+ int rc, nread;
+ uint8_t *buffer = base_buffer + sizeof(base_buffer) - MAX_UDP_PACKET;
/* 1) read from tun */
rc = read(tun->fd, buffer, MAX_UDP_PACKET);
@@ -164,7 +223,6 @@
exit(1);
}
nread = rc;
- gtph->length = htons(nread);
rc = parse_pkt(&pinfo, buffer, nread);
if (rc < 0) {
@@ -194,14 +252,7 @@
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_cancelst_unused);
continue;
}
- outfd = t->gtp_ep->fd;
- memcpy(&daddr, &t->remote_udp, sizeof(daddr));
- gtph->tid = htonl(t->tx_teid);
- pthread_rwlock_unlock(&d->rwlock);
-
- /* 4) write to GTP/UDP socket */
- rc = sendto(outfd, base_buffer, nread+sizeof(*gtph), 0,
- (struct sockaddr *)&daddr, sizeof(daddr));
+ rc = tx_gtp1u_pkt(t, base_buffer, buffer, nread);
if (rc < 0) {
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_cancelst_unused);
LOGTUN(tun, LOGL_FATAL, "Error Writing to UDP socket: %s\n", strerror(errno));
diff --git a/ttcn3/UECUPS_Types.ttcn b/ttcn3/UECUPS_Types.ttcn
index 2e6686b..29fa738 100644
--- a/ttcn3/UECUPS_Types.ttcn
+++ b/ttcn3/UECUPS_Types.ttcn
@@ -22,23 +22,37 @@
uint16_t Port
};
+const charstring UECUPS_GtpExtHdr_PduSessContainer_Type_ul_pdu_sess_info := "ul_pdu_sess_info";
+const charstring UECUPS_GtpExtHdr_PduSessContainer_Type_dl_pdu_sess_info := "dl_pdu_sess_info";
+type record UECUPS_GtpExtHdr_PduSessContainer {
+ charstring pdu_type, /* ("ul_pdu_sess_info"|"dl_pdu_sess_info") */
+ uint32_t qfi
+};
+
+type record UECUPS_GtpExtHdr {
+ boolean sequence_number optional,
+ boolean n_pdu_number optional,
+ UECUPS_GtpExtHdr_PduSessContainer pdu_session_container optional
+};
+
/* Create a new GTP-U tunnel in the user plane */
type record UECUPS_CreateTun {
/* TEID in transmit + receive direction */
- uint32_t tx_teid,
- uint32_t rx_teid,
+ uint32_t tx_teid,
+ uint32_t rx_teid,
/* user address (allocated inside the tunnel) */
- UECUPS_AddrType user_addr_type,
- OCT4_16n user_addr,
+ UECUPS_AddrType user_addr_type,
+ OCT4_16n user_addr,
/* GTP endpoint (UDP IP/Port tuples) */
- UECUPS_SockAddr local_gtp_ep,
- UECUPS_SockAddr remote_gtp_ep,
+ UECUPS_SockAddr local_gtp_ep,
+ UECUPS_SockAddr remote_gtp_ep,
/* TUN device */
- charstring tun_dev_name,
- charstring tun_netns_name optional
+ charstring tun_dev_name,
+ charstring tun_netns_name optional,
+ UECUPS_GtpExtHdr gtp_ext_hdr optional
};
type record UECUPS_CreateTunRes {
@@ -128,6 +142,24 @@
Port := Port
}
+template (value) UECUPS_GtpExtHdr_PduSessContainer
+ts_UECUPS_GtpExtHdr_PduSessContainer(template (value) charstring pdu_type,
+ template (value) uint32_t qfi)
+:= {
+ pdu_type := pdu_type,
+ qfi := qfi
+};
+
+template (value) UECUPS_GtpExtHdr
+ts_UECUPS_GtpExtHdr(template (omit) boolean sequence_number := omit,
+ template (omit) boolean n_pdu_number := omit,
+ template (omit) UECUPS_GtpExtHdr_PduSessContainer pdu_session_container := omit)
+:= {
+ sequence_number := sequence_number,
+ n_pdu_number := n_pdu_number,
+ pdu_session_container := pdu_session_container
+};
+
template (value) UECUPS_CreateTun
ts_UECUPS_CreateTun(template (value) uint32_t tx_teid,
template (value) uint32_t rx_teid,
@@ -136,7 +168,8 @@
template (value) UECUPS_SockAddr local_gtp_ep,
template (value) UECUPS_SockAddr remote_gtp_ep,
template (value) charstring tun_dev_name := "tun",
- template (omit) charstring tun_netns_name := omit)
+ template (omit) charstring tun_netns_name := omit,
+ template (omit) UECUPS_GtpExtHdr gtp_ext_hdr := omit)
:= {
tx_teid := tx_teid,
rx_teid := rx_teid,
@@ -145,7 +178,8 @@
local_gtp_ep := local_gtp_ep,
remote_gtp_ep := remote_gtp_ep,
tun_dev_name := tun_dev_name,
- tun_netns_name := tun_netns_name
+ tun_netns_name := tun_netns_name,
+ gtp_ext_hdr := gtp_ext_hdr
};
template (value) UECUPS_DestroyTun
--
To view, visit https://gerrit.osmocom.org/c/osmo-uecups/+/40763?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: osmo-uecups
Gerrit-Branch: master
Gerrit-Change-Id: I6262c3dfbf774b361aadf0aa53ce09b5fdc38da4
Gerrit-Change-Number: 40763
Gerrit-PatchSet: 5
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: daniel <dwillmann(a)sysmocom.de>
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
1
0
[S] Change in osmo-ttcn3-hacks[master]: pgw: Use templates to generate UECUPS commands
by pespin 29 Jul '25
by pespin 29 Jul '25
29 Jul '25
Attention is currently required from: fixeria.
pespin has posted comments on this change by pespin. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40762?usp=email )
Change subject: pgw: Use templates to generate UECUPS commands
......................................................................
Patch Set 1: Code-Review+2
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40762?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I4de6623318fe2abf9807702251fe420eb14de2cc
Gerrit-Change-Number: 40762
Gerrit-PatchSet: 1
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Comment-Date: Tue, 29 Jul 2025 08:31:29 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
1
0
[M] Change in osmo-ttcn3-hacks[master]: pgw: Move to library/ high level APIs to run commands over UECUPS
by pespin 29 Jul '25
by pespin 29 Jul '25
29 Jul '25
pespin has posted comments on this change by pespin. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40753?usp=email )
Change subject: pgw: Move to library/ high level APIs to run commands over UECUPS
......................................................................
Patch Set 3: Code-Review+2
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40753?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: I49c98fd423e47e16ddfb9ae4612b18db21ca3fa4
Gerrit-Change-Number: 40753
Gerrit-PatchSet: 3
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-Comment-Date: Tue, 29 Jul 2025 08:31:26 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
1
0
29 Jul '25
pespin has posted comments on this change by pespin. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40752?usp=email )
Change subject: Move ConnHdlr logic to its own file
......................................................................
Patch Set 2: Code-Review+2
--
To view, visit https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/40752?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: osmo-ttcn3-hacks
Gerrit-Branch: master
Gerrit-Change-Id: If7edf8ee63c71fbf949e2d340cf3881fd8e3ba41
Gerrit-Change-Number: 40752
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
Gerrit-Comment-Date: Tue, 29 Jul 2025 08:31:24 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
1
0