Neels Hofmeyr | c036b79 | 2018-11-29 22:37:51 +0100 | [diff] [blame] | 1 | /* MSC RAN connection implementation */ |
Harald Welte | b8b85a1 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 2 | |
| 3 | /* |
Vadim Yanitskiy | 999a593 | 2023-05-18 17:22:26 +0700 | [diff] [blame] | 4 | * (C) 2016-2018 by sysmocom s.f.m.c. <info@sysmocom.de> |
Harald Welte | b8b85a1 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 5 | * All Rights Reserved |
| 6 | * |
| 7 | * Author: Neels Hofmeyr |
| 8 | * |
| 9 | * This program is free software; you can redistribute it and/or modify |
| 10 | * it under the terms of the GNU Affero General Public License as published by |
| 11 | * the Free Software Foundation; either version 3 of the License, or |
| 12 | * (at your option) any later version. |
| 13 | * |
| 14 | * This program is distributed in the hope that it will be useful, |
| 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 17 | * GNU Affero General Public License for more details. |
| 18 | * |
| 19 | * You should have received a copy of the GNU Affero General Public License |
| 20 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| 21 | * |
| 22 | */ |
| 23 | |
| 24 | #include <osmocom/core/logging.h> |
| 25 | #include <osmocom/core/fsm.h> |
Harald Welte | 2483f1b | 2016-06-19 18:06:02 +0200 | [diff] [blame] | 26 | #include <osmocom/core/signal.h> |
Harald Welte | b8b85a1 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 27 | |
Neels Hofmeyr | a8945ce | 2018-11-30 00:44:32 +0100 | [diff] [blame] | 28 | #include <osmocom/msc/ran_conn.h> |
Neels Hofmeyr | 9084396 | 2017-09-04 15:04:35 +0200 | [diff] [blame] | 29 | #include <osmocom/msc/vlr.h> |
| 30 | #include <osmocom/msc/debug.h> |
| 31 | #include <osmocom/msc/transaction.h> |
| 32 | #include <osmocom/msc/signal.h> |
Harald Welte | 0df904d | 2018-12-03 11:00:04 +0100 | [diff] [blame] | 33 | #include <osmocom/msc/sgs_iface.h> |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 34 | #include <osmocom/msc/ran_peer.h> |
| 35 | #include <osmocom/msc/sccp_ran.h> |
| 36 | #include <osmocom/msc/ran_infra.h> |
| 37 | #include <osmocom/msc/msub.h> |
Philipp Maier | fbf6610 | 2017-04-09 12:32:51 +0200 | [diff] [blame] | 38 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 39 | struct ran_conn *ran_conn_create_incoming(struct ran_peer *ran_peer, uint32_t sccp_conn_id) |
Harald Welte | b8b85a1 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 40 | { |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 41 | struct ran_conn *conn; |
| 42 | |
| 43 | conn = talloc(ran_peer, struct ran_conn); |
| 44 | OSMO_ASSERT(conn); |
| 45 | |
| 46 | *conn = (struct ran_conn){ |
| 47 | .ran_peer = ran_peer, |
| 48 | .sccp_conn_id = sccp_conn_id, |
| 49 | }; |
| 50 | |
| 51 | llist_add(&conn->entry, &ran_peer->sri->ran_conns); |
| 52 | return conn; |
Neels Hofmeyr | e3d3dc6 | 2018-03-31 00:02:14 +0200 | [diff] [blame] | 53 | } |
| 54 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 55 | struct ran_conn *ran_conn_create_outgoing(struct ran_peer *ran_peer) |
Neels Hofmeyr | e3d3dc6 | 2018-03-31 00:02:14 +0200 | [diff] [blame] | 56 | { |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 57 | /* FIXME use method being developed in gerrit id Ifd55c6b7ed2558ff072042079cf45f5068a971de */ |
| 58 | static uint32_t next_outgoing_conn_id = 2342; |
| 59 | uint32_t conn_id = 0; |
| 60 | int attempts = 1000; |
| 61 | bool already_used = true; |
| 62 | while (attempts--) { |
| 63 | struct ran_conn *conn; |
Neels Hofmeyr | e3d3dc6 | 2018-03-31 00:02:14 +0200 | [diff] [blame] | 64 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 65 | conn_id = next_outgoing_conn_id; |
| 66 | next_outgoing_conn_id++; |
Neels Hofmeyr | e3d3dc6 | 2018-03-31 00:02:14 +0200 | [diff] [blame] | 67 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 68 | already_used = false; |
| 69 | llist_for_each_entry(conn, &ran_peer->sri->ran_conns, entry) { |
| 70 | if (conn->sccp_conn_id == conn_id) { |
| 71 | already_used = true; |
| 72 | break; |
Neels Hofmeyr | 84da6b1 | 2016-05-20 21:59:55 +0200 | [diff] [blame] | 73 | } |
| 74 | } |
Harald Welte | b8b85a1 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 75 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 76 | if (!already_used) |
Neels Hofmeyr | 4068ab2 | 2018-04-01 20:55:54 +0200 | [diff] [blame] | 77 | break; |
Neels Hofmeyr | e3d3dc6 | 2018-03-31 00:02:14 +0200 | [diff] [blame] | 78 | } |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 79 | if (already_used) |
| 80 | return NULL; |
| 81 | LOG_RAN_PEER(ran_peer, LOGL_DEBUG, "Outgoing conn id: %u\n", conn_id); |
| 82 | return ran_conn_create_incoming(ran_peer, conn_id); |
Neels Hofmeyr | e3d3dc6 | 2018-03-31 00:02:14 +0200 | [diff] [blame] | 83 | } |
| 84 | |
Neels Hofmeyr | 361e571 | 2019-01-03 02:32:14 +0100 | [diff] [blame] | 85 | /* Return statically allocated string of the ran_conn RAT type and id. */ |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 86 | const char *ran_conn_name(struct ran_conn *conn) |
Daniel Willmann | 4e825b6 | 2018-02-15 10:33:26 +0100 | [diff] [blame] | 87 | { |
Neels Hofmeyr | 361e571 | 2019-01-03 02:32:14 +0100 | [diff] [blame] | 88 | static char id[42]; |
| 89 | int rc; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 90 | const char *ran_peer_name; |
Daniel Willmann | 4e825b6 | 2018-02-15 10:33:26 +0100 | [diff] [blame] | 91 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 92 | if (!conn) |
| 93 | return "ran_conn==NULL"; |
Daniel Willmann | 4e825b6 | 2018-02-15 10:33:26 +0100 | [diff] [blame] | 94 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 95 | if (!conn->ran_peer || !conn->ran_peer->sri || !conn->ran_peer->sri->ran) |
| 96 | ran_peer_name = "no-RAN-peer"; |
| 97 | else |
| 98 | ran_peer_name = osmo_rat_type_name(conn->ran_peer->sri->ran->type); |
| 99 | |
| 100 | rc = snprintf(id, sizeof(id), "%s-%u", ran_peer_name, conn->sccp_conn_id); |
Neels Hofmeyr | 361e571 | 2019-01-03 02:32:14 +0100 | [diff] [blame] | 101 | /* < 0 is error, == 0 is empty, >= size means truncation. Not really expecting this to catch on in any practical |
| 102 | * situation. */ |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 103 | if (rc <= 0 || rc >= sizeof(id)) |
| 104 | return "conn-name-error"; |
Daniel Willmann | 4e825b6 | 2018-02-15 10:33:26 +0100 | [diff] [blame] | 105 | return id; |
| 106 | } |
| 107 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 108 | int ran_conn_down_l2_co(struct ran_conn *conn, struct msgb *l3, bool initial) |
Harald Welte | b8b85a1 | 2016-06-17 00:06:42 +0200 | [diff] [blame] | 109 | { |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 110 | struct ran_peer_ev_ctx co = { |
| 111 | .conn_id = conn->sccp_conn_id, |
| 112 | .conn = conn, |
| 113 | .msg = l3, |
Neels Hofmeyr | 93c7463 | 2018-04-02 23:10:28 +0200 | [diff] [blame] | 114 | }; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 115 | if (!conn->ran_peer) |
| 116 | return -EIO; |
| 117 | return osmo_fsm_inst_dispatch(conn->ran_peer->fi, |
| 118 | initial ? RAN_PEER_EV_MSG_DOWN_CO_INITIAL : RAN_PEER_EV_MSG_DOWN_CO, |
| 119 | &co); |
Neels Hofmeyr | 93c7463 | 2018-04-02 23:10:28 +0200 | [diff] [blame] | 120 | } |
| 121 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 122 | void ran_conn_msc_role_gone(struct ran_conn *conn, struct osmo_fsm_inst *msc_role) |
Neels Hofmeyr | 4068ab2 | 2018-04-01 20:55:54 +0200 | [diff] [blame] | 123 | { |
| 124 | if (!conn) |
| 125 | return; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 126 | |
| 127 | if (conn->msc_role != msc_role) |
Neels Hofmeyr | 4068ab2 | 2018-04-01 20:55:54 +0200 | [diff] [blame] | 128 | return; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 129 | |
| 130 | conn->msc_role = NULL; |
| 131 | ran_conn_close(conn); |
Neels Hofmeyr | 4068ab2 | 2018-04-01 20:55:54 +0200 | [diff] [blame] | 132 | } |
| 133 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 134 | /* Regularly close the conn */ |
| 135 | void ran_conn_close(struct ran_conn *conn) |
Neels Hofmeyr | 4068ab2 | 2018-04-01 20:55:54 +0200 | [diff] [blame] | 136 | { |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 137 | if (!conn) |
Vadim Yanitskiy | 114bad8 | 2019-01-25 19:42:52 +0700 | [diff] [blame] | 138 | return; |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 139 | if (conn->closing) |
| 140 | return; |
| 141 | conn->closing = true; |
| 142 | LOG_RAN_PEER(conn->ran_peer, LOGL_DEBUG, "Closing %s\n", ran_conn_name(conn)); |
| 143 | |
| 144 | if (conn->msc_role) { |
| 145 | osmo_fsm_inst_dispatch(conn->msc_role, MSC_EV_FROM_RAN_CONN_RELEASED, NULL); |
| 146 | conn->msc_role = NULL; |
Vadim Yanitskiy | 114bad8 | 2019-01-25 19:42:52 +0700 | [diff] [blame] | 147 | } |
| 148 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 149 | if (conn->ran_peer) { |
| 150 | /* Todo: pass a useful SCCP cause? */ |
| 151 | sccp_ran_disconnect(conn->ran_peer->sri, conn->sccp_conn_id, 0); |
| 152 | conn->ran_peer = NULL; |
| 153 | } |
Vadim Yanitskiy | 114bad8 | 2019-01-25 19:42:52 +0700 | [diff] [blame] | 154 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 155 | LOG_RAN_PEER(conn->ran_peer, LOGL_DEBUG, "Deallocating %s\n", ran_conn_name(conn)); |
| 156 | llist_del(&conn->entry); |
| 157 | talloc_free(conn); |
Vadim Yanitskiy | 114bad8 | 2019-01-25 19:42:52 +0700 | [diff] [blame] | 158 | } |
| 159 | |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 160 | /* Same as ran_conn_close() but without sending any SCCP messages (e.g. after RESET) */ |
| 161 | void ran_conn_discard(struct ran_conn *conn) |
Vadim Yanitskiy | 114bad8 | 2019-01-25 19:42:52 +0700 | [diff] [blame] | 162 | { |
Neels Hofmeyr | c4628a3 | 2018-12-07 14:47:34 +0100 | [diff] [blame] | 163 | if (!conn) |
| 164 | return; |
| 165 | /* Make sure to drop dead and don't dispatch things like DISCONNECT requests on SCCP. */ |
| 166 | conn->ran_peer = NULL; |
| 167 | ran_conn_close(conn); |
Vadim Yanitskiy | 114bad8 | 2019-01-25 19:42:52 +0700 | [diff] [blame] | 168 | } |