blob: 98fbb92122e7c43d2d3ce8b345264997f20ebbf5 [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 Welted86cdc62017-11-22 00:45:07 +010060}
61
62function f_connect(charstring remote_host, PortNumber remote_port,
63 charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
64 var Result res;
65 res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port,
66 local_host, local_port, 0, { tcp:={} });
67 g_ipa_conn_id := res.connId;
Harald Welte12188832017-11-29 11:47:13 +010068 /* Set function for dissecting the binary */
69 var f_IPL4_getMsgLen vl_f := refers(f_IPL4_fixedMsgLen);
70 IPA_CodecPort_CtrlFunct.f_IPL4_setGetMsgLen(IPA_PORT, g_ipa_conn_id, vl_f, {0, 2, 3, 1, 0});
71
Harald Weltec82eef42017-11-24 20:40:12 +010072 g_is_bsc_mgw := true;
Harald Welted86cdc62017-11-22 00:45:07 +010073}
74
Harald Welteb3414b22017-11-23 18:22:10 +010075function f_bind(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
76 var Result res;
77 res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT,
78 local_host, local_port, { tcp:={} });
79 g_ipa_conn_id := res.connId;
Harald Weltec82eef42017-11-24 20:40:12 +010080 g_is_bsc_mgw := false;
Harald Welteb3414b22017-11-23 18:22:10 +010081}
82
Harald Welted86cdc62017-11-22 00:45:07 +010083template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := {
84 sio := { '10'B, '00'B, '0011'B },
85 opc := opc,
86 dpc := 0,
87 sls := 0,
88 data := data
89}
90
91
92private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := {
93 len := 0, /* overwritten by codec */
94 tag := tag,
95 data := payload
96}
97
98/* build IPA CCM ID RESP response from IPA CCM GET */
99private function f_ccm_make_id_resp(PDU_IPA_CCM get) return PDU_IPA_CCM {
100 var integer i;
101 var PDU_IPA_CCM resp := {
102 msg_type := IPAC_MSGT_ID_RESP,
103 u := {
104 resp := {}
105 }
106 }
107
108 for (i := 0; i < sizeof(get.u.get); i := i + 1) {
109 var IpaCcmIdTag tag := get.u.get[i].tag;
110 var charstring foo;
111 select (tag) {
112 case (IPAC_IDTAG_UNIT) {
113 foo := "0/1/2";
114 }
115 case (IPAC_IDTAG_UNITNAME) {
116 foo := "mahlzeit";
117 }
118 case else {
119 foo := "foo";
120 }
121 }
122 resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo));
123 }
124
125 return resp;
126}
127
128/* transmit IPA CCM message */
129private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
Harald Weltec82eef42017-11-24 20:40:12 +0100130 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 +0100131 log("CCM Tx:", ccm);
132 IPA_PORT.send(ipa_tx);
133}
134
135template PDU_IPA_CCM ts_IPA_PONG := {
136 msg_type := IPAC_MSGT_PONG,
137 u := omit
138}
139
140template PDU_IPA_CCM ts_IPA_ACK := {
141 msg_type := IPAC_MSGT_ID_ACK,
142 u := omit
143}
144
Harald Welteb3414b22017-11-23 18:22:10 +0100145template PDU_IPA_CCM ts_IPA_ID_GET := {
146 msg_type := IPAC_MSGT_ID_GET,
147 u := {
148 get := {
149 { 1, IPAC_IDTAG_UNITNAME }
150 }
151 }
152}
153
Harald Welted86cdc62017-11-22 00:45:07 +0100154/* receive IPA CCM message */
155private function f_ccm_rx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT {
156 select (ccm.msg_type) {
157 case (IPAC_MSGT_PING) {
158 f_ccm_tx(valueof(ts_IPA_PONG));
159 }
160 case (IPAC_MSGT_ID_ACK) {
161 f_ccm_tx(valueof(ts_IPA_ACK));
162 }
163 case (IPAC_MSGT_ID_GET) {
164 f_ccm_tx(f_ccm_make_id_resp(ccm));
165 }
166 case else {
167 log("Unknown/unsupported IPA CCM message type", ccm);
168 }
169 }
170}
171
Harald Weltec76f29f2017-11-22 12:46:46 +0100172private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata {
173 var ASP_IPA_Unitdata ret := {
174 streamId := ipa_rx.streamId,
Harald Welte2a8f8472017-11-23 21:11:34 +0100175 streamIdExt := ipa_rx.streamIdExt,
Harald Weltec76f29f2017-11-22 12:46:46 +0100176 payload := ipa_rx.msg
177 }
178 return ret;
179}
180
181private function f_from_asp(ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send {
Harald Weltec82eef42017-11-24 20:40:12 +0100182 var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload,
183 ipa_tx.streamIdExt));
Harald Weltec76f29f2017-11-22 12:46:46 +0100184 return ret;
185}
Harald Welted86cdc62017-11-22 00:45:07 +0100186
Harald Welteb3414b22017-11-23 18:22:10 +0100187function main_client(charstring remote_host, PortNumber remote_port,
188 charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
189 g_mode := IPA_MODE_CLIENT;
190 f_connect(remote_host, remote_port, local_host, local_port);
191 ScanEvents();
192}
193
194function main_server(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT {
195 g_mode := IPA_MODE_SERVER;
196 f_bind(local_host, local_port);
197 ScanEvents();
198}
199
Harald Weltec82eef42017-11-24 20:40:12 +0100200private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT {
201 var charstring msg_ch := oct2char(msg);
202 if (g_is_bsc_mgw) {
203 log("============");
204 log(msg_ch);
205 IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch));
206 } else {
207 IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch));
208 }
209}
210
Harald Welte92632e12017-11-25 02:31:20 +0100211private function f_mgcp_to_ud(octetstring payload) runs on IPA_Emulation_CT return ASP_IPA_Unitdata {
212 if (mp_ipa_mgcp_uses_osmo_ext) {
213 return valueof(t_ASP_IPA_UD(IPAC_PROTO_MGCP_OLD, payload));
214 } else {
215 return valueof(t_ASP_IPA_UD(IPAC_PROTO_OSMO, payload, IPAC_PROTO_EXT_MGCP));
216 }
217}
218
Harald Welteb3414b22017-11-23 18:22:10 +0100219private function ScanEvents() runs on IPA_Emulation_CT {
Harald Welted86cdc62017-11-22 00:45:07 +0100220 var IPA_RecvFrom ipa_rx;
Harald Weltec76f29f2017-11-22 12:46:46 +0100221 var ASP_IPA_Unitdata ipa_ud;
Harald Welted86cdc62017-11-22 00:45:07 +0100222 var ASP_MTP3_TRANSFERreq mtp_req;
Harald Welteb3414b22017-11-23 18:22:10 +0100223 var ASP_Event asp_evt;
Harald Weltec82eef42017-11-24 20:40:12 +0100224 var MgcpCommand mgcp_cmd;
225 var MgcpResponse mgcp_rsp;
Harald Welte1dd8f372017-11-25 02:25:27 +0100226 var octetstring payload;
Harald Welted86cdc62017-11-22 00:45:07 +0100227
228 while (true) {
229 alt {
230 /* Received IPA -> up into SCCP stack */
231 [] IPA_PORT.receive(IPA_RecvFrom: ?) -> value ipa_rx {
232 select (ipa_rx.streamId) {
233 case (IPAC_PROTO_CCM) {
234 var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg);
235 log("CCM Rx:", ccm);
236 f_ccm_rx(ccm);
Harald Weltec82eef42017-11-24 20:40:12 +0100237 } case (IPAC_PROTO_SCCP) {
Harald Welted86cdc62017-11-22 00:45:07 +0100238 var ASP_MTP3_TRANSFERind mtp;
239 mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg));
240 MTP3_SP_PORT.send(mtp);
Harald Weltec82eef42017-11-24 20:40:12 +0100241 } case (IPAC_PROTO_MGCP_OLD) {
242 f_mgcp_to_user(ipa_rx.msg);
243 } case (IPAC_PROTO_OSMO) {
244 select (ipa_rx.streamIdExt) {
245 case (IPAC_PROTO_EXT_MGCP) {
246 f_mgcp_to_user(ipa_rx.msg);
247 } case else {
248 IPA_SP_PORT.send(f_to_asp(ipa_rx));
249 }
Harald Welted86cdc62017-11-22 00:45:07 +0100250 }
Harald Weltec82eef42017-11-24 20:40:12 +0100251 } case else {
Harald Weltec76f29f2017-11-22 12:46:46 +0100252 IPA_SP_PORT.send(f_to_asp(ipa_rx));
Harald Welted86cdc62017-11-22 00:45:07 +0100253 }
254 }
255 }
256
Harald Welteb3414b22017-11-23 18:22:10 +0100257 /* server only */
258 [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt {
259 log("IPA: Connected");
260 g_ipa_conn_id := asp_evt.connOpened.connId;
261 if (g_mode == IPA_MODE_SERVER) {
262 f_ccm_tx(valueof(ts_IPA_ID_GET));
263 }
264 }
265
266 [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt {
267 log("IPA: Closed");
268 g_ipa_conn_id := -1;
269 self.stop;
270 }
271
Harald Welted86cdc62017-11-22 00:45:07 +0100272 /* Received SCCP -> down into IPA */
273 [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req {
Harald Weltec82eef42017-11-24 20:40:12 +0100274 var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP,
275 mtp_req.data));
Harald Welted86cdc62017-11-22 00:45:07 +0100276 IPA_PORT.send(ipa_tx);
277 }
Harald Weltec76f29f2017-11-22 12:46:46 +0100278
Harald Weltec82eef42017-11-24 20:40:12 +0100279 /* Received MGCP -> down into IPA */
280 [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd {
Harald Welte92632e12017-11-25 02:31:20 +0100281 payload := char2oct(enc_MgcpCommand(mgcp_cmd));
282 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100283 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
284 }
285 [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp {
Harald Welte1dd8f372017-11-25 02:25:27 +0100286 payload := char2oct(enc_MgcpResponse(mgcp_rsp));
Harald Welte92632e12017-11-25 02:31:20 +0100287 ipa_ud := f_mgcp_to_ud(payload);
Harald Weltec82eef42017-11-24 20:40:12 +0100288 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
289 }
290
291
292 /* Received MISC (RSL/OML/CTRL) -> down into IPA */
Harald Weltec76f29f2017-11-22 12:46:46 +0100293 [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud {
294 IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud));
295 }
296
297
Harald Welted86cdc62017-11-22 00:45:07 +0100298 }
299 }
300}
301
302}