blob: 74c3a08c1eca5cfbbbeb9cf0853a7d5451b97fff [file] [log] [blame]
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +01001/* Interaction with the SCCP subsystem */
2/*
3 * (C) 2009-2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2009-2010 by On-Waves
5 * All Rights Reserved
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (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
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 */
22
23#include <openbsc/gsm_data.h>
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010024#include <openbsc/osmo_bsc.h>
25#include <openbsc/osmo_bsc_grace.h>
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010026#include <openbsc/osmo_msc_data.h>
27#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
31#include <osmocore/gsm0808.h>
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +010032#include <osmocore/talloc.h>
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +010033#include <osmocore/protocol/gsm_08_08.h>
34
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;
83 if(con_data->conn) {
84 LOGP(DMSC, LOGL_ERROR,
85 "ERROR: The lchan is still associated\n.");
86 gsm0808_clear(con_data->conn);
87 subscr_con_free(con_data->conn);
88 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
99 bsc_del_timer(&con_data->sccp_cc_timeout);
100 bsc_schedule_timer(&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);
110 subscr_con_free(data->conn);
111 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);
126 bsc_schedule_timer(&data->sccp_it_timeout, SCCP_IT_TIMER, 0);
127}
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 Freytherf3d1ae72010-11-03 16:40:03 +0100141static void msc_sccp_write_ipa(struct sccp_connection *conn, struct msgb *msg, void *data)
142{
Holger Hans Peter Freyther57d30482010-11-06 23:56:43 +0100143 struct gsm_network *net = (struct gsm_network *) data;
144 msc_queue_write(net->msc_data->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 Freyther3485feb2010-11-09 23:28:33 +0100155 struct gsm_network *net = (struct gsm_network *) data;
156 return bsc_handle_udt(net, net->msc_data->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;
185 struct osmo_bsc_sccp_con *bsc_con;
186 struct sccp_connection *sccp;
187
188 net = conn->bts->network;
189 if (!net->msc_data->msc_con->is_authenticated) {
190 LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
191 return -1;
192 }
193
194 if (!bsc_grace_allow_new_connection(net)) {
195 LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
196 return -1;
197 }
198
199 sccp = sccp_connection_socket();
200 if (!sccp) {
201 LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
202 return -ENOMEM;
203 }
204
205 bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
206 if (!bsc_con) {
207 LOGP(DMSC, LOGL_ERROR, "Failed to allocate.\n");
208 sccp_connection_free(sccp);
209 return -1;
210 }
211
212 /* callbacks */
213 sccp->state_cb = msc_outgoing_sccp_state;
214 sccp->data_cb = msc_outgoing_sccp_data;
215 sccp->data_ctx = bsc_con;
216
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100217 /* prepare the timers */
218 bsc_con->sccp_it_timeout.cb = sccp_it_timeout;
219 bsc_con->sccp_it_timeout.data = bsc_con;
220 bsc_con->sccp_cc_timeout.cb = sccp_cc_timeout;
221 bsc_con->sccp_cc_timeout.data = bsc_con;
222
Holger Hans Peter Freytherb4e72f82010-11-15 10:31:53 +0100223 INIT_LLIST_HEAD(&bsc_con->sccp_queue);
224
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100225 bsc_con->sccp = sccp;
226 bsc_con->msc_con = net->msc_data->msc_con;
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100227 bsc_con->conn = conn;
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100228 llist_add(&bsc_con->entry, &active_connections);
229 conn->sccp_con = bsc_con;
230 return 0;
Holger Hans Peter Freythercc48fb82010-11-05 11:10:46 +0100231}
232
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100233int bsc_open_connection(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100234{
Holger Hans Peter Freythercf256d62010-11-08 18:49:23 +0100235 bsc_schedule_timer(&conn->sccp_cc_timeout, 10, 0);
236 sccp_connection_connect(conn->sccp, &sccp_ssn_bssap, msg);
237 msgb_free(msg);
238 return 0;
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100239}
240
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100241int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100242{
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100243 if (!sccp)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100244 return 0;
245
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100246 if (sccp->conn)
247 LOGP(DMSC, LOGL_ERROR, "Should have been cleared.\n");
248
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100249 llist_del(&sccp->entry);
250 bsc_del_timer(&sccp->sccp_it_timeout);
251 bsc_del_timer(&sccp->sccp_cc_timeout);
252 talloc_free(sccp);
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100253 return 0;
254}
255
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100256static void bsc_close_connections(struct bsc_msc_connection *msc_con)
257{
258 struct osmo_bsc_sccp_con *con, *tmp;
259
260 llist_for_each_entry_safe(con, tmp, &active_connections, entry)
261 bsc_sccp_force_free(con);
262}
263
264static int handle_msc_signal(unsigned int subsys, unsigned int signal,
265 void *handler_data, void *signal_data)
266{
267 struct osmo_msc_data *data;
268
269 if (subsys != SS_MSC)
270 return 0;
271
272 data = (struct osmo_msc_data *) signal_data;
273 if (signal == S_MSC_LOST)
274 bsc_close_connections(data->msc_con);
275
276 return 0;
277}
278
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100279int osmo_bsc_sccp_init(struct gsm_network *gsmnet)
280{
281 sccp_set_log_area(DSCCP);
282 sccp_system_init(msc_sccp_write_ipa, gsmnet);
283 sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
Holger Hans Peter Freyther3485feb2010-11-09 23:28:33 +0100284 sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, gsmnet);
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100285
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100286 register_signal_handler(SS_MSC, handle_msc_signal, gsmnet);
287
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100288 return 0;
289}