lists.osmocom.org
Sign In Sign Up
Manage this list Sign In Sign Up

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

gerrit-log

Thread Start a new thread
Download
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
gerrit-log@lists.osmocom.org

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

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
0 0
[L] Change in osmo-ttcn3-hacks[master]: Move ConnHdlr logic to its own file
by pespin 29 Jul '25

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
0 0
[M] Change in osmo-ttcn3-hacks[master]: GTP1vU_Emulation: Make UECUPS support optional
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
0 0
[S] Change in osmo-ttcn3-hacks[master]: gbproxy: Drop unneeded GTP dependencies
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
0 0
[L] Change in osmo-ttcn3-hacks[master]: Split GTPv1U out of GTPv2_Emulation
by pespin 29 Jul '25

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
0 0
[S] Change in osmo-uecups[master]: ttcn3: UECUPS_Types: Add templates for existing json commands
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
0 0
[L] Change in osmo-uecups[master]: Introduce GTPv1U QFI support
by pespin 29 Jul '25

29 Jul '25
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
0 0
[S] Change in osmo-ttcn3-hacks[master]: pgw: Use templates to generate UECUPS commands
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
0 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

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
0 0
[L] Change in osmo-ttcn3-hacks[master]: Move ConnHdlr logic to its own file
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/+/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
0 0
  • ← Newer
  • 1
  • ...
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • ...
  • 150
  • Older →

HyperKitty Powered by HyperKitty version 1.3.12.