blob: a30708b9866371097e8c7f595f1ca5ae8fe1f22d [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
42static void msc_outgoing_sccp_data(struct sccp_connection *conn,
43 struct msgb *msg, unsigned int len)
44{
45}
46
47static void msc_outgoing_sccp_state(struct sccp_connection *conn, int old_state)
48{
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010049 struct osmo_bsc_sccp_con *con_data;
50
51 if (conn->connection_state >= SCCP_CONNECTION_STATE_RELEASE_COMPLETE) {
52 con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
53 if(con_data->conn) {
54 LOGP(DMSC, LOGL_ERROR,
55 "ERROR: The lchan is still associated\n.");
56 gsm0808_clear(con_data->conn);
57 subscr_con_free(con_data->conn);
58 con_data->conn = NULL;
59 }
60
61 con_data->sccp = NULL;
62 sccp_connection_free(conn);
63 bsc_delete_connection(con_data);
Holger Hans Peter Freyther933daaa2010-11-07 00:04:46 +010064 } else if (conn->connection_state == SCCP_CONNECTION_STATE_ESTABLISHED) {
65 LOGP(DMSC, LOGL_DEBUG, "Connection established: %p\n", conn);
66 con_data = (struct osmo_bsc_sccp_con *) conn->data_ctx;
67
68 bsc_del_timer(&con_data->sccp_cc_timeout);
69 bsc_schedule_timer(&con_data->sccp_it_timeout, SCCP_IT_TIMER, 0);
Holger Hans Peter Freytheraf4b5fb2010-11-07 00:03:02 +010070 }
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +010071}
72
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +010073static void bsc_sccp_force_free(struct osmo_bsc_sccp_con *data)
74{
75 if (data->conn) {
76 gsm0808_clear(data->conn);
77 subscr_con_free(data->conn);
78 data->conn = NULL;
79 }
80
81 sccp_connection_force_free(data->sccp);
82 data->sccp = NULL;
83 bsc_delete_connection(data);
84}
85
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +010086static void sccp_it_timeout(void *_data)
87{
88 struct osmo_bsc_sccp_con *data =
89 (struct osmo_bsc_sccp_con *) _data;
90
91 sccp_connection_send_it(data->sccp);
92 bsc_schedule_timer(&data->sccp_it_timeout, SCCP_IT_TIMER, 0);
93}
94
95static void sccp_cc_timeout(void *_data)
96{
97 struct osmo_bsc_sccp_con *data =
98 (struct osmo_bsc_sccp_con *) _data;
99
100 if (data->sccp->connection_state >= SCCP_CONNECTION_STATE_ESTABLISHED)
101 return;
102
103 LOGP(DMSC, LOGL_ERROR, "The connection was never established.\n");
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100104 bsc_sccp_force_free(data);
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100105}
106
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100107static void msc_sccp_write_ipa(struct sccp_connection *conn, struct msgb *msg, void *data)
108{
Holger Hans Peter Freyther57d30482010-11-06 23:56:43 +0100109 struct gsm_network *net = (struct gsm_network *) data;
110 msc_queue_write(net->msc_data->msc_con, msg, IPAC_PROTO_SCCP);
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100111}
112
113static int msc_sccp_accept(struct sccp_connection *connection, void *data)
114{
115 LOGP(DMSC, LOGL_DEBUG, "Rejecting incoming SCCP connection.\n");
116 return -1;
117}
118
119static int msc_sccp_read(struct msgb *msgb, unsigned int length, void *data)
120{
121 struct bssmap_header *bs;
122
123 LOGP(DMSC, LOGL_DEBUG, "Incoming SCCP message ftom MSC: %s\n",
124 hexdump(msgb->l3h, length));
125
126 if (length < sizeof(*bs)) {
127 LOGP(DMSC, LOGL_ERROR, "The header is too short.\n");
128 return -1;
129 }
130
131 bs = (struct bssmap_header *) msgb->l3h;
132 if (bs->length < length - sizeof(*bs))
133 return -1;
134
135 switch (bs->type) {
136 case BSSAP_MSG_BSS_MANAGEMENT:
Holger Hans Peter Freyther1999cf12010-11-03 18:46:52 +0100137 LOGP(DMSC, LOGL_ERROR, "BSS management not implemented.\n");
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100138 break;
139 default:
140 LOGP(DMSC, LOGL_ERROR, "Unimplemented msg type: %d\n", bs->type);
141 }
142
143 return 0;
144}
145
Holger Hans Peter Freyther45825862010-11-04 11:48:49 +0100146int bsc_queue_for_msc(struct gsm_subscriber_connection *conn, struct msgb *msg)
147{
Holger Hans Peter Freytherca5c0222010-11-06 23:35:02 +0100148 struct sccp_connection *sccp = conn->sccp_con->sccp;
149
150 if (sccp->connection_state != SCCP_CONNECTION_STATE_ESTABLISHED) {
151 LOGP(DMSC, LOGL_ERROR, "The connection is not established.\n");
152 msgb_free(msg);
153 return -1;
154 }
155
156 sccp_connection_write(sccp, msg);
Holger Hans Peter Freyther45825862010-11-04 11:48:49 +0100157 msgb_free(msg);
158 return 0;
159}
160
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100161int bsc_create_new_connection(struct gsm_subscriber_connection *conn)
Holger Hans Peter Freythercc48fb82010-11-05 11:10:46 +0100162{
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100163 struct gsm_network *net;
164 struct osmo_bsc_sccp_con *bsc_con;
165 struct sccp_connection *sccp;
166
167 net = conn->bts->network;
168 if (!net->msc_data->msc_con->is_authenticated) {
169 LOGP(DMSC, LOGL_ERROR, "Not connected to a MSC. Not forwarding data.\n");
170 return -1;
171 }
172
173 if (!bsc_grace_allow_new_connection(net)) {
174 LOGP(DMSC, LOGL_NOTICE, "BSC in grace period. No new connections.\n");
175 return -1;
176 }
177
178 sccp = sccp_connection_socket();
179 if (!sccp) {
180 LOGP(DMSC, LOGL_ERROR, "Failed to allocate memory.\n");
181 return -ENOMEM;
182 }
183
184 bsc_con = talloc_zero(conn->bts, struct osmo_bsc_sccp_con);
185 if (!bsc_con) {
186 LOGP(DMSC, LOGL_ERROR, "Failed to allocate.\n");
187 sccp_connection_free(sccp);
188 return -1;
189 }
190
191 /* callbacks */
192 sccp->state_cb = msc_outgoing_sccp_state;
193 sccp->data_cb = msc_outgoing_sccp_data;
194 sccp->data_ctx = bsc_con;
195
Holger Hans Peter Freytherc97d9b42010-11-06 20:23:58 +0100196 /* prepare the timers */
197 bsc_con->sccp_it_timeout.cb = sccp_it_timeout;
198 bsc_con->sccp_it_timeout.data = bsc_con;
199 bsc_con->sccp_cc_timeout.cb = sccp_cc_timeout;
200 bsc_con->sccp_cc_timeout.data = bsc_con;
201
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100202 bsc_con->sccp = sccp;
203 bsc_con->msc_con = net->msc_data->msc_con;
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100204 bsc_con->conn = conn;
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100205 llist_add(&bsc_con->entry, &active_connections);
206 conn->sccp_con = bsc_con;
207 return 0;
Holger Hans Peter Freythercc48fb82010-11-05 11:10:46 +0100208}
209
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100210int bsc_open_connection(struct osmo_bsc_sccp_con *conn, struct msgb *msg)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100211{
Holger Hans Peter Freythercf256d62010-11-08 18:49:23 +0100212 bsc_schedule_timer(&conn->sccp_cc_timeout, 10, 0);
213 sccp_connection_connect(conn->sccp, &sccp_ssn_bssap, msg);
214 msgb_free(msg);
215 return 0;
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100216}
217
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100218int bsc_delete_connection(struct osmo_bsc_sccp_con *sccp)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100219{
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100220 if (!sccp)
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100221 return 0;
222
Holger Hans Peter Freyther7e901082010-11-06 20:15:17 +0100223 if (sccp->conn)
224 LOGP(DMSC, LOGL_ERROR, "Should have been cleared.\n");
225
Holger Hans Peter Freytherb8781d22010-11-06 18:08:43 +0100226 llist_del(&sccp->entry);
227 bsc_del_timer(&sccp->sccp_it_timeout);
228 bsc_del_timer(&sccp->sccp_cc_timeout);
229 talloc_free(sccp);
Holger Hans Peter Freyther9b17c762010-11-05 19:48:47 +0100230 return 0;
231}
232
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100233static void bsc_close_connections(struct bsc_msc_connection *msc_con)
234{
235 struct osmo_bsc_sccp_con *con, *tmp;
236
237 llist_for_each_entry_safe(con, tmp, &active_connections, entry)
238 bsc_sccp_force_free(con);
239}
240
241static int handle_msc_signal(unsigned int subsys, unsigned int signal,
242 void *handler_data, void *signal_data)
243{
244 struct osmo_msc_data *data;
245
246 if (subsys != SS_MSC)
247 return 0;
248
249 data = (struct osmo_msc_data *) signal_data;
250 if (signal == S_MSC_LOST)
251 bsc_close_connections(data->msc_con);
252
253 return 0;
254}
255
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100256int osmo_bsc_sccp_init(struct gsm_network *gsmnet)
257{
258 sccp_set_log_area(DSCCP);
259 sccp_system_init(msc_sccp_write_ipa, gsmnet);
260 sccp_connection_set_incoming(&sccp_ssn_bssap, msc_sccp_accept, NULL);
261 sccp_set_read(&sccp_ssn_bssap, msc_sccp_read, NULL);
262
Holger Hans Peter Freyther00f4cc22010-11-06 23:50:06 +0100263 register_signal_handler(SS_MSC, handle_msc_signal, gsmnet);
264
Holger Hans Peter Freytherf3d1ae72010-11-03 16:40:03 +0100265 return 0;
266}