Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 1 | module MSC_ConnectionHandler { |
| 2 | |
Harald Welte | 34b5a95 | 2019-05-27 11:54:11 +0200 | [diff] [blame] | 3 | /* (C) 2017-2019 Harald Welte <laforge@gnumonks.org> |
| 4 | * All rights reserved. |
| 5 | * |
| 6 | * Released under the terms of GNU General Public License, Version 2 or |
| 7 | * (at your option) any later version. |
| 8 | * |
| 9 | * SPDX-License-Identifier: GPL-2.0-or-later |
| 10 | */ |
| 11 | |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 12 | import from General_Types all; |
| 13 | import from Osmocom_Types all; |
| 14 | import from SCCPasp_Types all; |
| 15 | import from BSSAP_Types all; |
Harald Welte | 004f5fb | 2017-12-16 17:54:40 +0100 | [diff] [blame] | 16 | import from BSSAP_CodecPort all; |
Harald Welte | 6811d10 | 2019-04-14 22:23:14 +0200 | [diff] [blame] | 17 | import from RAN_Emulation all; |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 18 | import from BSSMAP_Templates all; |
| 19 | |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 20 | import from MGCP_Types all; |
| 21 | import from MGCP_Templates all; |
| 22 | import from SDP_Types all; |
| 23 | |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 24 | type function void_fn_msc(charstring id) runs on MSC_ConnHdlr; |
| 25 | |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 26 | /* this component represents a single subscriber connection at the MSC. |
Harald Welte | 6811d10 | 2019-04-14 22:23:14 +0200 | [diff] [blame] | 27 | * There is a 1:1 mapping between SCCP connections and RAN_ConnHdlr components. |
| 28 | * We inherit all component variables, ports, functions, ... from RAN_ConnHdlr */ |
| 29 | type component MSC_ConnHdlr extends RAN_ConnHdlr { |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 30 | /* SCCP Connecction Identifier for the underlying SCCP connection */ |
| 31 | var integer g_sccp_conn_id; |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 32 | |
| 33 | var MSC_State g_state := MSC_STATE_NONE; |
| 34 | var MgcpEndpoint g_ep_name; |
| 35 | var MgcpCallId g_call_id; |
| 36 | var MgcpConnectionId g_mgcp_conn_id; |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 37 | var MSC_TestHdlrParams g_pars; |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 38 | } |
| 39 | |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 40 | type record MSC_TestHdlrParams { |
| 41 | integer connection_id, |
| 42 | integer e1_timeslot |
| 43 | }; |
| 44 | |
| 45 | /* helper function to create and connect a MSC_ConnHdlr component */ |
| 46 | private function f_connect_handler(inout MSC_ConnHdlr vc_conn) runs on RAN_Emulation_CT { |
| 47 | /* connect client BSSAP port to BSSAP dispatcher */ |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 48 | connect(vc_conn:BSSAP, self:CLIENT); |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 49 | } |
| 50 | |
| 51 | private function f_msc_start_handler(void_fn_msc fn, charstring id, template (omit) MSC_TestHdlrParams pars := omit) |
| 52 | runs on RAN_Emulation_CT return MSC_ConnHdlr { |
| 53 | var MSC_ConnHdlr vc_conn; |
| 54 | vc_conn := MSC_ConnHdlr.create(id); |
| 55 | f_connect_handler(vc_conn); |
| 56 | vc_conn.start(f_handler_init(fn, id, pars)); |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 57 | return vc_conn; |
| 58 | } |
| 59 | |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 60 | /* first function inside ConnHdlr component; sets g_pars + starts function */ |
| 61 | private function f_handler_init(void_fn_msc fn, charstring id, template (omit) MSC_TestHdlrParams pars := omit) |
| 62 | runs on MSC_ConnHdlr { |
| 63 | if (isvalue(pars)) { |
| 64 | g_pars := valueof(pars); |
| 65 | } |
| 66 | fn.apply(id); |
| 67 | } |
| 68 | |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 69 | /* Callback function from general BSSMAP_Emulation whenever a connectionless |
| 70 | * BSSMAP message arrives. Can retunr a PDU_BSSAP that should be sent in return */ |
| 71 | private function UnitdataCallback(PDU_BSSAP bssap) |
Harald Welte | 6811d10 | 2019-04-14 22:23:14 +0200 | [diff] [blame] | 72 | runs on RAN_Emulation_CT return template PDU_BSSAP { |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 73 | var template PDU_BSSAP resp := omit; |
| 74 | |
| 75 | if (match(bssap, tr_BSSMAP_Reset)) { |
| 76 | resp := ts_BSSMAP_ResetAck; |
| 77 | } |
| 78 | |
| 79 | return resp; |
| 80 | } |
| 81 | |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 82 | /* Callback function from general BSSMAP_Emulation whenever a new incoming |
| 83 | * SCCP connection arrivces. Must create + start a new component */ |
| 84 | private function CreateCallback_generic(void_fn_msc fn, BSSAP_N_CONNECT_ind conn_ind, charstring id) |
| 85 | runs on RAN_Emulation_CT return RAN_ConnHdlr { |
| 86 | var MSC_ConnHdlr vc_conn; |
| 87 | var MSC_TestHdlrParams pars; |
| 88 | pars.connection_id := conn_ind.connectionId; |
| 89 | pars.e1_timeslot := g_next_e1_ts; |
| 90 | |
| 91 | /* Create a new RAN_ConnHdlr component */ |
| 92 | vc_conn := f_msc_start_handler(fn, g_ran_id & "-Conn-" & int2str(conn_ind.connectionId), pars); |
| 93 | |
| 94 | /* increment next E1 timeslot */ |
| 95 | g_next_e1_ts := g_next_e1_ts + 1; |
| 96 | return vc_conn; |
| 97 | } |
| 98 | |
Harald Welte | 6811d10 | 2019-04-14 22:23:14 +0200 | [diff] [blame] | 99 | const RanOps MSC_RanOps := { |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 100 | create_cb := omit, |
Harald Welte | 0b47606 | 2018-01-21 19:07:32 +0100 | [diff] [blame] | 101 | unitdata_cb := refers(UnitdataCallback), |
| 102 | decode_dtap := false, |
Daniel Willmann | aa17059 | 2018-10-24 18:33:10 +0200 | [diff] [blame] | 103 | role_ms := false, |
Harald Welte | 2fce788 | 2019-04-15 11:48:05 +0200 | [diff] [blame] | 104 | protocol := RAN_PROTOCOL_BSSAP, |
Pau Espin Pedrol | c6b78ff | 2019-06-06 15:58:17 +0200 | [diff] [blame] | 105 | transport := BSSAP_TRANSPORT_AoIP, |
Pau Espin Pedrol | c6a53db | 2019-05-20 19:31:47 +0200 | [diff] [blame] | 106 | use_osmux := false, |
Daniel Willmann | aa17059 | 2018-10-24 18:33:10 +0200 | [diff] [blame] | 107 | sccp_addr_local := omit, |
| 108 | sccp_addr_peer := omit |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 109 | } |
| 110 | |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 111 | type enumerated MSC_State { |
| 112 | MSC_STATE_NONE, |
| 113 | MSC_STATE_WAIT_ASS_COMPL, |
| 114 | MSC_STATE_WAIT_CRCX_ACK, |
| 115 | MSC_STATE_WAIT_MDCX_ACK, |
| 116 | MSC_STATE_WAIT_CLEAR_COMPL, |
| 117 | MSC_STATE_WAIT_DLCX_ACK |
| 118 | } |
| 119 | |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 120 | /* Callback function from general BSSMAP_Emulation whenever a new incoming |
| 121 | * SCCP connection arrivces. Must create + start a new component */ |
| 122 | function CreateCallback_establish_fully(BSSAP_N_CONNECT_ind conn_ind, charstring id) |
| 123 | runs on RAN_Emulation_CT return RAN_ConnHdlr { |
| 124 | return CreateCallback_generic(refers(f_msc_establish_fully), conn_ind, id); |
| 125 | } |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 126 | /* main function processing various incoming events */ |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 127 | function f_msc_establish_fully(charstring id) runs on MSC_ConnHdlr { |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 128 | var MgcpResponse mgcp_rsp; |
Harald Welte | 98f1f41 | 2017-11-25 01:21:49 +0100 | [diff] [blame] | 129 | timer T := 5.0; |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 130 | |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 131 | g_sccp_conn_id := g_pars.connection_id; |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 132 | g_call_id := f_mgcp_alloc_call_id(); |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 133 | g_ep_name := hex2str(int2hex(g_pars.e1_timeslot, 1)) & "@mgw"; |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 134 | |
Harald Welte | 98f1f41 | 2017-11-25 01:21:49 +0100 | [diff] [blame] | 135 | /* we just accepted an incoming SCCP connection, start guard timer */ |
| 136 | T.start; |
| 137 | |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 138 | while (true) { |
| 139 | var PDU_BSSAP bssap; |
| 140 | alt { |
| 141 | /* new SCCP-level connection indication from BSC */ |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 142 | [g_state == MSC_STATE_NONE] BSSAP.receive(tr_BSSMAP_ComplL3) -> value bssap { |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 143 | /* respond with ASSIGNMENT CMD */ |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 144 | g_state := MSC_STATE_WAIT_ASS_COMPL; |
Pau Espin Pedrol | d1d4953 | 2019-06-10 18:09:16 +0200 | [diff] [blame] | 145 | BSSAP.send(ts_BSSMAP_AssignmentReq(ts_BSSMAP_IE_CIC(0, g_pars.e1_timeslot))); |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 146 | } |
Harald Welte | cc7e4dc | 2017-12-14 21:55:10 +0100 | [diff] [blame] | 147 | [g_state == MSC_STATE_WAIT_ASS_COMPL] BSSAP.receive(tr_BSSMAP_AssignmentComplete(?,*)) { |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 148 | /* FIXME: Send MGCP CRCX */ |
| 149 | g_state := MSC_STATE_WAIT_CRCX_ACK; |
| 150 | var MgcpTransId trans_id := f_mgcp_alloc_tid(); |
| 151 | //template SDP_Message sdp := omit; |
| 152 | BSSAP.send(ts_CRCX(trans_id, g_ep_name, "recvonly", g_call_id)); //, sdp)); |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 153 | } |
| 154 | /* |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 155 | [] BSSAP.receive(tr_BSSMAP_AssignmentFail) { |
| 156 | } |
| 157 | */ |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 158 | |
| 159 | /* receive CRCX ACK: transmit MDCX */ |
| 160 | [g_state == MSC_STATE_WAIT_CRCX_ACK] BSSAP.receive(tr_CRCX_ACK) -> value mgcp_rsp { |
| 161 | /* extract connection ID */ |
Harald Welte | 4c11d56 | 2017-11-24 23:39:00 +0100 | [diff] [blame] | 162 | g_mgcp_conn_id := f_MgcpResp_extract_conn_id(mgcp_rsp); |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 163 | g_state := MSC_STATE_WAIT_MDCX_ACK; |
| 164 | var MgcpTransId trans_id := f_mgcp_alloc_tid(); |
| 165 | BSSAP.send(ts_MDCX(trans_id, g_ep_name, "sendrecv", g_call_id, g_mgcp_conn_id)); |
| 166 | } |
| 167 | |
| 168 | /* receive MDCX ACK: wait + transmit CLEAR COMMAND */ |
| 169 | [g_state == MSC_STATE_WAIT_MDCX_ACK] BSSAP.receive(tr_CRCX_ACK) -> value mgcp_rsp { |
| 170 | g_state := MSC_STATE_WAIT_CLEAR_COMPL |
Harald Welte | 8ac9f02 | 2017-11-24 23:48:14 +0100 | [diff] [blame] | 171 | BSSAP.send(ts_BSSMAP_ClearCommand(9)); /* Cause: call control */ |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | /* CLEAR COMPLETE from BSS (response to CLEAR COMMAND) */ |
Harald Welte | 11e7808 | 2017-11-24 23:42:07 +0100 | [diff] [blame] | 175 | [g_state == MSC_STATE_WAIT_CLEAR_COMPL] BSSAP.receive(tr_BSSMAP_ClearComplete) { |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 176 | /* send DLCX */ |
| 177 | g_state := MSC_STATE_WAIT_DLCX_ACK; |
| 178 | var MgcpTransId trans_id := f_mgcp_alloc_tid(); |
| 179 | BSSAP.send(ts_DLCX(trans_id, g_ep_name, g_call_id)); |
| 180 | } |
| 181 | |
| 182 | [g_state == MSC_STATE_WAIT_DLCX_ACK] BSSAP.receive(tr_DLCX_ACK) { |
Harald Welte | 6811d10 | 2019-04-14 22:23:14 +0200 | [diff] [blame] | 183 | BSSAP.send(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ); |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 184 | setverdict(pass); |
| 185 | self.stop; |
| 186 | } |
| 187 | |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 188 | /* TODO: CLEAR REQUEST from BSS */ |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 189 | |
Harald Welte | 6811d10 | 2019-04-14 22:23:14 +0200 | [diff] [blame] | 190 | [] BSSAP.receive(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_IND) { |
Harald Welte | c82eef4 | 2017-11-24 20:40:12 +0100 | [diff] [blame] | 191 | setverdict(fail); |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 192 | self.stop; |
| 193 | } |
| 194 | |
| 195 | [] BSSAP.receive(PDU_BSSAP:?) -> value bssap { |
| 196 | log("Received unhandled SCCP-CO: ", bssap); |
| 197 | } |
Harald Welte | 98f1f41 | 2017-11-25 01:21:49 +0100 | [diff] [blame] | 198 | |
| 199 | /* Guard timer has expired, close connection */ |
| 200 | [] T.timeout { |
Harald Welte | 6811d10 | 2019-04-14 22:23:14 +0200 | [diff] [blame] | 201 | BSSAP.send(RAN_Conn_Prim:MSC_CONN_PRIM_DISC_REQ); |
Harald Welte | 458fd37 | 2018-03-21 11:26:23 +0100 | [diff] [blame] | 202 | setverdict(fail, "Timeout of guard timer"); |
Harald Welte | 98f1f41 | 2017-11-25 01:21:49 +0100 | [diff] [blame] | 203 | self.stop; |
| 204 | } |
| 205 | |
Harald Welte | 365f4ed | 2017-11-23 00:00:43 +0100 | [diff] [blame] | 206 | } |
| 207 | } |
| 208 | } |
| 209 | |
| 210 | } |