pespin has submitted this change. ( https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/43740?usp=email )
Change subject: smf,pgw: Fix missing s6b STR handling during release of s2b sessions ......................................................................
smf,pgw: Fix missing s6b STR handling during release of s2b sessions
Sesions created over s2b (EPDG) also create a session on the AAA over s6b. When the s2b session is released, a Diameter STR message is sent towards the AAA, which should answer with STA so that the session is properly terminated.
Change-Id: I9bc54205eaa3b26a5ec9a3666172ee35d3b98b0e --- M library/DIAMETER_ts29_273_Templates.ttcn M pgw/PGW_Session_CT.ttcn M pgw/PGW_Tests.ttcn M smf/SMF_Session_CT_4G.ttcn M smf/SMF_Tests.ttcn 5 files changed, 186 insertions(+), 18 deletions(-)
Approvals: pespin: Looks good to me, approved fixeria: Looks good to me, but someone else must approve Jenkins Builder: Verified
diff --git a/library/DIAMETER_ts29_273_Templates.ttcn b/library/DIAMETER_ts29_273_Templates.ttcn index a9f1769..d3915b0 100644 --- a/library/DIAMETER_ts29_273_Templates.ttcn +++ b/library/DIAMETER_ts29_273_Templates.ttcn @@ -505,6 +505,32 @@
/* TS 29.273 9.2.2.3.1 Session-Termination-Request (STR) Command, * Table 9.1.2.3.1/1: S6b Session Termination Request (STR), based on RFC 6733 8.4.1 */ +template (present) PDU_DIAMETER +tr_DIA_S6b_STR(template (present) hexstring imsi := ?, + template (present) BASE_NONE_Termination_Cause term_cause := ?, + template (present) octetstring sess_id := ?, + template (present) charstring orig_host := ?, + template (present) charstring orig_realm := ?, + template (present) charstring dest_realm := ?, + template (present) UINT32 hbh_id := ?, + template (present) UINT32 ete_id := ?) := + tr_DIAMETER(flags := '1???????'B, + cmd_code := Session_Termination, + app_id := int2oct(c_DIAMETER_3GPP_S6b_AID, 4), + hbh_id := hbh_id, + ete_id := ete_id, + avps := superset( + tr_AVP_SessionId(sess_id), + /* Optional: DRMP */ + tr_AVP_AuthAppId(int2oct(c_DIAMETER_3GPP_S6b_AID, 4)), + tr_AVP_OriginHost(orig_host), + tr_AVP_OriginRealm(orig_realm), + tr_AVP_DestinationRealm(dest_realm), + tr_AVP_TerminationCause(term_cause), + tr_AVP_UserNameImsi(imsi) + /* Optional: OC-Supported-Features */ + )); + template (value) PDU_DIAMETER ts_DIA_S6b_STR(template (value) hexstring imsi, template (value) BASE_NONE_Termination_Cause term_cause := DIAMETER_LOGOUT, @@ -554,6 +580,28 @@ /* Lots other Optional */ ));
+template (value) PDU_DIAMETER +ts_DIA_S6b_STA(template (value) DIAMETER_Resultcode res_code := DIAMETER_SUCCESS, + template (value) octetstring sess_id := c_def_sess_id, + template (value) charstring orig_host := "aaa.localdomain", + template (value) charstring orig_realm := "localdomain", + template (value) charstring dest_realm := "localdomain", + template (value) UINT32 hbh_id := '00000000'O, + template (value) UINT32 ete_id := '00000000'O) := + ts_DIAMETER(flags := '01000000'B, + cmd_code := Session_Termination, + app_id := int2oct(c_DIAMETER_3GPP_S6b_AID, 4), + hbh_id := hbh_id, + ete_id := ete_id, + avps := { + ts_AVP_SessionId(sess_id), + /* Optional: DRMP */ + ts_AVP_ResultCode(res_code), + ts_AVP_ResultCode(res_code), + ts_AVP_OriginHost(orig_host), + ts_AVP_OriginRealm(orig_realm) + /* Lots other Optional */ + });
/* TS 29.273 9.2.2.4.1 Abort-Session-Request (ASR) */ template (present) PDU_DIAMETER @@ -697,4 +745,29 @@ return tx_dia; }
+/* generate a send template successful answer based on received STR */ +function f_ts_DIA_S6b_STA(PDU_DIAMETER rx_s6b, + template (value) DIAMETER_Resultcode res_code := DIAMETER_SUCCESS, + template (value) charstring orig_host := "aaa.localdomain", + template (value) charstring orig_realm := "localdomain", + template (value) charstring dest_realm := "localdomain") +return template (value) PDU_DIAMETER +{ + var template (value) PDU_DIAMETER tx_dia; + var template (omit) AVP avp; + var octetstring sess_id; + + avp := f_DIAMETER_get_avp(rx_s6b, c_AVP_Code_BASE_NONE_Session_Id); + sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id); + + tx_dia := ts_DIA_S6b_STA(res_code, + sess_id, + orig_host, + orig_realm, + dest_realm, + rx_s6b.hop_by_hop_id, + rx_s6b.end_to_end_id); + return tx_dia; +} + } diff --git a/pgw/PGW_Session_CT.ttcn b/pgw/PGW_Session_CT.ttcn index 3de8d54..74aadfb 100644 --- a/pgw/PGW_Session_CT.ttcn +++ b/pgw/PGW_Session_CT.ttcn @@ -173,6 +173,24 @@ } }
+private altstep as_DIA_S6b_STR() runs on PGW_Session_CT { + var PDU_DIAMETER rx_dia; + [] DIAMETER[DIA_S6b].receive(tr_DIA_S6b_STR()) -> value rx_dia { + var template (value) PDU_DIAMETER tx_dia; + tx_dia := f_ts_DIA_S6b_STA(rx_dia, + DIAMETER_SUCCESS, + "aaa." & mp_diam_realm, + mp_diam_realm, + mp_diam_realm); + DIAMETER[DIA_S6b].send(tx_dia); + setverdict(pass); + } + [] DIAMETER[DIA_S6b].receive(PDU_DIAMETER:?) -> value rx_dia { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Received unexpected DIAMETER ", rx_dia)); + } +} + /* Gx emulation (PCRF)*/ altstep as_DIA_Gx_CCR(DCC_NONE_CC_Request_Type req_type) runs on PGW_Session_CT { var PDU_DIAMETER rx_dia; @@ -467,18 +485,21 @@ }
/* delete the session from the PGW */ -function f_delete_session(template (omit) GTP2C_Cause tx_cause := omit, +function f_delete_session(template (value) FullyQualifiedTEID fteid_c_ie, + template (omit) GTP2C_Cause tx_cause := omit, template (present) GTP2C_Cause exp_cause, - boolean expect_diameter := true) runs on PGW_Session_CT { - var template (value) FullyQualifiedTEID fteid_c_ie - fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S5S8_SGW_GTPC, g_pars.teic_local, 0, - f_inet_addr(mp_local_hostname_c), omit); + boolean expect_diameter := true) +runs on PGW_Session_CT { + var template PDU_GTPCv2 g2c := ts_GTP2C_DeleteSessionReq(d_teid := g_pars.teic_remote, cause := tx_cause, sender_fteid := fteid_c_ie, teid_list := {}, bearer_id := g_pars.bearer.ebi);
GTP2.send(g2c); + if (is_s2b_iface() and DIAMETER[DIA_S6b].checkstate("Connected") and expect_diameter) { + as_DIA_S6b_STR(); + } if (DIAMETER[DIA_Gx].checkstate("Connected") and expect_diameter) { as_DIA_Gx_CCR(TERMINATION_REQUEST); } @@ -511,6 +532,28 @@ } }
+function f_s5s8_delete_session(template (omit) GTP2C_Cause tx_cause := omit, + template (present) GTP2C_Cause exp_cause, + boolean expect_diameter := true) +runs on PGW_Session_CT { + var template (value) FullyQualifiedTEID fteid_c_ie; + + fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S5S8_SGW_GTPC, g_pars.teic_local, 0, + f_inet_addr(mp_local_hostname_c), omit); + f_delete_session(fteid_c_ie, tx_cause, exp_cause, expect_diameter); +} + +function f_s2b_delete_session(template (omit) GTP2C_Cause tx_cause := omit, + template (present) GTP2C_Cause exp_cause, + boolean expect_diameter := true) +runs on PGW_Session_CT { + var template (value) FullyQualifiedTEID fteid_c_ie; + + fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S2b_ePDG_GTPC, g_pars.teic_local, 0, + f_inet_addr(mp_local_hostname_c), omit); + + f_delete_session(fteid_c_ie, tx_cause, exp_cause, expect_diameter); +}
private function f_run_prog_init(charstring command) runs on PGW_Session_CT return UECUPS_StartProgram { diff --git a/pgw/PGW_Tests.ttcn b/pgw/PGW_Tests.ttcn index bd95090..ba660dd 100644 --- a/pgw/PGW_Tests.ttcn +++ b/pgw/PGW_Tests.ttcn @@ -375,7 +375,7 @@ /* create a session, then delete it again */ private function f_TC_createSession_deleteSession() runs on PGW_Session_CT { f_s5s8_create_session(); - f_delete_session(omit, Request_accepted); + f_s5s8_delete_session(omit, Request_accepted); setverdict(pass); } testcase TC_createSession_deleteSession() runs on PGW_Test_CT { @@ -389,7 +389,7 @@ /* send a DeleteSessionReq for an unknown/invalid TEID */ private function f_TC_deleteSession_unknown() runs on PGW_Session_CT { g_pars.teic_remote := f_rnd_octstring(4); - f_delete_session(omit, Context_Not_Found, false); + f_s5s8_delete_session(omit, Context_Not_Found, false); setverdict(pass); } testcase TC_deleteSession_unknown() runs on PGW_Test_CT { @@ -420,7 +420,7 @@ as_DIA_Gy_CCR(UPDATE_REQUEST); f_validate_gy_cc_report(g_rx_gy, VALIDITY_TIME, (3..4), ?, ?);
- f_delete_session(omit, Request_accepted); + f_s5s8_delete_session(omit, Request_accepted); f_validate_gy_cc_report(g_rx_gy, FINAL, (0..1), 0, 0); setverdict(pass); } @@ -466,6 +466,7 @@ var template (omit) APCO apco := omit; var template APCO exp_apco := omit; f_s2b_create_session(apco, exp_apco); + f_s2b_delete_session(omit, Request_accepted); setverdict(pass); } testcase TC_s2b_createSession_v4_noapco() runs on PGW_Test_CT { @@ -487,6 +488,7 @@ *, /* open5gs-smfd can contain several DNS servers */ tr_GTP2C_PCO_P_PCSCF_IPv4(?)}); f_s2b_create_session(apco, exp_apco); + f_s2b_delete_session(omit, Request_accepted); setverdict(pass); } testcase TC_s2b_createSession_v4_apco() runs on PGW_Test_CT { diff --git a/smf/SMF_Session_CT_4G.ttcn b/smf/SMF_Session_CT_4G.ttcn index 9e84218..ba230cb 100644 --- a/smf/SMF_Session_CT_4G.ttcn +++ b/smf/SMF_Session_CT_4G.ttcn @@ -75,6 +75,24 @@ } }
+private altstep as_DIA_S6b_STR() runs on SMF_Session_CT { + var PDU_DIAMETER rx_dia; + [] DIAMETER[DIA_S6b].receive(tr_DIA_S6b_STR()) -> value rx_dia { + var template (value) PDU_DIAMETER tx_dia; + tx_dia := f_ts_DIA_S6b_STA(rx_dia, + DIAMETER_SUCCESS, + "aaa." & mp_diam_realm, + mp_diam_realm, + mp_diam_realm); + DIAMETER[DIA_S6b].send(tx_dia); + setverdict(pass); + } + [] DIAMETER[DIA_S6b].receive(PDU_DIAMETER:?) -> value rx_dia { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, + log2str("Received unexpected DIAMETER ", rx_dia)); + } +} + /* Gx emulation (PCRF)*/ altstep as_DIA_Gx_CCR(DCC_NONE_CC_Request_Type req_type) runs on SMF_Session_CT { var PDU_DIAMETER rx_dia; @@ -361,13 +379,13 @@ }
/* delete the session from the SMF */ -function f_delete_session(template (omit) GTP2C_Cause tx_cause := omit, - template (present) GTP2C_Cause exp_cause, - boolean expect_pfcp := true, - boolean expect_diameter := true) runs on SMF_Session_CT { - var template (value) FullyQualifiedTEID fteid_c_ie - fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S5S8_SGW_GTPC, g_pars.teic_local, 0, - f_inet_addr(mp_local_hostname_c), omit); +private function f_delete_session(template (value) FullyQualifiedTEID fteid_c_ie, + template (omit) GTP2C_Cause tx_cause := omit, + template (present) GTP2C_Cause exp_cause, + boolean expect_pfcp := true, + boolean expect_diameter := true) +runs on SMF_Session_CT { + var template PDU_GTPCv2 g2c := ts_GTP2C_DeleteSessionReq(d_teid := g_pars.teic_remote, cause := tx_cause, sender_fteid := fteid_c_ie, @@ -379,6 +397,10 @@ as_pfcp_sess_del_req(); }
+ if (is_s2b_iface() and DIAMETER[DIA_S6b].checkstate("Connected") and expect_diameter) { + as_DIA_S6b_STR(); + } + if (DIAMETER[DIA_Gx].checkstate("Connected") and expect_diameter) { as_DIA_Gx_CCR(TERMINATION_REQUEST); } @@ -400,4 +422,30 @@ } }
+function f_s5s8_delete_session(template (omit) GTP2C_Cause tx_cause := omit, + template (present) GTP2C_Cause exp_cause, + boolean expect_pfcp := true, + boolean expect_diameter := true) +runs on SMF_Session_CT { + var template (value) FullyQualifiedTEID fteid_c_ie; + + fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S5S8_SGW_GTPC, g_pars.teic_local, 0, + f_inet_addr(mp_local_hostname_c), omit); + + f_delete_session(fteid_c_ie, tx_cause, exp_cause, expect_pfcp, expect_diameter); +} + +function f_s2b_delete_session(template (omit) GTP2C_Cause tx_cause := omit, + template (present) GTP2C_Cause exp_cause, + boolean expect_pfcp := true, + boolean expect_diameter := true) +runs on SMF_Session_CT { + var template (value) FullyQualifiedTEID fteid_c_ie; + + fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S2b_ePDG_GTPC, g_pars.teic_local, 0, + f_inet_addr(mp_local_hostname_c), omit); + + f_delete_session(fteid_c_ie, tx_cause, exp_cause, expect_pfcp, expect_diameter); +} + } diff --git a/smf/SMF_Tests.ttcn b/smf/SMF_Tests.ttcn index 609756a..4501520 100644 --- a/smf/SMF_Tests.ttcn +++ b/smf/SMF_Tests.ttcn @@ -337,7 +337,7 @@ /* create an IPv4 session, then delete it again */ private function f_TC_createSession_deleteSession() runs on SMF_Session_CT { f_s5s8_create_session(); - f_delete_session(omit, Request_accepted); + f_s5s8_delete_session(omit, Request_accepted); setverdict(pass); } testcase TC_createSession_deleteSession() runs on SMF_Test_CT { @@ -399,7 +399,7 @@ /* send a DeleteSessionReq for an unknown/invalid TEID */ private function f_TC_deleteSession_unknown() runs on SMF_Session_CT { g_pars.teic_remote := f_rnd_octstring(4); - f_delete_session(omit, Context_Not_Found, false, false); + f_s5s8_delete_session(omit, Context_Not_Found, false, false); setverdict(pass); } testcase TC_deleteSession_unknown() runs on SMF_Test_CT { @@ -451,7 +451,7 @@ /* SMF updates new Volume quota obtained from OCS on UPF: */ as_pfcp_sess_mod_req();
- f_delete_session(omit, Request_accepted); + f_s5s8_delete_session(omit, Request_accepted); f_validate_gy_cc_report(g_rx_gy, FINAL, (0..1), 0, 0); setverdict(pass); } @@ -506,6 +506,7 @@ var template (omit) APCO apco := omit; var template APCO exp_apco := omit; f_s2b_create_session(apco, exp_apco); + f_s2b_delete_session(omit, Request_accepted); setverdict(pass); } testcase TC_s2b_createSession_v4_noapco() runs on SMF_Test_CT { @@ -525,6 +526,7 @@ *, /* open5gs-smfd can contain several DNS servers */ tr_GTP2C_PCO_P_PCSCF_IPv4(?)}); f_s2b_create_session(apco, exp_apco); + f_s2b_delete_session(omit, Request_accepted); setverdict(pass); } testcase TC_s2b_createSession_v4_apco() runs on SMF_Test_CT {