blob: c8111e29919bf29ee5eeb9ee915d66202f8d9099 [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
56template ASP_RSL_Unitdata t_ASP_RSL_UD(IpaStreamId sid, template RSL_Message rsl) := {
57 streamId := sid,
58 rsl := valueof(rsl)
59}
60
61template IpaStreamId t_IpaSidRSL := ( IPAC_PROTO_RSL_TRX0, IPAC_PROTO_RSL_TRX1,
62 IPAC_PROTO_RSL_TRX2, IPAC_PROTO_RSL_TRX3 );
63
Harald Weltec76f29f2017-11-22 12:46:46 +010064type port IPA_SP_PT message {
Harald Welte0d846a72017-12-07 17:58:28 +010065 inout ASP_IPA_Unitdata, ASP_IPA_Event;
Harald Weltec76f29f2017-11-22 12:46:46 +010066} with { extension "internal" }
67
Harald Weltec82eef42017-11-24 20:40:12 +010068type port IPA_MGCP_PT message {
69 inout MgcpCommand, MgcpResponse;
70} with { extension "internal" }
71
Harald Welte0d846a72017-12-07 17:58:28 +010072type port IPA_RSL_PT message {
73 inout ASP_RSL_Unitdata, ASP_IPA_Event;
74} with { extension "internal" }
75
Harald Welted86cdc62017-11-22 00:45:07 +010076type component IPA_Emulation_CT {
77 /* down-facing port to IPA codec port */
78 port IPA_CODEC_PT IPA_PORT;
79 /* up-facing port to SCCP */
80 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltec82eef42017-11-24 20:40:12 +010081 /* up-facing port for MGCP */
82 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Welte0d846a72017-12-07 17:58:28 +010083 /* up-facing port for RSL */
84 port IPA_RSL_PT IPA_RSL_PORT;
Harald Weltec76f29f2017-11-22 12:46:46 +010085 /* up-facing port for other streams */
86 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +010087
88 var boolean g_initialized := false;
89 var ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +010090 /* Are we a BSC/MGW (truel) or MSC (false) */
91 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +010092
93 var IpaMode g_mode;
Harald Weltee09921f2017-12-07 17:49:00 +010094 var IPA_CCM_Parameters g_ccm_pars := c_IPA_default_ccm_pars;
Harald Welted86cdc62017-11-22 00:45:07 +010095}
96
Harald Weltee21096d2017-12-04 20:45:12 +010097type record IPA_CCM_Parameters {
98 charstring ser_nr optional,
99 charstring name optional,
100 charstring location1 optional,
101 charstring location2 optional,
102 charstring equip_version optional,
103 charstring sw_version optional,
104 charstring ip_addr optional,
105 charstring mac_addr optional,
106 charstring unit_id optional,
107 charstring osmo_rand optional
108}
109
Harald Weltee09921f2017-12-07 17:49:00 +0100110const IPA_CCM_Parameters c_IPA_default_ccm_pars := {
111 ser_nr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100112 name := "mahlzeit",
Harald Weltee09921f2017-12-07 17:49:00 +0100113 location1 := "",
114 location2 := "",
115 equip_version := "",
116 sw_version := "",
117 ip_addr := "",
118 mac_addr := "",
Harald Weltee21096d2017-12-04 20:45:12 +0100119 unit_id := "0/1/2",
Harald Weltee09921f2017-12-07 17:49:00 +0100120 osmo_rand := ""
Harald Weltee21096d2017-12-04 20:45:12 +0100121};
122
Harald Welted86cdc62017-11-22 00:45:07 +0100123function f_connect(charstring remote_host, PortNumber remote_port,
Harald Weltee21096d2017-12-04 20:45:12 +0100124 charstring local_host, PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100125 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100126 var Result res;
127 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
128 local_host, local_port, 0, { tcp:={} });
129 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100130 g_ccm_pars := ccm_pars;
Harald Welte12188832017-11-29 11:47:13 +0100131 /* Set function for dissecting the binary */
132 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
133 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
134
Harald Weltec82eef42017-11-24 20:40:12 +0100135 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +0100136}
137
Harald Weltee21096d2017-12-04 20:45:12 +0100138function f_bind(charstring local_host, PortNumber local_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100139 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100140 var Result res;
141 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
142 local_host, local_port, { tcp:={} });
143 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100144 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100145 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +0100146}
147
Harald Welted86cdc62017-11-22 00:45:07 +0100148template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
149 sio := { '10'B, '00'B, '0011'B },
150 opc := opc,
151 dpc := 0,
152 sls := 0,
153 data := data
154}
155
156
157private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
158 len := 0, /* overwritten by codec */
159 tag := tag,
160 data := payload
161}
162
Harald Welte0d846a72017-12-07 17:58:28 +0100163private function f_send_IPA_EVT(template ASP_IPA_Event evt) runs on IPA_Emulation_CT {
164 IPA_RSL_PORT.send(evt);
165 /* FIXME: to other ports */
166}
167
Harald Welted86cdc62017-11-22 00:45:07 +0100168/* build IPA CCM ID RESP response from IPA CCM GET */
Harald Weltee21096d2017-12-04 20:45:12 +0100169private 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 +0100170 var integer i;
171 var PDU_IPA_CCM resp := {
172 msg_type := IPAC_MSGT_ID_RESP,
173 u := {
174 resp := {}
175 }
176 }
177
178 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
179 var IpaCcmIdTag tag := get.u.get[i].tag;
180 var charstring foo;
181 select (tag) {
Harald Weltee21096d2017-12-04 20:45:12 +0100182 case (IPAC_IDTAG_SERNR) {
183 foo := g_ccm_pars.ser_nr;
Harald Welted86cdc62017-11-22 00:45:07 +0100184 }
185 case (IPAC_IDTAG_UNITNAME) {
Harald Weltee21096d2017-12-04 20:45:12 +0100186 foo := g_ccm_pars.name;
187 }
188 case (IPAC_IDTAG_LOCATION1) {
189 foo := g_ccm_pars.location1;
190 }
191 case (IPAC_IDTAG_LOCATION2) {
192 foo := g_ccm_pars.location2;
193 }
194 case (IPAC_IDTAG_EQUIPVERS) {
195 foo := g_ccm_pars.equip_version;
196 }
197 case (IPAC_IDTAG_SWVERSION) {
198 foo := g_ccm_pars.sw_version;
199 }
200 case (IPAC_IDTAG_IPADDR) {
201 foo := g_ccm_pars.ip_addr;
202 }
203 case (IPAC_IDTAG_MACADDR) {
204 foo := g_ccm_pars.mac_addr;
205 }
206 case (IPAC_IDTAG_UNIT) {
207 foo := g_ccm_pars.unit_id;
208 }
209 case (IPAC_IDTAG_OSMO_RAND) {
210 foo := g_ccm_pars.osmo_rand;
Harald Welted86cdc62017-11-22 00:45:07 +0100211 }
212 case else {
Harald Weltee21096d2017-12-04 20:45:12 +0100213 foo := "unknown";
Harald Welted86cdc62017-11-22 00:45:07 +0100214 }
215 }
216 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
217 }
218
219 return resp;
220}
221
222/* transmit IPA CCM message */
223private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100224 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 +0100225 log("CCM Tx:", ccm);
226 IPA_PORT.send(ipa_tx);
227}
228
229template PDU_IPA_CCM ts_IPA_PONG := {
230 msg_type := IPAC_MSGT_PONG,
231 u := omit
232}
233
234template PDU_IPA_CCM ts_IPA_ACK := {
235 msg_type := IPAC_MSGT_ID_ACK,
236 u := omit
237}
238
Harald Welteb3414b22017-11-23 18:22:10 +0100239template PDU_IPA_CCM ts_IPA_ID_GET := {
240 msg_type := IPAC_MSGT_ID_GET,
241 u := {
242 get := {
243 { 1, IPAC_IDTAG_UNITNAME }
244 }
245 }
246}
247
Harald Welted86cdc62017-11-22 00:45:07 +0100248/* receive IPA CCM message */
249private function f_ccm_rx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
250 select (ccm.msg_type) {
251 case (IPAC_MSGT_PING) {
252 f_ccm_tx(valueof(ts_IPA_PONG));
253 }
254 case (IPAC_MSGT_ID_ACK) {
255 f_ccm_tx(valueof(ts_IPA_ACK));
256 }
257 case (IPAC_MSGT_ID_GET) {
258 f_ccm_tx(f_ccm_make_id_resp(ccm));
259 }
260 case else {
261 log("Unknown/unsupported IPA CCM message type", ccm);
262 }
263 }
264}
265
Harald Weltec76f29f2017-11-22 12:46:46 +0100266private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
267 var ASP_IPA_Unitdata ret := {
268 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100269 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100270 payload := ipa_rx.msg
271 }
272 return ret;
273}
274
275private function f_from_asp(ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100276 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
277 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100278 return ret;
279}
Harald Welted86cdc62017-11-22 00:45:07 +0100280
Harald Welte0d846a72017-12-07 17:58:28 +0100281private function f_from_rsl(ConnectionId connId, ASP_RSL_Unitdata rsl_tx) return IPA_Send {
282 var octetstring payload := enc_RSL_Message(rsl_tx.rsl);
283 var IPA_Send ret := valueof(t_IPA_Send(connId, rsl_tx.streamId, payload));
284 return ret;
285}
286
Harald Welteb3414b22017-11-23 18:22:10 +0100287function main_client(charstring remote_host, PortNumber remote_port,
Harald Weltee09921f2017-12-07 17:49:00 +0100288 charstring local_host, PortNumber local_port,
289 IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100290 g_mode := IPA_MODE_CLIENT;
Harald Weltee09921f2017-12-07 17:49:00 +0100291 f_connect(remote_host, remote_port, local_host, local_port, ccm_pars);
Harald Welteb3414b22017-11-23 18:22:10 +0100292 ScanEvents();
293}
294
295function main_server(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
296 g_mode := IPA_MODE_SERVER;
297 f_bind(local_host, local_port);
298 ScanEvents();
299}
300
Harald Weltec82eef42017-11-24 20:40:12 +0100301private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
302 var charstring msg_ch := oct2char(msg);
303 if (g_is_bsc_mgw) {
304 log("============");
305 log(msg_ch);
306 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
307 } else {
308 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
309 }
310}
311
Harald Welte92632e12017-11-25 02:31:20 +0100312private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
313 if (mp_ipa_mgcp_uses_osmo_ext) {
314 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
315 } else {
316 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
317 }
318}
319
Harald Welteb3414b22017-11-23 18:22:10 +0100320private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100321 var IPA_RecvFrom ipa_rx;
Harald Weltec76f29f2017-11-22 12:46:46 +0100322 var ASP_IPA_Unitdata ipa_ud;
Harald Welted86cdc62017-11-22 00:45:07 +0100323 var ASP_MTP3_TRANSFERreq mtp_req;
Harald Welteb3414b22017-11-23 18:22:10 +0100324 var ASP_Event asp_evt;
Harald Weltec82eef42017-11-24 20:40:12 +0100325 var MgcpCommand mgcp_cmd;
326 var MgcpResponse mgcp_rsp;
Harald Welte1dd8f372017-11-25 02:25:27 +0100327 var octetstring payload;
Harald Welte0d846a72017-12-07 17:58:28 +0100328 var ASP_RSL_Unitdata rsl;
Harald Welted86cdc62017-11-22 00:45:07 +0100329
330 while (true) {
331 alt {
332 /* Received IPA -> up into SCCP stack */
333 [] IPA_PORT.receive(IPA_RecvFrom: ?) -> value ipa_rx {
334 select (ipa_rx.streamId) {
335 case (IPAC_PROTO_CCM) {
336 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
337 log("CCM Rx:", ccm);
338 f_ccm_rx(ccm);
Harald Weltec82eef42017-11-24 20:40:12 +0100339 } case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100340 var ASP_MTP3_TRANSFERind mtp;
341 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
342 MTP3_SP_PORT.send(mtp);
Harald Weltec82eef42017-11-24 20:40:12 +0100343 } case (IPAC_PROTO_MGCP_OLD) {
344 f_mgcp_to_user(ipa_rx.msg);
Harald Welte0d846a72017-12-07 17:58:28 +0100345 } case (t_IpaSidRSL) {
346 rsl := {
347 streamId := ipa_rx.streamId,
348 rsl := dec_RSL_Message(ipa_rx.msg)
349 };
350 IPA_RSL_PORT.send(rsl);
Harald Weltec82eef42017-11-24 20:40:12 +0100351 } case (IPAC_PROTO_OSMO) {
352 select (ipa_rx.streamIdExt) {
353 case (IPAC_PROTO_EXT_MGCP) {
354 f_mgcp_to_user(ipa_rx.msg);
355 } case else {
356 IPA_SP_PORT.send(f_to_asp(ipa_rx));
357 }
Harald Welted86cdc62017-11-22 00:45:07 +0100358 }
Harald Weltec82eef42017-11-24 20:40:12 +0100359 } case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100360 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100361 }
362 }
363 }
364
Harald Welteb3414b22017-11-23 18:22:10 +0100365 /* server only */
366 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
367 log("IPA: Connected");
368 g_ipa_conn_id := asp_evt.connOpened.connId;
Harald Welte0d846a72017-12-07 17:58:28 +0100369 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP));
Harald Welteb3414b22017-11-23 18:22:10 +0100370 if (g_mode == IPA_MODE_SERVER) {
371 f_ccm_tx(valueof(ts_IPA_ID_GET));
372 }
373 }
374
375 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
376 log("IPA: Closed");
377 g_ipa_conn_id := -1;
Harald Welte0d846a72017-12-07 17:58:28 +0100378 f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_DOWN));
Harald Welteb3414b22017-11-23 18:22:10 +0100379 self.stop;
380 }
381
Harald Welted86cdc62017-11-22 00:45:07 +0100382 /* Received SCCP -> down into IPA */
383 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100384 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
385 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100386 IPA_PORT.send(ipa_tx);
387 }
Harald Weltec76f29f2017-11-22 12:46:46 +0100388
Harald Weltec82eef42017-11-24 20:40:12 +0100389 /* Received MGCP -> down into IPA */
390 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100391 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
392 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100393 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
394 }
395 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100396 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100397 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100398 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
399 }
400
Harald Welte0d846a72017-12-07 17:58:28 +0100401 /* Received RSL -> down into IPA */
402 [] IPA_RSL_PORT.receive(ASP_RSL_Unitdata:?) -> value rsl {
403 IPA_PORT.send(f_from_rsl(g_ipa_conn_id, rsl));
404 }
Harald Weltec82eef42017-11-24 20:40:12 +0100405
Harald Welte0d846a72017-12-07 17:58:28 +0100406
407 /* Received MISC (OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100408 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
409 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
410 }
411
412
Harald Welted86cdc62017-11-22 00:45:07 +0100413 }
414 }
415}
416
417}