blob: b860fe25612d6a8ee0ff8b7584d657ce5e917c56 [file] [log] [blame]
Harald Welteaf5bce42018-10-09 09:20:45 +02001module SGsAP_Emulation {
2
3/* SGsAP Emulation, runs on top of SGsAP_CodecPort. It multiplexes/demultiplexes
4 * the individual IMSIs/subscribers, so there can be separate TTCN-3 components handling
5 * each of them.
6 *
7 * The SGsAP_Emulation.main() function processes SGsAP primitives from the SGsAP
8 * socket via the SGsAP_CodecPort, and dispatches them to the per-IMSI components.
9 *
10 * For each new IMSI, the SgsapOps.create_cb() is called. It can create
11 * or resolve a TTCN-3 component, and returns a component reference to which that IMSI
12 * is routed/dispatched.
13 *
14 * If a pre-existing component wants to register to handle a future inbound IMSI, it can
15 * do so by registering an "expect" with the expected IMSI.
16 *
17 * Inbound SGsAP messages without IMSI (such as RESET-IND/ACK) are dispatched to
18 * the SgsapOps.unitdata_cb() callback, which is registered with an argument to the
19 * main() function below.
20 *
21 * (C) 2018 by Harald Welte <laforge@gnumonks.org>
22 * All rights reserved.
23 *
24 * Released under the terms of GNU General Public License, Version 2 or
25 * (at your option) any later version.
Harald Welte34b5a952019-05-27 11:54:11 +020026 *
27 * SPDX-License-Identifier: GPL-2.0-or-later
Harald Welteaf5bce42018-10-09 09:20:45 +020028 */
29
30import from SGsAP_CodecPort all;
31import from SGsAP_CodecPort_CtrlFunct all;
32import from SGsAP_Types all;
33import from SGsAP_Templates all;
34import from Osmocom_Types all;
35import from IPL4asp_Types all;
Harald Welte9a5dd542018-10-28 10:33:23 +010036import from DNS_Helpers all;
Harald Welte4263c522018-12-06 11:56:27 +010037import from MobileL3_Types all;
Harald Welteaf5bce42018-10-09 09:20:45 +020038
39type component SGsAP_ConnHdlr {
40 port SGsAP_Conn_PT SGsAP;
41 /* procedure based port to register for incoming connections */
42 port SGsAPEM_PROC_PT SGsAP_PROC;
43}
44
45/* port between individual per-connection components and this dispatcher */
46type port SGsAP_Conn_PT message {
Harald Welte4263c522018-12-06 11:56:27 +010047 inout PDU_SGsAP, PDU_ML3_MS_NW, PDU_ML3_NW_MS;
Harald Welteaf5bce42018-10-09 09:20:45 +020048} with { extension "internal" };
49
Harald Welteb8a4ac82019-06-23 11:04:12 +020050/* global test port e.g. for non-imsi/conn specific messages */
51type port SGsAP_PT message {
52 inout PDU_SGsAP;
53} with { extension "internal" };
54
55
Harald Welteaf5bce42018-10-09 09:20:45 +020056/* represents a single SGsAP Association */
57type record AssociationData {
58 SGsAP_ConnHdlr comp_ref,
59 hexstring imsi optional
60};
61
62type component SGsAP_Emulation_CT {
63 /* Port facing to the UDP SUT */
64 port SGsAP_CODEC_PT SGsAP;
65 /* All SGsAP_ConnHdlr SGsAP ports connect here
66 * SGsAP_Emulation_CT.main needs to figure out what messages
67 * to send where with CLIENT.send() to vc_conn */
68 port SGsAP_Conn_PT SGsAP_CLIENT;
69 /* currently tracked connections */
70 var AssociationData SgsapAssociationTable[16];
71 /* pending expected CRCX */
72 var ExpectData SgsapExpectTable[8];
73 /* procedure based port to register for incoming connections */
74 port SGsAPEM_PROC_PT SGsAP_PROC;
Harald Welteb8a4ac82019-06-23 11:04:12 +020075 /* test port for unit data messages */
76 port SGsAP_PT SGsAP_UNIT;
Harald Welteaf5bce42018-10-09 09:20:45 +020077
78 var charstring g_sgsap_id;
79 var integer g_sgsap_conn_id := -1;
80}
81
82type function SGsAPCreateCallback(PDU_SGsAP msg, hexstring imsi, charstring id)
83runs on SGsAP_Emulation_CT return SGsAP_ConnHdlr;
84
85type function SGsAPUnitdataCallback(PDU_SGsAP msg)
86runs on SGsAP_Emulation_CT return template PDU_SGsAP;
87
88type record SGsAPOps {
89 SGsAPCreateCallback create_cb,
90 SGsAPUnitdataCallback unitdata_cb
91}
92
93type record SGsAP_conn_parameters {
94 HostName remote_ip,
95 PortNumber remote_sctp_port,
96 HostName local_ip,
97 PortNumber local_sctp_port
98}
99
100function tr_SGsAP_RecvFrom_R(template PDU_SGsAP msg)
101runs on SGsAP_Emulation_CT return template SGsAP_RecvFrom {
102 var template SGsAP_RecvFrom mrf := {
103 connId := g_sgsap_conn_id,
104 remName := ?,
105 remPort := ?,
106 locName := ?,
107 locPort := ?,
108 msg := msg
109 }
110 return mrf;
111}
112
113private function f_imsi_known(hexstring imsi)
114runs on SGsAP_Emulation_CT return boolean {
115 var integer i;
116 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
117 if (SgsapAssociationTable[i].imsi == imsi) {
118 return true;
119 }
120 }
121 return false;
122}
123
124private function f_comp_known(SGsAP_ConnHdlr client)
125runs on SGsAP_Emulation_CT return boolean {
126 var integer i;
127 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
128 if (SgsapAssociationTable[i].comp_ref == client) {
129 return true;
130 }
131 }
132 return false;
133}
134
135private function f_comp_by_imsi(hexstring imsi)
136runs on SGsAP_Emulation_CT return SGsAP_ConnHdlr {
137 var integer i;
138 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
139 if (SgsapAssociationTable[i].imsi == imsi) {
140 return SgsapAssociationTable[i].comp_ref;
141 }
142 }
143 setverdict(fail, "SGsAP Association Table not found by IMSI", imsi);
144 mtc.stop;
145}
146
147private function f_imsi_by_comp(SGsAP_ConnHdlr client)
148runs on SGsAP_Emulation_CT return hexstring {
149 var integer i;
150 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
151 if (SgsapAssociationTable[i].comp_ref == client) {
152 return SgsapAssociationTable[i].imsi;
153 }
154 }
155 setverdict(fail, "SGsAP Association Table not found by component ", client);
156 mtc.stop;
157}
158
159private function f_imsi_table_add(SGsAP_ConnHdlr comp_ref, hexstring imsi)
160runs on SGsAP_Emulation_CT {
161 var integer i;
162 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
163 if (not isvalue(SgsapAssociationTable[i].imsi)) {
164 SgsapAssociationTable[i].imsi := imsi;
165 SgsapAssociationTable[i].comp_ref := comp_ref;
166 return;
167 }
168 }
169 testcase.stop("SGsAP Association Table full!");
170}
171
172private function f_imsi_table_del(SGsAP_ConnHdlr comp_ref, hexstring imsi)
173runs on SGsAP_Emulation_CT {
174 var integer i;
175 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
176 if (SgsapAssociationTable[i].comp_ref == comp_ref and
177 SgsapAssociationTable[i].imsi == imsi) {
178 SgsapAssociationTable[i].imsi := omit;
179 SgsapAssociationTable[i].comp_ref := null;
180 return;
181 }
182 }
183 setverdict(fail, "SGsAP Association Table: Couldn't find to-be-deleted entry!");
184 mtc.stop;
185}
186
187
188private function f_imsi_table_init()
189runs on SGsAP_Emulation_CT {
190 for (var integer i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
191 SgsapAssociationTable[i].comp_ref := null;
192 SgsapAssociationTable[i].imsi := omit;
193 }
194}
195
196private function f_SGsAP_get_imsi(PDU_SGsAP pdu) return template (omit) IMSI
197{
198 if (ischosen(pdu.sGsAP_ALERT_ACK)) {
199 return pdu.sGsAP_ALERT_ACK.iMSI;
200 } else if (ischosen(pdu.sGsAP_ALERT_REJECT)) {
201 return pdu.sGsAP_ALERT_REJECT.iMSI;
202 } else if (ischosen(pdu.sGsAP_ALERT_REQUEST)) {
203 return pdu.sGsAP_ALERT_REQUEST.iMSI;
204 } else if (ischosen(pdu.sGsAP_DOWNLINK_UNITDATA)) {
205 return pdu.sGsAP_DOWNLINK_UNITDATA.iMSI;
206 } else if (ischosen(pdu.sGsAP_EPS_DETACH_ACK)) {
207 return pdu.sGsAP_EPS_DETACH_ACK.iMSI;
208 } else if (ischosen(pdu.sGsAP_EPS_DETACH_INDICATION)) {
209 return pdu.sGsAP_EPS_DETACH_INDICATION.iMSI;
210 } else if (ischosen(pdu.sGsAP_IMSI_DETACH_ACK)) {
211 return pdu.sGsAP_IMSI_DETACH_ACK.iMSI;
212 } else if (ischosen(pdu.sGsAP_IMSI_DETACH_INDICATION)) {
213 return pdu.sGsAP_IMSI_DETACH_INDICATION.iMSI;
214 } else if (ischosen(pdu.sGsAP_LOCATION_UPDATE_ACCEPT)) {
215 return pdu.sGsAP_LOCATION_UPDATE_ACCEPT.iMSI;
216 } else if (ischosen(pdu.sGsAP_LOCATION_UPDATE_REJECT)) {
217 return pdu.sGsAP_LOCATION_UPDATE_REJECT.iMSI;
218 } else if (ischosen(pdu.sGsAP_LOCATION_UPDATE_REQUEST)) {
219 return pdu.sGsAP_LOCATION_UPDATE_REQUEST.iMSI;
220 } else if (ischosen(pdu.sGsAP_MM_INFORMATION_REQUEST)) {
221 return pdu.sGsAP_MM_INFORMATION_REQUEST.iMSI;
222 } else if (ischosen(pdu.sGsAP_PAGING_REJECT)) {
223 return pdu.sGsAP_PAGING_REJECT.iMSI;
224 } else if (ischosen(pdu.sGsAP_PAGING_REQUEST)) {
225 return pdu.sGsAP_PAGING_REQUEST.iMSI;
226 } else if (ischosen(pdu.sGsAP_SERVICE_REQUEST)) {
227 return pdu.sGsAP_SERVICE_REQUEST.iMSI;
228 } else if (ischosen(pdu.sGsAP_STATUS)) {
229 return pdu.sGsAP_STATUS.iMSI;
230 } else if (ischosen(pdu.sGsAP_TMSI_REALLOCATION_COMPLETE)) {
231 return pdu.sGsAP_TMSI_REALLOCATION_COMPLETE.iMSI;
232 } else if (ischosen(pdu.sGsAP_UE_ACTIVITY_INDICATION)) {
233 return pdu.sGsAP_UE_ACTIVITY_INDICATION.iMSI;
234 } else if (ischosen(pdu.sGsAP_UE_UNREACHABLE)) {
235 return pdu.sGsAP_UE_UNREACHABLE.iMSI;
236 } else if (ischosen(pdu.sGsAP_UPLINK_UNITDATA)) {
237 return pdu.sGsAP_UPLINK_UNITDATA.iMSI;
238 } else if (ischosen(pdu.sGsAP_RELEASE_REQUEST)) {
239 return pdu.sGsAP_RELEASE_REQUEST.iMSI;
240 } else if (ischosen(pdu.sGsAP_SERVICE_ABORT_REQUEST)) {
241 return pdu.sGsAP_SERVICE_ABORT_REQUEST.iMSI;
242 } else if (ischosen(pdu.sGsAP_MO_CSFB_INDICATION)) {
243 return pdu.sGsAP_MO_CSFB_INDICATION.iMSI;
244 }
245 return omit;
246}
247
248private template (value) SctpTuple ts_SCTP(template (omit) integer ppid := omit) := {
249 sinfo_stream := omit,
250 sinfo_ppid := ppid,
251 remSocks := omit,
252 assocId := omit
253};
254
255private template PortEvent tr_SctpAssocChange := {
256 sctpEvent := {
257 sctpAssocChange := ?
258 }
259}
260private template PortEvent tr_SctpPeerAddrChange := {
261 sctpEvent := {
262 sctpPeerAddrChange := ?
263 }
264}
265
266private function f_sgsap_xceive(template (value) PDU_SGsAP tx,
267 template PDU_SGsAP rx_t := ?)
268runs on SGsAP_Emulation_CT return PDU_SGsAP {
269 timer T := 10.0;
270 var SGsAP_RecvFrom mrf;
271
272 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, tx));
273 alt {
274 [] SGsAP.receive(tr_SGsAP_RecvFrom_R(rx_t)) -> value mrf { }
275 [] SGsAP.receive(tr_SctpAssocChange) { repeat; }
276 [] SGsAP.receive(tr_SctpPeerAddrChange) { repeat; }
277 [] T.timeout {
278 setverdict(fail, "Timeout waiting for ", rx_t);
279 mtc.stop;
280 }
281 }
282 return mrf.msg;
283}
284
285function main(SGsAPOps ops, SGsAP_conn_parameters p, charstring id) runs on SGsAP_Emulation_CT {
286 var Result res;
287 g_sgsap_id := id;
288 f_imsi_table_init();
289 f_expect_table_init();
290
291 map(self:SGsAP, system:SGsAP_CODEC_PT);
292 if (p.remote_sctp_port == -1) {
293 res := SGsAP_CodecPort_CtrlFunct.f_IPL4_listen(SGsAP, p.local_ip, p.local_sctp_port, { sctp := valueof(ts_SCTP) });
294 } else {
295 res := SGsAP_CodecPort_CtrlFunct.f_IPL4_connect(SGsAP, p.remote_ip, p.remote_sctp_port,
296 p.local_ip, p.local_sctp_port, -1, { sctp := valueof(ts_SCTP) });
297 }
298 if (not ispresent(res.connId)) {
299 setverdict(fail, "Could not connect SGsAP socket, check your configuration");
300 mtc.stop;
301 }
302 g_sgsap_conn_id := res.connId;
303
304 while (true) {
305 var SGsAP_ConnHdlr vc_conn;
Harald Welte4263c522018-12-06 11:56:27 +0100306 var PDU_ML3_MS_NW l3_mo;
307 var PDU_ML3_NW_MS l3_mt;
Harald Welteaf5bce42018-10-09 09:20:45 +0200308 var template IMSI imsi_t;
309 var hexstring imsi;
310 var SGsAP_RecvFrom mrf;
311 var PDU_SGsAP msg;
Harald Welte9a5dd542018-10-28 10:33:23 +0100312 var charstring vlr_name, mme_name;
Harald Welteaf5bce42018-10-09 09:20:45 +0200313
314 alt {
315 /* SGsAP from client */
316 [] SGsAP_CLIENT.receive(PDU_SGsAP:?) -> value msg sender vc_conn {
317 /* Pass message through */
318 /* TODO: check which ConnectionID client has allocated + store in table? */
319 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, msg));
320 }
Harald Welte4263c522018-12-06 11:56:27 +0100321 /* DTAP/MobileL3 from client (emulated MS): wrap in SGsAP-UL-UD and send */
322 [] SGsAP_CLIENT.receive(PDU_ML3_MS_NW:?) -> value l3_mo sender vc_conn {
323 var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3_mo);
324 imsi := f_imsi_by_comp(vc_conn);
325 msg := valueof(ts_SGsAP_UL_UD(imsi, l3_enc));
326 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, msg));
327 }
328 [] SGsAP_CLIENT.receive(PDU_ML3_NW_MS:?) -> value l3_mt sender vc_conn {
329 var octetstring l3_enc := enc_PDU_ML3_NW_MS(l3_mt);
330 imsi := f_imsi_by_comp(vc_conn);
331 msg := valueof(ts_SGsAP_DL_UD(imsi, l3_enc));
332 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, msg));
333 }
334
335 /* DTAP/MobileL3 from MSC/VLR to MS wrapped in SGsAP-DL-UD: Extract, decode, forward */
336 [] SGsAP.receive(tr_SGsAP_RecvFrom_R(tr_SGsAP_DL_UD(?,?))) -> value mrf {
337 var octetstring l3_enc := mrf.msg.sGsAP_DOWNLINK_UNITDATA.nAS_MessageContainer.nAS_MessageContainer;
338 imsi := mrf.msg.sGsAP_DOWNLINK_UNITDATA.iMSI.iMSI.digits;
339 vc_conn := f_comp_by_imsi(imsi);
340 l3_mt := dec_PDU_ML3_NW_MS(l3_enc);
341 SGsAP_CLIENT.send(l3_mt) to vc_conn;
342 }
343 [] SGsAP.receive(tr_SGsAP_RecvFrom_R(tr_SGsAP_UL_UD(?,?))) -> value mrf {
344 var octetstring l3_enc := mrf.msg.sGsAP_UPLINK_UNITDATA.nAS_MessageContainer.nAS_MessageContainer;
345 imsi := mrf.msg.sGsAP_UPLINK_UNITDATA.iMSI.iMSI.digits;
346 l3_mo := dec_PDU_ML3_MS_NW(l3_enc);
347 vc_conn := f_comp_by_imsi(imsi);
348 SGsAP_CLIENT.send(l3_mo) to vc_conn;
349 }
350
351
352 /* any other SGsAP from MSC/VLR */
Harald Welteaf5bce42018-10-09 09:20:45 +0200353 [] SGsAP.receive(tr_SGsAP_RecvFrom_R(?)) -> value mrf {
354 imsi_t := f_SGsAP_get_imsi(mrf.msg);
355 if (isvalue(imsi_t)) {
356 imsi := valueof(imsi_t.iMSI.digits);
357 if (f_imsi_known(imsi)) {
358 vc_conn := f_comp_by_imsi(imsi);
359 SGsAP_CLIENT.send(mrf.msg) to vc_conn;
360 } else {
361 vc_conn := ops.create_cb.apply(mrf.msg, imsi, id);
362 f_imsi_table_add(vc_conn, imsi);
363 SGsAP_CLIENT.send(mrf.msg) to vc_conn;
364 }
365 } else {
366 /* message contained no IMSI; is not IMSI-oriented */
367 var template PDU_SGsAP resp := ops.unitdata_cb.apply(mrf.msg);
368 if (isvalue(resp)) {
369 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, valueof(resp)));
370 }
371 }
372 }
373 [] SGsAP.receive(tr_SctpAssocChange) { }
374 [] SGsAP.receive(tr_SctpPeerAddrChange) { }
375 [] SGsAP_PROC.getcall(SGsAPEM_register:{?,?}) -> param(imsi, vc_conn) {
376 f_create_expect(imsi, vc_conn);
377 SGsAP_PROC.reply(SGsAPEM_register:{imsi, vc_conn}) to vc_conn;
378 }
Harald Welte9a5dd542018-10-28 10:33:23 +0100379 [] SGsAP_PROC.getcall(SGsAPEM_reset_mme:{?,-}) -> param(mme_name) {
380 var octetstring mme_enc, vlr_enc;
381 mme_enc := f_enc_dns_hostname(mme_name);
382 msg := f_sgsap_xceive(ts_SGsAP_RESET_IND_MME(mme_enc));
383 vlr_enc := msg.sGsAP_RESET_ACK.vLR_Name.name;
384 vlr_name := f_dec_dns_hostname(vlr_enc);
385 SGsAP_PROC.reply(SGsAPEM_reset_mme:{mme_name, vlr_name});
386 }
387 [] SGsAP_PROC.getcall(SGsAPEM_reset_vlr:{?,-}) -> param(vlr_name) {
388 var octetstring mme_enc, vlr_enc;
389 vlr_enc := f_enc_dns_hostname(vlr_name);
390 msg := f_sgsap_xceive(ts_SGsAP_RESET_IND_VLR(vlr_enc));
391 mme_enc := msg.sGsAP_RESET_ACK.mME_Name.name;
392 mme_name := f_dec_dns_hostname(mme_enc);
393 SGsAP_PROC.reply(SGsAPEM_reset_vlr:{vlr_name, mme_name});
394 }
395
396
Harald Welteaf5bce42018-10-09 09:20:45 +0200397 }
398
399 }
400}
401
402/* "Expect" Handling */
403
404type record ExpectData {
405 hexstring imsi optional,
406 SGsAP_ConnHdlr vc_conn
407}
408
409signature SGsAPEM_register(in hexstring imsi, in SGsAP_ConnHdlr hdlr);
410
Harald Welte9a5dd542018-10-28 10:33:23 +0100411signature SGsAPEM_reset_vlr(in charstring vlr_name, out charstring mme_name);
412signature SGsAPEM_reset_mme(in charstring mme_name, out charstring vlr_name);
413
Harald Welteaf5bce42018-10-09 09:20:45 +0200414type port SGsAPEM_PROC_PT procedure {
Harald Welte9a5dd542018-10-28 10:33:23 +0100415 inout SGsAPEM_register, SGsAPEM_reset_vlr, SGsAPEM_reset_mme;
Harald Welteaf5bce42018-10-09 09:20:45 +0200416} with { extension "internal" };
417
Oliver Smith23e192e2023-02-13 15:00:46 +0100418/* Function that can be used as create_cb and will use the expect table */
Harald Welteaf5bce42018-10-09 09:20:45 +0200419function ExpectedCreateCallback(PDU_SGsAP msg, hexstring imsi, charstring id)
420runs on SGsAP_Emulation_CT return SGsAP_ConnHdlr {
421 var SGsAP_ConnHdlr ret := null;
422 var integer i;
423
424 for (i := 0; i < sizeof(SgsapExpectTable); i := i+1) {
425 if (not ispresent(SgsapExpectTable[i].imsi)) {
426 continue;
427 }
428 if (imsi == SgsapExpectTable[i].imsi) {
429 ret := SgsapExpectTable[i].vc_conn;
430 /* Release this entry */
431 SgsapExpectTable[i].imsi := omit;
432 SgsapExpectTable[i].vc_conn := null;
433 log("Found Expect[", i, "] for ", msg, " handled at ", ret);
434 return ret;
435 }
436 }
437 setverdict(fail, "Couldn't find Expect for ", msg);
438 mtc.stop;
439}
440
441private function f_create_expect(hexstring imsi, SGsAP_ConnHdlr hdlr)
442runs on SGsAP_Emulation_CT {
443 var integer i;
444
445 /* Check an entry like this is not already presnt */
446 for (i := 0; i < sizeof(SgsapExpectTable); i := i+1) {
447 if (imsi == SgsapExpectTable[i].imsi) {
448 setverdict(fail, "IMSI already present", imsi);
449 mtc.stop;
450 }
451 }
452 for (i := 0; i < sizeof(SgsapExpectTable); i := i+1) {
453 if (not ispresent(SgsapExpectTable[i].imsi)) {
454 SgsapExpectTable[i].imsi := imsi;
455 SgsapExpectTable[i].vc_conn := hdlr;
456 log("Created Expect[", i, "] for ", imsi, " to be handled at ", hdlr);
457 return;
458 }
459 }
460 testcase.stop("No space left in SgsapExpectTable")
461}
462
463/* client/conn_hdlr side function to use procedure port to create expect in emulation */
464function f_create_sgsap_expect(hexstring imsi) runs on SGsAP_ConnHdlr {
465 SGsAP_PROC.call(SGsAPEM_register:{imsi, self}) {
466 [] SGsAP_PROC.getreply(SGsAPEM_register:{?,?}) {};
467 }
468}
469
Harald Welte9a5dd542018-10-28 10:33:23 +0100470/* client/conn_hdlr side function to use procedure port to send RESET from emulated MME */
471function f_sgsap_reset_mme(charstring mme_name) runs on SGsAP_ConnHdlr return charstring {
472 var charstring vlr_name;
473 SGsAP_PROC.call(SGsAPEM_reset_mme:{mme_name, -}) {
474 [] SGsAP_PROC.getreply(SGsAPEM_reset_mme:{mme_name,?}) -> param(vlr_name) {
475 return vlr_name;
476 };
477 }
478}
479
480/* client/conn_hdlr side function to use procedure port to send RESET from emulated VLR */
481function f_sgsap_reset_vlr(charstring vlr_name) runs on SGsAP_ConnHdlr return charstring {
482 var charstring mme_name;
483 SGsAP_PROC.call(SGsAPEM_reset_vlr:{vlr_name, -}) {
484 [] SGsAP_PROC.getreply(SGsAPEM_reset_vlr:{vlr_name,?}) -> param(mme_name) {
485 return mme_name;
486 };
487 }
488}
Harald Welteaf5bce42018-10-09 09:20:45 +0200489
490private function f_expect_table_init()
491runs on SGsAP_Emulation_CT {
492 var integer i;
493 for (i := 0; i < sizeof(SgsapExpectTable); i := i + 1) {
494 SgsapExpectTable[i].imsi := omit;
495 }
496}
497
498function DummyUnitdataCallback(PDU_SGsAP msg)
499runs on SGsAP_Emulation_CT return template PDU_SGsAP {
500 log("Ignoring SGsAP ", msg);
501 return omit;
502}
503
504
505}