blob: 89a85f11eaba429c3308f089768a06b96ebc1e9e [file] [log] [blame]
Pau Espin Pedrol965ac642023-10-16 18:12:45 +02001module EPDG_Tests {
2
3import from Misc_Helpers all;
4import from General_Types all;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +02005import from Native_Functions all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +02006import from Osmocom_Types all;
7import from L3_Common all;
Pau Espin Pedrolc2cfd552024-02-07 17:51:55 +01008import from DNS_Helpers all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +02009
10import from IPA_Emulation all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020011import from GSUP_Types all;
Pau Espin Pedrol8f1403a2024-01-18 20:08:43 +010012import from GSUP_Templates all;
13import from GSUP_Emulation all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020014
15import from DIAMETER_Types all;
16import from DIAMETER_Templates all;
Pau Espin Pedrol4669b612023-10-23 17:43:14 +020017import from DIAMETER_ts29_273_Templates all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020018import from DIAMETER_Emulation all;
19
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +020020import from GTPv2_Types all;
21import from GTPv2_Templates all;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020022import from GTPv2_Emulation all;
23
24modulepar {
25 /* our emulated GSUP strongswan (CEAI iface) */
26 charstring mp_gsup_local_ip := "127.0.0.100";
27 integer mp_gsup_local_port := 0;
28 charstring mp_gsup_remote_ip := "127.0.0.1";
29 integer mp_gsup_remote_port := 4222;
30
31 /* our emulated HSS */
32 charstring mp_swx_local_ip := "127.0.0.100";
33 integer mp_swx_local_port := 3868;
34
35 /* our emulated PGW (Diameter S6b) */
36 charstring mp_s6b_local_ip := "127.0.0.100";
37 integer mp_s6b_local_port := 3869;
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +020038 charstring mp_s6b_remote_ip := "127.0.0.1";
39 integer mp_s6b_remote_port := 3869;
Pau Espin Pedrol8586b262024-02-09 18:12:21 +010040 /* 3GPP TS 23.003 clause 19: "nai.epc.mnc<MNC>.mcc<MCC>.3gppnetwork.org" */
41 charstring mp_s6b_nai_realm := "nai.epc.mnc001.mcc01.3gppnetwork.org";
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020042
43 /* our emulated PGW (GTPv2C S2b) */
44 charstring mp_s2b_local_ip := "127.0.0.100";
45 integer mp_s2b_local_port := GTP2C_PORT;
46 charstring mp_s2b_remote_ip := "127.0.0.1";
47 integer mp_s2b_remote_port := GTP2C_PORT;
48
49 charstring mp_diam_realm := "localdomain";
Pau Espin Pedrolc13a4cd2024-01-16 17:28:25 +010050 integer mp_diam_watchdog_initial_wait_sec := 6*3;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020051}
52
53
54type component MTC_CT {
55 var DIAMETER_Emulation_CT vc_SWx;
56 port DIAMETER_PT SWx_UNIT;
57 port DIAMETEREM_PROC_PT SWx_PROC;
58
59 var DIAMETER_Emulation_CT vc_S6b;
60 port DIAMETER_PT S6b_UNIT;
61 port DIAMETEREM_PROC_PT S6b_PROC;
62
63 var GSUP_Emulation_CT vc_GSUP;
64 var IPA_Emulation_CT vc_GSUP_IPA;
65 port IPA_CTRL_PT GSUP_IPA_EVENT;
66
67 var GTPv2_Emulation_CT vc_GTP2;
68 port GTP2EM_PT TEID0;
69
70 timer g_Tguard;
71};
72
73private altstep as_Tguard() runs on MTC_CT {
74 [] g_Tguard.timeout {
75 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
76 }
77}
78
79type component DIAMETER_ConnHdlr_CT extends DIAMETER_ConnHdlr {
80 port DIAMETER_Conn_PT DIAMETER_CLIENT;
81 port DIAMETEREM_PROC_PT DIAMETER_PROC_CLIENT;
82}
83
84function f_diam_connhldr_ct_main(hexstring imsi) runs on DIAMETER_ConnHdlr_CT {
85 var DIAMETER_ConnHdlr vc_conn_unused;
86 var PDU_DIAMETER msg;
87 var UINT32 ete_id;
88
89 f_diameter_expect_imsi(imsi);
90
91
92 while (true) {
93 alt {
94 [] DIAMETER_CLIENT.receive(PDU_DIAMETER:?) -> value msg {
95 DIAMETER.send(msg);
96 }
97 [] DIAMETER.receive(PDU_DIAMETER:?) -> value msg {
98 DIAMETER_CLIENT.send(msg);
99 }
100 [] DIAMETER_PROC_CLIENT.getcall(DIAMETEREM_register_eteid:{?,?}) -> param(ete_id, vc_conn_unused) {
101 DIAMETER_PROC.call(DIAMETEREM_register_eteid:{ete_id, self}) {
102 [] DIAMETER_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
103 }
104 DIAMETER_PROC_CLIENT.reply(DIAMETEREM_register_eteid:{ete_id, vc_conn_unused});
105 }
106 }
107 }
108}
109
110type component EPDG_ConnHdlr extends DIAMETER_ConnHdlr, GSUP_ConnHdlr, GTP2_ConnHdlr {
111 var EPDG_ConnHdlrPars g_pars;
112
113 port DIAMETER_Conn_PT SWx;
114 port DIAMETEREM_PROC_PT SWx_PROC;
115 port DIAMETER_Conn_PT S6b;
116 port DIAMETEREM_PROC_PT S6b_PROC;
117};
118
119
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200120type record BearerConfig {
121 /* EPS Bearer ID */
122 uint4_t ebi optional,
123 /* TEI (Data) local side */
124 OCT4 teid_local optional,
125 /* TEI (Data) remote side */
126 OCT4 teid_remote optional
127};
128
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200129type record EPDG_ConnHdlrPars {
130 hexstring imsi,
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200131 charstring apn,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200132 charstring ue_ip,
133
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200134 /* TEI (Control) local side */
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200135 OCT4 teic_local,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200136 /* TEI (Control) remote side */
137 OCT4 teic_remote optional,
138
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200139 BearerConfig bearer optional,
140
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200141 AuthVector vec optional
142};
143
144private function f_epdg_connhldr_SWx_expect_eteid(UINT32 ete_id) runs on EPDG_ConnHdlr {
145 SWx_PROC.call(DIAMETEREM_register_eteid:{ete_id, null}) {
146 [] SWx_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
147 }
148}
149private function f_epdg_connhldr_S6b_expect_eteid(UINT32 ete_id) runs on EPDG_ConnHdlr {
150 S6b_PROC.call(DIAMETEREM_register_eteid:{ete_id, null}) {
151 [] S6b_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
152 }
153}
154
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200155private function f_init_pars(integer imsi_suffix := 1)
156runs on MTC_CT return EPDG_ConnHdlrPars {
157 var EPDG_ConnHdlrPars pars := {
158 imsi := f_gen_imsi(imsi_suffix),
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200159 apn := "internet",
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200160 ue_ip := "192.168.123.50",
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200161 teic_local := '00000000'O,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200162 teic_remote := omit,
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200163 bearer := {
164 ebi := omit,
165 teid_local := omit,
166 teid_remote := omit
167 },
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200168 vec := f_gen_auth_vec_3g()
169 };
170 return pars;
171}
172
173private function f_init_gsup(charstring id) runs on MTC_CT {
174 id := id & "-GSUP";
175 var GsupOps ops := {
176 create_cb := refers(GSUP_Emulation.ExpectedCreateCallback)
177 };
178
179 vc_GSUP_IPA := IPA_Emulation_CT.create(id & "-IPA");
180 vc_GSUP := GSUP_Emulation_CT.create(id);
181
182 map(vc_GSUP_IPA:IPA_PORT, system:IPA_CODEC_PT);
183 connect(vc_GSUP:GSUP, vc_GSUP_IPA:IPA_GSUP_PORT);
184 /* we use this hack to get events like ASP_IPA_EVENT_UP */
185 connect(vc_GSUP_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT);
186
187 vc_GSUP.start(GSUP_Emulation.main(ops, id));
188 vc_GSUP_IPA.start(IPA_Emulation.main_client(mp_gsup_remote_ip, mp_gsup_remote_port,
189 mp_gsup_local_ip, mp_gsup_local_port));
190
191 /* wait for incoming connection to GSUP port before proceeding */
192 timer T := 10.0;
193 T.start;
194 alt {
195 [] GSUP_IPA_EVENT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { }
196 [] T.timeout {
197 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "No connection to GSUP Port");
198 }
199 }
200}
201
202private function DiameterForwardUnitdataCallback(PDU_DIAMETER msg)
203runs on DIAMETER_Emulation_CT return template PDU_DIAMETER {
204 DIAMETER_UNIT.send(msg);
205 return omit;
206}
207
208private function f_init_diameter(charstring id) runs on MTC_CT {
209 var DIAMETEROps ops := {
210 create_cb := refers(DIAMETER_Emulation.ExpectedCreateCallback),
211 unitdata_cb := refers(DiameterForwardUnitdataCallback),
212 raw := false /* handler mode (IMSI based routing) */
213 };
214 var DIAMETER_conn_parameters pars;
215
216 /* SWx setup: */
217 pars := {
218 remote_ip := "",
219 remote_sctp_port := -1, /* server mode */
220 local_ip := mp_swx_local_ip,
221 local_sctp_port := mp_swx_local_port,
222 origin_host := "hss." & mp_diam_realm,
223 origin_realm := mp_diam_realm,
224 auth_app_id := omit,
225 vendor_app_id := c_DIAMETER_3GPP_SWx_AID
226 };
227 vc_SWx := DIAMETER_Emulation_CT.create(id);
228 map(vc_SWx:DIAMETER, system:DIAMETER_CODEC_PT);
229 connect(vc_SWx:DIAMETER_UNIT, self:SWx_UNIT);
230 connect(vc_SWx:DIAMETER_PROC, self:SWx_PROC);
231 vc_SWx.start(DIAMETER_Emulation.main(ops, pars, id));
232
233 /* S6b setup: */
234 pars := {
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200235 remote_ip := mp_s6b_remote_ip,
236 remote_sctp_port := mp_s6b_remote_port, /* client mode */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200237 local_ip := mp_s6b_local_ip,
238 local_sctp_port := mp_s6b_local_port,
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200239 origin_host := "pgw." & mp_diam_realm,
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200240 origin_realm := mp_diam_realm,
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200241 auth_app_id := c_DIAMETER_3GPP_S6b_AID,
242 vendor_app_id := c_DIAMETER_3GPP_S6b_AID
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200243 };
244 vc_S6b := DIAMETER_Emulation_CT.create(id);
245 map(vc_S6b:DIAMETER, system:DIAMETER_CODEC_PT);
246 connect(vc_S6b:DIAMETER_UNIT, self:S6b_UNIT);
247 connect(vc_S6b:DIAMETER_PROC, self:S6b_PROC);
248 vc_S6b.start(DIAMETER_Emulation.main(ops, pars, id));
249
250 f_diameter_wait_capability(SWx_UNIT);
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200251 f_diameter_wait_capability(S6b_UNIT);
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200252
253 /* Give some time for our emulation to get out of SUSPECT list of SUT (3 watchdog ping-pongs):
254 * RFC6733 sec 5.1
255 * RFC3539 sec 3.4.1 [5]
256 * https://github.com/freeDiameter/freeDiameter/blob/master/libfdcore/p_psm.c#L49
257 */
Pau Espin Pedrolc13a4cd2024-01-16 17:28:25 +0100258 f_sleep(int2float(mp_diam_watchdog_initial_wait_sec));
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200259}
260
261private function f_init_gtp(charstring id) runs on MTC_CT {
262 var Gtp2EmulationCfg cfg := {
263 gtpc_bind_ip := mp_s2b_local_ip,
264 gtpc_bind_port := mp_s2b_local_port,
265 gtpc_remote_ip := mp_s2b_remote_ip,
266 gtpc_remote_port := mp_s2b_remote_port,
267 sgw_role := false,
268 use_gtpu_daemon := false /* TODO: maybe use, set to true */
269 };
270
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200271 vc_GTP2 := GTPv2_Emulation_CT.create(id & "-GTPV2");
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200272 map(vc_GTP2:GTP2C, system:GTP2C);
273 connect(vc_GTP2:TEID0, self:TEID0);
274 vc_GTP2.start(GTPv2_Emulation.main(cfg));
275}
276
277private function f_init(float t_guard := 40.0) runs on MTC_CT {
278
279 g_Tguard.start(t_guard);
280 activate(as_Tguard());
281
282 f_init_gsup(testcasename());
283 f_init_diameter(testcasename());
284 f_init_gtp(testcasename());
285}
286
287private type function void_fn(charstring id) runs on EPDG_ConnHdlr;
288
289private function f_init_handler(void_fn fn, charstring id, EPDG_ConnHdlrPars pars) runs on EPDG_ConnHdlr {
290 g_pars := pars;
291
292 /* tell GSUP dispatcher to send this IMSI to us */
293 f_create_gsup_expect(hex2str(g_pars.imsi));
294
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200295 /* tell GTPv2 dispatcher to send this IMSI to us */
296 f_gtp2_register_imsi(g_pars.imsi);
297
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200298 fn.apply(id);
299}
300
301private function f_start_handler(void_fn fn, EPDG_ConnHdlrPars pars)
302runs on MTC_CT return EPDG_ConnHdlr {
303 var EPDG_ConnHdlr vc_conn;
304 var charstring id := testcasename();
305 var DIAMETER_ConnHdlr_CT vc_conn_swx, vc_conn_s6b;
306
307 vc_conn := EPDG_ConnHdlr.create(id);
308
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200309 /* GSUP */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200310 connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
311 connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
312
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200313 /* GTP2 */
314 connect(vc_conn:GTP2, vc_GTP2:CLIENT);
315 connect(vc_conn:GTP2_PROC, vc_GTP2:CLIENT_PROC);
316
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200317 /* SWx */
318 vc_conn_swx := DIAMETER_ConnHdlr_CT.create(id);
319 connect(vc_conn_swx:DIAMETER, vc_SWx:DIAMETER_CLIENT);
320 connect(vc_conn_swx:DIAMETER_PROC, vc_SWx:DIAMETER_PROC);
321 connect(vc_conn:SWx, vc_conn_swx:DIAMETER_CLIENT);
322 connect(vc_conn:SWx_PROC, vc_conn_swx:DIAMETER_PROC_CLIENT);
323 vc_conn_swx.start(f_diam_connhldr_ct_main(pars.imsi));
324
325 /* S6b */
326 vc_conn_s6b := DIAMETER_ConnHdlr_CT.create(id);
327 connect(vc_conn_s6b:DIAMETER, vc_S6b:DIAMETER_CLIENT);
328 connect(vc_conn_s6b:DIAMETER_PROC, vc_S6b:DIAMETER_PROC);
329 connect(vc_conn:S6b, vc_conn_s6b:DIAMETER_CLIENT);
330 connect(vc_conn:S6b_PROC, vc_conn_s6b:DIAMETER_PROC_CLIENT);
331 vc_conn_s6b.start(f_diam_connhldr_ct_main(pars.imsi));
332
333 vc_conn.start(f_init_handler(fn, id, pars));
334 return vc_conn;
335}
336
Pau Espin Pedrol8586b262024-02-09 18:12:21 +0100337private function f_nai() runs on EPDG_ConnHdlr return charstring {
338 return hex2str(g_pars.imsi) & "@" & mp_s6b_nai_realm;
339}
340
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200341/* Diameter SWx MAR + MAA. */
342private altstep as_DIA_SWx_MA_success() runs on EPDG_ConnHdlr {
343 var PDU_DIAMETER rx_dia;
344 var template (omit) AVP avp;
345 var octetstring sess_id;
346 var template (value) GenericAVP sip_auth_data_item;
347 [] SWx.receive(tr_DIA_SWx_MAR(g_pars.imsi)) -> value rx_dia {
348 avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_BASE_NONE_Session_Id);
349 sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id);
350 sip_auth_data_item := ts_AVP_3GPP_SIPAuthDataItem(0,
351 g_pars.vec.rand,
352 g_pars.vec.ik,
353 g_pars.vec.ck,
354 g_pars.vec.autn,
355 g_pars.vec.auts);
356 /* Send MAA to translator; expect it to show up on GSUP side */
357 SWx.send(ts_DIA_SWx_MAA(g_pars.imsi, sip_auth_data_item,
358 sess_id := sess_id,
359 hbh_id := rx_dia.hop_by_hop_id,
360 ete_id := rx_dia.end_to_end_id));
361 setverdict(pass);
362 }
363 [] SWx.receive(PDU_DIAMETER:?) -> value rx_dia {
364 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter msg rx: ", rx_dia));
365 }
366}
367
368/* Diameter SWx SAR + SAA. */
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100369private altstep as_DIA_SWx_SA_success(template (present) CxDx_3GPP_Server_Assignment_Type server_ass_type := ?) runs on EPDG_ConnHdlr {
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200370 var PDU_DIAMETER rx_dia;
371 var template (omit) AVP avp;
372 var octetstring sess_id;
373 [] SWx.receive(tr_DIA_SWx_SAR(g_pars.imsi)) -> value rx_dia {
374 avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_BASE_NONE_Session_Id);
375 sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id);
376 /* Send SAA to translator; expect it to show up on GSUP side */
377 SWx.send(ts_DIA_SWx_SAA(g_pars.imsi,
378 sess_id := sess_id,
379 hbh_id := rx_dia.hop_by_hop_id,
380 ete_id := rx_dia.end_to_end_id));
381 setverdict(pass);
382 }
383 [] SWx.receive(PDU_DIAMETER:?) -> value rx_dia {
384 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter msg rx: ", rx_dia));
385 }
386}
387
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200388/* Send AAR as PGW to AAA server, expect back AAA */
389private function f_S6b_AA_success() runs on EPDG_ConnHdlr {
390 var PDU_DIAMETER rx_dia;
391 var UINT32 hbh_id := f_rnd_octstring(4);
392 var UINT32 ete_id := f_rnd_octstring(4);
393
394 /* Unlike AAR, AAA contains no IMSI. Register ete_id in DIAMETER_Emulation,
395 * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT.
396 */
397 f_epdg_connhldr_S6b_expect_eteid(ete_id);
398
Pau Espin Pedrol8586b262024-02-09 18:12:21 +0100399 S6b.send(ts_DIA_S6b_AAR(f_nai(),
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200400 int2oct(DIA_TS29_373_MIP6_Feature_Vector_GTPv2_SUPPORTED, 8),
401 g_pars.apn, hbh_id := hbh_id, ete_id := ete_id));
Pau Espin Pedrolc119ba02024-01-29 11:55:39 +0100402
403 /* AAR in S6b in AAA-Server triggers Service-Assignment Request/Answer towards HSS: */
404 as_DIA_SWx_SA_success();
405
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200406 alt {
407 [] S6b.receive(tr_DIA_S6b_AAA) -> value rx_dia {}
408 [] S6b.receive(PDU_DIAMETER:?) -> value rx_dia {
409 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter S6b msg rx: ", rx_dia));
410 }
411 }
412}
413
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100414/* Send STR as PGW to AAA server, expect back STA */
415private function f_S6b_ST_success() runs on EPDG_ConnHdlr {
416 var PDU_DIAMETER rx_dia;
417 var UINT32 hbh_id := f_rnd_octstring(4);
418 var UINT32 ete_id := f_rnd_octstring(4);
419
420 /* Unlike STR, STA contains no IMSI. Register ete_id in DIAMETER_Emulation,
421 * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT.
422 */
423 f_epdg_connhldr_S6b_expect_eteid(ete_id);
424
425 S6b.send(ts_DIA_S6b_STR(g_pars.imsi, DIAMETER_LOGOUT,
426 hbh_id := hbh_id, ete_id := ete_id));
427 alt {
428 [] S6b.receive(tr_DIA_S6b_STA(DIAMETER_SUCCESS)) -> value rx_dia {}
429 [] S6b.receive(PDU_DIAMETER:?) -> value rx_dia {
430 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter S6b msg rx: ", rx_dia));
431 }
432 }
433}
434
435/* ePDG Creates session at the PGW. PGW sends Diameter s6b AAR + AAA. */
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200436private altstep as_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr {
437 var PDU_GTPCv2 rx_msg;
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200438 var BearerContextIEs rx_bctx_ies;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200439 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
440 var template (value) PDN_AddressAllocation paa;
Pau Espin Pedrol8c746492023-10-23 20:56:09 +0200441 var template (value) BearerContextIEs bctx_ies;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200442
443 [] GTP2.receive(tr_GTP2C_CreateSessionReq(g_pars.imsi)) -> value rx_msg {
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200444 /* Parse TEIC and Bearer EBI and TEID and store it in g_pars */
445 g_pars.teic_remote := rx_msg.gtpcv2_pdu.createSessionRequest.fullyQualifiedTEID[0].tEID_GRE_Key;
446 rx_bctx_ies := rx_msg.gtpcv2_pdu.createSessionRequest.bearerContextGrouped[0].bearerContextIEs;
447 g_pars.bearer.ebi := rx_bctx_ies.ePS_Bearer_ID.ePS_Bearer_ID_Value;
448 g_pars.bearer.teid_remote := rx_bctx_ies.fullyQualifiedTEID[0].tEID_GRE_Key;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200449
450 /* allocate + register TEID-C on local side */
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200451 g_pars.teic_local := f_gtp2_allocate_teid();
452 g_pars.bearer.teid_local := g_pars.teic_local;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200453
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200454 /* Upon rx of CreateSession, emulate PGW asking the AAA server. */
455 f_S6b_AA_success();
456
Pau Espin Pedrol24b08592024-02-09 18:48:53 +0100457 fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S2b_PGW_GTPC, g_pars.teic_local, 1,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200458 f_inet_addr(mp_s2b_local_ip), omit);
Pau Espin Pedrol24b08592024-02-09 18:48:53 +0100459 fteid_u_ie := ts_GTP2C_FTEID(FTEID_IF_S2bU_PGW_GTPU, g_pars.bearer.teid_local, 4,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200460 f_inet_addr(mp_s2b_local_ip), omit);
461 paa := ts_GTP2C_PdnAddrAlloc_v4(f_inet_addr(g_pars.ue_ip));
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200462 bctx_ies := ts_GTP2C_BcContextIE(ebi := g_pars.bearer.ebi,
Pau Espin Pedrol8c746492023-10-23 20:56:09 +0200463 teid_list := { fteid_u_ie },
464 qos := ts_GTP2C_BearerQos('09'O, 0,0,0,0),
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200465 charging_id := ts_GTP2C_ChargingID(g_pars.teic_local));
Pau Espin Pedrolfa2b3842023-12-13 18:49:19 +0100466 GTP2.send(ts_GTP2C_CreateSessionResp(g_pars.teic_remote, rx_msg.sequenceNumber,
467 { fteid_c_ie }, paa,
468 { ts_GTP2C_BcGrouped(bctx_ies) } ));
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200469 setverdict(pass);
470 }
471 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
472 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
473 }
474}
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100475
476/* ePDG Deletes session at the PGW. PGW sends Diameter s6b AAR + AAA. */
477private altstep as_GTP2C_DeleteSession_success() runs on EPDG_ConnHdlr {
478 var PDU_GTPCv2 rx_msg;
479 var BearerContextIEs rx_bctx_ies;
480 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
481 var template (value) PDN_AddressAllocation paa;
482 var template (value) BearerContextIEs bctx_ies;
483
484 [] GTP2.receive(tr_GTP2C_DeleteSessionReq(g_pars.teic_local)) -> value rx_msg {
485 /* Upon rx of DeleteSession, emulate PGW requesting the AAA server for Sesssion Termination. */
486 f_S6b_ST_success();
487
488 GTP2.send(ts_GTP2C_DeleteSessionResp(g_pars.teic_remote,
489 rx_msg.sequenceNumber,
490 Request_accepted));
491 setverdict(pass);
492 }
493 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
494 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
495 }
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200496}
497
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100498/* Expect CreateBearerResponse */
499private altstep as_GTP2C_CreateBearer_success() runs on EPDG_ConnHdlr {
500 var PDU_GTPCv2 rx_msg;
501
502 [] GTP2.receive(tr_GTP2C_CreateBearerResp(g_pars.teic_local)) -> value rx_msg {
503 setverdict(pass);
504 }
505 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
506 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
507 }
508}
509private function f_GTP2C_CreateBearer_success(uint4_t dedicated_bearer_id := 6) runs on EPDG_ConnHdlr {
510
511 var template (value) FullyQualifiedTEID fteid_u_ie := ts_GTP2C_FTEID(FTEID_IF_S2bU_ePDG_GTPU, g_pars.bearer.teid_local, dedicated_bearer_id,
512 f_inet_addr(mp_s2b_local_ip), omit);
513 var template (value) FullyQualifiedTEID_List teid_list := { fteid_u_ie };
514
515 var template (value) FullyQualifiedPDN_ConnectionSetID pgw_fq_csid := ts_GTP2C_FQCSID_IPv4(f_inet_addr(mp_s2b_local_ip), int2oct(dedicated_bearer_id, 2));
516 var template (value) FullyQualifiedPDN_ConnectionSetID_List csid_list := { pgw_fq_csid };
517
518 var template (value) BearerContextGrouped_List bcg_list := {
519 ts_GTP2C_BcGrouped({
520 ePS_Bearer_ID := ts_GTP2C_EpsBearerId(dedicated_bearer_id),
521 cause := omit,
522 ePS_Bearer_TFT := omit,
523 fullyQualifiedTEID := teid_list,
524 bearerLevel_QoS := ts_GTP2C_BearerQos('09'O, 0,0,0,0),
525 chargingID := ts_GTP2C_ChargingID(f_rnd_octstring(4)),
526 bearerFlags := omit,
527 transactionIdentifier := omit,
528 protocolConfigOptions := omit,
529 rAN_NASCause := omit,
530 additionalProtocolConfigOptions := omit,
531 extendedProtocolConfigOptions := omit
532 })
533 };
534 GTP2.send(ts_GTP2C_CreateBearerReq(g_pars.teic_remote, omit, g_pars.bearer.ebi,
535 dedicated_bearer_id, bcg_list, csid_list));
536 as_GTP2C_CreateBearer_success();
537}
538
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200539/* Expect DeleteBearerResponse */
540private altstep as_GTP2C_DeleteBearer_success() runs on EPDG_ConnHdlr {
541 var PDU_GTPCv2 rx_msg;
542 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
543 var template (value) PDN_AddressAllocation paa;
544
545 [] GTP2.receive(tr_GTP2C_DeleteBearerResp(g_pars.teic_local)) -> value rx_msg {
546 setverdict(pass);
547 }
548 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
549 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
550 }
551}
552private function f_GTP2C_DeleteBearer_success() runs on EPDG_ConnHdlr {
553 var integer proc_trans_id := 3;
554 GTP2.send(ts_GTP2C_DeleteBearerReq(g_pars.teic_remote, proc_trans_id, g_pars.bearer.ebi, Access_changed_from_Non_3GPP_to_3GPP));
Pau Espin Pedrolcbe6eba2024-02-06 12:53:14 +0100555 as_GSUP_CancelLocation_success();
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200556 as_GTP2C_DeleteBearer_success();
557}
558
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200559/* GSUP AuthInfo Req + Resp, triggers SWx MAR + MAA. */
560private function f_GSUP_AI_success() runs on EPDG_ConnHdlr {
561 var GSUP_PDU rx_gsup;
Pau Espin Pedrolc2cfd552024-02-07 17:51:55 +0100562 var template (present) GSUP_IE auth_tuple_ie;
563 var template (value) GSUP_IEs pdp_info;
564 auth_tuple_ie := tr_GSUP_IE_AuthTuple3G(g_pars.vec.rand,
565 g_pars.vec.ik,
566 g_pars.vec.ck,
567 g_pars.vec.autn,
568 g_pars.vec.rand & g_pars.vec.auts);
569 pdp_info := { ts_GSUP_IE_PDP_CONTEXT_ID('00'O),
570 ts_GSUP_IE_PDP_ADDRESS(ts_EuaIPv4Dyn),
571 ts_GSUP_IE_APN(f_enc_dns_hostname(g_pars.apn)) };
572 GSUP.send(ts_GSUP_SAI_REQ_PDP_INFO(g_pars.imsi, pdp_info));
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200573 as_DIA_SWx_MA_success();
574 /* Expect a positive response back to the translator; expect AIA */
575 alt {
576 [] GSUP.receive(tr_GSUP_SAI_RES(g_pars.imsi, auth_tuple_ie));
577 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
578 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
579 }
580 }
581 setverdict(pass);
582}
583
584/* GSUP LU Req + Resp, triggers SWx SAR + SAA (Server Assignment). */
585private function f_GSUP_LU_success() runs on EPDG_ConnHdlr {
586 var GSUP_PDU rx_gsup;
587 var template octetstring destination_name := *;
588 GSUP.send(ts_GSUP_UL_REQ(g_pars.imsi));
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100589 as_DIA_SWx_SA_success(REGISTRATION);
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200590 /* Expect a positive response back to the translator */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200591 alt {
592 [] GSUP.receive(tr_GSUP_UL_RES(g_pars.imsi, destination_name));
593 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
594 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
595 }
596 }
597 setverdict(pass);
598}
599
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200600/* GSUP TunnelEPDG Tunnel Req + Resp, triggers S2b CreateSession Req + Response. */
601private function f_GSUP_EPDGTunnel_success() runs on EPDG_ConnHdlr {
602 var GSUP_PDU rx_gsup;
603 GSUP.send(ts_GSUP_EPDGTunnel_REQ(g_pars.imsi));
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100604 as_GTP2C_CreateSession_success();
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200605 /* Expect a positive response back to the translator; */
Pau Espin Pedrola6b0c1c2024-01-22 20:02:06 +0100606 var template (present) GSUP_IEs pdp_info := {
607 tr_GSUP_IE_PDP_CONTEXT_ID(?),
608 tr_GSUP_IE_PDP_ADDRESS(?),
609 tr_GSUP_IE_APN(?),
610 tr_GSUP_IE_PDP_QOS(?),
611 tr_GSUP_IE_Charging_Characteristics(?)
612 };
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200613 alt {
Pau Espin Pedrola6b0c1c2024-01-22 20:02:06 +0100614 [] GSUP.receive(tr_GSUP_EPDGTunnel_RES(g_pars.imsi, pdp_info));
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200615 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
616 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
617 }
618 }
619 setverdict(pass);
620}
621
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100622/* GSUP Purge MS Req + Resp, triggers S2b DeleteSession Req + Response. */
623private function f_GSUP_PurgeMS_success() runs on EPDG_ConnHdlr {
624 var GSUP_PDU rx_gsup;
625 GSUP.send(ts_GSUP_PURGE_MS_REQ(g_pars.imsi, OSMO_GSUP_CN_DOMAIN_PS));
626 as_GTP2C_DeleteSession_success();
627 /* ePDG internally sends STR to its AAA-Server. Since all sessions
628 become inactive, AAA-Server sends SAR(USER_DEREGISTRATION) to HSS: */
629
630 /* Expect a positive response back to the translator; */
631 as_DIA_SWx_SA_success(USER_DEREGISTRATION);
632 alt {
633 [] GSUP.receive(tr_GSUP_PURGE_MS_RES(g_pars.imsi));
634 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
635 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
636 }
637 }
638 setverdict(pass);
639}
640
Pau Espin Pedrolcbe6eba2024-02-06 12:53:14 +0100641/* Expect CancelLocationReq */
642private altstep as_GSUP_CancelLocation_success() runs on EPDG_ConnHdlr {
643 var GSUP_PDU rx_gsup;
644
645 [] GSUP.receive(tr_GSUP_CL_REQ(g_pars.imsi)) -> value rx_gsup {
646 GSUP.send(ts_GSUP_CL_RES(g_pars.imsi));
647 }
648 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
649 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
650 }
651}
652
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100653private function f_initial_attach() runs on EPDG_ConnHdlr {
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200654 f_GSUP_AI_success();
655 f_GSUP_LU_success();
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200656 f_GSUP_EPDGTunnel_success();
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100657}
658
659private function f_TC_authinfo_normal(charstring id) runs on EPDG_ConnHdlr {
660 f_initial_attach();
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100661 f_GSUP_PurgeMS_success();
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200662}
663
664testcase TC_authinfo_normal() runs on MTC_CT {
665 var EPDG_ConnHdlrPars pars := f_init_pars();
666 var EPDG_ConnHdlr vc_conn;
667 f_init();
668 vc_conn := f_start_handler(refers(f_TC_authinfo_normal), pars);
669 vc_conn.done;
670 setverdict(pass);
671}
672
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100673private function f_TC_ho_lte_to_wifi(charstring id) runs on EPDG_ConnHdlr {
674 f_initial_attach();
675 /* Whenever UE comes from 3GPP, PGW may activate a dedicated S2b bearer
676 * and notify ePDG with a Create Bearer Request */
677 f_GTP2C_CreateBearer_success();
678 f_GSUP_PurgeMS_success();
679}
680
681testcase TC_ho_lte_to_wifi() runs on MTC_CT {
682 var EPDG_ConnHdlrPars pars := f_init_pars();
683 var EPDG_ConnHdlr vc_conn;
684 f_init();
685 vc_conn := f_start_handler(refers(f_TC_ho_lte_to_wifi), pars);
686 vc_conn.done;
687 setverdict(pass);
688}
689
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200690private function f_TC_ho_wifi_to_lte(charstring id) runs on EPDG_ConnHdlr {
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100691 f_initial_attach();
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200692 /* Whenever UE goes back to 3GPP, PGW will notify ePDG with a Delete Bearer Request
693 * cause="Access changed from non-3gpp to 3gpp" */
694 f_GTP2C_DeleteBearer_success();
695}
696
697testcase TC_ho_wifi_to_lte() runs on MTC_CT {
698 var EPDG_ConnHdlrPars pars := f_init_pars();
699 var EPDG_ConnHdlr vc_conn;
700 f_init();
701 vc_conn := f_start_handler(refers(f_TC_ho_wifi_to_lte), pars);
702 vc_conn.done;
703 setverdict(pass);
704}
705
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200706control {
707 execute ( TC_authinfo_normal() );
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100708 execute ( TC_ho_lte_to_wifi() );
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200709 execute ( TC_ho_wifi_to_lte() );
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200710}
711
712}