blob: 8418c9eb59bc682b72db08662030aef9475feb52 [file] [log] [blame]
Neels Hofmeyrc036b792018-11-29 22:37:51 +01001/* MSC RAN connection implementation */
Harald Welteb8b85a12016-06-17 00:06:42 +02002
3/*
Neels Hofmeyrdbaab502018-11-30 00:45:07 +01004 * (C) 2016-2018 by sysmocom s.m.f.c. <info@sysmocom.de>
Harald Welteb8b85a12016-06-17 00:06:42 +02005 * 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 Welte2483f1b2016-06-19 18:06:02 +020026#include <osmocom/core/signal.h>
Harald Welteb8b85a12016-06-17 00:06:42 +020027
Neels Hofmeyra8945ce2018-11-30 00:44:32 +010028#include <osmocom/msc/ran_conn.h>
Neels Hofmeyr90843962017-09-04 15:04:35 +020029#include <osmocom/msc/vlr.h>
30#include <osmocom/msc/debug.h>
31#include <osmocom/msc/transaction.h>
32#include <osmocom/msc/signal.h>
Harald Welte0df904d2018-12-03 11:00:04 +010033#include <osmocom/msc/sgs_iface.h>
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010034#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 Maierfbf66102017-04-09 12:32:51 +020038
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010039struct ran_conn *ran_conn_create_incoming(struct ran_peer *ran_peer, uint32_t sccp_conn_id)
Harald Welteb8b85a12016-06-17 00:06:42 +020040{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010041 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 Hofmeyre3d3dc62018-03-31 00:02:14 +020053}
54
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010055struct ran_conn *ran_conn_create_outgoing(struct ran_peer *ran_peer)
Neels Hofmeyre3d3dc62018-03-31 00:02:14 +020056{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010057 /* 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 Hofmeyre3d3dc62018-03-31 00:02:14 +020064
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010065 conn_id = next_outgoing_conn_id;
66 next_outgoing_conn_id++;
Neels Hofmeyre3d3dc62018-03-31 00:02:14 +020067
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010068 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 Hofmeyr84da6b12016-05-20 21:59:55 +020073 }
74 }
Harald Welteb8b85a12016-06-17 00:06:42 +020075
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010076 if (!already_used)
Neels Hofmeyr4068ab22018-04-01 20:55:54 +020077 break;
Neels Hofmeyre3d3dc62018-03-31 00:02:14 +020078 }
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010079 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 Hofmeyre3d3dc62018-03-31 00:02:14 +020083}
84
Neels Hofmeyr361e5712019-01-03 02:32:14 +010085/* Return statically allocated string of the ran_conn RAT type and id. */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010086const char *ran_conn_name(struct ran_conn *conn)
Daniel Willmann4e825b62018-02-15 10:33:26 +010087{
Neels Hofmeyr361e5712019-01-03 02:32:14 +010088 static char id[42];
89 int rc;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010090 const char *ran_peer_name;
Daniel Willmann4e825b62018-02-15 10:33:26 +010091
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010092 if (!conn)
93 return "ran_conn==NULL";
Daniel Willmann4e825b62018-02-15 10:33:26 +010094
Neels Hofmeyrc4628a32018-12-07 14:47:34 +010095 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 Hofmeyr361e5712019-01-03 02:32:14 +0100101 /* < 0 is error, == 0 is empty, >= size means truncation. Not really expecting this to catch on in any practical
102 * situation. */
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100103 if (rc <= 0 || rc >= sizeof(id))
104 return "conn-name-error";
Daniel Willmann4e825b62018-02-15 10:33:26 +0100105 return id;
106}
107
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100108int ran_conn_down_l2_co(struct ran_conn *conn, struct msgb *l3, bool initial)
Harald Welteb8b85a12016-06-17 00:06:42 +0200109{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100110 struct ran_peer_ev_ctx co = {
111 .conn_id = conn->sccp_conn_id,
112 .conn = conn,
113 .msg = l3,
Neels Hofmeyr93c74632018-04-02 23:10:28 +0200114 };
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100115 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 Hofmeyr93c74632018-04-02 23:10:28 +0200120}
121
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100122void ran_conn_msc_role_gone(struct ran_conn *conn, struct osmo_fsm_inst *msc_role)
Neels Hofmeyr4068ab22018-04-01 20:55:54 +0200123{
124 if (!conn)
125 return;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100126
127 if (conn->msc_role != msc_role)
Neels Hofmeyr4068ab22018-04-01 20:55:54 +0200128 return;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100129
130 conn->msc_role = NULL;
131 ran_conn_close(conn);
Neels Hofmeyr4068ab22018-04-01 20:55:54 +0200132}
133
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100134/* Regularly close the conn */
135void ran_conn_close(struct ran_conn *conn)
Neels Hofmeyr4068ab22018-04-01 20:55:54 +0200136{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100137 if (!conn)
Vadim Yanitskiy114bad82019-01-25 19:42:52 +0700138 return;
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100139 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 Yanitskiy114bad82019-01-25 19:42:52 +0700147 }
148
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100149 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 Yanitskiy114bad82019-01-25 19:42:52 +0700154
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100155 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 Yanitskiy114bad82019-01-25 19:42:52 +0700158}
159
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100160/* Same as ran_conn_close() but without sending any SCCP messages (e.g. after RESET) */
161void ran_conn_discard(struct ran_conn *conn)
Vadim Yanitskiy114bad82019-01-25 19:42:52 +0700162{
Neels Hofmeyrc4628a32018-12-07 14:47:34 +0100163 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 Yanitskiy114bad82019-01-25 19:42:52 +0700168}