module IPA_Emulation { import from IPA_Types all; import from IPA_CodecPort all; import from IPA_CodecPort_CtrlFunct all; import from IPL4asp_Types all; import from MTP3asp_Types all; import from MTP3asp_PortType all; import from MGCP_Types all; /* modulepar { } */ type enumerated IpaMode { IPA_MODE_CLIENT, IPA_MODE_SERVER } type record ASP_IPA_Unitdata { IpaStreamId streamId, IpaExtStreamId streamIdExt optional, octetstring payload } type port IPA_SP_PT message { inout ASP_IPA_Unitdata; } with { extension "internal" } type port IPA_MGCP_PT message { inout MgcpCommand, MgcpResponse; } with { extension "internal" } type component IPA_Emulation_CT { /* down-facing port to IPA codec port */ port IPA_CODEC_PT IPA_PORT; /* up-facing port to SCCP */ port MTP3asp_SP_PT MTP3_SP_PORT; /* up-facing port for MGCP */ port IPA_MGCP_PT IPA_MGCP_PORT; /* up-facing port for other streams */ port IPA_SP_PT IPA_SP_PORT; var boolean g_initialized := false; var ConnectionId g_ipa_conn_id := -1; /* Are we a BSC/MGW (truel) or MSC (false) */ var boolean g_is_bsc_mgw; var IpaMode g_mode; } function f_connect(charstring remote_host, PortNumber remote_port, charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT { var Result res; res := IPA_CodecPort_CtrlFunct.f_IPL4_connect(IPA_PORT, remote_host, remote_port, local_host, local_port, 0, { tcp:={} }); g_ipa_conn_id := res.connId; g_is_bsc_mgw := true; } function f_bind(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT { var Result res; res := IPA_CodecPort_CtrlFunct.f_IPL4_listen(IPA_PORT, local_host, local_port, { tcp:={} }); g_ipa_conn_id := res.connId; g_is_bsc_mgw := false; } template ASP_MTP3_TRANSFERind ts_MTP3_XFER_ind(integer opc, octetstring data) := { sio := { '10'B, '00'B, '0011'B }, opc := opc, dpc := 0, sls := 0, data := data } private template IpaCcmRespPart t_IdRespPart(IpaCcmIdTag tag, charstring payload) := { len := 0, /* overwritten by codec */ tag := tag, data := payload } /* build IPA CCM ID RESP response from IPA CCM GET */ private function f_ccm_make_id_resp(PDU_IPA_CCM get) return PDU_IPA_CCM { var integer i; var PDU_IPA_CCM resp := { msg_type := IPAC_MSGT_ID_RESP, u := { resp := {} } } for (i := 0; i < sizeof(get.u.get); i := i + 1) { var IpaCcmIdTag tag := get.u.get[i].tag; var charstring foo; select (tag) { case (IPAC_IDTAG_UNIT) { foo := "0/1/2"; } case (IPAC_IDTAG_UNITNAME) { foo := "mahlzeit"; } case else { foo := "foo"; } } resp.u.resp[sizeof(resp.u.resp)] := valueof(t_IdRespPart(tag, foo)); } return resp; } /* transmit IPA CCM message */ private function f_ccm_tx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT { var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_CCM, enc_PDU_IPA_CCM(ccm))); log("CCM Tx:", ccm); IPA_PORT.send(ipa_tx); } template PDU_IPA_CCM ts_IPA_PONG := { msg_type := IPAC_MSGT_PONG, u := omit } template PDU_IPA_CCM ts_IPA_ACK := { msg_type := IPAC_MSGT_ID_ACK, u := omit } template PDU_IPA_CCM ts_IPA_ID_GET := { msg_type := IPAC_MSGT_ID_GET, u := { get := { { 1, IPAC_IDTAG_UNITNAME } } } } /* receive IPA CCM message */ private function f_ccm_rx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT { select (ccm.msg_type) { case (IPAC_MSGT_PING) { f_ccm_tx(valueof(ts_IPA_PONG)); } case (IPAC_MSGT_ID_ACK) { f_ccm_tx(valueof(ts_IPA_ACK)); } case (IPAC_MSGT_ID_GET) { f_ccm_tx(f_ccm_make_id_resp(ccm)); } case else { log("Unknown/unsupported IPA CCM message type", ccm); } } } private function f_to_asp(IPA_RecvFrom ipa_rx) return ASP_IPA_Unitdata { var ASP_IPA_Unitdata ret := { streamId := ipa_rx.streamId, streamIdExt := ipa_rx.streamIdExt, payload := ipa_rx.msg } return ret; } private function f_from_asp(ConnectionId connId, ASP_IPA_Unitdata ipa_tx) return IPA_Send { var IPA_Send ret := valueof(t_IPA_Send(connId, ipa_tx.streamId, ipa_tx.payload, ipa_tx.streamIdExt)); return ret; } function main_client(charstring remote_host, PortNumber remote_port, charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT { g_mode := IPA_MODE_CLIENT; f_connect(remote_host, remote_port, local_host, local_port); ScanEvents(); } function main_server(charstring local_host, PortNumber local_port) runs on IPA_Emulation_CT { g_mode := IPA_MODE_SERVER; f_bind(local_host, local_port); ScanEvents(); } private function f_mgcp_to_user(octetstring msg) runs on IPA_Emulation_CT { var charstring msg_ch := oct2char(msg); if (g_is_bsc_mgw) { log("============"); log(msg_ch); IPA_MGCP_PORT.send(dec_MgcpCommand(msg_ch)); } else { IPA_MGCP_PORT.send(dec_MgcpResponse(msg_ch)); } } private function ScanEvents() runs on IPA_Emulation_CT { var IPA_RecvFrom ipa_rx; var ASP_IPA_Unitdata ipa_ud; var ASP_MTP3_TRANSFERreq mtp_req; var ASP_Event asp_evt; var MgcpCommand mgcp_cmd; var MgcpResponse mgcp_rsp; while (true) { alt { /* Received IPA -> up into SCCP stack */ [] IPA_PORT.receive(IPA_RecvFrom: ?) -> value ipa_rx { select (ipa_rx.streamId) { case (IPAC_PROTO_CCM) { var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg); log("CCM Rx:", ccm); f_ccm_rx(ccm); } case (IPAC_PROTO_SCCP) { var ASP_MTP3_TRANSFERind mtp; mtp := valueof(ts_MTP3_XFER_ind(0, ipa_rx.msg)); MTP3_SP_PORT.send(mtp); } case (IPAC_PROTO_MGCP_OLD) { f_mgcp_to_user(ipa_rx.msg); } case (IPAC_PROTO_OSMO) { select (ipa_rx.streamIdExt) { case (IPAC_PROTO_EXT_MGCP) { f_mgcp_to_user(ipa_rx.msg); } case else { IPA_SP_PORT.send(f_to_asp(ipa_rx)); } } } case else { IPA_SP_PORT.send(f_to_asp(ipa_rx)); } } } /* server only */ [] IPA_PORT.receive(ASP_Event:{connOpened:=?}) -> value asp_evt { log("IPA: Connected"); g_ipa_conn_id := asp_evt.connOpened.connId; if (g_mode == IPA_MODE_SERVER) { f_ccm_tx(valueof(ts_IPA_ID_GET)); } } [] IPA_PORT.receive(ASP_Event:{connClosed:=?}) -> value asp_evt { log("IPA: Closed"); g_ipa_conn_id := -1; self.stop; } /* Received SCCP -> down into IPA */ [] MTP3_SP_PORT.receive(ASP_MTP3_TRANSFERreq: ?) -> value mtp_req { var IPA_Send ipa_tx := valueof(t_IPA_Send(g_ipa_conn_id, IPAC_PROTO_SCCP, mtp_req.data)); IPA_PORT.send(ipa_tx); } /* Received MGCP -> down into IPA */ [] IPA_MGCP_PORT.receive(MgcpCommand:?) -> value mgcp_cmd { ipa_ud := { streamId := IPAC_PROTO_OSMO, streamIdExt := IPAC_PROTO_EXT_MGCP, payload := char2oct(enc_MgcpCommand(mgcp_cmd)) } IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud)); } [] IPA_MGCP_PORT.receive(MgcpResponse:?) -> value mgcp_rsp { ipa_ud := { streamId := IPAC_PROTO_OSMO, streamIdExt := IPAC_PROTO_EXT_MGCP, payload := char2oct(enc_MgcpResponse(mgcp_rsp)) } IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud)); } /* Received MISC (RSL/OML/CTRL) -> down into IPA */ [] IPA_SP_PORT.receive(ASP_IPA_Unitdata: ?) -> value ipa_ud { IPA_PORT.send(f_from_asp(g_ipa_conn_id, ipa_ud)); } } } } }