blob: b9efaa4a4a7241540f735da6da38c3284daaaeea [file] [log] [blame]
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +01001/* The routines to handle the state */
2/*
3 * (C) 2010-2011 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 2010-2011 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 Affero General Public License as published by
9 * the Free Software Foundation, either version 3 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 Affero General Public License for more details.
16 *
17 * 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/>.
19 *
20 */
21
22#include <mtp_data.h>
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +010023#include <msc_connection.h>
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010024#include <mtp_level3.h>
25#include <bss_patch.h>
26#include <bssap_sccp.h>
27#include <bsc_data.h>
28#include <cellmgr_debug.h>
29#include <bsc_sccp.h>
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +010030#include <bsc_ussd.h>
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +010031#include <ss7_application.h>
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010032
Harald Welteff397ed2011-05-08 10:29:23 +020033#include <osmocom/core/talloc.h>
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010034
35#include <osmocom/vty/vty.h>
36#include <osmocom/vty/telnet_interface.h>
37
38#include <sys/stat.h>
39#include <sys/types.h>
40
41#include <fcntl.h>
42#include <signal.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46#include <assert.h>
47#include <unistd.h>
48
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +010049static void send_reset_ack(struct mtp_link_set *set, int sls);
50static void handle_local_sccp(struct mtp_link_set *set, struct msgb *inp, struct sccp_parse_result *res, int sls);
51static void send_local_rlsd(struct mtp_link_set *set, struct sccp_parse_result *res);
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +010052static void update_con_state(struct ss7_application *ss7, int rc, struct sccp_parse_result *result, struct msgb *msg, int from_msc, int sls);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010053
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010054/*
55 * methods called from the MTP Level3 part
56 */
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +010057void app_forward_sccp(struct ss7_application *app, struct msgb *_msg, int sls)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010058{
59 int rc;
60 struct sccp_parse_result result;
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +010061 struct msc_connection *msc;
62 struct mtp_link_set *set;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +010063
Holger Hans Peter Freyther2cdb73c2011-02-15 21:27:20 +010064 struct msgb *msg;
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010065
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +010066 set = app->route_src.set;
67 msc = app->route_dst.msc;
Holger Hans Peter Freytherdd32ae52011-02-10 20:07:30 +010068
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +010069 if (app->forward_only) {
70 msc_send_direct(msc, _msg);
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +010071 return;
72 }
Holger Hans Peter Freytherdd32ae52011-02-10 20:07:30 +010073
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010074 rc = bss_patch_filter_msg(_msg, &result);
75 if (rc == BSS_FILTER_RESET) {
76 LOGP(DMSC, LOGL_NOTICE, "Filtering BSS Reset from the BSC\n");
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +010077 msc_mgcp_reset(msc);
78 send_reset_ack(set, sls);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010079 return;
80 }
81
82 /* special responder */
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +010083 if (msc->msc_link_down) {
84 if (rc == BSS_FILTER_RESET_ACK && app->reset_count > 0) {
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010085 LOGP(DMSC, LOGL_ERROR, "Received reset ack for closing.\n");
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +010086 app_clear_connections(app);
87 app_resources_released(app);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010088 return;
89 }
90
91 if (rc != 0 && rc != BSS_FILTER_RLSD && rc != BSS_FILTER_RLC) {
92 LOGP(DMSC, LOGL_ERROR, "Ignoring unparsable msg during closedown.\n");
93 return;
94 }
95
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +010096 return handle_local_sccp(set, _msg, &result, sls);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +010097 }
98
99 /* update the connection state */
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +0100100 update_con_state(app, rc, &result, _msg, 0, sls);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100101
102 if (rc == BSS_FILTER_CLEAR_COMPL) {
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +0100103 send_local_rlsd(set, &result);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100104 } else if (rc == BSS_FILTER_RLC || rc == BSS_FILTER_RLSD) {
105 LOGP(DMSC, LOGL_DEBUG, "Not forwarding RLC/RLSD to the MSC.\n");
106 return;
107 }
108
Holger Hans Peter Freyther2cdb73c2011-02-15 21:27:20 +0100109 /* now send it out */
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +0100110 bsc_ussd_handle_out_msg(msc, &result, _msg);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100111
Holger Hans Peter Freyther2cdb73c2011-02-15 21:27:20 +0100112 msg = msgb_alloc_headroom(4096, 128, "SCCP to MSC");
113 if (!msg) {
114 LOGP(DMSC, LOGL_ERROR, "Failed to alloc MSC msg.\n");
115 return;
116 }
117
118 bss_rewrite_header_for_msc(rc, msg, _msg, &result);
Holger Hans Peter Freyther64b7d562011-02-16 23:00:50 +0100119 msc_send_direct(msc, msg);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100120}
121
122/*
123 * handle local message in close down mode
124 */
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100125static void handle_local_sccp(struct mtp_link_set *set, struct msgb *inpt, struct sccp_parse_result *result, int sls)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100126{
127 /* Handle msg with a reject */
128 if (inpt->l2h[0] == SCCP_MSG_TYPE_CR) {
129 struct sccp_connection_request *cr;
130 struct msgb *msg;
131
132 LOGP(DINP, LOGL_NOTICE, "Handling CR localy.\n");
133 cr = (struct sccp_connection_request *) inpt->l2h;
134 msg = create_sccp_refuse(&cr->source_local_reference);
135 if (msg) {
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100136 mtp_link_set_submit_sccp_data(set, sls, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100137 msgb_free(msg);
138 }
139 return;
140 } else if (inpt->l2h[0] == SCCP_MSG_TYPE_DT1 && result->data_len >= 3) {
141 struct active_sccp_con *con;
142 struct sccp_data_form1 *form1;
143 struct msgb *msg;
144
145 if (inpt->l3h[0] == 0 && inpt->l3h[2] == BSS_MAP_MSG_CLEAR_COMPLETE) {
146 LOGP(DINP, LOGL_DEBUG, "Received Clear Complete. Sending Release.\n");
147
148 form1 = (struct sccp_data_form1 *) inpt->l2h;
149
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100150 llist_for_each_entry(con, &set->app->sccp_connections, entry) {
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100151 if (memcmp(&form1->destination_local_reference,
152 &con->dst_ref, sizeof(con->dst_ref)) == 0) {
153 LOGP(DINP, LOGL_DEBUG, "Sending a release request now.\n");
154 msg = create_sccp_rlsd(&con->dst_ref, &con->src_ref);
155 if (msg) {
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100156 mtp_link_set_submit_sccp_data(set, con->sls, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100157 msgb_free(msg);
158 }
159 return;
160 }
161 }
162
163 LOGP(DINP, LOGL_ERROR, "Could not find connection for the Clear Command.\n");
164 }
165 } else if (inpt->l2h[0] == SCCP_MSG_TYPE_UDT && result->data_len >= 3) {
166 if (inpt->l3h[0] == 0 && inpt->l3h[2] == BSS_MAP_MSG_RESET_ACKNOWLEDGE) {
167 LOGP(DINP, LOGL_NOTICE, "Reset ACK. Connecting to the MSC again.\n");
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100168 app_resources_released(set->app);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100169 return;
170 }
171 }
172
173
174 /* Update the state, maybe the connection was released? */
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100175 update_con_state(set->app, 0, result, inpt, 0, sls);
176 if (llist_empty(&set->app->sccp_connections))
177 app_resources_released(set->app);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100178 return;
179}
180
Holger Hans Peter Freytherc5200fc2011-02-16 22:35:30 +0100181void app_clear_connections(struct ss7_application *app)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100182{
183 struct active_sccp_con *tmp, *con;
184
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100185 llist_for_each_entry_safe(con, tmp, &app->sccp_connections, entry) {
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100186 free_con(con);
187 }
188
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100189 link_clear_all(app->route_src.set);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100190}
191
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100192void app_resources_released(struct ss7_application *app)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100193{
Harald Welteff397ed2011-05-08 10:29:23 +0200194 osmo_timer_del(&app->reset_timeout);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100195}
196
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100197static void bsc_reset_timeout(void *_app)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100198{
199 struct msgb *msg;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100200 struct ss7_application *app = _app;
201 struct mtp_link_set *set = app->route_src.set;
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100202
203 /* no reset */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100204 if (app->reset_count > 0) {
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100205 LOGP(DINP, LOGL_ERROR, "The BSC did not answer the GSM08.08 reset. Restart MTP\n");
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100206 mtp_link_set_stop(app->route_src.set);
207 app_clear_connections(app);
208 link_reset_all(app->route_src.set);
209 app_resources_released(app);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100210 return;
211 }
212
213 msg = create_reset();
214 if (!msg) {
Harald Welteff397ed2011-05-08 10:29:23 +0200215 osmo_timer_schedule(&app->reset_timeout, 10, 0);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100216 return;
217 }
218
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100219 ++app->reset_count;
220 mtp_link_set_submit_sccp_data(set, -1, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100221 msgb_free(msg);
Harald Welteff397ed2011-05-08 10:29:23 +0200222 osmo_timer_schedule(&app->reset_timeout, 20, 0);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100223}
224
225/*
226 * We have lost the connection to the MSC. This is tough. We
227 * can not just bring down the MTP link as this will disable
228 * the BTS radio. We will have to do the following:
229 *
230 * 1.) Bring down all open SCCP connections. As this will close
231 * all radio resources
232 * 2.) Bring down all MGCP endpoints
233 * 3.) Clear the connection data.
234 *
235 * To make things worse we need to buffer the BSC messages... atfer
236 * everything has been sent we will try to connect to the MSC again.
237 *
238 * We will have to veriy that all connections are closed properly..
239 * this means we need to parse response message. In the case the
240 * MTP link is going down while we are sending. We will simply
241 * reconnect to the MSC.
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100242 *
243 * This could be called for the relay type and the cellmgr type, in case
244 * of the relay type the list of connections should be empty so we can
245 * avoid branching out.
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100246 */
Holger Hans Peter Freyther84ec8712011-02-15 20:01:47 +0100247void release_bsc_resources(struct msc_connection *fw)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100248{
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100249 struct ss7_application *app;
250 struct mtp_link_set *set;
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100251 struct active_sccp_con *tmp;
252 struct active_sccp_con *con;
253
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100254 if (!fw->app) {
255 LOGP(DINP, LOGL_ERROR, "No app assigned to the MSC connection %d/%s\n",
256 fw->nr, fw->name);
257 return;
258 }
259
260 app = fw->app;
261 set = app->route_src.set;
Harald Welteff397ed2011-05-08 10:29:23 +0200262 osmo_timer_del(&app->reset_timeout);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100263
264 /* 2. clear the MGCP endpoints */
Holger Hans Peter Freytherc5200fc2011-02-16 22:35:30 +0100265 msc_mgcp_reset(fw);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100266
267 /* 1. send BSSMAP Cleanup.. if we have any connection */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100268 llist_for_each_entry_safe(con, tmp, &app->sccp_connections, entry) {
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100269 if (!con->has_dst_ref) {
270 free_con(con);
271 continue;
272 }
273
274 struct msgb *msg = create_clear_command(&con->src_ref);
275 if (!msg)
276 continue;
277
278 /* wait for the clear commands */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100279 mtp_link_set_submit_sccp_data(set, con->sls, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100280 msgb_free(msg);
281 }
282
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100283 if (llist_empty(&app->sccp_connections)) {
284 app_resources_released(app);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100285 } else {
286 /* Send a reset in 20 seconds if we fail to bring everything down */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100287 app->reset_timeout.cb = bsc_reset_timeout;
288 app->reset_timeout.data = app;
289 app->reset_count = 0;
Harald Welteff397ed2011-05-08 10:29:23 +0200290 osmo_timer_schedule(&app->reset_timeout, 10, 0);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100291 }
292}
293
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100294/**
295 * update the connection state and helpers below
296 */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100297static void send_rlc_to_bsc(struct mtp_link_set *set,
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100298 unsigned int sls, struct sccp_source_reference *src,
299 struct sccp_source_reference *dst)
300{
301 struct msgb *msg;
302
303 msg = create_sccp_rlc(src, dst);
304 if (!msg)
305 return;
306
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100307 mtp_link_set_submit_sccp_data(set, sls, msg->l2h, msgb_l2len(msg));
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100308 msgb_free(msg);
309}
310
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100311static void handle_rlsd(struct ss7_application *app, struct sccp_connection_released *rlsd, int from_msc)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100312{
313 struct active_sccp_con *con;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100314 struct msc_connection *msc = app->route_dst.msc;
315 struct mtp_link_set *set = app->route_src.set;
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100316
317 if (from_msc) {
318 /* search for a connection, reverse src/dest for MSC */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100319 con = find_con_by_src_dest_ref(app, &rlsd->destination_local_reference,
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100320 &rlsd->source_local_reference);
321 if (con) {
322 LOGP(DINP, LOGL_DEBUG, "RLSD conn still alive: local: 0x%x remote: 0x%x\n",
323 sccp_src_ref_to_int(&con->src_ref),
324 sccp_src_ref_to_int(&con->dst_ref));
325 con->released_from_msc = 1;
326 } else {
327 /* send RLC */
328 LOGP(DINP, LOGL_DEBUG, "Sending RLC for MSC: src: 0x%x dst: 0x%x\n",
329 sccp_src_ref_to_int(&rlsd->destination_local_reference),
330 sccp_src_ref_to_int(&rlsd->source_local_reference));
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100331 msc_send_rlc(msc, &rlsd->destination_local_reference,
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100332 &rlsd->source_local_reference);
333 }
334 } else {
335 unsigned int sls = -1;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100336 con = find_con_by_src_dest_ref(app, &rlsd->source_local_reference,
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100337 &rlsd->destination_local_reference);
338 if (con) {
339 LOGP(DINP, LOGL_DEBUG, "Timeout on BSC. Sending RLC. src: 0x%x\n",
340 sccp_src_ref_to_int(&rlsd->source_local_reference));
341
342 if (con->released_from_msc)
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100343 msc_send_rlc(msc, &con->src_ref, &con->dst_ref);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100344 sls = con->sls;
345 free_con(con);
346 } else {
347 LOGP(DINP, LOGL_ERROR, "Timeout on BSC for unknown connection. src: 0x%x\n",
348 sccp_src_ref_to_int(&rlsd->source_local_reference));
349 }
350
351 /* now send a rlc back to the BSC */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100352 send_rlc_to_bsc(set, sls, &rlsd->destination_local_reference, &rlsd->source_local_reference);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100353 }
354}
355
356/**
357 * Update connection state and also send message.....
358 *
359 * RLSD from MSC:
360 * 1.) We don't find the entry in this case we will send a
361 * forged RLC to the MSC and we are done.
362 * 2.) We find an entry in this we will need to register that
363 * we need to send a RLC and we are done for now.
364 * RLSD from BSC:
365 * 1.) This is an error we are ignoring for now.
366 * RLC from BSC:
367 * 1.) We are destroying the connection, we might send a RLC to
368 * the MSC if we are waiting for one.
369 */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100370void update_con_state(struct ss7_application *app, int rc, struct sccp_parse_result *res, struct msgb *msg, int from_msc, int sls)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100371{
372 struct active_sccp_con *con;
373 struct sccp_connection_request *cr;
374 struct sccp_connection_confirm *cc;
375 struct sccp_connection_release_complete *rlc;
376 struct sccp_connection_refused *cref;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100377 struct msc_connection *msc;
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100378
379 /* was the header okay? */
380 if (rc < 0)
381 return;
382
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100383 msc = app->route_dst.msc;
384
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100385 /* the header was size checked */
386 switch (msg->l2h[0]) {
387 case SCCP_MSG_TYPE_CR:
388 if (from_msc) {
389 LOGP(DMSC, LOGL_ERROR, "CR from MSC is not handled.\n");
390 return;
391 }
392
393 cr = (struct sccp_connection_request *) msg->l2h;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100394 con = find_con_by_src_ref(app, &cr->source_local_reference);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100395 if (con) {
396 LOGP(DINP, LOGL_ERROR, "Duplicate SRC reference for: 0x%x. Reusing\n",
397 sccp_src_ref_to_int(&con->src_ref));
398 free_con(con);
399 }
400
401 con = talloc_zero(NULL, struct active_sccp_con);
402 if (!con) {
403 LOGP(DINP, LOGL_ERROR, "Failed to allocate\n");
404 return;
405 }
406
407 con->src_ref = cr->source_local_reference;
408 con->sls = sls;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100409 con->app = app;
410 llist_add_tail(&con->entry, &app->sccp_connections);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100411 LOGP(DINP, LOGL_DEBUG, "Adding CR: local ref: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
412 break;
413 case SCCP_MSG_TYPE_CC:
414 if (!from_msc) {
415 LOGP(DINP, LOGL_ERROR, "CC from BSC is not handled.\n");
416 return;
417 }
418
419 cc = (struct sccp_connection_confirm *) msg->l2h;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100420 con = find_con_by_src_ref(app, &cc->destination_local_reference);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100421 if (con) {
422 con->dst_ref = cc->source_local_reference;
423 con->has_dst_ref = 1;
424 LOGP(DINP, LOGL_DEBUG, "Updating CC: local: 0x%x remote: 0x%x\n",
425 sccp_src_ref_to_int(&con->src_ref), sccp_src_ref_to_int(&con->dst_ref));
426 return;
427 }
428
429 LOGP(DINP, LOGL_ERROR, "CCed connection can not be found: 0x%x\n",
430 sccp_src_ref_to_int(&cc->destination_local_reference));
431 break;
432 case SCCP_MSG_TYPE_CREF:
433 if (!from_msc) {
434 LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n");
435 return;
436 }
437
438 cref = (struct sccp_connection_refused *) msg->l2h;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100439 con = find_con_by_src_ref(app, &cref->destination_local_reference);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100440 if (con) {
441 LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
442 free_con(con);
443 return;
444 }
445
446 LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n");
447 break;
448 case SCCP_MSG_TYPE_RLSD:
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100449 handle_rlsd(app, (struct sccp_connection_released *) msg->l2h, from_msc);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100450 break;
451 case SCCP_MSG_TYPE_RLC:
452 if (from_msc) {
453 LOGP(DINP, LOGL_ERROR, "RLC from MSC is wrong.\n");
454 return;
455 }
456
457 rlc = (struct sccp_connection_release_complete *) msg->l2h;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100458 con = find_con_by_src_dest_ref(app, &rlc->source_local_reference,
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100459 &rlc->destination_local_reference);
460 if (con) {
461 LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
462 if (con->released_from_msc)
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100463 msc_send_rlc(msc, &con->src_ref, &con->dst_ref);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100464 free_con(con);
465 return;
466 }
467
468 LOGP(DINP, LOGL_ERROR, "RLC can not be found. 0x%x 0x%x\n",
469 sccp_src_ref_to_int(&rlc->source_local_reference),
470 sccp_src_ref_to_int(&rlc->destination_local_reference));
471 break;
472 }
473}
474
475static void send_local_rlsd_for_con(void *data)
476{
477 struct msgb *rlsd;
478 struct active_sccp_con *con = (struct active_sccp_con *) data;
Holger Hans Peter Freyther4c9dd162011-02-23 16:11:21 +0100479 struct mtp_link_set *set;
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100480
481 /* try again in three seconds */
482 con->rlc_timeout.data = con;
483 con->rlc_timeout.cb = send_local_rlsd_for_con;
Harald Welteff397ed2011-05-08 10:29:23 +0200484 osmo_timer_schedule(&con->rlc_timeout, 3, 0);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100485
486 /* we send this to the BSC so we need to switch src and dest */
487 rlsd = create_sccp_rlsd(&con->dst_ref, &con->src_ref);
488 if (!rlsd)
489 return;
490
491 ++con->rls_tries;
Holger Hans Peter Freyther4c9dd162011-02-23 16:11:21 +0100492
493 set = con->app->route_src.set;
494 if (!set) {
495 LOGP(DINP, LOGL_DEBUG, "Application %d has no linkset\n", con->app->nr);
496 return;
497 }
498
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100499 LOGP(DINP, LOGL_DEBUG, "Sending RLSD for 0x%x the %d time.\n",
500 sccp_src_ref_to_int(&con->src_ref), con->rls_tries);
Holger Hans Peter Freyther4c9dd162011-02-23 16:11:21 +0100501 mtp_link_set_submit_sccp_data(set, con->sls, rlsd->l2h, msgb_l2len(rlsd));
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100502 msgb_free(rlsd);
503}
504
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100505static void send_local_rlsd(struct mtp_link_set *set, struct sccp_parse_result *res)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100506{
507 struct active_sccp_con *con;
508
509 LOGP(DINP, LOGL_DEBUG, "Received GSM Clear Complete. Sending RLSD locally.\n");
510
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100511 con = find_con_by_dest_ref(set->app, res->destination_local_reference);
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100512 if (!con)
513 return;
514 con->rls_tries = 0;
515 send_local_rlsd_for_con(con);
516}
517
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100518static void send_reset_ack(struct mtp_link_set *set, int sls)
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100519{
520 static const uint8_t reset_ack[] = {
521 0x09, 0x00, 0x03, 0x05, 0x7, 0x02, 0x42, 0xfe,
522 0x02, 0x42, 0xfe, 0x03,
523 0x00, 0x01, 0x31
524 };
525
Holger Hans Peter Freytherd062f832011-02-23 16:58:15 +0100526 mtp_link_set_submit_sccp_data(set, sls, reset_ack, sizeof(reset_ack));
Holger Hans Peter Freyther43b015a2011-02-10 17:35:35 +0100527}
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100528
529void msc_dispatch_sccp(struct msc_connection *msc, struct msgb *msg)
530{
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100531 struct mtp_link_set *set;
532
533 if (!msc->app) {
534 LOGP(DINP, LOGL_ERROR, "The MSC Connection %d/%s has no app assigned.\n",
535 msc->nr, msc->name);
536 return;
537 }
538
539
540 set = msc->app->route_src.set;
541
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100542 /* we can not forward it right now */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100543 if (msc->app->forward_only) {
544 if (!set->sccp_up)
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100545 return;
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100546 mtp_link_set_submit_sccp_data(set, -1,
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100547 msg->l2h, msgb_l2len(msg));
548 } else {
549 struct sccp_parse_result result;
550 int rc;
551
552 rc = bss_patch_filter_msg(msg, &result);
553
554 if (rc == BSS_FILTER_RESET_ACK) {
555 LOGP(DMSC, LOGL_NOTICE, "Filtering reset ack from the MSC\n");
556 } else if (rc == BSS_FILTER_RLSD) {
557 LOGP(DMSC, LOGL_DEBUG, "Filtering RLSD from the MSC\n");
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100558 update_con_state(msc->app, rc, &result, msg, 1, 0);
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100559 } else if (rc == BSS_FILTER_RLC) {
560 /* if we receive this we have forwarded a RLSD to the network */
561 LOGP(DMSC, LOGL_ERROR, "RLC from the network. BAD!\n");
562 } else if (rc == BSS_FILTER_CLEAR_COMPL) {
563 LOGP(DMSC, LOGL_ERROR, "Clear Complete from the network.\n");
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100564 } else if (set->sccp_up) {
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100565 unsigned int sls;
566
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100567 update_con_state(msc->app, rc, &result, msg, 1, 0);
568 sls = sls_for_src_ref(msc->app, result.destination_local_reference);
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100569
570 /* Check for Location Update Accept */
571 bsc_ussd_handle_in_msg(msc, &result, msg);
572
573 /* patch a possible PC */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100574 bss_rewrite_header_to_bsc(msg, set->opc, set->dpc);
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100575
576 /* we can not forward it right now */
Holger Hans Peter Freythera7bc3aa2011-02-16 16:12:07 +0100577 mtp_link_set_submit_sccp_data(set, sls,
Holger Hans Peter Freyther3d4d8c72011-02-15 21:14:09 +0100578 msg->l2h, msgb_l2len(msg));
579 }
580 }
581}