blob: e242390efc8b79dfb4a63821f728dbcc88e0237d [file] [log] [blame]
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +01001/* Interaction with the SCCP subsystem */
2/*
Holger Hans Peter Freyther56cb7292014-09-02 17:28:40 +02003 * (C) 2009-2014 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2009-2014 by On-Waves
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +01005 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
Harald Welte9af6ddf2011-01-01 15:25:50 +01008 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010010 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Harald Welte9af6ddf2011-01-01 15:25:50 +010015 * GNU Affero General Public License for more details.
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010016 *
Harald Welte9af6ddf2011-01-01 15:25:50 +010017 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010019 *
20 */
21
22#include <openbsc/gsm_data.h>
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010023#include <openbsc/osmo_bsc.h>
24#include <openbsc/osmo_bsc_grace.h>
Neels Hofmeyra42855f2017-02-23 21:49:55 +010025#include <openbsc/bsc_msc_data.h>
Holger Hans Peter Freytherc85ed4e2013-09-02 10:58:35 +020026#include <openbsc/gsm_04_80.h>
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010027#include <openbsc/debug.h>
Holger Hans Peter Freyther57d30482010-11-06 23:56:43 +010028#include <openbsc/ipaccess.h>
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +010029#include <openbsc/signal.h>
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010030
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010031#include <osmocom/core/talloc.h>
Harald Welted36ff762011-03-23 18:26:56 +010032#include <osmocom/gsm/gsm0808.h>
33#include <osmocom/gsm/protocol/gsm_08_08.h>
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010034
35#include <osmocom/sccp/sccp.h>
36
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +010037/* SCCP helper */
38#define SCCP_IT_TIMER 60
39
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010040static LLIST_HEAD(active_connections);
41
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +010042static void free_queued(struct osmo_bsc_sccp_con *conn)
43{
44 struct msgb *msg;
45
46 while (!llist_empty(&conn->sccp_queue)) {
47 /* this is not allowed to fail */
48 msg = msgb_dequeue(&conn->sccp_queue);
49 msgb_free(msg);
50 }
51
52 conn->sccp_queue_size = 0;
53}
54
55static void send_queued(struct osmo_bsc_sccp_con *conn)
56{
57 struct msgb *msg;
58
59 while (!llist_empty(&conn->sccp_queue)) {
60 /* this is not allowed to fail */
61 msg = msgb_dequeue(&conn->sccp_queue);
62 sccp_connection_write(conn->sccp, msg);
63 msgb_free(msg);
64 conn->sccp_queue_size -= 1;
65 }
66}
67
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010068static void msc_outgoing_sccp_data(struct sccp_connection *conn,
69 struct msgb *msg, unsigned int len)
70{
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010071 struct osmo_bsc_sccp_con *bsc_con =
72 (struct osmo_bsc_sccp_con *) conn->data_ctx;
73
74 bsc_handle_dt1(bsc_con, msg, len);
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010075}
76
77static void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
78{
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010079 struct osmo_bsc_sccp_con *con_data;
80
81 if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
82 con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
Harald Welte7e5bb622016-09-28 08:20:58 +080083 if (con_data->conn) {
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010084 LOGP(DMSC, LOGL_ERROR,
Holger Hans Peter Freyther74c7dc32011-07-20 14:30:28 +020085 "ERROR: The lchan is still associated.\n");
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010086 gsm0808_clear(con_data->conn);
Neels Hofmeyr42eb0142016-05-20 17:15:44 +020087 bsc_subscr_con_free(con_data->conn);
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010088 con_data->conn = NULL;
89 }
90
91 con_data->sccp = NULL;
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +010092 free_queued(con_data);
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010093 sccp_connection_free(conn);
94 bsc_delete_connection(con_data);
Holger Hans Peter Freyther933daaa2010-11-07 00:04:46 +010095 } else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
96 LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
97 con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
98
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +020099 osmo_timer_del(&con_data->sccp_cc_timeout);
100 osmo_timer_schedule(&con_data->sccp_it_timeout, SCCP_IT_TIMER, 0);
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100101
102 send_queued(con_data);
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +0100103 }
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100104}
105
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100106static void bsc_sccp_force_free(struct osmo_bsc_sccp_con *data)
107{
108 if (data->conn) {
109 gsm0808_clear(data->conn);
Neels Hofmeyr42eb0142016-05-20 17:15:44 +0200110 bsc_subscr_con_free(data->conn);
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100111 data->conn = NULL;
112 }
113
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100114 free_queued(data);
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100115 sccp_connection_force_free(data->sccp);
116 data->sccp = NULL;
117 bsc_delete_connection(data);
118}
119
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100120static void sccp_it_timeout(void *_data)
121{
122 struct osmo_bsc_sccp_con *data =
123 (struct osmo_bsc_sccp_con *) _data;
124
125 sccp_connection_send_it(data->sccp);
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200126 osmo_timer_schedule(&data->sccp_it_timeout, SCCP_IT_TIMER, 0);
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100127}
128
129static void sccp_cc_timeout(void *_data)
130{
131 struct osmo_bsc_sccp_con *data =
132 (struct osmo_bsc_sccp_con *) _data;
133
134 if (data->sccp->connection_state >= SCCP_CONNECTION_STATE_ESTABLISHED)
135 return;
136
137 LOGP(DMSC, LOGL_ERROR, "The connection was never established.\n");
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100138 bsc_sccp_force_free(data);
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100139}
140
Holger Hans Peter Freyther784ca9c2011-06-04 16:59:37 +0200141static void msc_sccp_write_ipa(struct sccp_connection *conn, struct msgb *msg,
142 void *global_ctx, void *ctx)
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100143{
Holger Hans Peter Freyther44e5dad2011-06-04 17:34:02 +0200144 struct bsc_msc_connection *msc_con;
145
146 if (conn) {
147 struct osmo_bsc_sccp_con *bsc_con = conn->data_ctx;
148 msc_con = bsc_con->msc->msc_con;
Holger Hans Peter Freyther56cb7292014-09-02 17:28:40 +0200149 if (bsc_con->send_ping) {
150 bsc_con->send_ping = 0;
151 msc_queue_write_with_ping(msc_con, msg, IPAC_PROTO_SCCP);
152 return;
153 }
Holger Hans Peter Freyther44e5dad2011-06-04 17:34:02 +0200154 } else {
155 msc_con = ctx;
156 }
157
158 msc_queue_write(msc_con, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100159}
160
161static int msc_sccp_accept(struct sccp_connection *connection, void *data)
162{
163 LOGP(DMSC, LOGL_DEBUG, "Rejecting incoming SCCP connection.\n");
164 return -1;
165}
166
167static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
168{
Neels Hofmeyra369e242017-02-23 21:57:23 +0100169 struct bsc_msc_data *msc = (struct bsc_msc_data *) msgb->cb[0];
Holger Hans Peter Freyther644b0bf2011-06-08 15:52:07 +0200170 return bsc_handle_udt(msc, msgb, length);
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100171}
172
Holger Hans Peter Freyther863a55d2010-11-10 09:31:41 +0100173int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
Holger Hans Peter Freyther45825862010-11-04 11:48:49 +0100174{
Holger Hans Peter Freyther863a55d2010-11-10 09:31:41 +0100175 struct sccp_connection *sccp = conn->sccp;
Holger Hans Peter Freytherca5c0222010-11-06 23:35:02 +0100176
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100177 if (sccp->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
178 LOGP(DMSC, LOGL_ERROR, "Connection closing, dropping packet on: %p\n", sccp);
Holger Hans Peter Freytherca5c0222010-11-06 23:35:02 +0100179 msgb_free(msg);
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100180 } else if (sccp->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED
181 && conn->sccp_queue_size == 0) {
182 sccp_connection_write(sccp, msg);
183 msgb_free(msg);
184 } else if (conn->sccp_queue_size > 10) {
185 LOGP(DMSC, LOGL_ERROR, "Connection closing, dropping packet on: %p\n", sccp);
186 msgb_free(msg);
187 } else {
188 LOGP(DMSC, LOGL_DEBUG, "Queueing packet on %p. Queue size: %d\n", sccp, conn->sccp_queue_size);
189 conn->sccp_queue_size += 1;
190 msgb_enqueue(&conn->sccp_queue, msg);
Holger Hans Peter Freytherca5c0222010-11-06 23:35:02 +0100191 }
192
Holger Hans Peter Freyther45825862010-11-04 11:48:49 +0100193 return 0;
194}
195
Jacob Erlbeck56595f82013-09-11 10:46:55 +0200196enum bsc_con bsc_create_new_connection(struct gsm_subscriber_connection *conn,
Neels Hofmeyra369e242017-02-23 21:57:23 +0100197 struct bsc_msc_data *msc, int send_ping)
Holger Hans Peter Freythercc48fb82010-11-05 11:10:46 +0100198{
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100199 struct osmo_bsc_sccp_con *bsc_con;
200 struct sccp_connection *sccp;
201
Holger Hans Peter Freyther354c87c2011-06-07 11:40:20 +0200202 /* This should not trigger */
Jacob Erlbeck56595f82013-09-11 10:46:55 +0200203 if (!msc || !msc->msc_con->is_authenticated) {
Holger Hans Peter Freyther354c87c2011-06-07 11:40:20 +0200204 LOGP(DMSC, LOGL_ERROR,
205 "How did this happen? MSC is not connected. Dropping.\n");
Jacob Erlbeck56595f82013-09-11 10:46:55 +0200206 return BSC_CON_REJECT_NO_LINK;
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100207 }
208
Holger Hans Peter Freyther3d119f12012-08-30 16:43:28 +0200209 if (!bsc_grace_allow_new_connection(conn->bts->network, conn->bts)) {
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100210 LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
Jacob Erlbeck56595f82013-09-11 10:46:55 +0200211 return BSC_CON_REJECT_RF_GRACE;
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100212 }
213
214 sccp = sccp_connection_socket();
215 if (!sccp) {
216 LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
Jacob Erlbeck56595f82013-09-11 10:46:55 +0200217 return BSC_CON_NO_MEM;
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100218 }
219
220 bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
221 if (!bsc_con) {
222 LOGP(DMSC, LOGL_ERROR, "Failed to allocate.\n");
223 sccp_connection_free(sccp);
Jacob Erlbeck56595f82013-09-11 10:46:55 +0200224 return BSC_CON_NO_MEM;
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100225 }
226
227 /* callbacks */
228 sccp->state_cb = msc_outgoing_sccp_state;
229 sccp->data_cb = msc_outgoing_sccp_data;
230 sccp->data_ctx = bsc_con;
231
Holger Hans Peter Freyther56cb7292014-09-02 17:28:40 +0200232 bsc_con->send_ping = send_ping;
233
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100234 /* prepare the timers */
Pablo Neira Ayuso51215762017-05-08 20:57:52 +0200235 osmo_timer_setup(&bsc_con->sccp_it_timeout, sccp_it_timeout, bsc_con);
236 osmo_timer_setup(&bsc_con->sccp_cc_timeout, sccp_cc_timeout, bsc_con);
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100237
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100238 INIT_LLIST_HEAD(&bsc_con->sccp_queue);
239
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100240 bsc_con->sccp = sccp;
Holger Hans Peter Freyther4cdb0502011-06-04 14:51:51 +0200241 bsc_con->msc = msc;
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100242 bsc_con->conn = conn;
Holger Hans Peter Freythercc98d182011-06-27 21:02:44 +0200243 llist_add_tail(&bsc_con->entry, &active_connections);
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100244 conn->sccp_con = bsc_con;
Jacob Erlbeck56595f82013-09-11 10:46:55 +0200245 return BSC_CON_SUCCESS;
Holger Hans Peter Freythercc48fb82010-11-05 11:10:46 +0100246}
247
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100248int bsc_open_connection(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100249{
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200250 osmo_timer_schedule(&conn->sccp_cc_timeout, 10, 0);
Holger Hans Peter Freythercf256d62010-11-08 18:49:23 +0100251 sccp_connection_connect(conn->sccp, &sccp_ssn_bssap, msg);
252 msgb_free(msg);
253 return 0;
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100254}
255
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100256int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100257{
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100258 if (!sccp)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100259 return 0;
260
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100261 if (sccp->conn)
262 LOGP(DMSC, LOGL_ERROR, "Should have been cleared.\n");
263
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100264 llist_del(&sccp->entry);
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200265 osmo_timer_del(&sccp->sccp_it_timeout);
266 osmo_timer_del(&sccp->sccp_cc_timeout);
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100267 talloc_free(sccp);
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100268 return 0;
269}
270
Jacob Erlbeck1b894022013-08-28 10:16:54 +0200271static void bsc_notify_msc_lost(struct osmo_bsc_sccp_con *con)
272{
273 struct gsm_subscriber_connection *conn = con->conn;
274
275 /* send USSD notification if string configured and con->data is set */
276 if (!conn)
277 return;
278
279 /* check for config string */
280 if (!con->msc->ussd_msc_lost_txt)
281 return;
282 if (con->msc->ussd_msc_lost_txt[0] == '\0')
283 return;
284
285 /* send USSD notification */
Neels Hofmeyr43273c62016-05-10 12:50:31 +0200286 bsc_send_ussd_notify(conn, 1, conn->sccp_con->msc->ussd_msc_lost_txt);
287 bsc_send_ussd_release_complete(conn);
Jacob Erlbeck1b894022013-08-28 10:16:54 +0200288}
289
290static void bsc_notify_and_close_conns(struct bsc_msc_connection *msc_con)
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100291{
292 struct osmo_bsc_sccp_con *con, *tmp;
293
Holger Hans Peter Freyther8c176cc2011-06-25 14:47:57 +0200294 llist_for_each_entry_safe(con, tmp, &active_connections, entry) {
Jacob Erlbeck1b894022013-08-28 10:16:54 +0200295 if (con->msc->msc_con != msc_con)
296 continue;
297
298 bsc_notify_msc_lost(con);
299 bsc_sccp_force_free(con);
Holger Hans Peter Freyther8c176cc2011-06-25 14:47:57 +0200300 }
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100301}
302
303static int handle_msc_signal(unsigned int subsys, unsigned int signal,
304 void *handler_data, void *signal_data)
305{
Holger Hans Peter Freyther0e412c72011-06-27 21:01:55 +0200306 struct msc_signal_data *msc;
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100307
308 if (subsys != SS_MSC)
309 return 0;
310
Holger Hans Peter Freyther0e412c72011-06-27 21:01:55 +0200311 msc = signal_data;
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100312 if (signal == S_MSC_LOST)
Jacob Erlbeck1b894022013-08-28 10:16:54 +0200313 bsc_notify_and_close_conns(msc->data->msc_con);
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100314
315 return 0;
316}
317
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100318int osmo_bsc_sccp_init(struct gsm_network *gsmnet)
319{
320 sccp_set_log_area(DSCCP);
321 sccp_system_init(msc_sccp_write_ipa, gsmnet);
322 sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100323 sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, gsmnet);
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100324
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200325 osmo_signal_register_handler(SS_MSC, handle_msc_signal, gsmnet);
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100326
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100327 return 0;
328}