blob: 92e0a357a6f9da3849bbae5173883072917caf21 [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;
10
Harald Weltec82eef42017-11-24 20:40:12 +010011import from MGCP_Types all;
12
Harald Welted86cdc62017-11-22 00:45:07 +010013modulepar {
Harald Welte92632e12017-11-25 02:31:20 +010014 /* Use Osmocom extended IPA mux header */
15 boolean mp_ipa_mgcp_uses_osmo_ext := true;
Harald Welted86cdc62017-11-22 00:45:07 +010016}
Harald Welted86cdc62017-11-22 00:45:07 +010017
Harald Welteb3414b22017-11-23 18:22:10 +010018type enumerated IpaMode {
19 IPA_MODE_CLIENT,
20 IPA_MODE_SERVER
21}
22
Harald Weltec76f29f2017-11-22 12:46:46 +010023type record ASP_IPA_Unitdata {
24 IpaStreamId streamId,
Harald Weltec82eef42017-11-24 20:40:12 +010025 IpaExtStreamId streamIdExt optional,
Harald Weltec76f29f2017-11-22 12:46:46 +010026 octetstring payload
27}
28
Harald Welte1dd8f372017-11-25 02:25:27 +010029template ASP_IPA_Unitdata t_ASP_IPA_UD(IpaStreamId sid, octetstring pl,
30 template IpaExtStreamId esid := omit) := {
31 streamId := sid,
32 streamIdExt := esid,
33 payload := pl
34}
35
Harald Weltec76f29f2017-11-22 12:46:46 +010036type port IPA_SP_PT message {
37 inout ASP_IPA_Unitdata;
38} with { extension "internal" }
39
Harald Weltec82eef42017-11-24 20:40:12 +010040type port IPA_MGCP_PT message {
41 inout MgcpCommand, MgcpResponse;
42} with { extension "internal" }
43
Harald Welted86cdc62017-11-22 00:45:07 +010044type component IPA_Emulation_CT {
45 /* down-facing port to IPA codec port */
46 port IPA_CODEC_PT IPA_PORT;
47 /* up-facing port to SCCP */
48 port MTP3asp_SP_PT MTP3_SP_PORT;
Harald Weltec82eef42017-11-24 20:40:12 +010049 /* up-facing port for MGCP */
50 port IPA_MGCP_PT IPA_MGCP_PORT;
Harald Weltec76f29f2017-11-22 12:46:46 +010051 /* up-facing port for other streams */
52 port IPA_SP_PT IPA_SP_PORT;
Harald Welted86cdc62017-11-22 00:45:07 +010053
54 var boolean g_initialized := false;
55 var ConnectionId g_ipa_conn_id := -1;
Harald Weltec82eef42017-11-24 20:40:12 +010056 /* Are we a BSC/MGW (truel) or MSC (false) */
57 var boolean g_is_bsc_mgw;
Harald Welteb3414b22017-11-23 18:22:10 +010058
59 var IpaMode g_mode;
Harald Weltee21096d2017-12-04 20:45:12 +010060 var IPA_CCM_Parameters g_ccm_pars := c_default_ccm_pars;
Harald Welted86cdc62017-11-22 00:45:07 +010061}
62
Harald Weltee21096d2017-12-04 20:45:12 +010063type record IPA_CCM_Parameters {
64 charstring ser_nr optional,
65 charstring name optional,
66 charstring location1 optional,
67 charstring location2 optional,
68 charstring equip_version optional,
69 charstring sw_version optional,
70 charstring ip_addr optional,
71 charstring mac_addr optional,
72 charstring unit_id optional,
73 charstring osmo_rand optional
74}
75
76private const IPA_CCM_Parameters c_default_ccm_pars := {
77 ser_nr := omit,
78 name := "mahlzeit",
79 location1 := omit,
80 location2 := omit,
81 equip_version := omit,
82 sw_version := omit,
83 ip_addr := omit,
84 mac_addr := omit,
85 unit_id := "0/1/2",
86 osmo_rand := omit
87};
88
Harald Welted86cdc62017-11-22 00:45:07 +010089function f_connect(charstring remote_host, PortNumber remote_port,
Harald Weltee21096d2017-12-04 20:45:12 +010090 charstring local_host, PortNumber local_port,
91 IPA_CCM_Parameters ccm_pars := c_default_ccm_pars) runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +010092 var Result res;
93 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
94 local_host, local_port, 0, { tcp:={} });
95 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +010096 g_ccm_pars := ccm_pars;
Harald Welte12188832017-11-29 11:47:13 +010097 /* Set function for dissecting the binary */
98 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
99 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
100
Harald Weltec82eef42017-11-24 20:40:12 +0100101 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +0100102}
103
Harald Weltee21096d2017-12-04 20:45:12 +0100104function f_bind(charstring local_host, PortNumber local_port,
105 IPA_CCM_Parameters ccm_pars := c_default_ccm_pars) runs on IPA_Emulation_CT {
Harald Welteb3414b22017-11-23 18:22:10 +0100106 var Result res;
107 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
108 local_host, local_port, { tcp:={} });
109 g_ipa_conn_id := res.connId;
Harald Weltee21096d2017-12-04 20:45:12 +0100110 g_ccm_pars := ccm_pars;
Harald Weltec82eef42017-11-24 20:40:12 +0100111 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +0100112}
113
Harald Welted86cdc62017-11-22 00:45:07 +0100114template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
115 sio := { '10'B, '00'B, '0011'B },
116 opc := opc,
117 dpc := 0,
118 sls := 0,
119 data := data
120}
121
122
123private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
124 len := 0, /* overwritten by codec */
125 tag := tag,
126 data := payload
127}
128
129/* build IPA CCM ID RESP response from IPA CCM GET */
Harald Weltee21096d2017-12-04 20:45:12 +0100130private 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 +0100131 var integer i;
132 var PDU_IPA_CCM resp := {
133 msg_type := IPAC_MSGT_ID_RESP,
134 u := {
135 resp := {}
136 }
137 }
138
139 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
140 var IpaCcmIdTag tag := get.u.get[i].tag;
141 var charstring foo;
142 select (tag) {
Harald Weltee21096d2017-12-04 20:45:12 +0100143 case (IPAC_IDTAG_SERNR) {
144 foo := g_ccm_pars.ser_nr;
Harald Welted86cdc62017-11-22 00:45:07 +0100145 }
146 case (IPAC_IDTAG_UNITNAME) {
Harald Weltee21096d2017-12-04 20:45:12 +0100147 foo := g_ccm_pars.name;
148 }
149 case (IPAC_IDTAG_LOCATION1) {
150 foo := g_ccm_pars.location1;
151 }
152 case (IPAC_IDTAG_LOCATION2) {
153 foo := g_ccm_pars.location2;
154 }
155 case (IPAC_IDTAG_EQUIPVERS) {
156 foo := g_ccm_pars.equip_version;
157 }
158 case (IPAC_IDTAG_SWVERSION) {
159 foo := g_ccm_pars.sw_version;
160 }
161 case (IPAC_IDTAG_IPADDR) {
162 foo := g_ccm_pars.ip_addr;
163 }
164 case (IPAC_IDTAG_MACADDR) {
165 foo := g_ccm_pars.mac_addr;
166 }
167 case (IPAC_IDTAG_UNIT) {
168 foo := g_ccm_pars.unit_id;
169 }
170 case (IPAC_IDTAG_OSMO_RAND) {
171 foo := g_ccm_pars.osmo_rand;
Harald Welted86cdc62017-11-22 00:45:07 +0100172 }
173 case else {
Harald Weltee21096d2017-12-04 20:45:12 +0100174 foo := "unknown";
Harald Welted86cdc62017-11-22 00:45:07 +0100175 }
176 }
177 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
178 }
179
180 return resp;
181}
182
183/* transmit IPA CCM message */
184private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100185 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 +0100186 log("CCM Tx:", ccm);
187 IPA_PORT.send(ipa_tx);
188}
189
190template PDU_IPA_CCM ts_IPA_PONG := {
191 msg_type := IPAC_MSGT_PONG,
192 u := omit
193}
194
195template PDU_IPA_CCM ts_IPA_ACK := {
196 msg_type := IPAC_MSGT_ID_ACK,
197 u := omit
198}
199
Harald Welteb3414b22017-11-23 18:22:10 +0100200template PDU_IPA_CCM ts_IPA_ID_GET := {
201 msg_type := IPAC_MSGT_ID_GET,
202 u := {
203 get := {
204 { 1, IPAC_IDTAG_UNITNAME }
205 }
206 }
207}
208
Harald Welted86cdc62017-11-22 00:45:07 +0100209/* receive IPA CCM message */
210private function f_ccm_rx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
211 select (ccm.msg_type) {
212 case (IPAC_MSGT_PING) {
213 f_ccm_tx(valueof(ts_IPA_PONG));
214 }
215 case (IPAC_MSGT_ID_ACK) {
216 f_ccm_tx(valueof(ts_IPA_ACK));
217 }
218 case (IPAC_MSGT_ID_GET) {
219 f_ccm_tx(f_ccm_make_id_resp(ccm));
220 }
221 case else {
222 log("Unknown/unsupported IPA CCM message type", ccm);
223 }
224 }
225}
226
Harald Weltec76f29f2017-11-22 12:46:46 +0100227private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
228 var ASP_IPA_Unitdata ret := {
229 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100230 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100231 payload := ipa_rx.msg
232 }
233 return ret;
234}
235
236private function f_from_asp(ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100237 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
238 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100239 return ret;
240}
Harald Welted86cdc62017-11-22 00:45:07 +0100241
Harald Welteb3414b22017-11-23 18:22:10 +0100242function main_client(charstring remote_host, PortNumber remote_port,
243 charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
244 g_mode := IPA_MODE_CLIENT;
245 f_connect(remote_host, remote_port, local_host, local_port);
246 ScanEvents();
247}
248
249function main_server(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
250 g_mode := IPA_MODE_SERVER;
251 f_bind(local_host, local_port);
252 ScanEvents();
253}
254
Harald Weltec82eef42017-11-24 20:40:12 +0100255private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
256 var charstring msg_ch := oct2char(msg);
257 if (g_is_bsc_mgw) {
258 log("============");
259 log(msg_ch);
260 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
261 } else {
262 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
263 }
264}
265
Harald Welte92632e12017-11-25 02:31:20 +0100266private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
267 if (mp_ipa_mgcp_uses_osmo_ext) {
268 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
269 } else {
270 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
271 }
272}
273
Harald Welteb3414b22017-11-23 18:22:10 +0100274private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100275 var IPA_RecvFrom ipa_rx;
Harald Weltec76f29f2017-11-22 12:46:46 +0100276 var ASP_IPA_Unitdata ipa_ud;
Harald Welted86cdc62017-11-22 00:45:07 +0100277 var ASP_MTP3_TRANSFERreq mtp_req;
Harald Welteb3414b22017-11-23 18:22:10 +0100278 var ASP_Event asp_evt;
Harald Weltec82eef42017-11-24 20:40:12 +0100279 var MgcpCommand mgcp_cmd;
280 var MgcpResponse mgcp_rsp;
Harald Welte1dd8f372017-11-25 02:25:27 +0100281 var octetstring payload;
Harald Welted86cdc62017-11-22 00:45:07 +0100282
283 while (true) {
284 alt {
285 /* Received IPA -> up into SCCP stack */
286 [] IPA_PORT.receive(IPA_RecvFrom: ?) -> value ipa_rx {
287 select (ipa_rx.streamId) {
288 case (IPAC_PROTO_CCM) {
289 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
290 log("CCM Rx:", ccm);
291 f_ccm_rx(ccm);
Harald Weltec82eef42017-11-24 20:40:12 +0100292 } case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100293 var ASP_MTP3_TRANSFERind mtp;
294 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
295 MTP3_SP_PORT.send(mtp);
Harald Weltec82eef42017-11-24 20:40:12 +0100296 } case (IPAC_PROTO_MGCP_OLD) {
297 f_mgcp_to_user(ipa_rx.msg);
298 } case (IPAC_PROTO_OSMO) {
299 select (ipa_rx.streamIdExt) {
300 case (IPAC_PROTO_EXT_MGCP) {
301 f_mgcp_to_user(ipa_rx.msg);
302 } case else {
303 IPA_SP_PORT.send(f_to_asp(ipa_rx));
304 }
Harald Welted86cdc62017-11-22 00:45:07 +0100305 }
Harald Weltec82eef42017-11-24 20:40:12 +0100306 } case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100307 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100308 }
309 }
310 }
311
Harald Welteb3414b22017-11-23 18:22:10 +0100312 /* server only */
313 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
314 log("IPA: Connected");
315 g_ipa_conn_id := asp_evt.connOpened.connId;
316 if (g_mode == IPA_MODE_SERVER) {
317 f_ccm_tx(valueof(ts_IPA_ID_GET));
318 }
319 }
320
321 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
322 log("IPA: Closed");
323 g_ipa_conn_id := -1;
324 self.stop;
325 }
326
Harald Welted86cdc62017-11-22 00:45:07 +0100327 /* Received SCCP -> down into IPA */
328 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100329 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
330 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100331 IPA_PORT.send(ipa_tx);
332 }
Harald Weltec76f29f2017-11-22 12:46:46 +0100333
Harald Weltec82eef42017-11-24 20:40:12 +0100334 /* Received MGCP -> down into IPA */
335 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100336 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
337 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100338 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
339 }
340 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100341 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100342 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100343 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
344 }
345
346
347 /* Received MISC (RSL/OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100348 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
349 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
350 }
351
352
Harald Welted86cdc62017-11-22 00:45:07 +0100353 }
354 }
355}
356
357}