From 2d86affc8cbff74dd71f0467388608cc78fafa95 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 17 Apr 2018 11:23:04 +0200 Subject: IPA: Fix wrong CCM ID_ACK logic; disable CCM on CTRL interface Our TTCN3 implementation of the IPA multiplex with CCM handshaking has been based on some wrong assumptions about the protocol logic. To make the code stricter, we * send an ID_ACK immediately after connecting TCP in a client * separate client and server CCM responder logic * always respond with ID_ACK to ID_RESP (we accept any identity) Also, as the Osmocom CTRL interface uses an IPA multiplex but no CCM, we introduce a boolean variable (and function argument) to clearly enable/disable CCM support in a given IPA_Emulation component. The CTRL_Adapter has been modified to use this flag to disable CCM. This also removes the need of cherry-picking "HACK: Work around IPA CCM bug in OsmoBSC" Change-Id: I304535d28a165f76a0a140dc0a15dd81a9db28c8 from the laforge/bsc-workaround branch. Change-Id: I6d9eaf0d69457caacc03b9049a8bc57976480617 --- library/IPA_Emulation.ttcnpp | 62 ++++++++++++++++++++++++++++++++------- library/Osmocom_CTRL_Adapter.ttcn | 3 +- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/library/IPA_Emulation.ttcnpp b/library/IPA_Emulation.ttcnpp index c3cfe8d1..be64dd17 100644 --- a/library/IPA_Emulation.ttcnpp +++ b/library/IPA_Emulation.ttcnpp @@ -164,6 +164,7 @@ type component IPA_Emulation_CT { var boolean g_is_bsc_mgw; var IpaMode g_mode; + var boolean g_ccm_enabled; var IPA_CCM_Parameters g_ccm_pars := c_IPA_default_ccm_pars; } @@ -331,19 +332,39 @@ template PDU_IPA_CCM ts_IPA_ID_GET := { } /* receive IPA CCM message */ -private function f_ccm_rx(PDU_IPA_CCM ccm) runs on IPA_Emulation_CT { +private function f_ccm_rx_client(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)); + f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_ID_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_ccm_rx_server(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) { + /* the IPA server should at some point receive an ID_ACK from the client, + * in case of RSL/OML from nanoBTS, this is actually the first message after + * the TCP connection is established. Other implementations may differ. + * We currently ignore it completely - but actually we should make sure that + * one ID_ACK is received by the server at some point */ + } case (IPAC_MSGT_ID_RESP) { log("IPA ID RESP: ", ccm.u.resp); + /* acknowledge any identity that the client may have sent */ + f_ccm_tx(valueof(ts_IPA_ACK)); } case else { log("Unknown/unsupported IPA CCM message type", ccm); @@ -377,16 +398,24 @@ private function f_from_rsl(IPL4asp_Types.ConnectionId connId, ASP_RSL_Unitdata /* main function to use for a client-side IPA implementation */ function main_client(charstring remote_host, IPL4asp_Types.PortNumber remote_port, charstring local_host, IPL4asp_Types.PortNumber local_port, - IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars) runs on IPA_Emulation_CT { + IPA_CCM_Parameters ccm_pars := c_IPA_default_ccm_pars, + boolean ccm_enabled := true) runs on IPA_Emulation_CT { g_mode := IPA_MODE_CLIENT; + g_ccm_enabled := ccm_enabled; f_connect(remote_host, remote_port, local_host, local_port, ccm_pars); + if (g_ccm_enabled) { + /* we're a client: Send ID_ACK immediately after connect */ + f_ccm_tx(valueof(ts_IPA_ACK)); + } f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)); ScanEvents(); } /* main function to use for a server-side IPA implementation */ -function main_server(charstring local_host, IPL4asp_Types.PortNumber local_port) runs on IPA_Emulation_CT { +function main_server(charstring local_host, IPL4asp_Types.PortNumber local_port, + boolean ccm_enabled := true) runs on IPA_Emulation_CT { g_mode := IPA_MODE_SERVER; + g_ccm_enabled := ccm_enabled; f_bind(local_host, local_port); ScanEvents(); } @@ -454,13 +483,24 @@ private function ScanEvents() runs on IPA_Emulation_CT { 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); + [g_ccm_enabled] IPA_PORT.receive(IPA_RecvFrom:{?,IPAC_PROTO_CCM,omit,?}) -> value ipa_rx { + var PDU_IPA_CCM ccm := dec_PDU_IPA_CCM(ipa_rx.msg); + log("CCM Rx:", ccm); + select (g_mode) { + case (IPA_MODE_CLIENT) { + f_ccm_rx_client(ccm); + } + case (IPA_MODE_SERVER) { + f_ccm_rx_server(ccm); + } + case else { + setverdict(fail, "Unknown mode"); + self.stop; + } } + } + [] IPA_PORT.receive(IPA_RecvFrom:?) -> value ipa_rx { + select (ipa_rx.streamId) { #ifdef IPA_EMULATION_SCCP case (IPAC_PROTO_SCCP) { var ASP_MTP3_TRANSFERind mtp; @@ -513,7 +553,7 @@ private function ScanEvents() runs on IPA_Emulation_CT { log("IPA: Connected"); g_ipa_conn_id := asp_evt.connOpened.connId; f_send_IPA_EVT(t_ASP_IPA_EVT_UD(ASP_IPA_EVENT_UP)); - if (g_mode == IPA_MODE_SERVER) { + if (g_mode == IPA_MODE_SERVER and g_ccm_enabled) { f_ccm_tx(valueof(ts_IPA_ID_GET)); } } diff --git a/library/Osmocom_CTRL_Adapter.ttcn b/library/Osmocom_CTRL_Adapter.ttcn index 9baa6a2c..22195c89 100644 --- a/library/Osmocom_CTRL_Adapter.ttcn +++ b/library/Osmocom_CTRL_Adapter.ttcn @@ -29,7 +29,8 @@ runs on CTRL_Adapter_CT { map(vc_CTRL_IPA:IPA_PORT, system:IPA_CODEC_PT); connect(vc_CTRL_IPA:IPA_CTRL_PORT, self:IPA_CTRL); - vc_CTRL_IPA.start(IPA_Emulation.main_client(bsc_host, bsc_port, "", -1)); + vc_CTRL_IPA.start(IPA_Emulation.main_client(bsc_host, bsc_port, "", -1, + c_IPA_default_ccm_pars, false)); /* wait for IPA CTRL link to connect and send UP */ T.start; -- cgit v1.2.3