blob: 30dea0f4f86857f86511e7692806667ef6e41446 [file] [log] [blame]
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +01001/* Interaction with the SCCP subsystem */
2/*
Holger Hans Peter Freyther8ec49522011-08-15 15:53:00 +02003 * (C) 2009-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2009-2011 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>
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010025#include <openbsc/osmo_msc_data.h>
26#include <openbsc/debug.h>
Holger Hans Peter Freyther57d30482010-11-06 23:56:43 +010027#include <openbsc/ipaccess.h>
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +010028#include <openbsc/signal.h>
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010029
Pablo Neira Ayuso136f4532011-03-22 16:47:59 +010030#include <osmocom/core/talloc.h>
Harald Welted36ff762011-03-23 18:26:56 +010031#include <osmocom/gsm/gsm0808.h>
32#include <osmocom/gsm/protocol/gsm_08_08.h>
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010033
34#include <osmocom/sccp/sccp.h>
35
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +010036/* SCCP helper */
37#define SCCP_IT_TIMER 60
38
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010039static LLIST_HEAD(active_connections);
40
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +010041static void free_queued(struct osmo_bsc_sccp_con *conn)
42{
43 struct msgb *msg;
44
45 while (!llist_empty(&conn->sccp_queue)) {
46 /* this is not allowed to fail */
47 msg = msgb_dequeue(&conn->sccp_queue);
48 msgb_free(msg);
49 }
50
51 conn->sccp_queue_size = 0;
52}
53
54static void send_queued(struct osmo_bsc_sccp_con *conn)
55{
56 struct msgb *msg;
57
58 while (!llist_empty(&conn->sccp_queue)) {
59 /* this is not allowed to fail */
60 msg = msgb_dequeue(&conn->sccp_queue);
61 sccp_connection_write(conn->sccp, msg);
62 msgb_free(msg);
63 conn->sccp_queue_size -= 1;
64 }
65}
66
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010067static void msc_outgoing_sccp_data(struct sccp_connection *conn,
68 struct msgb *msg, unsigned int len)
69{
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +010070 struct osmo_bsc_sccp_con *bsc_con =
71 (struct osmo_bsc_sccp_con *) conn->data_ctx;
72
73 bsc_handle_dt1(bsc_con, msg, len);
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010074}
75
76static void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
77{
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010078 struct osmo_bsc_sccp_con *con_data;
79
80 if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
81 con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
82 if(con_data->conn) {
83 LOGP(DMSC, LOGL_ERROR,
Holger Hans Peter Freyther74c7dc32011-07-20 14:30:28 +020084 "ERROR: The lchan is still associated.\n");
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010085 gsm0808_clear(con_data->conn);
86 subscr_con_free(con_data->conn);
87 con_data->conn = NULL;
88 }
89
90 con_data->sccp = NULL;
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +010091 free_queued(con_data);
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010092 sccp_connection_free(conn);
93 bsc_delete_connection(con_data);
Holger Hans Peter Freyther933daaa2010-11-07 00:04:46 +010094 } else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
95 LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
96 con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
97
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +020098 osmo_timer_del(&con_data->sccp_cc_timeout);
99 osmo_timer_schedule(&con_data->sccp_it_timeout, SCCP_IT_TIMER, 0);
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100100
101 send_queued(con_data);
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +0100102 }
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100103}
104
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100105static void bsc_sccp_force_free(struct osmo_bsc_sccp_con *data)
106{
107 if (data->conn) {
108 gsm0808_clear(data->conn);
109 subscr_con_free(data->conn);
110 data->conn = NULL;
111 }
112
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100113 free_queued(data);
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100114 sccp_connection_force_free(data->sccp);
115 data->sccp = NULL;
116 bsc_delete_connection(data);
117}
118
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100119static void sccp_it_timeout(void *_data)
120{
121 struct osmo_bsc_sccp_con *data =
122 (struct osmo_bsc_sccp_con *) _data;
123
124 sccp_connection_send_it(data->sccp);
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200125 osmo_timer_schedule(&data->sccp_it_timeout, SCCP_IT_TIMER, 0);
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100126}
127
128static void sccp_cc_timeout(void *_data)
129{
130 struct osmo_bsc_sccp_con *data =
131 (struct osmo_bsc_sccp_con *) _data;
132
133 if (data->sccp->connection_state >= SCCP_CONNECTION_STATE_ESTABLISHED)
134 return;
135
136 LOGP(DMSC, LOGL_ERROR, "The connection was never established.\n");
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100137 bsc_sccp_force_free(data);
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100138}
139
Holger Hans Peter Freyther784ca9c2011-06-04 16:59:37 +0200140static void msc_sccp_write_ipa(struct sccp_connection *conn, struct msgb *msg,
141 void *global_ctx, void *ctx)
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100142{
Holger Hans Peter Freyther784ca9c2011-06-04 16:59:37 +0200143 struct gsm_network *net = (struct gsm_network *) global_ctx;
Holger Hans Peter Freyther8ec49522011-08-15 15:53:00 +0200144 msc_queue_write(net->bsc_data->msc.msc_con, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100145}
146
147static int msc_sccp_accept(struct sccp_connection *connection, void *data)
148{
149 LOGP(DMSC, LOGL_DEBUG, "Rejecting incoming SCCP connection.\n");
150 return -1;
151}
152
153static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
154{
Holger Hans Peter Freytherf31a4a42011-06-04 13:20:04 +0200155 struct osmo_msc_data *msc = (struct osmo_msc_data *) msgb->cb[0];
156 return bsc_handle_udt(msc->network, msc->msc_con, msgb, length);
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100157}
158
Holger Hans Peter Freyther863a55d2010-11-10 09:31:41 +0100159int bsc_queue_for_msc(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
Holger Hans Peter Freyther45825862010-11-04 11:48:49 +0100160{
Holger Hans Peter Freyther863a55d2010-11-10 09:31:41 +0100161 struct sccp_connection *sccp = conn->sccp;
Holger Hans Peter Freytherca5c0222010-11-06 23:35:02 +0100162
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100163 if (sccp->connection_state > SCCP_CONNECTION_STATE_ESTABLISHED) {
164 LOGP(DMSC, LOGL_ERROR, "Connection closing, dropping packet on: %p\n", sccp);
Holger Hans Peter Freytherca5c0222010-11-06 23:35:02 +0100165 msgb_free(msg);
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100166 } else if (sccp->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED
167 && conn->sccp_queue_size == 0) {
168 sccp_connection_write(sccp, msg);
169 msgb_free(msg);
170 } else if (conn->sccp_queue_size > 10) {
171 LOGP(DMSC, LOGL_ERROR, "Connection closing, dropping packet on: %p\n", sccp);
172 msgb_free(msg);
173 } else {
174 LOGP(DMSC, LOGL_DEBUG, "Queueing packet on %p. Queue size: %d\n", sccp, conn->sccp_queue_size);
175 conn->sccp_queue_size += 1;
176 msgb_enqueue(&conn->sccp_queue, msg);
Holger Hans Peter Freytherca5c0222010-11-06 23:35:02 +0100177 }
178
Holger Hans Peter Freyther45825862010-11-04 11:48:49 +0100179 return 0;
180}
181
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100182int bsc_create_new_connection(struct gsm_subscriber_connection *conn)
Holger Hans Peter Freythercc48fb82010-11-05 11:10:46 +0100183{
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100184 struct gsm_network *net;
Holger Hans Peter Freytherf31a4a42011-06-04 13:20:04 +0200185 struct bsc_msc_connection *msc;
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100186 struct osmo_bsc_sccp_con *bsc_con;
187 struct sccp_connection *sccp;
188
189 net = conn->bts->network;
Holger Hans Peter Freytherf31a4a42011-06-04 13:20:04 +0200190 msc = net->bsc_data->msc.msc_con;
191 if (!msc->is_authenticated) {
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100192 LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
193 return -1;
194 }
195
196 if (!bsc_grace_allow_new_connection(net)) {
197 LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
198 return -1;
199 }
200
201 sccp = sccp_connection_socket();
202 if (!sccp) {
203 LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
204 return -ENOMEM;
205 }
206
207 bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
208 if (!bsc_con) {
209 LOGP(DMSC, LOGL_ERROR, "Failed to allocate.\n");
210 sccp_connection_free(sccp);
211 return -1;
212 }
213
214 /* callbacks */
215 sccp->state_cb = msc_outgoing_sccp_state;
216 sccp->data_cb = msc_outgoing_sccp_data;
217 sccp->data_ctx = bsc_con;
218
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100219 /* prepare the timers */
220 bsc_con->sccp_it_timeout.cb = sccp_it_timeout;
221 bsc_con->sccp_it_timeout.data = bsc_con;
222 bsc_con->sccp_cc_timeout.cb = sccp_cc_timeout;
223 bsc_con->sccp_cc_timeout.data = bsc_con;
224
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100225 INIT_LLIST_HEAD(&bsc_con->sccp_queue);
226
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100227 bsc_con->sccp = sccp;
Holger Hans Peter Freytherf31a4a42011-06-04 13:20:04 +0200228 bsc_con->msc_con = msc;
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100229 bsc_con->conn = conn;
Holger Hans Peter Freythercc98d182011-06-27 21:02:44 +0200230 llist_add_tail(&bsc_con->entry, &active_connections);
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100231 conn->sccp_con = bsc_con;
232 return 0;
Holger Hans Peter Freythercc48fb82010-11-05 11:10:46 +0100233}
234
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100235int bsc_open_connection(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100236{
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200237 osmo_timer_schedule(&conn->sccp_cc_timeout, 10, 0);
Holger Hans Peter Freythercf256d62010-11-08 18:49:23 +0100238 sccp_connection_connect(conn->sccp, &sccp_ssn_bssap, msg);
239 msgb_free(msg);
240 return 0;
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100241}
242
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100243int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100244{
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100245 if (!sccp)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100246 return 0;
247
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100248 if (sccp->conn)
249 LOGP(DMSC, LOGL_ERROR, "Should have been cleared.\n");
250
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100251 llist_del(&sccp->entry);
Pablo Neira Ayusobf540cb2011-05-06 12:11:06 +0200252 osmo_timer_del(&sccp->sccp_it_timeout);
253 osmo_timer_del(&sccp->sccp_cc_timeout);
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100254 talloc_free(sccp);
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100255 return 0;
256}
257
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100258static void bsc_close_connections(struct bsc_msc_connection *msc_con)
259{
260 struct osmo_bsc_sccp_con *con, *tmp;
261
262 llist_for_each_entry_safe(con, tmp, &active_connections, entry)
263 bsc_sccp_force_free(con);
264}
265
266static int handle_msc_signal(unsigned int subsys, unsigned int signal,
267 void *handler_data, void *signal_data)
268{
Holger Hans Peter Freyther0e412c72011-06-27 21:01:55 +0200269 struct msc_signal_data *msc;
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100270
271 if (subsys != SS_MSC)
272 return 0;
273
Holger Hans Peter Freyther0e412c72011-06-27 21:01:55 +0200274 msc = signal_data;
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100275 if (signal == S_MSC_LOST)
Holger Hans Peter Freyther0e412c72011-06-27 21:01:55 +0200276 bsc_close_connections(msc->data->msc_con);
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100277
278 return 0;
279}
280
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100281int osmo_bsc_sccp_init(struct gsm_network *gsmnet)
282{
283 sccp_set_log_area(DSCCP);
284 sccp_system_init(msc_sccp_write_ipa, gsmnet);
285 sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100286 sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, gsmnet);
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100287
Pablo Neira Ayusobbc5b992011-05-06 12:12:31 +0200288 osmo_signal_register_handler(SS_MSC, handle_msc_signal, gsmnet);
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100289
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100290 return 0;
291}