lists.osmocom.org
Sign In
Sign Up
Sign In
Sign Up
Manage this list
×
Keyboard Shortcuts
Thread View
j
: Next unread message
k
: Previous unread message
j a
: Jump to all threads
j l
: Jump to MailingList overview
2025
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
List overview
Download
gerrit-log
February 2024
----- 2025 -----
July 2025
June 2025
May 2025
April 2025
March 2025
February 2025
January 2025
----- 2024 -----
December 2024
November 2024
October 2024
September 2024
August 2024
July 2024
June 2024
May 2024
April 2024
March 2024
February 2024
January 2024
----- 2023 -----
December 2023
November 2023
October 2023
September 2023
August 2023
July 2023
June 2023
May 2023
April 2023
March 2023
February 2023
January 2023
----- 2022 -----
December 2022
November 2022
October 2022
September 2022
August 2022
July 2022
June 2022
May 2022
April 2022
March 2022
February 2022
January 2022
gerrit-log@lists.osmocom.org
1 participants
1748 discussions
Start a n
N
ew thread
[S] Change in osmocom-bb[master]: trxcon/l1gprs: print dropped prims in l1sched_reset_lchan()
by fixeria
fixeria has submitted this change. (
https://gerrit.osmocom.org/c/osmocom-bb/+/35766?usp=email
) Change subject: trxcon/l1gprs: print dropped prims in l1sched_reset_lchan() ...................................................................... trxcon/l1gprs: print dropped prims in l1sched_reset_lchan() Change-Id: Iaa11b5cee16dc43ef01c38be756864c2b3b57835 --- M src/host/trxcon/src/sched_trx.c 1 file changed, 15 insertions(+), 1 deletion(-) Approvals: laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved Jenkins Builder: Verified diff --git a/src/host/trxcon/src/sched_trx.c b/src/host/trxcon/src/sched_trx.c index d07a579..f412400 100644 --- a/src/host/trxcon/src/sched_trx.c +++ b/src/host/trxcon/src/sched_trx.c @@ -525,8 +525,13 @@ lchan->tx_bursts = NULL; /* Flush the queue of pending Tx prims */ - while ((msg = msgb_dequeue(&lchan->tx_prims)) != NULL) + while ((msg = msgb_dequeue(&lchan->tx_prims)) != NULL) { + const struct l1sched_prim *prim = l1sched_prim_from_msgb(msg); + + LOGP_LCHANC(lchan, LOGL_NOTICE, "%s(): dropping Tx prim (fn=%u): %s\n", + __func__, prim->data_req.frame_nr, msgb_hexdump_l2(msg)); msgb_free(msg); + } /* Channel specific stuff */ if (L1SCHED_CHAN_IS_TCH(lchan->type)) { -- To view, visit
https://gerrit.osmocom.org/c/osmocom-bb/+/35766?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: Iaa11b5cee16dc43ef01c38be756864c2b3b57835 Gerrit-Change-Number: 35766 Gerrit-PatchSet: 2 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 year, 5 months
1
0
0
0
[S] Change in osmocom-bb[master]: trxcon/l1gprs: print msgb hexdump in prim_dequeue_pdtch()
by fixeria
fixeria has submitted this change. (
https://gerrit.osmocom.org/c/osmocom-bb/+/35767?usp=email
) Change subject: trxcon/l1gprs: print msgb hexdump in prim_dequeue_pdtch() ...................................................................... trxcon/l1gprs: print msgb hexdump in prim_dequeue_pdtch() Change-Id: I1f82d53a46017c805c70b9dcccad058048549220 --- M src/host/trxcon/src/sched_lchan_pdtch.c 1 file changed, 11 insertions(+), 2 deletions(-) Approvals: pespin: Looks good to me, approved laforge: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/src/host/trxcon/src/sched_lchan_pdtch.c b/src/host/trxcon/src/sched_lchan_pdtch.c index 915b060..4c49504 100644 --- a/src/host/trxcon/src/sched_lchan_pdtch.c +++ b/src/host/trxcon/src/sched_lchan_pdtch.c @@ -118,8 +118,8 @@ } /* else: the ship has sailed, drop your ticket */ LOGP_LCHAND(lchan, LOGL_ERROR, - "%s(): dropping stale Tx primitive (current Fn=%u, prim Fn=%u)\n", - __func__, fn, prim->data_req.frame_nr); + "%s(): dropping stale Tx prim (current Fn=%u, prim Fn=%u): %s\n", + __func__, fn, prim->data_req.frame_nr, msgb_hexdump_l2(msg)); llist_del(&msg->list); msgb_free(msg); } -- To view, visit
https://gerrit.osmocom.org/c/osmocom-bb/+/35767?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: I1f82d53a46017c805c70b9dcccad058048549220 Gerrit-Change-Number: 35767 Gerrit-PatchSet: 2 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 year, 5 months
1
0
0
0
[S] Change in osmocom-bb[master]: trxcon/l1gprs: print msgb hexdump in prim_dequeue_pdtch()
by pespin
Attention is currently required from: fixeria. pespin has posted comments on this change. (
https://gerrit.osmocom.org/c/osmocom-bb/+/35767?usp=email
) Change subject: trxcon/l1gprs: print msgb hexdump in prim_dequeue_pdtch() ...................................................................... Patch Set 2: Code-Review+2 -- To view, visit
https://gerrit.osmocom.org/c/osmocom-bb/+/35767?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: I1f82d53a46017c805c70b9dcccad058048549220 Gerrit-Change-Number: 35767 Gerrit-PatchSet: 2 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Thu, 01 Feb 2024 20:12:23 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 year, 5 months
1
0
0
0
[S] Change in osmocom-bb[master]: trxcon/l1gprs: print dropped prims in l1sched_reset_lchan()
by pespin
Attention is currently required from: fixeria. pespin has posted comments on this change. (
https://gerrit.osmocom.org/c/osmocom-bb/+/35766?usp=email
) Change subject: trxcon/l1gprs: print dropped prims in l1sched_reset_lchan() ...................................................................... Patch Set 2: Code-Review+2 -- To view, visit
https://gerrit.osmocom.org/c/osmocom-bb/+/35766?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmocom-bb Gerrit-Branch: master Gerrit-Change-Id: Iaa11b5cee16dc43ef01c38be756864c2b3b57835 Gerrit-Change-Number: 35766 Gerrit-PatchSet: 2 Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Attention: fixeria <vyanitskiy(a)sysmocom.de> Gerrit-Comment-Date: Thu, 01 Feb 2024 20:12:12 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 year, 5 months
1
0
0
0
[S] Change in libosmo-gprs[master]: cosmetic: tbf_ul_fsm: add missing state to tdef_state_timeout array
by pespin
pespin has submitted this change. (
https://gerrit.osmocom.org/c/libosmo-gprs/+/35765?usp=email
) Change subject: cosmetic: tbf_ul_fsm: add missing state to tdef_state_timeout array ...................................................................... cosmetic: tbf_ul_fsm: add missing state to tdef_state_timeout array Change-Id: I6e825a105de4a49329912db6c79aaebbfd3ddf9f --- M src/rlcmac/tbf_ul_fsm.c 1 file changed, 10 insertions(+), 0 deletions(-) Approvals: pespin: Looks good to me, approved laforge: Looks good to me, but someone else must approve Jenkins Builder: Verified diff --git a/src/rlcmac/tbf_ul_fsm.c b/src/rlcmac/tbf_ul_fsm.c index 43cb02f..0949ca6 100644 --- a/src/rlcmac/tbf_ul_fsm.c +++ b/src/rlcmac/tbf_ul_fsm.c @@ -46,6 +46,7 @@ [GPRS_RLCMAC_TBF_UL_ST_WAIT_ASSIGN] = { }, [GPRS_RLCMAC_TBF_UL_ST_FLOW] = { .T = 3164 }, [GPRS_RLCMAC_TBF_UL_ST_FINISHED] = { .keep_timer = true }, /* keep FLOW state's T3164 / T3166 */ + [GPRS_RLCMAC_TBF_UL_ST_RELEASING] = { }, }; /* Transition to a state, using the T timer defined in tbf_fsm_timeouts. -- To view, visit
https://gerrit.osmocom.org/c/libosmo-gprs/+/35765?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: libosmo-gprs Gerrit-Branch: master Gerrit-Change-Id: I6e825a105de4a49329912db6c79aaebbfd3ddf9f Gerrit-Change-Number: 35765 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 year, 5 months
1
0
0
0
[S] Change in libosmo-gprs[master]: cosmetic: tbf_ul_fsm: add missing state to tdef_state_timeout array
by pespin
pespin has posted comments on this change. (
https://gerrit.osmocom.org/c/libosmo-gprs/+/35765?usp=email
) Change subject: cosmetic: tbf_ul_fsm: add missing state to tdef_state_timeout array ...................................................................... Patch Set 1: Code-Review+2 -- To view, visit
https://gerrit.osmocom.org/c/libosmo-gprs/+/35765?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: libosmo-gprs Gerrit-Branch: master Gerrit-Change-Id: I6e825a105de4a49329912db6c79aaebbfd3ddf9f Gerrit-Change-Number: 35765 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Comment-Date: Thu, 01 Feb 2024 20:08:45 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 year, 5 months
1
0
0
0
[M] Change in osmo-ttcn3-hacks[master]: epdg: Test UE-initiated Detach Procedure
by pespin
pespin has submitted this change. (
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/35758?usp=email
) Change subject: epdg: Test UE-initiated Detach Procedure ...................................................................... epdg: Test UE-initiated Detach Procedure Related: OS#6333 Change-Id: I19114c69119e42622f323378dd356217d107cb32 --- M epdg/EPDG_Tests.ttcn M library/DIAMETER_Templates.ttcn M library/DIAMETER_ts29_273_Templates.ttcn 3 files changed, 136 insertions(+), 6 deletions(-) Approvals: laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved Jenkins Builder: Verified diff --git a/epdg/EPDG_Tests.ttcn b/epdg/EPDG_Tests.ttcn index de5e7a8..82a2375 100644 --- a/epdg/EPDG_Tests.ttcn +++ b/epdg/EPDG_Tests.ttcn @@ -359,7 +359,7 @@ } /* Diameter SWx SAR + SAA. */ -private altstep as_DIA_SWx_SA_success() runs on EPDG_ConnHdlr { +private altstep as_DIA_SWx_SA_success(template (present) CxDx_3GPP_Server_Assignment_Type server_ass_type := ?) runs on EPDG_ConnHdlr { var PDU_DIAMETER rx_dia; var template (omit) AVP avp; var octetstring sess_id; @@ -404,7 +404,28 @@ } } -/* Diameter SWx SAR + SAA. */ +/* Send STR as PGW to AAA server, expect back STA */ +private function f_S6b_ST_success() runs on EPDG_ConnHdlr { + var PDU_DIAMETER rx_dia; + var UINT32 hbh_id := f_rnd_octstring(4); + var UINT32 ete_id := f_rnd_octstring(4); + + /* Unlike STR, STA contains no IMSI. Register ete_id in DIAMETER_Emulation, + * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT. + */ + f_epdg_connhldr_S6b_expect_eteid(ete_id); + + S6b.send(ts_DIA_S6b_STR(g_pars.imsi, DIAMETER_LOGOUT, + hbh_id := hbh_id, ete_id := ete_id)); + alt { + [] S6b.receive(tr_DIA_S6b_STA(DIAMETER_SUCCESS)) -> value rx_dia {} + [] S6b.receive(PDU_DIAMETER:?) -> value rx_dia { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter S6b msg rx: ", rx_dia)); + } + } +} + +/* ePDG Creates session at the PGW. PGW sends Diameter s6b AAR + AAA. */ private altstep as_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr { var PDU_GTPCv2 rx_msg; var BearerContextIEs rx_bctx_ies; @@ -444,8 +465,27 @@ Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg)); } } -private function f_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr { - as_GTP2C_CreateSession_success(); + +/* ePDG Deletes session at the PGW. PGW sends Diameter s6b AAR + AAA. */ +private altstep as_GTP2C_DeleteSession_success() runs on EPDG_ConnHdlr { + var PDU_GTPCv2 rx_msg; + var BearerContextIEs rx_bctx_ies; + var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie; + var template (value) PDN_AddressAllocation paa; + var template (value) BearerContextIEs bctx_ies; + + [] GTP2.receive(tr_GTP2C_DeleteSessionReq(g_pars.teic_local)) -> value rx_msg { + /* Upon rx of DeleteSession, emulate PGW requesting the AAA server for Sesssion Termination. */ + f_S6b_ST_success(); + + GTP2.send(ts_GTP2C_DeleteSessionResp(g_pars.teic_remote, + rx_msg.sequenceNumber, + Request_accepted)); + setverdict(pass); + } + [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg)); + } } /* Expect DeleteBearerResponse */ @@ -493,7 +533,7 @@ var GSUP_PDU rx_gsup; var template octetstring destination_name := *; GSUP.send(ts_GSUP_UL_REQ(g_pars.imsi)); - as_DIA_SWx_SA_success(); + as_DIA_SWx_SA_success(REGISTRATION); /* Expect a positive response back to the translator */ alt { [] GSUP.receive(tr_GSUP_UL_RES(g_pars.imsi, destination_name)); @@ -508,7 +548,7 @@ private function f_GSUP_EPDGTunnel_success() runs on EPDG_ConnHdlr { var GSUP_PDU rx_gsup; GSUP.send(ts_GSUP_EPDGTunnel_REQ(g_pars.imsi)); - f_GTP2C_CreateSession_success(); + as_GTP2C_CreateSession_success(); /* Expect a positive response back to the translator; */ var template (present) GSUP_IEs pdp_info := { tr_GSUP_IE_PDP_CONTEXT_ID(?), @@ -526,10 +566,30 @@ setverdict(pass); } +/* GSUP Purge MS Req + Resp, triggers S2b DeleteSession Req + Response. */ +private function f_GSUP_PurgeMS_success() runs on EPDG_ConnHdlr { + var GSUP_PDU rx_gsup; + GSUP.send(ts_GSUP_PURGE_MS_REQ(g_pars.imsi, OSMO_GSUP_CN_DOMAIN_PS)); + as_GTP2C_DeleteSession_success(); + /* ePDG internally sends STR to its AAA-Server. Since all sessions + become inactive, AAA-Server sends SAR(USER_DEREGISTRATION) to HSS: */ + + /* Expect a positive response back to the translator; */ + as_DIA_SWx_SA_success(USER_DEREGISTRATION); + alt { + [] GSUP.receive(tr_GSUP_PURGE_MS_RES(g_pars.imsi)); + [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup { + Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup)); + } + } + setverdict(pass); +} + private function f_TC_authinfo_normal(charstring id) runs on EPDG_ConnHdlr { f_GSUP_AI_success(); f_GSUP_LU_success(); f_GSUP_EPDGTunnel_success(); + f_GSUP_PurgeMS_success(); } testcase TC_authinfo_normal() runs on MTC_CT { diff --git a/library/DIAMETER_Templates.ttcn b/library/DIAMETER_Templates.ttcn index 82a433c..98ca9bd 100644 --- a/library/DIAMETER_Templates.ttcn +++ b/library/DIAMETER_Templates.ttcn @@ -307,6 +307,15 @@ } } +template (value) GenericAVP ts_AVP_TerminationCause(template (value) BASE_NONE_Termination_Cause tc) := { + avp := { + avp_header := ts_DIA_Hdr(c_AVP_Code_BASE_NONE_Termination_Cause), + avp_data := { + avp_BASE_NONE_Termination_Cause := tc + } + } +} + template (present) GenericAVP tr_AVP_TerminationCause(template (present) BASE_NONE_Termination_Cause tc) := { avp := { avp_header := tr_DIA_Hdr(c_AVP_Code_BASE_NONE_Termination_Cause), diff --git a/library/DIAMETER_ts29_273_Templates.ttcn b/library/DIAMETER_ts29_273_Templates.ttcn index 38355e7..71f6cfc 100644 --- a/library/DIAMETER_ts29_273_Templates.ttcn +++ b/library/DIAMETER_ts29_273_Templates.ttcn @@ -257,4 +257,55 @@ tr_AVP_OriginRealm(orig_realm) )); + /* 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 (value) PDU_DIAMETER +ts_DIA_S6b_STR(template (value) hexstring imsi, + template (value) BASE_NONE_Termination_Cause term_cause := DIAMETER_LOGOUT, + template (value) octetstring sess_id := c_def_sess_id, + template (value) charstring orig_host := "pgw.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 := '11000000'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_AuthAppId(int2oct(c_DIAMETER_3GPP_S6b_AID, 4)), + ts_AVP_OriginHost(orig_host), + ts_AVP_OriginRealm(orig_realm), + ts_AVP_DestinationRealm(dest_realm), + ts_AVP_TerminationCause(term_cause), + ts_AVP_UserNameImsi(valueof(imsi)) + /* Optional: OC-Supported-Features */ + }); + +/* TS 29.273 9.2.2.3.2 Session-Termination-Answer (STA) Command, + * Table 9.1.2.3.1/2: S6b Session Termination Answer (STA), based on RFC 6733 8.4.2 */ +template (present) PDU_DIAMETER +tr_DIA_S6b_STA(template (present) DIAMETER_Resultcode res_code := ?, + 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 := '0???????'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_ResultCode(res_code), + tr_AVP_OriginHost(orig_host), + tr_AVP_OriginRealm(orig_realm) + /* Lots other Optional */ + )); + } -- To view, visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/35758?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-Change-Id: I19114c69119e42622f323378dd356217d107cb32 Gerrit-Change-Number: 35758 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 year, 5 months
1
0
0
0
[M] Change in osmo-ttcn3-hacks[master]: epdg: Test UE-initiated Detach Procedure
by pespin
Attention is currently required from: lynxis lazus. pespin has posted comments on this change. (
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/35758?usp=email
) Change subject: epdg: Test UE-initiated Detach Procedure ...................................................................... Patch Set 1: Code-Review+2 -- To view, visit
https://gerrit.osmocom.org/c/osmo-ttcn3-hacks/+/35758?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: osmo-ttcn3-hacks Gerrit-Branch: master Gerrit-Change-Id: I19114c69119e42622f323378dd356217d107cb32 Gerrit-Change-Number: 35758 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-Attention: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Comment-Date: Thu, 01 Feb 2024 20:08:38 +0000 Gerrit-HasComments: No Gerrit-Has-Labels: Yes Gerrit-MessageType: comment
1 year, 5 months
1
0
0
0
[M] Change in ...osmo-epdg[master]: Send SAR(DEREGISTRATION) to HSS when all sessions are terminated
by pespin
pespin has submitted this change. (
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35760?usp=email
) Change subject: Send SAR(DEREGISTRATION) to HSS when all sessions are terminated ...................................................................... Send SAR(DEREGISTRATION) to HSS when all sessions are terminated Change-Id: I62eba8ef916d52964df4135d1031f3950b6818a2 --- M src/aaa_diameter_s6b.erl M src/aaa_diameter_s6b_cb.erl M src/aaa_diameter_swm.erl M src/aaa_diameter_swx_cb.erl M src/aaa_ue_fsm.erl 5 files changed, 157 insertions(+), 21 deletions(-) Approvals: laforge: Looks good to me, but someone else must approve Jenkins Builder: Verified pespin: Looks good to me, approved diff --git a/src/aaa_diameter_s6b.erl b/src/aaa_diameter_s6b.erl index 2de479c..2792b6a 100644 --- a/src/aaa_diameter_s6b.erl +++ b/src/aaa_diameter_s6b.erl @@ -51,7 +51,7 @@ -export([code_change/3]). -export([multimedia_auth_request/6]). -export([server_assignment_request/3]). --export([tx_aa_answer/2]). +-export([tx_aa_answer/2, tx_st_answer/2]). -export([test/0, test/1]). %% Diameter Application Definitions @@ -151,6 +151,10 @@ % handle_request(AAR) was spawned into its own process, and it's blocked waiting for AAA: Pid ! {aaa, ResultCode}. +tx_st_answer(Pid, ResultCode) -> + % handle_request(STR) was spawned into its own process, and it's blocked waiting for STA: + Pid ! {sta, ResultCode}. + result_code_success(2001) -> ok; result_code_success(2002) -> ok; result_code_success(_) -> invalid_result_code. diff --git a/src/aaa_diameter_s6b_cb.erl b/src/aaa_diameter_s6b_cb.erl index b03bce1..339f735 100644 --- a/src/aaa_diameter_s6b_cb.erl +++ b/src/aaa_diameter_s6b_cb.erl @@ -86,10 +86,30 @@ #diameter_caps{origin_host = {OH,_}, origin_realm = {OR,_}} = Caps, #'STR'{'Session-Id' = SessionId, 'Auth-Application-Id' = _AuthAppId, - 'User-Name' = _UserNameOpt} = Req, + 'Termination-Cause' = _TermCause, + 'User-Name' = [UserName]} = Req, + Result = aaa_diameter_swm:get_ue_fsm_by_imsi(UserName), + case Result of + {ok, Pid} -> + case aaa_ue_fsm:ev_rx_s6b_str(Pid) of + ok -> + lager:debug("Waiting for S6b STA~n", []), + receive + {sta, ResultCode} -> lager:debug("Rx STA with ResultCode=~p~n", [ResultCode]) + end; + {ok, DiaRC} when is_integer(DiaRC) -> + ResultCode = DiaRC; + {error, Err} when is_integer(Err) -> + ResultCode = Err; + {error, _} -> + ResultCode = ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED' + end; + _ -> lager:error("Error looking up FSM for IMSI~n", [UserName]), + ResultCode = ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED' + end, % 3GPP TS 29.273 9.2.2.3.2 Session-Termination-Answer (STA) Command: Resp = #'STA'{'Session-Id' = SessionId, - 'Result-Code' = 2001, + 'Result-Code' = ResultCode, 'Origin-Host' = OH, 'Origin-Realm' = OR}, lager:info("S6b Tx to ~p: ~p~n", [Caps, Resp]), diff --git a/src/aaa_diameter_swm.erl b/src/aaa_diameter_swm.erl index 68aa054..9458383 100644 --- a/src/aaa_diameter_swm.erl +++ b/src/aaa_diameter_swm.erl @@ -4,7 +4,7 @@ -module(aaa_diameter_swm). -behaviour(gen_server). --include_lib("diameter_3gpp_ts29_273_swx.hrl"). +-include_lib("diameter_3gpp_ts29_273.hrl"). -record(swm_state, { table_id, % ets table id, @@ -22,7 +22,7 @@ -export([get_ue_fsm_by_imsi/1]). -export([auth_request/1, auth_compl_request/2, session_termination_request/1]). --export([auth_response/2, auth_compl_response/2]). +-export([auth_response/2, auth_compl_response/2, session_termination_answer/2]). -define(SERVER, ?MODULE). @@ -45,6 +45,9 @@ auth_compl_response(Imsi, Result) -> _Result = gen_server:call(?SERVER, {epdg_auth_compl_resp, Imsi, Result}). +session_termination_answer(Imsi, Result) -> + _Result = gen_server:call(?SERVER, {sta, Imsi, Result}). + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Rx from emulated SWm wire: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -73,7 +76,21 @@ {noreply, State}; handle_cast({str, Imsi}, State) -> - ok = epdg_diameter_swm:session_termination_answer(Imsi, 2001), + Sess = find_swm_session_by_imsi(Imsi, State), + case Sess of + #swm_session{} -> + case aaa_ue_fsm:ev_rx_swm_str(Sess#swm_session.pid) of + ok -> ok; % Answering delayed due to SAR+SAA towards HSS. + {ok, DiaRC} when is_integer(DiaRC) -> + ok = epdg_diameter_swm:session_termination_answer(Imsi, DiaRC); + {error, Err} when is_integer(Err) -> + ok = epdg_diameter_swm:session_termination_answer(Imsi, Err); + {error, _} -> + ok = epdg_diameter_swm:session_termination_answer(Imsi, ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED') + end; + undefined -> + ok = epdg_diameter_swm:session_termination_answer(Imsi, ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED') + end, {noreply, State}; handle_cast(Info, S) -> @@ -102,6 +119,10 @@ epdg_diameter_swm:auth_compl_response(Imsi, Result), {reply, ok, State}; +handle_call({sta, Imsi, DiaRC}, _From, State) -> + epdg_diameter_swm:session_termination_answer(Imsi, DiaRC), + {reply, ok, State}; + handle_call(Request, From, S) -> error_logger:error_report(["unknown handle_call", {module, ?MODULE}, {request, Request}, {from, From}, {state, S}]), {noreply, S}. diff --git a/src/aaa_diameter_swx_cb.erl b/src/aaa_diameter_swx_cb.erl index a7b9b7c..472f1d4 100644 --- a/src/aaa_diameter_swx_cb.erl +++ b/src/aaa_diameter_swx_cb.erl @@ -71,10 +71,13 @@ lager:info("SWx Rx MAA ~p: ~p/ Errors ~p ~n", [Peer, Msg, Errors]), aaa_ue_fsm:ev_rx_swx_maa(ReqPid, Msg), {ok, Msg}; -handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, Peer, ReqPid) when is_record(Msg, 'SAA') -> +handle_answer(#diameter_packet{msg = Msg, errors = Errors}, Request, _SvcName, Peer, ReqPid) when is_record(Msg, 'SAA') -> lager:info("SWx Rx SAA ~p: ~p/ Errors ~p ~n", [Peer, Msg, Errors]), + % Recover fields from originating request: + #'SAR'{'Server-Assignment-Type' = SAType} = Request, + % Retrieve fields from answer: #'SAA'{'Result-Code' = [ResultCode]} = Msg, - aaa_ue_fsm:ev_rx_swx_saa(ReqPid, ResultCode), + aaa_ue_fsm:ev_rx_swx_saa(ReqPid, {SAType, ResultCode}), {ok, Msg}. handle_answer(#diameter_packet{msg = Msg, errors = []}, _Request, _SvcName, Peer) -> lager:info("SWx Rx ~p: ~p~n", [Peer, Msg]), diff --git a/src/aaa_ue_fsm.erl b/src/aaa_ue_fsm.erl index e214540..c043cdb 100644 --- a/src/aaa_ue_fsm.erl +++ b/src/aaa_ue_fsm.erl @@ -35,15 +35,18 @@ -define(NAME, aaa_ue_fsm). -include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter_3gpp_ts29_229.hrl"). -include_lib("diameter_3gpp_ts29_273_s6b.hrl"). -export([start_link/1]). -export([init/1,callback_mode/0,terminate/3]). --export([ev_swm_auth_req/1, ev_swm_auth_compl/2, ev_rx_swx_maa/2, ev_rx_swx_saa/2, ev_rx_s6b_aar/2]). +-export([ev_swm_auth_req/1, ev_swm_auth_compl/2, ev_rx_swm_str/1, ev_rx_swx_maa/2, ev_rx_swx_saa/2, + ev_rx_s6b_aar/2, ev_rx_s6b_str/1]). -export([state_new/3, state_wait_swx_maa/3, state_wait_swx_saa/3, state_authenticated/3, state_authenticated_wait_swx_saa/3]). -record(ue_fsm_data, { imsi = unknown :: binary(), + apn :: string(), epdg_sess_active = false :: boolean(), pgw_sess_active = false :: boolean(), s6b_resp_pid :: pid() @@ -72,6 +75,15 @@ {error, Err} end. +ev_rx_swm_str(Pid) -> + lager:info("ue_fsm ev_rx_swm_str~n", []), + try + gen_statem:call(Pid, rx_swm_str) + catch + exit:Err -> + {error, Err} + end. + ev_rx_swx_maa(Pid, MAA) -> lager:info("ue_fsm ev_rx_swx_maa~n", []), try @@ -81,10 +93,10 @@ {error, Err} end. -ev_rx_swx_saa(Pid, ResultCode) -> +ev_rx_swx_saa(Pid, {SAType, ResultCode}) -> lager:info("ue_fsm ev_rx_swx_saa~n", []), try - gen_statem:call(Pid, {rx_swx_saa, ResultCode}) + gen_statem:call(Pid, {rx_swx_saa, SAType, ResultCode}) catch exit:Err -> {error, Err} @@ -99,6 +111,15 @@ {error, Err} end. +ev_rx_s6b_str(Pid) -> + lager:info("ue_fsm ev_rx_s6b_str: ~p~n", []), + try + gen_statem:call(Pid, rx_s6b_str) + catch + exit:Err -> + {error, Err} + end. + %% ------------------------------------------------------------------ %% Internal helpers %% ------------------------------------------------------------------ @@ -151,9 +172,9 @@ state_wait_swx_saa(enter, _OldState, Data) -> {keep_state, Data}; -state_wait_swx_saa({call, From}, {rx_swx_saa, SAA}, Data) -> +state_wait_swx_saa({call, From}, {rx_swx_saa, _SAType, ResultCode}, Data) -> lager:info("ue_fsm state_wait_swx_saa event=rx_swx_saa, ~p~n", [Data]), - aaa_diameter_swm:auth_compl_response(Data#ue_fsm_data.imsi, {ok, SAA}), + aaa_diameter_swm:auth_compl_response(Data#ue_fsm_data.imsi, {ok, ResultCode}), % TODO: don't transit if SAS returned error code. {next_state, state_authenticated, Data, [{reply,From,ok}]}. @@ -164,12 +185,57 @@ state_authenticated({call, {Pid, _Tag} = From}, {rx_s6b_aar, Apn}, Data) -> lager:info("ue_fsm state_authenticated event=rx_s6b_aar Apn=~p, ~p~n", [Apn, Data]), - case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, 1, Apn) of - ok -> Data1 = Data#ue_fsm_data{s6b_resp_pid = Pid}, + case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_REGISTRATION', + Apn) of + ok -> Data1 = Data#ue_fsm_data{s6b_resp_pid = Pid, apn = Apn}, {next_state, state_authenticated_wait_swx_saa, Data1, [{reply,From,ok}]}; {error, Err} -> {keep_state, Data, [{reply,From,{error, Err}}]} end; +state_authenticated({call, From}, rx_swm_str, Data) -> + lager:info("ue_fsm state_authenticated event=rx_swm_str, ~p~n", [Data]), + case {Data#ue_fsm_data.epdg_sess_active, Data#ue_fsm_data.pgw_sess_active} of + {false, _} -> %% The SWm session is not active... + DiaRC = 5002, %% UNKNOWN_SESSION_ID + {keep_state, Data, [{reply,From,{error, DiaRC}}]}; + {true, true} -> %% The other session is still active, no need to send SAR Type=USER_DEREGISTRATION + lager:info("ue_fsm state_authenticated event=rx_swn_str: PGW session still active, skip updating the HSS~n", []), + Data1 = Data#ue_fsm_data{epdg_sess_active = false}, + {keep_state, Data1, [{reply,From,{ok, 2001}}]}; + {true, false} -> %% All sessions will now be gone, trigger SAR Type=USER_DEREGISTRATION + case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_USER_DEREGISTRATION', + Data#ue_fsm_data.apn) of + ok -> {next_state, state_authenticated_wait_swx_saa, Data, [{reply,From,ok}]}; + {error, _Err} -> + DiaRC = 5002, %% UNKNOWN_SESSION_ID + {keep_state, Data, [{reply,From,{error, DiaRC}}]} + end + end; + +state_authenticated({call, {Pid, _Tag} = From}, rx_s6b_str, Data) -> + lager:info("ue_fsm state_authenticated event=rx_s6b_str, ~p~n", [Data]), + case {Data#ue_fsm_data.pgw_sess_active, Data#ue_fsm_data.epdg_sess_active} of + {false, _} -> %% The S6b session is not active... + DiaRC = 5002, %% UNKNOWN_SESSION_ID + {keep_state, Data, [{reply,From,{error, DiaRC}}]}; + {true, true} -> %% The other session is still active, no need to send SAR Type=USER_DEREGISTRATION + lager:info("ue_fsm state_authenticated event=rx_s6b_str: ePDG session still active, skip updating the HSS~n", []), + Data1 = Data#ue_fsm_data{pgw_sess_active = false}, + {keep_state, Data1, [{reply,From,{ok, 2001}}]}; + {true, false} -> %% All sessions will now be gone, trigger SAR Type=USER_DEREGISTRATION + case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_USER_DEREGISTRATION', + Data#ue_fsm_data.apn) of + ok -> Data1 = Data#ue_fsm_data{s6b_resp_pid = Pid}, + {next_state, state_authenticated_wait_swx_saa, Data1, [{reply,From,ok}]}; + {error, _Err} -> + DiaRC = 5002, %% UNKNOWN_SESSION_ID + {keep_state, Data, [{reply,From,{error, DiaRC}}]} + end + end; + state_authenticated({call, From}, _Whatever, Data) -> lager:info("ue_fsm state_authenticated event=purge_ms_request, ~p~n", [Data]), {keep_state, Data, [{reply,From,ok}]}. @@ -177,9 +243,22 @@ state_authenticated_wait_swx_saa(enter, _OldState, Data) -> {keep_state, Data}; -state_authenticated_wait_swx_saa({call, From}, {rx_swx_saa, ResultCode}, Data) -> - lager:info("ue_fsm state_authenticated_wait_swx_saa event=rx_swx_saa ResulCode=~p, ~p~n", [ResultCode, Data]), - aaa_diameter_s6b:tx_aa_answer(Data#ue_fsm_data.s6b_resp_pid, ResultCode), - Data1 = Data#ue_fsm_data{s6b_resp_pid = undefined}, - {next_state, state_authenticated, Data1, [{reply,From,ok}]}. - +state_authenticated_wait_swx_saa({call, From}, {rx_swx_saa, SAType, ResultCode}, Data) -> + lager:info("ue_fsm state_authenticated_wait_swx_saa event=rx_swx_saa SAType=~p ResulCode=~p, ~p~n", [SAType, ResultCode, Data]), + case SAType of + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_REGISTRATION' -> + aaa_diameter_s6b:tx_aa_answer(Data#ue_fsm_data.s6b_resp_pid, ResultCode), + Data1 = Data#ue_fsm_data{pgw_sess_active = true, s6b_resp_pid = undefined}, + {next_state, state_authenticated, Data1, [{reply,From,ok}]}; + ?'DIAMETER_CX_SERVER-ASSIGNMENT-TYPE_USER_DEREGISTRATION' -> + case Data#ue_fsm_data.s6b_resp_pid of + undefined -> %% SWm initiated + aaa_diameter_swm:session_termination_answer(Data#ue_fsm_data.imsi, ResultCode), + Data1 = Data#ue_fsm_data{epdg_sess_active = false}, + {next_state, state_new, Data1, [{reply,From,ok}]}; + _ -> %% S6b initiated + aaa_diameter_s6b:tx_st_answer(Data#ue_fsm_data.s6b_resp_pid, ResultCode), + Data1 = Data#ue_fsm_data{pgw_sess_active = false, s6b_resp_pid = undefined}, + {next_state, state_new, Data1, [{reply,From,ok}]} + end + end. \ No newline at end of file -- To view, visit
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35760?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: erlang/osmo-epdg Gerrit-Branch: master Gerrit-Change-Id: I62eba8ef916d52964df4135d1031f3950b6818a2 Gerrit-Change-Number: 35760 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 year, 5 months
1
0
0
0
[L] Change in ...osmo-epdg[master]: AAA-Server: Process S6b, SWx requests async through new aaa_ue_fsm
by pespin
pespin has submitted this change. (
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35759?usp=email
) Change subject: AAA-Server: Process S6b, SWx requests async through new aaa_ue_fsm ...................................................................... AAA-Server: Process S6b, SWx requests async through new aaa_ue_fsm This will allow keeping per-UE session state, and for instance send a SAR(USER_DEREGISTRATION) towards HSS when all sessions from all interfaces (s6b, SWm) are terminated. Change-Id: I78ebda4679d0a2f3ecede94598e74b20c2ff8836 --- M src/aaa_diameter_s6b.erl M src/aaa_diameter_s6b_cb.erl M src/aaa_diameter_swm.erl M src/aaa_diameter_swx.erl M src/aaa_diameter_swx_cb.erl A src/aaa_ue_fsm.erl 6 files changed, 343 insertions(+), 72 deletions(-) Approvals: Jenkins Builder: Verified laforge: Looks good to me, but someone else must approve pespin: Looks good to me, approved diff --git a/src/aaa_diameter_s6b.erl b/src/aaa_diameter_s6b.erl index 59b9679..2de479c 100644 --- a/src/aaa_diameter_s6b.erl +++ b/src/aaa_diameter_s6b.erl @@ -40,8 +40,8 @@ -behaviour(gen_server). --include_lib("diameter_3gpp_ts29_273_s6b.hrl"). -include_lib("diameter/include/diameter_gen_base_rfc6733.hrl"). +-include_lib("diameter_3gpp_ts29_273_s6b.hrl"). %% API Function Exports -export([start_link/0]). @@ -51,6 +51,7 @@ -export([code_change/3]). -export([multimedia_auth_request/6]). -export([server_assignment_request/3]). +-export([tx_aa_answer/2]). -export([test/0, test/1]). %% Diameter Application Definitions @@ -146,6 +147,10 @@ gen_server:call(?SERVER, {sar, {IMSI, Type, APN}}). +tx_aa_answer(Pid, ResultCode) -> + % handle_request(AAR) was spawned into its own process, and it's blocked waiting for AAA: + Pid ! {aaa, ResultCode}. + result_code_success(2001) -> ok; result_code_success(2002) -> ok; result_code_success(_) -> invalid_result_code. diff --git a/src/aaa_diameter_s6b_cb.erl b/src/aaa_diameter_s6b_cb.erl index ccfcaff..b03bce1 100644 --- a/src/aaa_diameter_s6b_cb.erl +++ b/src/aaa_diameter_s6b_cb.erl @@ -23,17 +23,17 @@ State. %% pick_peer/4 -pick_peer([_Peer | _], _, _SvcName, _State) -> - ?UNEXPECTED. +pick_peer([Peer | _], _, _SvcName, _State) -> + {ok, Peer}. %% prepare_request/3 - -prepare_request(_, _SvcName, _Peer) -> - ?UNEXPECTED. +prepare_request(_Req, _SvcName, _Peer) -> + lager:error("Unexpected prepare_request(): ~p~n", [_Req]), + ?UNEXPECTED. %% prepare_retransmit/3 -prepare_retransmit(_Packet, _SvcName, _Peer) -> - ?UNEXPECTED. +prepare_retransmit(Packet, SvcName, Peer) -> + prepare_request(Packet, SvcName, Peer). %% handle_answer/4 @@ -42,12 +42,12 @@ %% the former case, return in the latter. handle_answer(_Packet, _Request, _SvcName, _Peer) -> - ?UNEXPECTED. + ?UNEXPECTED. %% handle_error/4 handle_error(Reason, Request, _SvcName, _Peer) when is_list(Request) -> lager:error("Request error: ~p~n", [Reason]), - ?UNEXPECTED. + ?UNEXPECTED. % 3GPP TS 29.273 9.1.2.2 handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) when is_record(Req, 'AAR') -> @@ -59,21 +59,25 @@ 'Auth-Request-Type' = AuthReqType, 'User-Name' = [UserName], 'Service-Selection' = [Apn]} = Req, - Result = aaa_diameter_swx:server_assignment_request(UserName, 1, Apn), + Result = aaa_diameter_swm:get_ue_fsm_by_imsi(UserName), case Result of - {ok, _} -> - ResultCode = 2001; - {error, _Err} -> - ResultCode = ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED' + {ok, Pid} -> + ok = aaa_ue_fsm:ev_rx_s6b_aar(Pid, Apn), + lager:debug("Waiting for S6b AAA~n", []), + receive + {aaa, ResultCode} -> lager:debug("Rx AAA with ResultCode=~p~n", [ResultCode]) + end; + _ -> lager:error("Error looking up FSM for IMSI~n", [UserName]), + ResultCode = ?'RULE-FAILURE-CODE_CM_AUTHORIZATION_REJECTED' end, - Resp = #'AAA'{'Session-Id'=SessionId, + Resp = #'AAA'{'Session-Id'= SessionId, 'Auth-Application-Id' = AuthAppId, 'Auth-Request-Type' = AuthReqType, 'Result-Code' = ResultCode, 'Origin-Host' = OH, 'Origin-Realm' = OR}, lager:info("S6b Tx to ~p: ~p~n", [Caps, Resp]), - {reply, Resp}; + {reply, Resp}; % 3GPP TS 29.273 9.2.2.3.1 Session-Termination-Request (STR) Command: handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps}) when is_record(Req, 'STR') -> diff --git a/src/aaa_diameter_swm.erl b/src/aaa_diameter_swm.erl index a3e5132..68aa054 100644 --- a/src/aaa_diameter_swm.erl +++ b/src/aaa_diameter_swm.erl @@ -7,14 +7,22 @@ -include_lib("diameter_3gpp_ts29_273_swx.hrl"). -record(swm_state, { - table_id % ets table id + table_id, % ets table id, + ues = sets:new() }). +-record(swm_session, { + imsi :: binary(), + pid :: pid() + }). + -export([start_link/0]). -export([init/1, handle_call/3, handle_cast/2, handle_info/2]). -export([code_change/3, terminate/2]). +-export([get_ue_fsm_by_imsi/1]). -export([auth_request/1, auth_compl_request/2, session_termination_request/1]). +-export([auth_response/2, auth_compl_response/2]). -define(SERVER, ?MODULE). @@ -25,7 +33,21 @@ TableId = ets:new(auth_req, [bag, named_table]), {ok, #swm_state{table_id = TableId}}. +get_ue_fsm_by_imsi(Imsi) -> + _Result = gen_server:call(?SERVER, {get_ue_fsm_by_imsi, Imsi}). +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Tx over emulated SWm wire: +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +auth_response(Imsi, Result) -> + _Result = gen_server:call(?SERVER, {epdg_auth_resp, Imsi, Result}). + +auth_compl_response(Imsi, Result) -> + _Result = gen_server:call(?SERVER, {epdg_auth_compl_resp, Imsi, Result}). + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Rx from emulated SWm wire: +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% auth_request(Imsi) -> gen_server:cast(?SERVER, {epdg_auth_req, Imsi}). @@ -35,25 +57,18 @@ session_termination_request(Imsi) -> gen_server:cast(?SERVER, {str, Imsi}). -handle_cast({epdg_auth_req, Imsi}, State) -> - % request the diameter code for a tuple - CKey = [], - IntegrityKey = [], - Result = aaa_diameter_swx:multimedia_auth_request(Imsi, 1, "EAP-AKA", 1, CKey, IntegrityKey), - case Result of - {ok, _MAA} -> epdg_diameter_swm:auth_response(Imsi, Result); - {error, _Err} -> epdg_diameter_swm:auth_response(Imsi, Result); - _ -> epdg_diameter_swm:auth_response(Imsi, {error, unknown}) - end, - {noreply, State}; +handle_cast({epdg_auth_req, Imsi}, State0) -> + {Sess, State1} = find_or_new_swm_session(Imsi, State0), + aaa_ue_fsm:ev_swm_auth_req(Sess#swm_session.pid), + {noreply, State1}; handle_cast({epdg_auth_compl_req, Imsi, Apn}, State) -> - % request the diameter code for a tuple - Result = aaa_diameter_swx:server_assignment_request(Imsi, 1, Apn), - case Result of - {ok, _SAA} -> epdg_diameter_swm:auth_compl_response(Imsi, Result); - {error, _Err} -> epdg_diameter_swm:auth_compl_response(Imsi, Result); - _ -> epdg_diameter_swm:auth_compl_response(Imsi, {error, unknown}) + Sess = find_swm_session_by_imsi(Imsi, State), + case Sess of + #swm_session{imsi = Imsi} -> + aaa_ue_fsm:ev_swm_auth_compl(Sess#swm_session.pid, Apn); + undefined -> + epdg_diameter_swm:auth_compl_response(Imsi, {error, imsi_unknown}) end, {noreply, State}; @@ -69,6 +84,24 @@ error_logger:error_report(["unknown handle_info", {module, ?MODULE}, {info, Info}, {state, S}]), {noreply, S}. +handle_call({get_ue_fsm_by_imsi, Imsi}, _From, State) -> + Sess = find_swm_session_by_imsi(Imsi, State), + lager:debug("find_swm_session_by_imsi(~p) returned ~p~n", [Imsi, Sess]), + case Sess of + #swm_session{} -> + {reply, {ok ,Sess#swm_session.pid}, State}; + undefined -> + {reply, {error, imsi_unknown}, State} + end; + +handle_call({epdg_auth_resp, Imsi, Result}, _From, State) -> + epdg_diameter_swm:auth_response(Imsi, Result), + {reply, ok, State}; + +handle_call({epdg_auth_compl_resp, Imsi, Result}, _From, State) -> + epdg_diameter_swm:auth_compl_response(Imsi, Result), + {reply, ok, State}; + handle_call(Request, From, S) -> error_logger:error_report(["unknown handle_call", {module, ?MODULE}, {request, Request}, {from, From}, {state, S}]), {noreply, S}. @@ -81,3 +114,35 @@ terminate(Reason, _S) -> lager:info("terminating ~p with reason ~p~n", [?MODULE, Reason]). + +%% ------------------------------------------------------------------ +%% Internal Function Definitions +%% ------------------------------------------------------------------ + +new_swm_session(Imsi, State) -> + {ok, Pid} = aaa_ue_fsm:start_link(Imsi), + UE = #swm_session{imsi = Imsi, pid = Pid}, + NewSt = State#swm_state{ues = sets:add_element(UE, State#swm_state.ues)}, + {UE, NewSt}. + +% returns swm_session if found, undefined if not +find_swm_session_by_imsi(Imsi, State) -> + sets:fold( + fun(UEsIt = #swm_session{imsi = Imsi}, _AccIn) -> UEsIt; + (_, AccIn) -> AccIn + end, + undefined, + State#swm_state.ues). + +find_or_new_swm_session(Imsi, State) -> + UE = find_swm_session_by_imsi(Imsi, State), + case UE of + #swm_session{imsi = Imsi} -> + {UE, State}; + undefined -> + new_swm_session(Imsi, State) + end. + +delete_swm_session(Imsi, State) -> + SetRemoved = sets:del_element(Imsi, State#swm_state.ues), + State#swm_state{ues = SetRemoved}. \ No newline at end of file diff --git a/src/aaa_diameter_swx.erl b/src/aaa_diameter_swx.erl index 411c000..1db5809 100644 --- a/src/aaa_diameter_swx.erl +++ b/src/aaa_diameter_swx.erl @@ -181,7 +181,7 @@ parse_saa(Saa) -> {unknown_err, []}. -handle_call({mar, {IMSI, NumAuthItems, AuthScheme, RAT, CKey, IntegrityKey}}, _From, State) -> +handle_call({mar, {IMSI, NumAuthItems, AuthScheme, RAT, CKey, IntegrityKey}}, {Pid, _Tag} = _From, State) -> SessionId = diameter:session_id(application:get_env(?ENV_APP_NAME, origin_host, ?ENV_DEFAULT_ORIG_HOST)), MAR = #'MAR'{'Vendor-Specific-Application-Id' = #'Vendor-Specific-Application-Id'{ 'Vendor-Id' = ?VENDOR_ID_3GPP, @@ -196,20 +196,17 @@ 'SIP-Number-Auth-Items' = NumAuthItems, 'RAT-Type' = RAT }, - Ret = diameter:call(?SVC_NAME, ?APP_ALIAS, MAR, []), + Ret = diameter:call(?SVC_NAME, ?APP_ALIAS, MAR, [{extra, [Pid]}, detach]), case Ret of - {ok, MAA} -> - SuccessCode = parse_maa(MAA), - case SuccessCode of - {ok, _} -> {reply, {ok, MAA}, State}; - {Err, Info} -> {reply, {error, {Err, Info, MAA}}, State} - end; + ok -> + {reply, ok, State}; {error, Err} -> lager:error("Error: ~w~n", [Err]), {reply, {error, Err}, State} end; -handle_call({sar, {IMSI, Type, APN}}, _From, State) -> +handle_call({sar, {IMSI, Type, APN}}, {Pid, _Tag} = _From, State) -> + lager:debug("SWx Tx SAR Imsi=~p Type=~p APN=~p~n", [IMSI, Type, APN]), SessionId = diameter:session_id(application:get_env(?ENV_APP_NAME, origin_host, ?ENV_DEFAULT_ORIG_HOST)), SAR = #'SAR'{'Vendor-Specific-Application-Id' = #'Vendor-Specific-Application-Id'{ 'Vendor-Id' = ?VENDOR_ID_3GPP, @@ -220,14 +217,10 @@ 'Server-Assignment-Type' = Type, 'Service-Selection' = [APN] }, - Ret = diameter:call(?SVC_NAME, ?APP_ALIAS, SAR, []), + Ret = diameter:call(?SVC_NAME, ?APP_ALIAS, SAR, [{extra, [Pid]}, detach]), case Ret of - {ok, Saa} -> - SuccessCode = parse_saa(Saa), - case SuccessCode of - {ok, _} -> {reply, {ok, Saa}, State}; - {Err, Info} -> {reply, {error, {Err, Info, Saa}}, State} - end; + ok -> + {reply, ok, State}; {error, Err} -> lager:error("Error: ~w~n", [Err]), {reply, {error, Err}, State} diff --git a/src/aaa_diameter_swx_cb.erl b/src/aaa_diameter_swx_cb.erl index 215e051..a7b9b7c 100644 --- a/src/aaa_diameter_swx_cb.erl +++ b/src/aaa_diameter_swx_cb.erl @@ -7,13 +7,14 @@ -include_lib("diameter_3gpp_ts29_273_swx.hrl"). %% diameter callbacks --export([peer_up/3, peer_down/3, pick_peer/4, prepare_request/3, prepare_retransmit/3, - handle_answer/4, handle_error/4, handle_request/3]). +-export([peer_up/3, peer_down/3, pick_peer/4, pick_peer/5, prepare_request/3, prepare_request/4, + prepare_retransmit/3, prepare_retransmit/4, + handle_answer/4, handle_answer/5, handle_error/4, handle_request/3]). %% peer_up/3 peer_up(_SvcName, Peer, State) -> lager:info("Peer up: ~p~n", [Peer]), - State. + State. %% peer_down/3 peer_down(_SvcName, Peer, State) -> @@ -23,9 +24,10 @@ %% pick_peer/4 pick_peer([Peer | _], _, _SvcName, _State) -> {ok, Peer}. +pick_peer([Peer | _], _, _SvcName, _State, _ExtraPars) -> + {ok, Peer}. %% prepare_request/3 - prepare_request(#diameter_packet{msg = [ T | Avps ]}, _, {_, Caps}) when is_list(Avps) -> #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps, @@ -35,9 +37,9 @@ {'Origin-Realm', OR}, {'Destination-Host', [DH]}, {'Destination-Realm', DR} - | Avps]}; + | Avps]}. % TODO: is there a simple way to capture all the following requests? -prepare_request(#diameter_packet{msg = Req}, _, {_, Caps}) +prepare_request(#diameter_packet{msg = Req}, _, {_, Caps}, _ExtraPars) when is_record(Req, 'MAR') -> #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps, Msg = Req#'MAR'{'Origin-Host' = OH, @@ -45,36 +47,40 @@ 'Destination-Host' = [DH], 'Destination-Realm' = DR}, {send, Msg}; -prepare_request(#diameter_packet{msg = Req}, _, {_, Caps}) +%% prepare_request/4 +prepare_request(#diameter_packet{msg = Req}, _, {_, Caps}, _ExtraPars) when is_record(Req, 'SAR') -> #diameter_caps{origin_host = {OH, DH}, origin_realm = {OR, DR}} = Caps, Msg = Req#'SAR'{'Origin-Host' = OH, 'Origin-Realm' = OR, 'Destination-Host' = [DH], 'Destination-Realm' = DR}, + lager:debug("SWx prepare_request: ~p~n", [Msg]), {send, Msg}. %% prepare_retransmit/3 prepare_retransmit(Packet, SvcName, Peer) -> prepare_request(Packet, SvcName, Peer). +%% prepare_retransmit/4 +prepare_retransmit(Packet, SvcName, Peer, ExtraPars) -> + prepare_request(Packet, SvcName, Peer, ExtraPars). + %% handle_answer/4 - -%% Since client.erl has detached the call when using the list -%% encoding and not otherwise, output to the terminal in the -%% the former case, return in the latter. - -handle_answer(#diameter_packet{msg = Msg, errors = []}, Request, _SvcName, _Peer) - when is_list(Request) -> +handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, Peer, ReqPid) when is_record(Msg, 'MAA') -> + lager:info("SWx Rx MAA ~p: ~p/ Errors ~p ~n", [Peer, Msg, Errors]), + aaa_ue_fsm:ev_rx_swx_maa(ReqPid, Msg), {ok, Msg}; -handle_answer(#diameter_packet{msg = Msg, errors = Errors}, Request, _SvcName, _Peer) - when is_list(Request) -> - {error, Errors}; - -handle_answer(#diameter_packet{msg = Msg, errors = []}, _Request, _SvcName, _Peer) -> +handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, Peer, ReqPid) when is_record(Msg, 'SAA') -> + lager:info("SWx Rx SAA ~p: ~p/ Errors ~p ~n", [Peer, Msg, Errors]), + #'SAA'{'Result-Code' = [ResultCode]} = Msg, + aaa_ue_fsm:ev_rx_swx_saa(ReqPid, ResultCode), + {ok, Msg}. +handle_answer(#diameter_packet{msg = Msg, errors = []}, _Request, _SvcName, Peer) -> + lager:info("SWx Rx ~p: ~p~n", [Peer, Msg]), {ok, Msg}; -handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, _Peer) -> - lager:info("Some Answer res: ~p / Errors ~p ~n", [Msg, Errors]), +handle_answer(#diameter_packet{msg = Msg, errors = Errors}, _Request, _SvcName, Peer) -> + lager:info("SWx Rx ~p: ~p / Errors ~p ~n", [Peer, Msg, Errors]), {error, Errors}. %% handle_error/4 diff --git a/src/aaa_ue_fsm.erl b/src/aaa_ue_fsm.erl new file mode 100644 index 0000000..e214540 --- /dev/null +++ b/src/aaa_ue_fsm.erl @@ -0,0 +1,185 @@ +% UE FSM +% (C) 2023 by sysmocom +% +% All Rights Reserved +% +% This program is free software; you can redistribute it and/or modify +% it under the terms of the GNU Affero General Public License as +% published by the Free Software Foundation; either version 3 of the +% License, or (at your option) any later version. +% +% This program is distributed in the hope that it will be useful, +% but WITHOUT ANY WARRANTY; without even the implied warranty of +% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +% GNU General Public License for more details. +% +% You should have received a copy of the GNU Affero General Public License +% along with this program. If not, see <
http://www.gnu.org/licenses/
>. +% +% Additional Permission under GNU AGPL version 3 section 7: +% +% If you modify this Program, or any covered work, by linking or +% combining it with runtime libraries of Erlang/OTP as released by +% Ericsson on
http://www.erlang.org
(or a modified version of these +% libraries), containing parts covered by the terms of the Erlang Public +% License (
http://www.erlang.org/EPLICENSE
), the licensors of this +% Program grant you additional permission to convey the resulting work +% without the need to license the runtime libraries of Erlang/OTP under +% the GNU Affero General Public License. Corresponding Source for a +% non-source form of such a combination shall include the source code +% for the parts of the runtime libraries of Erlang/OTP used as well as +% that of the covered work. + +-module(aaa_ue_fsm). +-behaviour(gen_statem). +-define(NAME, aaa_ue_fsm). + +-include_lib("diameter/include/diameter.hrl"). +-include_lib("diameter_3gpp_ts29_273_s6b.hrl"). + +-export([start_link/1]). +-export([init/1,callback_mode/0,terminate/3]). +-export([ev_swm_auth_req/1, ev_swm_auth_compl/2, ev_rx_swx_maa/2, ev_rx_swx_saa/2, ev_rx_s6b_aar/2]). +-export([state_new/3, state_wait_swx_maa/3, state_wait_swx_saa/3, state_authenticated/3, state_authenticated_wait_swx_saa/3]). + +-record(ue_fsm_data, { + imsi = unknown :: binary(), + epdg_sess_active = false :: boolean(), + pgw_sess_active = false :: boolean(), + s6b_resp_pid :: pid() + }). + +start_link(Imsi) -> + ServerName = lists:concat([?NAME, "_", binary_to_list(Imsi)]), + lager:info("ue_fsm start_link(~p)~n", [ServerName]), + gen_statem:start_link({local, list_to_atom(ServerName)}, ?MODULE, Imsi, [{debug, [trace]}]). + +ev_swm_auth_req(Pid) -> + lager:info("ue_fsm ev_swm_auth_req~n", []), + try + gen_statem:call(Pid, swm_auth_req) + catch + exit:Err -> + {error, Err} + end. + +ev_swm_auth_compl(Pid, Apn) -> + lager:info("ue_fsm ev_swm_auth_compl~n", []), + try + gen_statem:call(Pid, {swm_auth_compl, Apn}) + catch + exit:Err -> + {error, Err} + end. + +ev_rx_swx_maa(Pid, MAA) -> + lager:info("ue_fsm ev_rx_swx_maa~n", []), + try + gen_statem:call(Pid, {rx_swx_maa, MAA}) + catch + exit:Err -> + {error, Err} + end. + +ev_rx_swx_saa(Pid, ResultCode) -> + lager:info("ue_fsm ev_rx_swx_saa~n", []), + try + gen_statem:call(Pid, {rx_swx_saa, ResultCode}) + catch + exit:Err -> + {error, Err} + end. + +ev_rx_s6b_aar(Pid, Apn) -> + lager:info("ue_fsm ev_rx_s6b_aar: ~p~n", [Apn]), + try + gen_statem:call(Pid, {rx_s6b_aar, Apn}) + catch + exit:Err -> + {error, Err} + end. + +%% ------------------------------------------------------------------ +%% Internal helpers +%% ------------------------------------------------------------------ + +%% ------------------------------------------------------------------ +%% gen_statem Function Definitions +%% ------------------------------------------------------------------ + +init(Imsi) -> + lager:info("ue_fsm init(~p)~n", [Imsi]), + Data = #ue_fsm_data{imsi = Imsi}, + {ok, state_new, Data}. + +callback_mode() -> + [state_functions, state_enter]. + +terminate(Reason, State, Data) -> + lager:info("terminating ~p with reason ~p state=~p, ~p~n", [?MODULE, Reason, State, Data]), + ok. + +state_new(enter, _OldState, Data) -> + {keep_state, Data}; + +state_new({call, From}, swm_auth_req, Data) -> + lager:info("ue_fsm state_new event=swm_auth_req, ~p~n", [Data]), + % request the diameter code for a tuple + CKey = [], + IntegrityKey = [], + case aaa_diameter_swx:multimedia_auth_request(Data#ue_fsm_data.imsi, 1, "EAP-AKA", 1, CKey, IntegrityKey) of + ok -> {next_state, state_wait_swx_maa, Data, [{reply,From,ok}]}; + {error, Err} -> {keep_state, Data, [{reply,From,{error, Err}}]} + end; + +state_new({call, From}, {swm_auth_compl, Apn}, Data) -> + lager:info("ue_fsm state_new event=swm_auth_compl, ~p~n", [Data]), + case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, 1, Apn) of + ok -> {next_state, state_wait_swx_saa, Data, [{reply,From,ok}]}; + {error, Err} -> {keep_state, Data, [{reply,From,{error, Err}}]} + end. + +state_wait_swx_maa(enter, _OldState, Data) -> + {keep_state, Data}; + +state_wait_swx_maa({call, From}, {rx_swx_maa, MAA}, Data) -> + lager:info("ue_fsm state_wait_swx_maa event=rx_swx_maa, ~p~n", [Data]), + aaa_diameter_swm:auth_response(Data#ue_fsm_data.imsi, {ok, MAA}), + % TODO: don't transit if SAS returned error code. + {next_state, state_new, Data, [{reply,From,ok}]}. + +state_wait_swx_saa(enter, _OldState, Data) -> + {keep_state, Data}; + +state_wait_swx_saa({call, From}, {rx_swx_saa, SAA}, Data) -> + lager:info("ue_fsm state_wait_swx_saa event=rx_swx_saa, ~p~n", [Data]), + aaa_diameter_swm:auth_compl_response(Data#ue_fsm_data.imsi, {ok, SAA}), + % TODO: don't transit if SAS returned error code. + {next_state, state_authenticated, Data, [{reply,From,ok}]}. + +state_authenticated(enter, _OldState, Data) -> + % Mark ePDG session as active: + Data1 = Data#ue_fsm_data{epdg_sess_active = true}, + {keep_state, Data1}; + +state_authenticated({call, {Pid, _Tag} = From}, {rx_s6b_aar, Apn}, Data) -> + lager:info("ue_fsm state_authenticated event=rx_s6b_aar Apn=~p, ~p~n", [Apn, Data]), + case aaa_diameter_swx:server_assignment_request(Data#ue_fsm_data.imsi, 1, Apn) of + ok -> Data1 = Data#ue_fsm_data{s6b_resp_pid = Pid}, + {next_state, state_authenticated_wait_swx_saa, Data1, [{reply,From,ok}]}; + {error, Err} -> {keep_state, Data, [{reply,From,{error, Err}}]} + end; + +state_authenticated({call, From}, _Whatever, Data) -> + lager:info("ue_fsm state_authenticated event=purge_ms_request, ~p~n", [Data]), + {keep_state, Data, [{reply,From,ok}]}. + +state_authenticated_wait_swx_saa(enter, _OldState, Data) -> + {keep_state, Data}; + +state_authenticated_wait_swx_saa({call, From}, {rx_swx_saa, ResultCode}, Data) -> + lager:info("ue_fsm state_authenticated_wait_swx_saa event=rx_swx_saa ResulCode=~p, ~p~n", [ResultCode, Data]), + aaa_diameter_s6b:tx_aa_answer(Data#ue_fsm_data.s6b_resp_pid, ResultCode), + Data1 = Data#ue_fsm_data{s6b_resp_pid = undefined}, + {next_state, state_authenticated, Data1, [{reply,From,ok}]}. + -- To view, visit
https://gerrit.osmocom.org/c/erlang/osmo-epdg/+/35759?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings
Gerrit-Project: erlang/osmo-epdg Gerrit-Branch: master Gerrit-Change-Id: I78ebda4679d0a2f3ecede94598e74b20c2ff8836 Gerrit-Change-Number: 35759 Gerrit-PatchSet: 1 Gerrit-Owner: pespin <pespin(a)sysmocom.de> Gerrit-Reviewer: Jenkins Builder Gerrit-Reviewer: laforge <laforge(a)osmocom.org> Gerrit-Reviewer: lynxis lazus <lynxis(a)fe80.eu> Gerrit-Reviewer: pespin <pespin(a)sysmocom.de> Gerrit-MessageType: merged
1 year, 5 months
1
0
0
0
← Newer
1
...
168
169
170
171
172
173
174
175
Older →
Jump to page:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
Results per page:
10
25
50
100
200