blob: aceedd48b3eeb2c782f41ae9e1a9e97c760f3a37 [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 Pedrol965ac642023-10-16 18:12:45 +020040
41 /* our emulated PGW (GTPv2C S2b) */
42 charstring mp_s2b_local_ip := "127.0.0.100";
43 integer mp_s2b_local_port := GTP2C_PORT;
44 charstring mp_s2b_remote_ip := "127.0.0.1";
45 integer mp_s2b_remote_port := GTP2C_PORT;
46
47 charstring mp_diam_realm := "localdomain";
Pau Espin Pedrolc13a4cd2024-01-16 17:28:25 +010048 integer mp_diam_watchdog_initial_wait_sec := 6*3;
Pau Espin Pedrol965ac642023-10-16 18:12:45 +020049}
50
51
52type component MTC_CT {
53 var DIAMETER_Emulation_CT vc_SWx;
54 port DIAMETER_PT SWx_UNIT;
55 port DIAMETEREM_PROC_PT SWx_PROC;
56
57 var DIAMETER_Emulation_CT vc_S6b;
58 port DIAMETER_PT S6b_UNIT;
59 port DIAMETEREM_PROC_PT S6b_PROC;
60
61 var GSUP_Emulation_CT vc_GSUP;
62 var IPA_Emulation_CT vc_GSUP_IPA;
63 port IPA_CTRL_PT GSUP_IPA_EVENT;
64
65 var GTPv2_Emulation_CT vc_GTP2;
66 port GTP2EM_PT TEID0;
67
68 timer g_Tguard;
69};
70
71private altstep as_Tguard() runs on MTC_CT {
72 [] g_Tguard.timeout {
73 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "Tguard timeout");
74 }
75}
76
77type component DIAMETER_ConnHdlr_CT extends DIAMETER_ConnHdlr {
78 port DIAMETER_Conn_PT DIAMETER_CLIENT;
79 port DIAMETEREM_PROC_PT DIAMETER_PROC_CLIENT;
80}
81
82function f_diam_connhldr_ct_main(hexstring imsi) runs on DIAMETER_ConnHdlr_CT {
83 var DIAMETER_ConnHdlr vc_conn_unused;
84 var PDU_DIAMETER msg;
85 var UINT32 ete_id;
86
87 f_diameter_expect_imsi(imsi);
88
89
90 while (true) {
91 alt {
92 [] DIAMETER_CLIENT.receive(PDU_DIAMETER:?) -> value msg {
93 DIAMETER.send(msg);
94 }
95 [] DIAMETER.receive(PDU_DIAMETER:?) -> value msg {
96 DIAMETER_CLIENT.send(msg);
97 }
98 [] DIAMETER_PROC_CLIENT.getcall(DIAMETEREM_register_eteid:{?,?}) -> param(ete_id, vc_conn_unused) {
99 DIAMETER_PROC.call(DIAMETEREM_register_eteid:{ete_id, self}) {
100 [] DIAMETER_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
101 }
102 DIAMETER_PROC_CLIENT.reply(DIAMETEREM_register_eteid:{ete_id, vc_conn_unused});
103 }
104 }
105 }
106}
107
108type component EPDG_ConnHdlr extends DIAMETER_ConnHdlr, GSUP_ConnHdlr, GTP2_ConnHdlr {
109 var EPDG_ConnHdlrPars g_pars;
110
111 port DIAMETER_Conn_PT SWx;
112 port DIAMETEREM_PROC_PT SWx_PROC;
113 port DIAMETER_Conn_PT S6b;
114 port DIAMETEREM_PROC_PT S6b_PROC;
115};
116
117
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200118type record BearerConfig {
119 /* EPS Bearer ID */
120 uint4_t ebi optional,
121 /* TEI (Data) local side */
122 OCT4 teid_local optional,
123 /* TEI (Data) remote side */
124 OCT4 teid_remote optional
125};
126
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200127type record EPDG_ConnHdlrPars {
128 hexstring imsi,
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200129 charstring apn,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200130 charstring ue_ip,
131
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200132 /* TEI (Control) local side */
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200133 OCT4 teic_local,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200134 /* TEI (Control) remote side */
135 OCT4 teic_remote optional,
136
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200137 BearerConfig bearer optional,
138
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200139 AuthVector vec optional
140};
141
142private function f_epdg_connhldr_SWx_expect_eteid(UINT32 ete_id) runs on EPDG_ConnHdlr {
143 SWx_PROC.call(DIAMETEREM_register_eteid:{ete_id, null}) {
144 [] SWx_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
145 }
146}
147private function f_epdg_connhldr_S6b_expect_eteid(UINT32 ete_id) runs on EPDG_ConnHdlr {
148 S6b_PROC.call(DIAMETEREM_register_eteid:{ete_id, null}) {
149 [] S6b_PROC.getreply(DIAMETEREM_register_eteid:{?,?}) {};
150 }
151}
152
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200153private function f_init_pars(integer imsi_suffix := 1)
154runs on MTC_CT return EPDG_ConnHdlrPars {
155 var EPDG_ConnHdlrPars pars := {
156 imsi := f_gen_imsi(imsi_suffix),
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200157 apn := "internet",
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200158 ue_ip := "192.168.123.50",
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200159 teic_local := '00000000'O,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200160 teic_remote := omit,
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200161 bearer := {
162 ebi := omit,
163 teid_local := omit,
164 teid_remote := omit
165 },
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200166 vec := f_gen_auth_vec_3g()
167 };
168 return pars;
169}
170
171private function f_init_gsup(charstring id) runs on MTC_CT {
172 id := id & "-GSUP";
173 var GsupOps ops := {
174 create_cb := refers(GSUP_Emulation.ExpectedCreateCallback)
175 };
176
177 vc_GSUP_IPA := IPA_Emulation_CT.create(id & "-IPA");
178 vc_GSUP := GSUP_Emulation_CT.create(id);
179
180 map(vc_GSUP_IPA:IPA_PORT, system:IPA_CODEC_PT);
181 connect(vc_GSUP:GSUP, vc_GSUP_IPA:IPA_GSUP_PORT);
182 /* we use this hack to get events like ASP_IPA_EVENT_UP */
183 connect(vc_GSUP_IPA:IPA_CTRL_PORT, self:GSUP_IPA_EVENT);
184
185 vc_GSUP.start(GSUP_Emulation.main(ops, id));
186 vc_GSUP_IPA.start(IPA_Emulation.main_client(mp_gsup_remote_ip, mp_gsup_remote_port,
187 mp_gsup_local_ip, mp_gsup_local_port));
188
189 /* wait for incoming connection to GSUP port before proceeding */
190 timer T := 10.0;
191 T.start;
192 alt {
193 [] GSUP_IPA_EVENT.receive(tr_ASP_IPA_EV(ASP_IPA_EVENT_UP)) { }
194 [] T.timeout {
195 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, "No connection to GSUP Port");
196 }
197 }
198}
199
200private function DiameterForwardUnitdataCallback(PDU_DIAMETER msg)
201runs on DIAMETER_Emulation_CT return template PDU_DIAMETER {
202 DIAMETER_UNIT.send(msg);
203 return omit;
204}
205
206private function f_init_diameter(charstring id) runs on MTC_CT {
207 var DIAMETEROps ops := {
208 create_cb := refers(DIAMETER_Emulation.ExpectedCreateCallback),
209 unitdata_cb := refers(DiameterForwardUnitdataCallback),
210 raw := false /* handler mode (IMSI based routing) */
211 };
212 var DIAMETER_conn_parameters pars;
213
214 /* SWx setup: */
215 pars := {
216 remote_ip := "",
217 remote_sctp_port := -1, /* server mode */
218 local_ip := mp_swx_local_ip,
219 local_sctp_port := mp_swx_local_port,
220 origin_host := "hss." & mp_diam_realm,
221 origin_realm := mp_diam_realm,
222 auth_app_id := omit,
223 vendor_app_id := c_DIAMETER_3GPP_SWx_AID
224 };
225 vc_SWx := DIAMETER_Emulation_CT.create(id);
226 map(vc_SWx:DIAMETER, system:DIAMETER_CODEC_PT);
227 connect(vc_SWx:DIAMETER_UNIT, self:SWx_UNIT);
228 connect(vc_SWx:DIAMETER_PROC, self:SWx_PROC);
229 vc_SWx.start(DIAMETER_Emulation.main(ops, pars, id));
230
231 /* S6b setup: */
232 pars := {
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200233 remote_ip := mp_s6b_remote_ip,
234 remote_sctp_port := mp_s6b_remote_port, /* client mode */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200235 local_ip := mp_s6b_local_ip,
236 local_sctp_port := mp_s6b_local_port,
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200237 origin_host := "pgw." & mp_diam_realm,
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200238 origin_realm := mp_diam_realm,
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200239 auth_app_id := c_DIAMETER_3GPP_S6b_AID,
240 vendor_app_id := c_DIAMETER_3GPP_S6b_AID
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200241 };
242 vc_S6b := DIAMETER_Emulation_CT.create(id);
243 map(vc_S6b:DIAMETER, system:DIAMETER_CODEC_PT);
244 connect(vc_S6b:DIAMETER_UNIT, self:S6b_UNIT);
245 connect(vc_S6b:DIAMETER_PROC, self:S6b_PROC);
246 vc_S6b.start(DIAMETER_Emulation.main(ops, pars, id));
247
248 f_diameter_wait_capability(SWx_UNIT);
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200249 f_diameter_wait_capability(S6b_UNIT);
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200250
251 /* Give some time for our emulation to get out of SUSPECT list of SUT (3 watchdog ping-pongs):
252 * RFC6733 sec 5.1
253 * RFC3539 sec 3.4.1 [5]
254 * https://github.com/freeDiameter/freeDiameter/blob/master/libfdcore/p_psm.c#L49
255 */
Pau Espin Pedrolc13a4cd2024-01-16 17:28:25 +0100256 f_sleep(int2float(mp_diam_watchdog_initial_wait_sec));
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200257}
258
259private function f_init_gtp(charstring id) runs on MTC_CT {
260 var Gtp2EmulationCfg cfg := {
261 gtpc_bind_ip := mp_s2b_local_ip,
262 gtpc_bind_port := mp_s2b_local_port,
263 gtpc_remote_ip := mp_s2b_remote_ip,
264 gtpc_remote_port := mp_s2b_remote_port,
265 sgw_role := false,
266 use_gtpu_daemon := false /* TODO: maybe use, set to true */
267 };
268
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200269 vc_GTP2 := GTPv2_Emulation_CT.create(id & "-GTPV2");
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200270 map(vc_GTP2:GTP2C, system:GTP2C);
271 connect(vc_GTP2:TEID0, self:TEID0);
272 vc_GTP2.start(GTPv2_Emulation.main(cfg));
273}
274
275private function f_init(float t_guard := 40.0) runs on MTC_CT {
276
277 g_Tguard.start(t_guard);
278 activate(as_Tguard());
279
280 f_init_gsup(testcasename());
281 f_init_diameter(testcasename());
282 f_init_gtp(testcasename());
283}
284
285private type function void_fn(charstring id) runs on EPDG_ConnHdlr;
286
287private function f_init_handler(void_fn fn, charstring id, EPDG_ConnHdlrPars pars) runs on EPDG_ConnHdlr {
288 g_pars := pars;
289
290 /* tell GSUP dispatcher to send this IMSI to us */
291 f_create_gsup_expect(hex2str(g_pars.imsi));
292
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200293 /* tell GTPv2 dispatcher to send this IMSI to us */
294 f_gtp2_register_imsi(g_pars.imsi);
295
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200296 fn.apply(id);
297}
298
299private function f_start_handler(void_fn fn, EPDG_ConnHdlrPars pars)
300runs on MTC_CT return EPDG_ConnHdlr {
301 var EPDG_ConnHdlr vc_conn;
302 var charstring id := testcasename();
303 var DIAMETER_ConnHdlr_CT vc_conn_swx, vc_conn_s6b;
304
305 vc_conn := EPDG_ConnHdlr.create(id);
306
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200307 /* GSUP */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200308 connect(vc_conn:GSUP, vc_GSUP:GSUP_CLIENT);
309 connect(vc_conn:GSUP_PROC, vc_GSUP:GSUP_PROC);
310
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200311 /* GTP2 */
312 connect(vc_conn:GTP2, vc_GTP2:CLIENT);
313 connect(vc_conn:GTP2_PROC, vc_GTP2:CLIENT_PROC);
314
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200315 /* SWx */
316 vc_conn_swx := DIAMETER_ConnHdlr_CT.create(id);
317 connect(vc_conn_swx:DIAMETER, vc_SWx:DIAMETER_CLIENT);
318 connect(vc_conn_swx:DIAMETER_PROC, vc_SWx:DIAMETER_PROC);
319 connect(vc_conn:SWx, vc_conn_swx:DIAMETER_CLIENT);
320 connect(vc_conn:SWx_PROC, vc_conn_swx:DIAMETER_PROC_CLIENT);
321 vc_conn_swx.start(f_diam_connhldr_ct_main(pars.imsi));
322
323 /* S6b */
324 vc_conn_s6b := DIAMETER_ConnHdlr_CT.create(id);
325 connect(vc_conn_s6b:DIAMETER, vc_S6b:DIAMETER_CLIENT);
326 connect(vc_conn_s6b:DIAMETER_PROC, vc_S6b:DIAMETER_PROC);
327 connect(vc_conn:S6b, vc_conn_s6b:DIAMETER_CLIENT);
328 connect(vc_conn:S6b_PROC, vc_conn_s6b:DIAMETER_PROC_CLIENT);
329 vc_conn_s6b.start(f_diam_connhldr_ct_main(pars.imsi));
330
331 vc_conn.start(f_init_handler(fn, id, pars));
332 return vc_conn;
333}
334
335/* Diameter SWx MAR + MAA. */
336private altstep as_DIA_SWx_MA_success() runs on EPDG_ConnHdlr {
337 var PDU_DIAMETER rx_dia;
338 var template (omit) AVP avp;
339 var octetstring sess_id;
340 var template (value) GenericAVP sip_auth_data_item;
341 [] SWx.receive(tr_DIA_SWx_MAR(g_pars.imsi)) -> value rx_dia {
342 avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_BASE_NONE_Session_Id);
343 sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id);
344 sip_auth_data_item := ts_AVP_3GPP_SIPAuthDataItem(0,
345 g_pars.vec.rand,
346 g_pars.vec.ik,
347 g_pars.vec.ck,
348 g_pars.vec.autn,
349 g_pars.vec.auts);
350 /* Send MAA to translator; expect it to show up on GSUP side */
351 SWx.send(ts_DIA_SWx_MAA(g_pars.imsi, sip_auth_data_item,
352 sess_id := sess_id,
353 hbh_id := rx_dia.hop_by_hop_id,
354 ete_id := rx_dia.end_to_end_id));
355 setverdict(pass);
356 }
357 [] SWx.receive(PDU_DIAMETER:?) -> value rx_dia {
358 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter msg rx: ", rx_dia));
359 }
360}
361
362/* Diameter SWx SAR + SAA. */
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100363private 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 +0200364 var PDU_DIAMETER rx_dia;
365 var template (omit) AVP avp;
366 var octetstring sess_id;
367 [] SWx.receive(tr_DIA_SWx_SAR(g_pars.imsi)) -> value rx_dia {
368 avp := f_DIAMETER_get_avp(rx_dia, c_AVP_Code_BASE_NONE_Session_Id);
369 sess_id := valueof(avp.avp_data.avp_BASE_NONE_Session_Id);
370 /* Send SAA to translator; expect it to show up on GSUP side */
371 SWx.send(ts_DIA_SWx_SAA(g_pars.imsi,
372 sess_id := sess_id,
373 hbh_id := rx_dia.hop_by_hop_id,
374 ete_id := rx_dia.end_to_end_id));
375 setverdict(pass);
376 }
377 [] SWx.receive(PDU_DIAMETER:?) -> value rx_dia {
378 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter msg rx: ", rx_dia));
379 }
380}
381
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200382/* Send AAR as PGW to AAA server, expect back AAA */
383private function f_S6b_AA_success() runs on EPDG_ConnHdlr {
384 var PDU_DIAMETER rx_dia;
385 var UINT32 hbh_id := f_rnd_octstring(4);
386 var UINT32 ete_id := f_rnd_octstring(4);
387
388 /* Unlike AAR, AAA contains no IMSI. Register ete_id in DIAMETER_Emulation,
389 * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT.
390 */
391 f_epdg_connhldr_S6b_expect_eteid(ete_id);
392
Pau Espin Pedrol2c2e1872023-10-23 18:31:03 +0200393 S6b.send(ts_DIA_S6b_AAR(g_pars.imsi,
394 int2oct(DIA_TS29_373_MIP6_Feature_Vector_GTPv2_SUPPORTED, 8),
395 g_pars.apn, hbh_id := hbh_id, ete_id := ete_id));
Pau Espin Pedrolc119ba02024-01-29 11:55:39 +0100396
397 /* AAR in S6b in AAA-Server triggers Service-Assignment Request/Answer towards HSS: */
398 as_DIA_SWx_SA_success();
399
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200400 alt {
401 [] S6b.receive(tr_DIA_S6b_AAA) -> value rx_dia {}
402 [] S6b.receive(PDU_DIAMETER:?) -> value rx_dia {
403 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter S6b msg rx: ", rx_dia));
404 }
405 }
406}
407
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100408/* Send STR as PGW to AAA server, expect back STA */
409private function f_S6b_ST_success() runs on EPDG_ConnHdlr {
410 var PDU_DIAMETER rx_dia;
411 var UINT32 hbh_id := f_rnd_octstring(4);
412 var UINT32 ete_id := f_rnd_octstring(4);
413
414 /* Unlike STR, STA contains no IMSI. Register ete_id in DIAMETER_Emulation,
415 * so AIA is forwarded back to us in DIAMETER port instead of MTC_CT.DIAMETER_UNIT.
416 */
417 f_epdg_connhldr_S6b_expect_eteid(ete_id);
418
419 S6b.send(ts_DIA_S6b_STR(g_pars.imsi, DIAMETER_LOGOUT,
420 hbh_id := hbh_id, ete_id := ete_id));
421 alt {
422 [] S6b.receive(tr_DIA_S6b_STA(DIAMETER_SUCCESS)) -> value rx_dia {}
423 [] S6b.receive(PDU_DIAMETER:?) -> value rx_dia {
424 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected Diameter S6b msg rx: ", rx_dia));
425 }
426 }
427}
428
429/* ePDG Creates session at the PGW. PGW sends Diameter s6b AAR + AAA. */
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200430private altstep as_GTP2C_CreateSession_success() runs on EPDG_ConnHdlr {
431 var PDU_GTPCv2 rx_msg;
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200432 var BearerContextIEs rx_bctx_ies;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200433 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
434 var template (value) PDN_AddressAllocation paa;
Pau Espin Pedrol8c746492023-10-23 20:56:09 +0200435 var template (value) BearerContextIEs bctx_ies;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200436
437 [] GTP2.receive(tr_GTP2C_CreateSessionReq(g_pars.imsi)) -> value rx_msg {
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200438 /* Parse TEIC and Bearer EBI and TEID and store it in g_pars */
439 g_pars.teic_remote := rx_msg.gtpcv2_pdu.createSessionRequest.fullyQualifiedTEID[0].tEID_GRE_Key;
440 rx_bctx_ies := rx_msg.gtpcv2_pdu.createSessionRequest.bearerContextGrouped[0].bearerContextIEs;
441 g_pars.bearer.ebi := rx_bctx_ies.ePS_Bearer_ID.ePS_Bearer_ID_Value;
442 g_pars.bearer.teid_remote := rx_bctx_ies.fullyQualifiedTEID[0].tEID_GRE_Key;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200443
444 /* allocate + register TEID-C on local side */
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200445 g_pars.teic_local := f_gtp2_allocate_teid();
446 g_pars.bearer.teid_local := g_pars.teic_local;
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200447
Pau Espin Pedrolcdd41622023-10-23 14:38:20 +0200448 /* Upon rx of CreateSession, emulate PGW asking the AAA server. */
449 f_S6b_AA_success();
450
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200451 fteid_c_ie := ts_GTP2C_FTEID(FTEID_IF_S2b_ePDG_GTPC, g_pars.teic_local, 0,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200452 f_inet_addr(mp_s2b_local_ip), omit);
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200453 fteid_u_ie := ts_GTP2C_FTEID(FTEID_IF_S2bU_ePDG_GTPU, g_pars.bearer.teid_local, 2,
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200454 f_inet_addr(mp_s2b_local_ip), omit);
455 paa := ts_GTP2C_PdnAddrAlloc_v4(f_inet_addr(g_pars.ue_ip));
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200456 bctx_ies := ts_GTP2C_BcContextIE(ebi := g_pars.bearer.ebi,
Pau Espin Pedrol8c746492023-10-23 20:56:09 +0200457 teid_list := { fteid_u_ie },
458 qos := ts_GTP2C_BearerQos('09'O, 0,0,0,0),
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200459 charging_id := ts_GTP2C_ChargingID(g_pars.teic_local));
Pau Espin Pedrolfa2b3842023-12-13 18:49:19 +0100460 GTP2.send(ts_GTP2C_CreateSessionResp(g_pars.teic_remote, rx_msg.sequenceNumber,
461 { fteid_c_ie }, paa,
462 { ts_GTP2C_BcGrouped(bctx_ies) } ));
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200463 setverdict(pass);
464 }
465 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
466 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
467 }
468}
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100469
470/* ePDG Deletes session at the PGW. PGW sends Diameter s6b AAR + AAA. */
471private altstep as_GTP2C_DeleteSession_success() runs on EPDG_ConnHdlr {
472 var PDU_GTPCv2 rx_msg;
473 var BearerContextIEs rx_bctx_ies;
474 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
475 var template (value) PDN_AddressAllocation paa;
476 var template (value) BearerContextIEs bctx_ies;
477
478 [] GTP2.receive(tr_GTP2C_DeleteSessionReq(g_pars.teic_local)) -> value rx_msg {
479 /* Upon rx of DeleteSession, emulate PGW requesting the AAA server for Sesssion Termination. */
480 f_S6b_ST_success();
481
482 GTP2.send(ts_GTP2C_DeleteSessionResp(g_pars.teic_remote,
483 rx_msg.sequenceNumber,
484 Request_accepted));
485 setverdict(pass);
486 }
487 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
488 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
489 }
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200490}
491
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100492/* Expect CreateBearerResponse */
493private altstep as_GTP2C_CreateBearer_success() runs on EPDG_ConnHdlr {
494 var PDU_GTPCv2 rx_msg;
495
496 [] GTP2.receive(tr_GTP2C_CreateBearerResp(g_pars.teic_local)) -> value rx_msg {
497 setverdict(pass);
498 }
499 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
500 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
501 }
502}
503private function f_GTP2C_CreateBearer_success(uint4_t dedicated_bearer_id := 6) runs on EPDG_ConnHdlr {
504
505 var template (value) FullyQualifiedTEID fteid_u_ie := ts_GTP2C_FTEID(FTEID_IF_S2bU_ePDG_GTPU, g_pars.bearer.teid_local, dedicated_bearer_id,
506 f_inet_addr(mp_s2b_local_ip), omit);
507 var template (value) FullyQualifiedTEID_List teid_list := { fteid_u_ie };
508
509 var template (value) FullyQualifiedPDN_ConnectionSetID pgw_fq_csid := ts_GTP2C_FQCSID_IPv4(f_inet_addr(mp_s2b_local_ip), int2oct(dedicated_bearer_id, 2));
510 var template (value) FullyQualifiedPDN_ConnectionSetID_List csid_list := { pgw_fq_csid };
511
512 var template (value) BearerContextGrouped_List bcg_list := {
513 ts_GTP2C_BcGrouped({
514 ePS_Bearer_ID := ts_GTP2C_EpsBearerId(dedicated_bearer_id),
515 cause := omit,
516 ePS_Bearer_TFT := omit,
517 fullyQualifiedTEID := teid_list,
518 bearerLevel_QoS := ts_GTP2C_BearerQos('09'O, 0,0,0,0),
519 chargingID := ts_GTP2C_ChargingID(f_rnd_octstring(4)),
520 bearerFlags := omit,
521 transactionIdentifier := omit,
522 protocolConfigOptions := omit,
523 rAN_NASCause := omit,
524 additionalProtocolConfigOptions := omit,
525 extendedProtocolConfigOptions := omit
526 })
527 };
528 GTP2.send(ts_GTP2C_CreateBearerReq(g_pars.teic_remote, omit, g_pars.bearer.ebi,
529 dedicated_bearer_id, bcg_list, csid_list));
530 as_GTP2C_CreateBearer_success();
531}
532
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200533/* Expect DeleteBearerResponse */
534private altstep as_GTP2C_DeleteBearer_success() runs on EPDG_ConnHdlr {
535 var PDU_GTPCv2 rx_msg;
536 var template (value) FullyQualifiedTEID fteid_c_ie, fteid_u_ie;
537 var template (value) PDN_AddressAllocation paa;
538
539 [] GTP2.receive(tr_GTP2C_DeleteBearerResp(g_pars.teic_local)) -> value rx_msg {
540 setverdict(pass);
541 }
542 [] GTP2.receive(PDU_GTPCv2:?) -> value rx_msg {
543 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GTP2C msg rx: ", rx_msg));
544 }
545}
546private function f_GTP2C_DeleteBearer_success() runs on EPDG_ConnHdlr {
547 var integer proc_trans_id := 3;
548 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 +0100549 as_GSUP_CancelLocation_success();
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200550 as_GTP2C_DeleteBearer_success();
551}
552
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200553/* GSUP AuthInfo Req + Resp, triggers SWx MAR + MAA. */
554private function f_GSUP_AI_success() runs on EPDG_ConnHdlr {
555 var GSUP_PDU rx_gsup;
Pau Espin Pedrolc2cfd552024-02-07 17:51:55 +0100556 var template (present) GSUP_IE auth_tuple_ie;
557 var template (value) GSUP_IEs pdp_info;
558 auth_tuple_ie := tr_GSUP_IE_AuthTuple3G(g_pars.vec.rand,
559 g_pars.vec.ik,
560 g_pars.vec.ck,
561 g_pars.vec.autn,
562 g_pars.vec.rand & g_pars.vec.auts);
563 pdp_info := { ts_GSUP_IE_PDP_CONTEXT_ID('00'O),
564 ts_GSUP_IE_PDP_ADDRESS(ts_EuaIPv4Dyn),
565 ts_GSUP_IE_APN(f_enc_dns_hostname(g_pars.apn)) };
566 GSUP.send(ts_GSUP_SAI_REQ_PDP_INFO(g_pars.imsi, pdp_info));
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200567 as_DIA_SWx_MA_success();
568 /* Expect a positive response back to the translator; expect AIA */
569 alt {
570 [] GSUP.receive(tr_GSUP_SAI_RES(g_pars.imsi, auth_tuple_ie));
571 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
572 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
573 }
574 }
575 setverdict(pass);
576}
577
578/* GSUP LU Req + Resp, triggers SWx SAR + SAA (Server Assignment). */
579private function f_GSUP_LU_success() runs on EPDG_ConnHdlr {
580 var GSUP_PDU rx_gsup;
581 var template octetstring destination_name := *;
582 GSUP.send(ts_GSUP_UL_REQ(g_pars.imsi));
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100583 as_DIA_SWx_SA_success(REGISTRATION);
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200584 /* Expect a positive response back to the translator */
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200585 alt {
586 [] GSUP.receive(tr_GSUP_UL_RES(g_pars.imsi, destination_name));
587 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
588 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
589 }
590 }
591 setverdict(pass);
592}
593
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200594/* GSUP TunnelEPDG Tunnel Req + Resp, triggers S2b CreateSession Req + Response. */
595private function f_GSUP_EPDGTunnel_success() runs on EPDG_ConnHdlr {
596 var GSUP_PDU rx_gsup;
597 GSUP.send(ts_GSUP_EPDGTunnel_REQ(g_pars.imsi));
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100598 as_GTP2C_CreateSession_success();
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200599 /* Expect a positive response back to the translator; */
Pau Espin Pedrola6b0c1c2024-01-22 20:02:06 +0100600 var template (present) GSUP_IEs pdp_info := {
601 tr_GSUP_IE_PDP_CONTEXT_ID(?),
602 tr_GSUP_IE_PDP_ADDRESS(?),
603 tr_GSUP_IE_APN(?),
604 tr_GSUP_IE_PDP_QOS(?),
605 tr_GSUP_IE_Charging_Characteristics(?)
606 };
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200607 alt {
Pau Espin Pedrola6b0c1c2024-01-22 20:02:06 +0100608 [] GSUP.receive(tr_GSUP_EPDGTunnel_RES(g_pars.imsi, pdp_info));
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200609 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
610 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
611 }
612 }
613 setverdict(pass);
614}
615
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100616/* GSUP Purge MS Req + Resp, triggers S2b DeleteSession Req + Response. */
617private function f_GSUP_PurgeMS_success() runs on EPDG_ConnHdlr {
618 var GSUP_PDU rx_gsup;
619 GSUP.send(ts_GSUP_PURGE_MS_REQ(g_pars.imsi, OSMO_GSUP_CN_DOMAIN_PS));
620 as_GTP2C_DeleteSession_success();
621 /* ePDG internally sends STR to its AAA-Server. Since all sessions
622 become inactive, AAA-Server sends SAR(USER_DEREGISTRATION) to HSS: */
623
624 /* Expect a positive response back to the translator; */
625 as_DIA_SWx_SA_success(USER_DEREGISTRATION);
626 alt {
627 [] GSUP.receive(tr_GSUP_PURGE_MS_RES(g_pars.imsi));
628 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
629 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
630 }
631 }
632 setverdict(pass);
633}
634
Pau Espin Pedrolcbe6eba2024-02-06 12:53:14 +0100635/* Expect CancelLocationReq */
636private altstep as_GSUP_CancelLocation_success() runs on EPDG_ConnHdlr {
637 var GSUP_PDU rx_gsup;
638
639 [] GSUP.receive(tr_GSUP_CL_REQ(g_pars.imsi)) -> value rx_gsup {
640 GSUP.send(ts_GSUP_CL_RES(g_pars.imsi));
641 }
642 [] GSUP.receive(GSUP_PDU:?) -> value rx_gsup {
643 Misc_Helpers.f_shutdown(__BFILE__, __LINE__, fail, log2str("Unexpected GSUP msg rx: ", rx_gsup));
644 }
645}
646
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100647private function f_initial_attach() runs on EPDG_ConnHdlr {
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200648 f_GSUP_AI_success();
649 f_GSUP_LU_success();
Pau Espin Pedrold19fdf52023-10-19 16:58:24 +0200650 f_GSUP_EPDGTunnel_success();
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100651}
652
653private function f_TC_authinfo_normal(charstring id) runs on EPDG_ConnHdlr {
654 f_initial_attach();
Pau Espin Pedrol4944a5c2024-01-24 17:23:01 +0100655 f_GSUP_PurgeMS_success();
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200656}
657
658testcase TC_authinfo_normal() runs on MTC_CT {
659 var EPDG_ConnHdlrPars pars := f_init_pars();
660 var EPDG_ConnHdlr vc_conn;
661 f_init();
662 vc_conn := f_start_handler(refers(f_TC_authinfo_normal), pars);
663 vc_conn.done;
664 setverdict(pass);
665}
666
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100667private function f_TC_ho_lte_to_wifi(charstring id) runs on EPDG_ConnHdlr {
668 f_initial_attach();
669 /* Whenever UE comes from 3GPP, PGW may activate a dedicated S2b bearer
670 * and notify ePDG with a Create Bearer Request */
671 f_GTP2C_CreateBearer_success();
672 f_GSUP_PurgeMS_success();
673}
674
675testcase TC_ho_lte_to_wifi() runs on MTC_CT {
676 var EPDG_ConnHdlrPars pars := f_init_pars();
677 var EPDG_ConnHdlr vc_conn;
678 f_init();
679 vc_conn := f_start_handler(refers(f_TC_ho_lte_to_wifi), pars);
680 vc_conn.done;
681 setverdict(pass);
682}
683
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200684private function f_TC_ho_wifi_to_lte(charstring id) runs on EPDG_ConnHdlr {
Pau Espin Pedrolaf8ba582024-02-05 21:05:10 +0100685 f_initial_attach();
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200686 /* Whenever UE goes back to 3GPP, PGW will notify ePDG with a Delete Bearer Request
687 * cause="Access changed from non-3gpp to 3gpp" */
688 f_GTP2C_DeleteBearer_success();
689}
690
691testcase TC_ho_wifi_to_lte() runs on MTC_CT {
692 var EPDG_ConnHdlrPars pars := f_init_pars();
693 var EPDG_ConnHdlr vc_conn;
694 f_init();
695 vc_conn := f_start_handler(refers(f_TC_ho_wifi_to_lte), pars);
696 vc_conn.done;
697 setverdict(pass);
698}
699
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200700control {
701 execute ( TC_authinfo_normal() );
Pau Espin Pedrol14abac52024-02-05 21:05:17 +0100702 execute ( TC_ho_lte_to_wifi() );
Pau Espin Pedrold4a20082023-10-23 19:59:24 +0200703 execute ( TC_ho_wifi_to_lte() );
Pau Espin Pedrol965ac642023-10-16 18:12:45 +0200704}
705
706}