blob: bb125a5223552610af399bf6e2af7fb14809834e [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;
Vadim Yanitskiy741aa572024-06-12 06:16:43 +070034import from SCTP_Templates all;
Harald Welteaf5bce42018-10-09 09:20:45 +020035import from Osmocom_Types all;
36import from IPL4asp_Types all;
Harald Welte9a5dd542018-10-28 10:33:23 +010037import from DNS_Helpers all;
Harald Welte4263c522018-12-06 11:56:27 +010038import from MobileL3_Types all;
Harald Welteaf5bce42018-10-09 09:20:45 +020039
40type component SGsAP_ConnHdlr {
41 port SGsAP_Conn_PT SGsAP;
42 /* procedure based port to register for incoming connections */
43 port SGsAPEM_PROC_PT SGsAP_PROC;
44}
45
46/* port between individual per-connection components and this dispatcher */
47type port SGsAP_Conn_PT message {
Harald Welte4263c522018-12-06 11:56:27 +010048 inout PDU_SGsAP, PDU_ML3_MS_NW, PDU_ML3_NW_MS;
Harald Welteaf5bce42018-10-09 09:20:45 +020049} with { extension "internal" };
50
Harald Welteb8a4ac82019-06-23 11:04:12 +020051/* global test port e.g. for non-imsi/conn specific messages */
52type port SGsAP_PT message {
53 inout PDU_SGsAP;
54} with { extension "internal" };
55
56
Harald Welteaf5bce42018-10-09 09:20:45 +020057/* represents a single SGsAP Association */
58type record AssociationData {
59 SGsAP_ConnHdlr comp_ref,
60 hexstring imsi optional
61};
62
63type component SGsAP_Emulation_CT {
64 /* Port facing to the UDP SUT */
65 port SGsAP_CODEC_PT SGsAP;
66 /* All SGsAP_ConnHdlr SGsAP ports connect here
67 * SGsAP_Emulation_CT.main needs to figure out what messages
68 * to send where with CLIENT.send() to vc_conn */
69 port SGsAP_Conn_PT SGsAP_CLIENT;
70 /* currently tracked connections */
71 var AssociationData SgsapAssociationTable[16];
72 /* pending expected CRCX */
73 var ExpectData SgsapExpectTable[8];
74 /* procedure based port to register for incoming connections */
75 port SGsAPEM_PROC_PT SGsAP_PROC;
Harald Welteb8a4ac82019-06-23 11:04:12 +020076 /* test port for unit data messages */
77 port SGsAP_PT SGsAP_UNIT;
Harald Welteaf5bce42018-10-09 09:20:45 +020078
79 var charstring g_sgsap_id;
80 var integer g_sgsap_conn_id := -1;
81}
82
83type function SGsAPCreateCallback(PDU_SGsAP msg, hexstring imsi, charstring id)
84runs on SGsAP_Emulation_CT return SGsAP_ConnHdlr;
85
86type function SGsAPUnitdataCallback(PDU_SGsAP msg)
87runs on SGsAP_Emulation_CT return template PDU_SGsAP;
88
89type record SGsAPOps {
90 SGsAPCreateCallback create_cb,
91 SGsAPUnitdataCallback unitdata_cb
92}
93
94type record SGsAP_conn_parameters {
95 HostName remote_ip,
96 PortNumber remote_sctp_port,
97 HostName local_ip,
98 PortNumber local_sctp_port
99}
100
101function tr_SGsAP_RecvFrom_R(template PDU_SGsAP msg)
102runs on SGsAP_Emulation_CT return template SGsAP_RecvFrom {
103 var template SGsAP_RecvFrom mrf := {
104 connId := g_sgsap_conn_id,
105 remName := ?,
106 remPort := ?,
107 locName := ?,
108 locPort := ?,
109 msg := msg
110 }
111 return mrf;
112}
113
114private function f_imsi_known(hexstring imsi)
115runs on SGsAP_Emulation_CT return boolean {
116 var integer i;
117 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
118 if (SgsapAssociationTable[i].imsi == imsi) {
119 return true;
120 }
121 }
122 return false;
123}
124
125private function f_comp_known(SGsAP_ConnHdlr client)
126runs on SGsAP_Emulation_CT return boolean {
127 var integer i;
128 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
129 if (SgsapAssociationTable[i].comp_ref == client) {
130 return true;
131 }
132 }
133 return false;
134}
135
136private function f_comp_by_imsi(hexstring imsi)
137runs on SGsAP_Emulation_CT return SGsAP_ConnHdlr {
138 var integer i;
139 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
140 if (SgsapAssociationTable[i].imsi == imsi) {
141 return SgsapAssociationTable[i].comp_ref;
142 }
143 }
144 setverdict(fail, "SGsAP Association Table not found by IMSI", imsi);
145 mtc.stop;
146}
147
148private function f_imsi_by_comp(SGsAP_ConnHdlr client)
149runs on SGsAP_Emulation_CT return hexstring {
150 var integer i;
151 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
152 if (SgsapAssociationTable[i].comp_ref == client) {
153 return SgsapAssociationTable[i].imsi;
154 }
155 }
156 setverdict(fail, "SGsAP Association Table not found by component ", client);
157 mtc.stop;
158}
159
160private function f_imsi_table_add(SGsAP_ConnHdlr comp_ref, hexstring imsi)
161runs on SGsAP_Emulation_CT {
162 var integer i;
163 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
164 if (not isvalue(SgsapAssociationTable[i].imsi)) {
165 SgsapAssociationTable[i].imsi := imsi;
166 SgsapAssociationTable[i].comp_ref := comp_ref;
167 return;
168 }
169 }
170 testcase.stop("SGsAP Association Table full!");
171}
172
173private function f_imsi_table_del(SGsAP_ConnHdlr comp_ref, hexstring imsi)
174runs on SGsAP_Emulation_CT {
175 var integer i;
176 for (i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
177 if (SgsapAssociationTable[i].comp_ref == comp_ref and
178 SgsapAssociationTable[i].imsi == imsi) {
179 SgsapAssociationTable[i].imsi := omit;
180 SgsapAssociationTable[i].comp_ref := null;
181 return;
182 }
183 }
184 setverdict(fail, "SGsAP Association Table: Couldn't find to-be-deleted entry!");
185 mtc.stop;
186}
187
188
189private function f_imsi_table_init()
190runs on SGsAP_Emulation_CT {
191 for (var integer i := 0; i < sizeof(SgsapAssociationTable); i := i+1) {
192 SgsapAssociationTable[i].comp_ref := null;
193 SgsapAssociationTable[i].imsi := omit;
194 }
195}
196
197private function f_SGsAP_get_imsi(PDU_SGsAP pdu) return template (omit) IMSI
198{
199 if (ischosen(pdu.sGsAP_ALERT_ACK)) {
200 return pdu.sGsAP_ALERT_ACK.iMSI;
201 } else if (ischosen(pdu.sGsAP_ALERT_REJECT)) {
202 return pdu.sGsAP_ALERT_REJECT.iMSI;
203 } else if (ischosen(pdu.sGsAP_ALERT_REQUEST)) {
204 return pdu.sGsAP_ALERT_REQUEST.iMSI;
205 } else if (ischosen(pdu.sGsAP_DOWNLINK_UNITDATA)) {
206 return pdu.sGsAP_DOWNLINK_UNITDATA.iMSI;
207 } else if (ischosen(pdu.sGsAP_EPS_DETACH_ACK)) {
208 return pdu.sGsAP_EPS_DETACH_ACK.iMSI;
209 } else if (ischosen(pdu.sGsAP_EPS_DETACH_INDICATION)) {
210 return pdu.sGsAP_EPS_DETACH_INDICATION.iMSI;
211 } else if (ischosen(pdu.sGsAP_IMSI_DETACH_ACK)) {
212 return pdu.sGsAP_IMSI_DETACH_ACK.iMSI;
213 } else if (ischosen(pdu.sGsAP_IMSI_DETACH_INDICATION)) {
214 return pdu.sGsAP_IMSI_DETACH_INDICATION.iMSI;
215 } else if (ischosen(pdu.sGsAP_LOCATION_UPDATE_ACCEPT)) {
216 return pdu.sGsAP_LOCATION_UPDATE_ACCEPT.iMSI;
217 } else if (ischosen(pdu.sGsAP_LOCATION_UPDATE_REJECT)) {
218 return pdu.sGsAP_LOCATION_UPDATE_REJECT.iMSI;
219 } else if (ischosen(pdu.sGsAP_LOCATION_UPDATE_REQUEST)) {
220 return pdu.sGsAP_LOCATION_UPDATE_REQUEST.iMSI;
221 } else if (ischosen(pdu.sGsAP_MM_INFORMATION_REQUEST)) {
222 return pdu.sGsAP_MM_INFORMATION_REQUEST.iMSI;
223 } else if (ischosen(pdu.sGsAP_PAGING_REJECT)) {
224 return pdu.sGsAP_PAGING_REJECT.iMSI;
225 } else if (ischosen(pdu.sGsAP_PAGING_REQUEST)) {
226 return pdu.sGsAP_PAGING_REQUEST.iMSI;
227 } else if (ischosen(pdu.sGsAP_SERVICE_REQUEST)) {
228 return pdu.sGsAP_SERVICE_REQUEST.iMSI;
229 } else if (ischosen(pdu.sGsAP_STATUS)) {
230 return pdu.sGsAP_STATUS.iMSI;
231 } else if (ischosen(pdu.sGsAP_TMSI_REALLOCATION_COMPLETE)) {
232 return pdu.sGsAP_TMSI_REALLOCATION_COMPLETE.iMSI;
233 } else if (ischosen(pdu.sGsAP_UE_ACTIVITY_INDICATION)) {
234 return pdu.sGsAP_UE_ACTIVITY_INDICATION.iMSI;
235 } else if (ischosen(pdu.sGsAP_UE_UNREACHABLE)) {
236 return pdu.sGsAP_UE_UNREACHABLE.iMSI;
237 } else if (ischosen(pdu.sGsAP_UPLINK_UNITDATA)) {
238 return pdu.sGsAP_UPLINK_UNITDATA.iMSI;
239 } else if (ischosen(pdu.sGsAP_RELEASE_REQUEST)) {
240 return pdu.sGsAP_RELEASE_REQUEST.iMSI;
241 } else if (ischosen(pdu.sGsAP_SERVICE_ABORT_REQUEST)) {
242 return pdu.sGsAP_SERVICE_ABORT_REQUEST.iMSI;
243 } else if (ischosen(pdu.sGsAP_MO_CSFB_INDICATION)) {
244 return pdu.sGsAP_MO_CSFB_INDICATION.iMSI;
245 }
246 return omit;
247}
248
Harald Welteaf5bce42018-10-09 09:20:45 +0200249private function f_sgsap_xceive(template (value) PDU_SGsAP tx,
250 template PDU_SGsAP rx_t := ?)
251runs on SGsAP_Emulation_CT return PDU_SGsAP {
252 timer T := 10.0;
253 var SGsAP_RecvFrom mrf;
254
255 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, tx));
256 alt {
257 [] SGsAP.receive(tr_SGsAP_RecvFrom_R(rx_t)) -> value mrf { }
258 [] SGsAP.receive(tr_SctpAssocChange) { repeat; }
259 [] SGsAP.receive(tr_SctpPeerAddrChange) { repeat; }
260 [] T.timeout {
261 setverdict(fail, "Timeout waiting for ", rx_t);
262 mtc.stop;
263 }
264 }
265 return mrf.msg;
266}
267
268function main(SGsAPOps ops, SGsAP_conn_parameters p, charstring id) runs on SGsAP_Emulation_CT {
269 var Result res;
270 g_sgsap_id := id;
271 f_imsi_table_init();
272 f_expect_table_init();
273
274 map(self:SGsAP, system:SGsAP_CODEC_PT);
275 if (p.remote_sctp_port == -1) {
Vadim Yanitskiy741aa572024-06-12 06:16:43 +0700276 res := SGsAP_CodecPort_CtrlFunct.f_IPL4_listen(SGsAP, p.local_ip, p.local_sctp_port,
277 { sctp := valueof(ts_SctpTuple) });
Harald Welteaf5bce42018-10-09 09:20:45 +0200278 } else {
279 res := SGsAP_CodecPort_CtrlFunct.f_IPL4_connect(SGsAP, p.remote_ip, p.remote_sctp_port,
Vadim Yanitskiy741aa572024-06-12 06:16:43 +0700280 p.local_ip, p.local_sctp_port, -1,
281 { sctp := valueof(ts_SctpTuple) });
Harald Welteaf5bce42018-10-09 09:20:45 +0200282 }
283 if (not ispresent(res.connId)) {
284 setverdict(fail, "Could not connect SGsAP socket, check your configuration");
285 mtc.stop;
286 }
287 g_sgsap_conn_id := res.connId;
288
289 while (true) {
290 var SGsAP_ConnHdlr vc_conn;
Harald Welte4263c522018-12-06 11:56:27 +0100291 var PDU_ML3_MS_NW l3_mo;
292 var PDU_ML3_NW_MS l3_mt;
Harald Welteaf5bce42018-10-09 09:20:45 +0200293 var template IMSI imsi_t;
294 var hexstring imsi;
295 var SGsAP_RecvFrom mrf;
296 var PDU_SGsAP msg;
Harald Welte9a5dd542018-10-28 10:33:23 +0100297 var charstring vlr_name, mme_name;
Harald Welteaf5bce42018-10-09 09:20:45 +0200298
299 alt {
300 /* SGsAP from client */
301 [] SGsAP_CLIENT.receive(PDU_SGsAP:?) -> value msg sender vc_conn {
302 /* Pass message through */
303 /* TODO: check which ConnectionID client has allocated + store in table? */
304 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, msg));
305 }
Harald Welte4263c522018-12-06 11:56:27 +0100306 /* DTAP/MobileL3 from client (emulated MS): wrap in SGsAP-UL-UD and send */
307 [] SGsAP_CLIENT.receive(PDU_ML3_MS_NW:?) -> value l3_mo sender vc_conn {
308 var octetstring l3_enc := enc_PDU_ML3_MS_NW(l3_mo);
309 imsi := f_imsi_by_comp(vc_conn);
310 msg := valueof(ts_SGsAP_UL_UD(imsi, l3_enc));
311 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, msg));
312 }
313 [] SGsAP_CLIENT.receive(PDU_ML3_NW_MS:?) -> value l3_mt sender vc_conn {
314 var octetstring l3_enc := enc_PDU_ML3_NW_MS(l3_mt);
315 imsi := f_imsi_by_comp(vc_conn);
316 msg := valueof(ts_SGsAP_DL_UD(imsi, l3_enc));
317 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, msg));
318 }
319
320 /* DTAP/MobileL3 from MSC/VLR to MS wrapped in SGsAP-DL-UD: Extract, decode, forward */
321 [] SGsAP.receive(tr_SGsAP_RecvFrom_R(tr_SGsAP_DL_UD(?,?))) -> value mrf {
322 var octetstring l3_enc := mrf.msg.sGsAP_DOWNLINK_UNITDATA.nAS_MessageContainer.nAS_MessageContainer;
323 imsi := mrf.msg.sGsAP_DOWNLINK_UNITDATA.iMSI.iMSI.digits;
324 vc_conn := f_comp_by_imsi(imsi);
325 l3_mt := dec_PDU_ML3_NW_MS(l3_enc);
326 SGsAP_CLIENT.send(l3_mt) to vc_conn;
327 }
328 [] SGsAP.receive(tr_SGsAP_RecvFrom_R(tr_SGsAP_UL_UD(?,?))) -> value mrf {
329 var octetstring l3_enc := mrf.msg.sGsAP_UPLINK_UNITDATA.nAS_MessageContainer.nAS_MessageContainer;
330 imsi := mrf.msg.sGsAP_UPLINK_UNITDATA.iMSI.iMSI.digits;
331 l3_mo := dec_PDU_ML3_MS_NW(l3_enc);
332 vc_conn := f_comp_by_imsi(imsi);
333 SGsAP_CLIENT.send(l3_mo) to vc_conn;
334 }
335
336
337 /* any other SGsAP from MSC/VLR */
Harald Welteaf5bce42018-10-09 09:20:45 +0200338 [] SGsAP.receive(tr_SGsAP_RecvFrom_R(?)) -> value mrf {
339 imsi_t := f_SGsAP_get_imsi(mrf.msg);
340 if (isvalue(imsi_t)) {
341 imsi := valueof(imsi_t.iMSI.digits);
342 if (f_imsi_known(imsi)) {
343 vc_conn := f_comp_by_imsi(imsi);
344 SGsAP_CLIENT.send(mrf.msg) to vc_conn;
345 } else {
346 vc_conn := ops.create_cb.apply(mrf.msg, imsi, id);
347 f_imsi_table_add(vc_conn, imsi);
348 SGsAP_CLIENT.send(mrf.msg) to vc_conn;
349 }
350 } else {
351 /* message contained no IMSI; is not IMSI-oriented */
352 var template PDU_SGsAP resp := ops.unitdata_cb.apply(mrf.msg);
353 if (isvalue(resp)) {
354 SGsAP.send(t_SGsAP_Send(g_sgsap_conn_id, valueof(resp)));
355 }
356 }
357 }
358 [] SGsAP.receive(tr_SctpAssocChange) { }
359 [] SGsAP.receive(tr_SctpPeerAddrChange) { }
360 [] SGsAP_PROC.getcall(SGsAPEM_register:{?,?}) -> param(imsi, vc_conn) {
361 f_create_expect(imsi, vc_conn);
362 SGsAP_PROC.reply(SGsAPEM_register:{imsi, vc_conn}) to vc_conn;
363 }
Harald Welte9a5dd542018-10-28 10:33:23 +0100364 [] SGsAP_PROC.getcall(SGsAPEM_reset_mme:{?,-}) -> param(mme_name) {
365 var octetstring mme_enc, vlr_enc;
366 mme_enc := f_enc_dns_hostname(mme_name);
367 msg := f_sgsap_xceive(ts_SGsAP_RESET_IND_MME(mme_enc));
368 vlr_enc := msg.sGsAP_RESET_ACK.vLR_Name.name;
369 vlr_name := f_dec_dns_hostname(vlr_enc);
370 SGsAP_PROC.reply(SGsAPEM_reset_mme:{mme_name, vlr_name});
371 }
372 [] SGsAP_PROC.getcall(SGsAPEM_reset_vlr:{?,-}) -> param(vlr_name) {
373 var octetstring mme_enc, vlr_enc;
374 vlr_enc := f_enc_dns_hostname(vlr_name);
375 msg := f_sgsap_xceive(ts_SGsAP_RESET_IND_VLR(vlr_enc));
376 mme_enc := msg.sGsAP_RESET_ACK.mME_Name.name;
377 mme_name := f_dec_dns_hostname(mme_enc);
378 SGsAP_PROC.reply(SGsAPEM_reset_vlr:{vlr_name, mme_name});
379 }
380
381
Harald Welteaf5bce42018-10-09 09:20:45 +0200382 }
383
384 }
385}
386
387/* "Expect" Handling */
388
389type record ExpectData {
390 hexstring imsi optional,
391 SGsAP_ConnHdlr vc_conn
392}
393
394signature SGsAPEM_register(in hexstring imsi, in SGsAP_ConnHdlr hdlr);
395
Harald Welte9a5dd542018-10-28 10:33:23 +0100396signature SGsAPEM_reset_vlr(in charstring vlr_name, out charstring mme_name);
397signature SGsAPEM_reset_mme(in charstring mme_name, out charstring vlr_name);
398
Harald Welteaf5bce42018-10-09 09:20:45 +0200399type port SGsAPEM_PROC_PT procedure {
Harald Welte9a5dd542018-10-28 10:33:23 +0100400 inout SGsAPEM_register, SGsAPEM_reset_vlr, SGsAPEM_reset_mme;
Harald Welteaf5bce42018-10-09 09:20:45 +0200401} with { extension "internal" };
402
Oliver Smith23e192e2023-02-13 15:00:46 +0100403/* Function that can be used as create_cb and will use the expect table */
Harald Welteaf5bce42018-10-09 09:20:45 +0200404function ExpectedCreateCallback(PDU_SGsAP msg, hexstring imsi, charstring id)
405runs on SGsAP_Emulation_CT return SGsAP_ConnHdlr {
406 var SGsAP_ConnHdlr ret := null;
407 var integer i;
408
409 for (i := 0; i < sizeof(SgsapExpectTable); i := i+1) {
410 if (not ispresent(SgsapExpectTable[i].imsi)) {
411 continue;
412 }
413 if (imsi == SgsapExpectTable[i].imsi) {
414 ret := SgsapExpectTable[i].vc_conn;
415 /* Release this entry */
416 SgsapExpectTable[i].imsi := omit;
417 SgsapExpectTable[i].vc_conn := null;
418 log("Found Expect[", i, "] for ", msg, " handled at ", ret);
419 return ret;
420 }
421 }
422 setverdict(fail, "Couldn't find Expect for ", msg);
423 mtc.stop;
424}
425
426private function f_create_expect(hexstring imsi, SGsAP_ConnHdlr hdlr)
427runs on SGsAP_Emulation_CT {
428 var integer i;
429
430 /* Check an entry like this is not already presnt */
431 for (i := 0; i < sizeof(SgsapExpectTable); i := i+1) {
432 if (imsi == SgsapExpectTable[i].imsi) {
433 setverdict(fail, "IMSI already present", imsi);
434 mtc.stop;
435 }
436 }
437 for (i := 0; i < sizeof(SgsapExpectTable); i := i+1) {
438 if (not ispresent(SgsapExpectTable[i].imsi)) {
439 SgsapExpectTable[i].imsi := imsi;
440 SgsapExpectTable[i].vc_conn := hdlr;
441 log("Created Expect[", i, "] for ", imsi, " to be handled at ", hdlr);
442 return;
443 }
444 }
445 testcase.stop("No space left in SgsapExpectTable")
446}
447
448/* client/conn_hdlr side function to use procedure port to create expect in emulation */
449function f_create_sgsap_expect(hexstring imsi) runs on SGsAP_ConnHdlr {
450 SGsAP_PROC.call(SGsAPEM_register:{imsi, self}) {
451 [] SGsAP_PROC.getreply(SGsAPEM_register:{?,?}) {};
452 }
453}
454
Harald Welte9a5dd542018-10-28 10:33:23 +0100455/* client/conn_hdlr side function to use procedure port to send RESET from emulated MME */
456function f_sgsap_reset_mme(charstring mme_name) runs on SGsAP_ConnHdlr return charstring {
457 var charstring vlr_name;
458 SGsAP_PROC.call(SGsAPEM_reset_mme:{mme_name, -}) {
459 [] SGsAP_PROC.getreply(SGsAPEM_reset_mme:{mme_name,?}) -> param(vlr_name) {
460 return vlr_name;
461 };
462 }
463}
464
465/* client/conn_hdlr side function to use procedure port to send RESET from emulated VLR */
466function f_sgsap_reset_vlr(charstring vlr_name) runs on SGsAP_ConnHdlr return charstring {
467 var charstring mme_name;
468 SGsAP_PROC.call(SGsAPEM_reset_vlr:{vlr_name, -}) {
469 [] SGsAP_PROC.getreply(SGsAPEM_reset_vlr:{vlr_name,?}) -> param(mme_name) {
470 return mme_name;
471 };
472 }
473}
Harald Welteaf5bce42018-10-09 09:20:45 +0200474
475private function f_expect_table_init()
476runs on SGsAP_Emulation_CT {
477 var integer i;
478 for (i := 0; i < sizeof(SgsapExpectTable); i := i + 1) {
479 SgsapExpectTable[i].imsi := omit;
480 }
481}
482
483function DummyUnitdataCallback(PDU_SGsAP msg)
484runs on SGsAP_Emulation_CT return template PDU_SGsAP {
485 log("Ignoring SGsAP ", msg);
486 return omit;
487}
488
489
490}