blob: 534fdef8a49a89e6abe521bc5a86958717735731 [file] [log] [blame]
Harald Weltec69cf4e2018-02-17 20:57:02 +01001module GTP_Emulation {
2
3import from IPL4asp_Types all;
4import from General_Types all;
5import from Osmocom_Types all;
6import from GTPC_Types all;
7import from GTPU_Types all;
8import from GTP_CodecPort all;
9import from GTP_CodecPort_CtrlFunct all;
10
11/***********************************************************************
12 * Main Emulation Component
13 ***********************************************************************/
14
15const integer GTP0_PORT := 3386;
16const integer GTP1C_PORT := 2123;
17const integer GTP1U_PORT := 2152;
18
19type record GtpEmulationCfg {
20 HostName gtpc_bind_ip,
21 PortNumber gtpc_bind_port,
22 HostName gtpu_bind_ip,
23 PortNumber gtpu_bind_port,
24 boolean sgsn_role
25};
26
27type component GTP_Emulation_CT {
28 /* Communication with underlying GTP CodecPort */
29 port GTPC_PT GTPC;
30 port GTPU_PT GTPU;
31
32 /* Communication with Clients */
33 port GTPEM_PT CLIENT;
34 port GTPEM_PROC_PT CLIENT_PROC;
35
36 /* Configuration by the user */
37 var GtpEmulationCfg g_gtp_cfg;
38
39 /* State */
40 var integer g_gtpc_id, g_gtpu_id;
41 var OCT1 g_restart_ctr;
42 var uint16_t g_c_seq_nr, g_u_seq_nr;
43 var TidTableRec TidTable[16];
44 var ImsiTableRec ImsiTable[16];
45};
46
47type record TidTableRec {
48 OCT4 teid,
49 GTP_ConnHdlr vc_conn
50};
51
52type record ImsiTableRec {
53 hexstring imsi,
54 GTP_ConnHdlr vc_conn
55};
56
57private function f_comp_by_teid(OCT4 teid) runs on GTP_Emulation_CT return GTP_ConnHdlr {
58 var integer i;
59 for (i := 0; i < sizeof(TidTable); i := i+1) {
60 if (isbound(TidTable[i].teid) and TidTable[i].teid == teid) {
61 return TidTable[i].vc_conn;
62 }
63 }
64 setverdict(fail, "No Component for TEID ", teid);
65 self.stop;
66}
67
68private function f_comp_by_imsi(hexstring imsi) runs on GTP_Emulation_CT return GTP_ConnHdlr {
69 var integer i;
70 for (i := 0; i < sizeof(ImsiTable); i := i+1) {
71 if (isbound(ImsiTable[i].imsi) and ImsiTable[i].imsi == imsi) {
72 return ImsiTable[i].vc_conn;
73 }
74 }
75 setverdict(fail, "No Component for IMSI ", imsi);
76 self.stop;
77}
78
79private function f_tid_tbl_add(OCT4 teid, GTP_ConnHdlr vc_conn) runs on GTP_Emulation_CT {
80 var integer i;
81 for (i := 0; i < sizeof(TidTable); i := i+1) {
82 if (not isbound(TidTable[i].teid)) {
83 TidTable[i].teid := teid;
84 TidTable[i].vc_conn := vc_conn;
85 return;
86 }
87 }
88 setverdict(fail, "No Space in TidTable for ", teid);
89 self.stop;
90}
91
92private function f_imsi_tbl_add(hexstring imsi, GTP_ConnHdlr vc_conn) runs on GTP_Emulation_CT {
93 var integer i;
94 for (i := 0; i < sizeof(ImsiTable); i := i+1) {
95 if (not isbound(ImsiTable[i].imsi)) {
96 ImsiTable[i].imsi := imsi;
97 ImsiTable[i].vc_conn := vc_conn;
98 return;
99 }
100 }
101 setverdict(fail, "No Space in IMSI Table for ", imsi);
102 self.stop;
103}
104
105function f_gtpc_extract_imsi(PDU_GTPC gtp) return template (omit) hexstring {
106 if (ischosen(gtp.gtpc_pdu.createPDPContextRequest)) {
107 return gtp.gtpc_pdu.createPDPContextRequest.imsi.digits;
108 } else if (ischosen(gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestSGSN)) {
109 return gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestSGSN.imsi.digits;
110 } else if (ischosen(gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestGGSN)) {
111 return gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestGGSN.imsi.digits;
112 } else if (ischosen(gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestCGW)) {
113 return gtp.gtpc_pdu.updatePDPContextRequest.updatePDPContextRequestCGW.imsi.digits;
114 } else if (ischosen(gtp.gtpc_pdu.pdu_NotificationRequest)) {
115 return gtp.gtpc_pdu.pdu_NotificationRequest.imsi.digits;
116 } else if (ischosen(gtp.gtpc_pdu.sendRouteingInformationForGPRSRequest)) {
117 return gtp.gtpc_pdu.sendRouteingInformationForGPRSRequest.imsi.digits;
118 } else if (ischosen(gtp.gtpc_pdu.sendRouteingInformationForGPRSResponse)) {
119 return gtp.gtpc_pdu.sendRouteingInformationForGPRSResponse.imsi.digits;
120 } else if (ischosen(gtp.gtpc_pdu.failureReportRequest)) {
121 return gtp.gtpc_pdu.failureReportRequest.imsi.digits;
122 } else if (ischosen(gtp.gtpc_pdu.noteMS_GPRSPresentRequest)) {
123 return gtp.gtpc_pdu.noteMS_GPRSPresentRequest.imsi.digits;
124 } else if (ischosen(gtp.gtpc_pdu.identificationResponse) ){
125 return gtp.gtpc_pdu.identificationResponse.imsi.digits;
126 } else if (ischosen(gtp.gtpc_pdu.sgsn_ContextRequest)) {
127 return gtp.gtpc_pdu.sgsn_ContextRequest.imsi.digits;
128 } else if (ischosen(gtp.gtpc_pdu.sgsn_ContextResponse)) {
129 return gtp.gtpc_pdu.sgsn_ContextResponse.imsi.digits;
130 } else if (ischosen(gtp.gtpc_pdu.forwardRelocationRequest)) {
131 return gtp.gtpc_pdu.forwardRelocationRequest.imsi.digits;
132 } else if (ischosen(gtp.gtpc_pdu.relocationCancelRequest)) {
133 return gtp.gtpc_pdu.relocationCancelRequest.imsi.digits;
134 } else if (ischosen(gtp.gtpc_pdu.uERegistrationQueryRequest)) {
135 return gtp.gtpc_pdu.uERegistrationQueryRequest.imsi.digits;
136 } else if (ischosen(gtp.gtpc_pdu.uERegistrationQueryResponse)) {
137 return gtp.gtpc_pdu.uERegistrationQueryResponse.imsi.digits;
138 } else if (ischosen(gtp.gtpc_pdu.mBMSNotificationRequest)) {
139 return gtp.gtpc_pdu.mBMSNotificationRequest.imsi.digits;
140 } else if (ischosen(gtp.gtpc_pdu.createMBMSContextRequest)) {
141 return gtp.gtpc_pdu.createMBMSContextRequest.imsi.digits;
142 } else if (ischosen(gtp.gtpc_pdu.deleteMBMSContextRequest)) {
143 return gtp.gtpc_pdu.deleteMBMSContextRequest.imsi.digits;
144 } else if (ischosen(gtp.gtpc_pdu.mS_InfoChangeNotificationRequest)) {
145 return gtp.gtpc_pdu.mS_InfoChangeNotificationRequest.imsi.digits;
146 } else if (ischosen(gtp.gtpc_pdu.mS_InfoChangeNotificationResponse)) {
147 return gtp.gtpc_pdu.mS_InfoChangeNotificationResponse.imsi.digits;
148 } else {
149 return omit;
150 }
151}
152
153private function f_init(GtpEmulationCfg cfg) runs on GTP_Emulation_CT {
154 var Result res;
155
156 map(self:GTPC, system:GTPC);
157 res := GTP_CodecPort_CtrlFunct.f_IPL4_listen(GTPC, cfg.gtpc_bind_ip,
158 cfg.gtpc_bind_port, {udp:={}});
159 g_gtpc_id := res.connId;
160
161 map(self:GTPU, system:GTPU);
162 res := GTP_CodecPort_CtrlFunct.f_GTPU_listen(GTPU, cfg.gtpu_bind_ip,
163 cfg.gtpu_bind_port, {udp:={}});
164 g_gtpu_id := res.connId;
165
166 g_restart_ctr := f_rnd_octstring(1);
167 g_c_seq_nr := f_rnd_int(65535);
168 g_u_seq_nr := f_rnd_int(65535);
169 g_gtp_cfg := cfg;
170}
171
172function main(GtpEmulationCfg cfg) runs on GTP_Emulation_CT {
173 var Gtp1cUnitdata g1c_ud;
174 var Gtp1uUnitdata g1u_ud;
175 var GTP_ConnHdlr vc_conn;
176 var hexstring imsi;
177 var OCT4 teid;
178
179 f_init(cfg);
180
181 while (true) {
182 alt {
183 /* route inbound GTP-C based on IMSI or TEID */
184 [] GTPC.receive(Gtp1cUnitdata:?) -> value g1c_ud {
185 var template hexstring imsi_t := f_gtpc_extract_imsi(g1c_ud.gtpc);
186 if (isvalue(imsi_t)) {
187 vc_conn := f_comp_by_imsi(valueof(imsi_t));
188 } else {
189 vc_conn := f_comp_by_teid(g1c_ud.gtpc.teid);
190 }
191 CLIENT.send(g1c_ud) to vc_conn;
192 }
193 [] GTPU.receive(Gtp1uUnitdata:?) -> value g1u_ud {
194 vc_conn := f_comp_by_teid(g1u_ud.gtpu.teid);
195 CLIENT.send(g1u_ud) to vc_conn;
196 }
197
198 /* transparently forward any GTP-C / GTP-U from clients to peer[s] */
199 [] CLIENT.receive(Gtp1cUnitdata:?) -> value g1c_ud sender vc_conn {
200 GTPC.send(g1c_ud);
201 }
202 [] CLIENT.receive(Gtp1uUnitdata:?) -> value g1u_ud sender vc_conn {
203 GTPU.send(g1u_ud);
204 }
205
206
207 [] CLIENT_PROC.getcall(GTPEM_register_imsi:{?}) -> param(imsi) sender vc_conn {
208 f_imsi_tbl_add(imsi, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200209 CLIENT_PROC.reply(GTPEM_register_imsi:{imsi}) to vc_conn;
Harald Weltec69cf4e2018-02-17 20:57:02 +0100210 }
211
212 [] CLIENT_PROC.getcall(GTPEM_register_teid:{?}) -> param(teid) sender vc_conn {
213 f_tid_tbl_add(teid, vc_conn);
Harald Weltee32ad992018-05-31 22:17:46 +0200214 CLIENT_PROC.reply(GTPEM_register_teid:{teid}) to vc_conn;
Harald Weltec69cf4e2018-02-17 20:57:02 +0100215 }
216
217 }
218 }
219}
220
221
222/***********************************************************************
223 * Interaction between Main and Client Components
224 ***********************************************************************/
225type port GTPEM_PT message {
226 inout Gtp1cUnitdata, Gtp1uUnitdata;
227} with { extension "internal" };
228
229signature GTPEM_register_imsi(hexstring imsi);
230signature GTPEM_register_teid(OCT4 teid);
231
232type port GTPEM_PROC_PT procedure {
233 inout GTPEM_register_imsi, GTPEM_register_teid;
234} with { extension "internal" };
235
236/***********************************************************************
237 * Client Compoennt
238 ***********************************************************************/
239
240type component GTP_ConnHdlr {
241 port GTPEM_PT GTP;
242 port GTPEM_PROC_PT GTP_PROC;
243};
244
245function f_gtp_register_imsi(hexstring imsi) runs on GTP_ConnHdlr {
246 GTP_PROC.call(GTPEM_register_imsi:{imsi}) {
247 [] GTP_PROC.getreply(GTPEM_register_imsi:{imsi});
248 }
249}
250
251function f_gtp_register_teid(OCT4 teid) runs on GTP_ConnHdlr {
252 GTP_PROC.call(GTPEM_register_teid:{teid}) {
253 [] GTP_PROC.getreply(GTPEM_register_teid:{teid});
254 }
255}
256
257}