blob: 755cbba2295a26b4556fd1b72fe3480310b97f19 [file] [log] [blame]
Harald Welted86cdc62017-11-22 00:45:07 +01001module IPA_Emulation {
2
3import from IPA_Types all;
4import from IPA_CodecPort all;
5import from IPA_CodecPort_CtrlFunct all;
6import from IPL4asp_Types all;
Harald Welte12188832017-11-29 11:47:13 +01007import from IPL4asp_PortType all;
Harald Welted86cdc62017-11-22 00:45:07 +01008import from MTP3asp_Types all;
9import from MTP3asp_PortType all;
Harald Welte0d846a72017-12-07 17:58:28 +010010import from RSL_Types all;
Harald Welted86cdc62017-11-22 00:45:07 +010011
Harald Weltec82eef42017-11-24 20:40:12 +010012import from MGCP_Types all;
13
Harald Welted86cdc62017-11-22 00:45:07 +010014modulepar {
Harald Welte92632e12017-11-25 02:31:20 +010015 /* Use Osmocom extended IPA mux header */
16 boolean mp_ipa_mgcp_uses_osmo_ext := true;
Harald Welted86cdc62017-11-22 00:45:07 +010017}
Harald Welted86cdc62017-11-22 00:45:07 +010018
Harald Welteb3414b22017-11-23 18:22:10 +010019type enumerated IpaMode {
20 IPA_MODE_CLIENT,
21 IPA_MODE_SERVER
22}
23
Harald Weltec76f29f2017-11-22 12:46:46 +010024type record ASP_IPA_Unitdata {
25 IpaStreamId streamId,
Harald Weltec82eef42017-11-24 20:40:12 +010026 IpaExtStreamId streamIdExt optional,
Harald Weltec76f29f2017-11-22 12:46:46 +010027 octetstring payload
28}
29
Harald Welte0d846a72017-12-07 17:58:28 +010030type enumerated ASP_IPA_EventUpDown {
31 ASP_IPA_EVENT_DOWN,
32 ASP_IPA_EVENT_UP,
33 ASP_IPA_EVENT_ID_ACK
34}
35
36type union ASP_IPA_Event {
37 ASP_IPA_EventUpDown up_down
38}
39
40template ASP_IPA_Event t_ASP_IPA_EVT_UD(ASP_IPA_EventUpDown ud) := {
41 up_down := ud
42}
43
Harald Welte1dd8f372017-11-25 02:25:27 +010044template ASP_IPA_Unitdata t_ASP_IPA_UD(IpaStreamId sid, octetstring pl,
45 template IpaExtStreamId esid := omit) := {
46 streamId := sid,
47 streamIdExt := esid,
48 payload := pl
49}
50
Harald Welte0d846a72017-12-07 17:58:28 +010051type record ASP_RSL_Unitdata {
52 IpaStreamId streamId,
53 RSL_Message rsl
54};
55
Harald Welte7ae019e2017-12-09 00:54:15 +010056template ASP_RSL_Unitdata ts_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
Harald Welte0d846a72017-12-07 17:58:28 +010057 streamId := sid,
58 rsl := valueof(rsl)
59}
60
Harald Welte7ae019e2017-12-09 00:54:15 +010061template ASP_RSL_Unitdata tr_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
62 streamId := sid,
63 rsl := rsl
64}
65
66
Harald Welte0d846a72017-12-07 17:58:28 +010067template IpaStreamId t_IpaSidRSL := ( IPAC_PROTO_RSL_TRX0, IPAC_PROTO_RSL_TRX1,
68 IPAC_PROTO_RSL_TRX2, IPAC_PROTO_RSL_TRX3 );
69
Harald Weltec76f29f2017-11-22 12:46:46 +010070type port IPA_SP_PT message {
Harald Welte0d846a72017-12-07 17:58:28 +010071 inout ASP_IPA_Unitdata, ASP_IPA_Event;
Harald Weltec76f29f2017-11-22 12:46:46 +010072} with { extension "internal" }
73
Harald Weltec82eef42017-11-24 20:40:12 +010074type port IPA_MGCP_PT message {
75 inout MgcpCommand, MgcpResponse;
76} with { extension "internal" }
77
Harald Welte0d846a72017-12-07 17:58:28 +010078type port IPA_RSL_PT message {
79 inout ASP_RSL_Unitdata, ASP_IPA_Event;
80} with { extension "internal" }
81
Harald Welted86cdc62017-11-22 00:45:07 +010082type component IPA_Emulation_CT {
83 /* down-facing port to IPA codec port */
84 port IPA_CODEC_PT IPA_PORT;
85 /* up-facing port to SCCP */
86 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltec82eef42017-11-24 20:40:12 +010087 /* up-facing port for MGCP */
88 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Welte0d846a72017-12-07 17:58:28 +010089 /* up-facing port for RSL */
90 port IPA_RSL_PT IPA_RSL_PORT;
Harald Weltec76f29f2017-11-22 12:46:46 +010091 /* up-facing port for other streams */
92 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +010093
94 var boolean g_initialized := false;
95 var ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +010096 /* Are we a BSC/MGW (truel) or MSC (false) */
97 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +010098
99 var IpaMode g_mode;
Harald Weltee09921f2017-12-07 17:49:00 +0100100 var IPA_CCM_Parameters g_ccm_pars := c_IPA_default_ccm_pars;
Harald Welted86cdc62017-11-22 00:45:07 +0100101}
102
Harald Weltee21096d2017-12-04 20:45:12 +0100103type record IPA_CCM_Parameters {
104 charstring ser_nr optional,
105 charstring name optional,
106 charstring location1 optional,
107 charstring location2 optional,
108 charstring equip_version optional,
109 charstring sw_version optional,
110 charstring ip_addr optional,
111 charstring mac_addr optional,
112 charstring unit_id optional,
113 charstring osmo_rand optional
114}
115
Harald Weltee09921f2017-12-07 17:49:00 +0100116const IPA_CCM_Parameters c_IPA_default_ccm_pars := {
117 ser_nr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100118 name := "mahlzeit",
Harald Weltee09921f2017-12-07 17:49:00 +0100119 location1 := "",
120 location2 := "",
121 equip_version := "",
122 sw_version := "",
123 ip_addr := "",
124 mac_addr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100125 unit_id := "0/1/2",
Harald Weltee09921f2017-12-07 17:49:00 +0100126 osmo_rand := ""
Harald Weltee21096d2017-12-04 20:45:12 +0100127};
128
Harald Welted86cdc62017-11-22 00:45:07 +0100129function f_connect(charstring remote_host, PortNumber remote_port,
Harald Weltee21096d2017-12-04 20:45:12 +0100130 charstring local_host, PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100131 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100132 var Result res;
133 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
134 local_host, local_port, 0, { tcp:={} });
135 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100136 g_ccm_pars := ccm_pars;
Harald Welte12188832017-11-29 11:47:13 +0100137 /* Set function for dissecting the binary */
138 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
139 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
140
Harald Weltec82eef42017-11-24 20:40:12 +0100141 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +0100142}
143
Harald Weltee21096d2017-12-04 20:45:12 +0100144function f_bind(charstring local_host, PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100145 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100146 var Result res;
147 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
148 local_host, local_port, { tcp:={} });
149 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100150 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100151 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +0100152}
153
Harald Welted86cdc62017-11-22 00:45:07 +0100154template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
155 sio := { '10'B, '00'B, '0011'B },
156 opc := opc,
157 dpc := 0,
158 sls := 0,
159 data := data
160}
161
162
163private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
164 len := 0, /* overwritten by codec */
165 tag := tag,
166 data := payload
167}
168
Harald Welte0d846a72017-12-07 17:58:28 +0100169private function f_send_IPA_EVT(template ASP_IPA_Event evt) runs on IPA_Emulation_CT {
170 IPA_RSL_PORT.send(evt);
171 /* FIXME: to other ports */
172}
173
Harald Welted86cdc62017-11-22 00:45:07 +0100174/* build IPA CCM ID RESP response from IPA CCM GET */
Harald Weltee21096d2017-12-04 20:45:12 +0100175private function f_ccm_make_id_resp(PDU_IPA_CCM get) runs on IPA_Emulation_CT return PDU_IPA_CCM {
Harald Welted86cdc62017-11-22 00:45:07 +0100176 var integer i;
177 var PDU_IPA_CCM resp := {
178 msg_type := IPAC_MSGT_ID_RESP,
179 u := {
180 resp := {}
181 }
182 }
183
184 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
185 var IpaCcmIdTag tag := get.u.get[i].tag;
186 var charstring foo;
187 select (tag) {
Harald Weltee21096d2017-12-04 20:45:12 +0100188 case (IPAC_IDTAG_SERNR) {
189 foo := g_ccm_pars.ser_nr;
Harald Welted86cdc62017-11-22 00:45:07 +0100190 }
191 case (IPAC_IDTAG_UNITNAME) {
Harald Weltee21096d2017-12-04 20:45:12 +0100192 foo := g_ccm_pars.name;
193 }
194 case (IPAC_IDTAG_LOCATION1) {
195 foo := g_ccm_pars.location1;
196 }
197 case (IPAC_IDTAG_LOCATION2) {
198 foo := g_ccm_pars.location2;
199 }
200 case (IPAC_IDTAG_EQUIPVERS) {
201 foo := g_ccm_pars.equip_version;
202 }
203 case (IPAC_IDTAG_SWVERSION) {
204 foo := g_ccm_pars.sw_version;
205 }
206 case (IPAC_IDTAG_IPADDR) {
207 foo := g_ccm_pars.ip_addr;
208 }
209 case (IPAC_IDTAG_MACADDR) {
210 foo := g_ccm_pars.mac_addr;
211 }
212 case (IPAC_IDTAG_UNIT) {
213 foo := g_ccm_pars.unit_id;
214 }
215 case (IPAC_IDTAG_OSMO_RAND) {
216 foo := g_ccm_pars.osmo_rand;
Harald Welted86cdc62017-11-22 00:45:07 +0100217 }
218 case else {
Harald Weltee21096d2017-12-04 20:45:12 +0100219 foo := "unknown";
Harald Welted86cdc62017-11-22 00:45:07 +0100220 }
221 }
222 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
223 }
224
225 return resp;
226}
227
228/* transmit IPA CCM message */
229private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100230 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_CCM, enc_PDU_IPA_CCM(ccm)));
Harald Welted86cdc62017-11-22 00:45:07 +0100231 log("CCM Tx:", ccm);
232 IPA_PORT.send(ipa_tx);
233}
234
235template PDU_IPA_CCM ts_IPA_PONG := {
236 msg_type := IPAC_MSGT_PONG,
237 u := omit
238}
239
240template PDU_IPA_CCM ts_IPA_ACK := {
241 msg_type := IPAC_MSGT_ID_ACK,
242 u := omit
243}
244
Harald Welteb3414b22017-11-23 18:22:10 +0100245template PDU_IPA_CCM ts_IPA_ID_GET := {
246 msg_type := IPAC_MSGT_ID_GET,
247 u := {
248 get := {
249 { 1, IPAC_IDTAG_UNITNAME }
250 }
251 }
252}
253
Harald Welted86cdc62017-11-22 00:45:07 +0100254/* receive IPA CCM message */
255private function f_ccm_rx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
256 select (ccm.msg_type) {
257 case (IPAC_MSGT_PING) {
258 f_ccm_tx(valueof(ts_IPA_PONG));
259 }
260 case (IPAC_MSGT_ID_ACK) {
261 f_ccm_tx(valueof(ts_IPA_ACK));
262 }
263 case (IPAC_MSGT_ID_GET) {
264 f_ccm_tx(f_ccm_make_id_resp(ccm));
265 }
266 case else {
267 log("Unknown/unsupported IPA CCM message type", ccm);
268 }
269 }
270}
271
Harald Weltec76f29f2017-11-22 12:46:46 +0100272private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
273 var ASP_IPA_Unitdata ret := {
274 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100275 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100276 payload := ipa_rx.msg
277 }
278 return ret;
279}
280
281private function f_from_asp(ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100282 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
283 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100284 return ret;
285}
Harald Welted86cdc62017-11-22 00:45:07 +0100286
Harald Welte0d846a72017-12-07 17:58:28 +0100287private function f_from_rsl(ConnectionId connId, ASP_RSL_Unitdata rsl_tx) return IPA_Send {
288 var octetstring payload := enc_RSL_Message(rsl_tx.rsl);
289 var IPA_Send ret := valueof(t_IPA_Send(connId, rsl_tx.streamId, payload));
290 return ret;
291}
292
Harald Welteb3414b22017-11-23 18:22:10 +0100293function main_client(charstring remote_host, PortNumber remote_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100294 charstring local_host, PortNumber local_port,
295 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100296 g_mode := IPA_MODE_CLIENT;
Harald Weltee09921f2017-12-07 17:49:00 +0100297 f_connect(remote_host, remote_port, local_host, local_port, ccm_pars);
Harald Welteb3414b22017-11-23 18:22:10 +0100298 ScanEvents();
299}
300
301function main_server(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
302 g_mode := IPA_MODE_SERVER;
303 f_bind(local_host, local_port);
304 ScanEvents();
305}
306
Harald Weltec82eef42017-11-24 20:40:12 +0100307private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
308 var charstring msg_ch := oct2char(msg);
309 if (g_is_bsc_mgw) {
310 log("============");
311 log(msg_ch);
312 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
313 } else {
314 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
315 }
316}
317
Harald Welte92632e12017-11-25 02:31:20 +0100318private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
319 if (mp_ipa_mgcp_uses_osmo_ext) {
320 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
321 } else {
322 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
323 }
324}
325
Harald Welteb3414b22017-11-23 18:22:10 +0100326private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100327 var IPA_RecvFrom ipa_rx;
Harald Weltec76f29f2017-11-22 12:46:46 +0100328 var ASP_IPA_Unitdata ipa_ud;
Harald Welted86cdc62017-11-22 00:45:07 +0100329 var ASP_MTP3_TRANSFERreq mtp_req;
Harald Welteb3414b22017-11-23 18:22:10 +0100330 var ASP_Event asp_evt;
Harald Weltec82eef42017-11-24 20:40:12 +0100331 var MgcpCommand mgcp_cmd;
332 var MgcpResponse mgcp_rsp;
Harald Welte1dd8f372017-11-25 02:25:27 +0100333 var octetstring payload;
Harald Welte0d846a72017-12-07 17:58:28 +0100334 var ASP_RSL_Unitdata rsl;
Harald Welted86cdc62017-11-22 00:45:07 +0100335
336 while (true) {
337 alt {
338 /* Received IPA -> up into SCCP stack */
339 [] IPA_PORT.receive(IPA_RecvFrom: ?) -> value ipa_rx {
340 select (ipa_rx.streamId) {
341 case (IPAC_PROTO_CCM) {
342 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
343 log("CCM Rx:", ccm);
344 f_ccm_rx(ccm);
Harald Weltec82eef42017-11-24 20:40:12 +0100345 } case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100346 var ASP_MTP3_TRANSFERind mtp;
347 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
348 MTP3_SP_PORT.send(mtp);
Harald Weltec82eef42017-11-24 20:40:12 +0100349 } case (IPAC_PROTO_MGCP_OLD) {
350 f_mgcp_to_user(ipa_rx.msg);
Harald Welte0d846a72017-12-07 17:58:28 +0100351 } case (t_IpaSidRSL) {
352 rsl := {
353 streamId := ipa_rx.streamId,
354 rsl := dec_RSL_Message(ipa_rx.msg)
355 };
356 IPA_RSL_PORT.send(rsl);
Harald Weltec82eef42017-11-24 20:40:12 +0100357 } case (IPAC_PROTO_OSMO) {
358 select (ipa_rx.streamIdExt) {
359 case (IPAC_PROTO_EXT_MGCP) {
360 f_mgcp_to_user(ipa_rx.msg);
361 } case else {
362 IPA_SP_PORT.send(f_to_asp(ipa_rx));
363 }
Harald Welted86cdc62017-11-22 00:45:07 +0100364 }
Harald Weltec82eef42017-11-24 20:40:12 +0100365 } case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100366 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100367 }
368 }
369 }
370
Harald Welteb3414b22017-11-23 18:22:10 +0100371 /* server only */
372 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
373 log("IPA: Connected");
374 g_ipa_conn_id := asp_evt.connOpened.connId;
Harald Welte0d846a72017-12-07 17:58:28 +0100375 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welteb3414b22017-11-23 18:22:10 +0100376 if (g_mode == IPA_MODE_SERVER) {
377 f_ccm_tx(valueof(ts_IPA_ID_GET));
378 }
379 }
380
381 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
382 log("IPA: Closed");
383 g_ipa_conn_id := -1;
Harald Welte0d846a72017-12-07 17:58:28 +0100384 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
Harald Welteb3414b22017-11-23 18:22:10 +0100385 self.stop;
386 }
387
Harald Welted86cdc62017-11-22 00:45:07 +0100388 /* Received SCCP -> down into IPA */
389 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100390 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
391 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100392 IPA_PORT.send(ipa_tx);
393 }
Harald Weltec76f29f2017-11-22 12:46:46 +0100394
Harald Weltec82eef42017-11-24 20:40:12 +0100395 /* Received MGCP -> down into IPA */
396 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100397 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
398 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100399 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
400 }
401 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100402 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100403 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100404 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
405 }
406
Harald Welte0d846a72017-12-07 17:58:28 +0100407 /* Received RSL -> down into IPA */
408 [] IPA_RSL_PORT.receive(ASP_RSL_Unitdata:?) -> value rsl {
409 IPA_PORT.send(f_from_rsl(g_ipa_conn_id, rsl));
410 }
Harald Weltec82eef42017-11-24 20:40:12 +0100411
Harald Welte0d846a72017-12-07 17:58:28 +0100412
413 /* Received MISC (OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100414 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
415 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
416 }
417
418
Harald Welted86cdc62017-11-22 00:45:07 +0100419 }
420 }
421}
422
423}