blob: 26777716a7807ad01561a82951cb1f4b48ba6454 [file] [log] [blame]
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001/* Bloated main routine, refactor */
2/*
3 * (C) 2010 by Holger Hans Peter Freyther <zecke@selfish.org>
4 * (C) 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 <mtp_data.h>
Holger Hans Peter Freytherb38b33b2010-11-26 21:21:04 +010024#include <mtp_level3.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080025#include <mtp_pcap.h>
26#include <thread.h>
27#include <bss_patch.h>
28#include <bssap_sccp.h>
29#include <bsc_data.h>
30#include <snmp_mtp.h>
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080031#include <cellmgr_debug.h>
Holger Hans Peter Freytherb3e10682010-09-30 01:57:45 +080032#include <bsc_sccp.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080033
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080034#include <osmocore/talloc.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080035
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080036#include <osmocom/vty/vty.h>
Holger Hans Peter Freytherfdae5c92010-09-30 01:01:03 +080037#include <osmocom/vty/telnet_interface.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080038
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080039#include <sys/stat.h>
40#include <sys/types.h>
41
42#include <fcntl.h>
43#include <signal.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <assert.h>
48#include <unistd.h>
49
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080050#ifndef _GNU_SOURCE
51#define _GNU_SOURCE
52#endif
53#include <getopt.h>
54
Holger Hans Peter Freyther4bbfa272010-09-15 20:53:56 +080055#undef PACKAGE_NAME
56#undef PACKAGE_VERSION
57#undef PACKAGE_BUGREPORT
58#undef PACKAGE_TARNAME
59#undef PACKAGE_STRING
60#include <cellmgr_config.h>
61
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080062static struct log_target *stderr_target;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080063
64static char *config = "cellmgr_ng.cfg";
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080065static int flood = 0;
66static struct timer_list flood_timer;
67
Holger Hans Peter Freyther7942abc2010-09-30 00:34:46 +080068struct bsc_data bsc;
69extern void cell_vty_init(void);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080070
71static void send_reset_ack(struct mtp_link *link, int sls);
72static void bsc_resources_released(struct bsc_data *bsc);
73static void handle_local_sccp(struct mtp_link *link, struct msgb *inp, struct sccp_parse_result *res, int sls);
74static void clear_connections(struct bsc_data *bsc);
75static void send_local_rlsd(struct mtp_link *link, struct sccp_parse_result *res);
76static void start_flood();
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080077
Holger Hans Peter Freyther48f4d632010-08-04 04:51:38 +080078int link_c7_init(struct link_data *data) __attribute__((__weak__));
79
80int link_c7_init(struct link_data *data)
81{
82 return -1;
83}
84
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080085/* send a RSIP to the MGCP GW */
86static void mgcp_reset(struct bsc_data *bsc)
87{
88 static const char mgcp_reset[] = {
89 "RSIP 1 13@mgw MGCP 1.0\r\n"
90 };
91
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +080092 mgcp_forward(bsc, (const uint8_t *) mgcp_reset, strlen(mgcp_reset));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080093}
94
95/*
96 * methods called from the MTP Level3 part
97 */
98void mtp_link_submit(struct mtp_link *link, struct msgb *msg)
99{
100 bsc.link.write(&bsc.link, msg);
101}
102
103void mtp_link_restart(struct mtp_link *link)
104{
105 LOGP(DINP, LOGL_ERROR, "Need to restart the SS7 link.\n");
106 bsc.link.reset(&bsc.link);
107}
108
109void mtp_link_sccp_down(struct mtp_link *link)
110{
111 msc_clear_queue(&bsc);
112}
113
114void mtp_link_forward_sccp(struct mtp_link *link, struct msgb *_msg, int sls)
115{
116 int rc;
117 struct sccp_parse_result result;
118
119 rc = bss_patch_filter_msg(_msg, &result);
120 if (rc == BSS_FILTER_RESET) {
121 LOGP(DMSC, LOGL_NOTICE, "Filtering BSS Reset from the BSC\n");
122 msc_clear_queue(&bsc);
123 mgcp_reset(&bsc);
124 send_reset_ack(link, sls);
125 return;
126 }
127
128 /* special responder */
Holger Hans Peter Freyther0c95c6a2010-08-07 02:37:43 +0800129 if (bsc.msc_link_down) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800130 if (rc == BSS_FILTER_RESET_ACK && bsc.reset_count > 0) {
131 LOGP(DMSC, LOGL_ERROR, "Received reset ack for closing.\n");
132 clear_connections(&bsc);
133 bsc_resources_released(&bsc);
134 return;
135 }
136
137 if (rc != 0 && rc != BSS_FILTER_RLSD && rc != BSS_FILTER_RLC) {
138 LOGP(DMSC, LOGL_ERROR, "Ignoring unparsable msg during closedown.\n");
139 return;
140 }
141
142 return handle_local_sccp(link, _msg, &result, sls);
143 }
144
145 /* update the connection state */
Holger Hans Peter Freyther5d930f82010-10-08 23:18:15 +0800146 update_con_state(link, rc, &result, _msg, 0, sls);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800147
148 if (rc == BSS_FILTER_CLEAR_COMPL) {
149 send_local_rlsd(link, &result);
150 } else if (rc == BSS_FILTER_RLC || rc == BSS_FILTER_RLSD) {
151 LOGP(DMSC, LOGL_DEBUG, "Not forwarding RLC/RLSD to the MSC.\n");
152 return;
153 }
154
155
156 msc_send_msg(&bsc, rc, &result, _msg);
157}
158
159/*
160 * handle local message in close down mode
161 */
162static void handle_local_sccp(struct mtp_link *link, struct msgb *inpt, struct sccp_parse_result *result, int sls)
163{
164 /* Handle msg with a reject */
165 if (inpt->l2h[0] == SCCP_MSG_TYPE_CR) {
166 struct sccp_connection_request *cr;
167 struct msgb *msg;
168
169 LOGP(DINP, LOGL_NOTICE, "Handling CR localy.\n");
170 cr = (struct sccp_connection_request *) inpt->l2h;
171 msg = create_sccp_refuse(&cr->source_local_reference);
172 if (msg) {
173 mtp_link_submit_sccp_data(link, sls, msg->l2h, msgb_l2len(msg));
174 msgb_free(msg);
175 }
176 return;
177 } else if (inpt->l2h[0] == SCCP_MSG_TYPE_DT1 && result->data_len >= 3) {
178 struct active_sccp_con *con;
179 struct sccp_data_form1 *form1;
180 struct msgb *msg;
181
182 if (inpt->l3h[0] == 0 && inpt->l3h[2] == BSS_MAP_MSG_CLEAR_COMPLETE) {
183 LOGP(DINP, LOGL_DEBUG, "Received Clear Complete. Sending Release.\n");
184
185 form1 = (struct sccp_data_form1 *) inpt->l2h;
186
187 llist_for_each_entry(con, &bsc.sccp_connections, entry) {
188 if (memcmp(&form1->destination_local_reference,
189 &con->dst_ref, sizeof(con->dst_ref)) == 0) {
190 LOGP(DINP, LOGL_DEBUG, "Sending a release request now.\n");
191 msg = create_sccp_rlsd(&con->dst_ref, &con->src_ref);
192 if (msg) {
193 mtp_link_submit_sccp_data(link, con->sls, msg->l2h, msgb_l2len(msg));
194 msgb_free(msg);
195 }
196 return;
197 }
198 }
199
200 LOGP(DINP, LOGL_ERROR, "Could not find connection for the Clear Command.\n");
201 }
202 } else if (inpt->l2h[0] == SCCP_MSG_TYPE_UDT && result->data_len >= 3) {
203 if (inpt->l3h[0] == 0 && inpt->l3h[2] == BSS_MAP_MSG_RESET_ACKNOWLEDGE) {
204 LOGP(DINP, LOGL_NOTICE, "Reset ACK. Connecting to the MSC again.\n");
205 bsc_resources_released(&bsc);
206 return;
207 }
208 }
209
210
211 /* Update the state, maybe the connection was released? */
Holger Hans Peter Freyther5d930f82010-10-08 23:18:15 +0800212 update_con_state(link, 0, result, inpt, 0, sls);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800213 if (llist_empty(&bsc.sccp_connections))
214 bsc_resources_released(&bsc);
215 return;
216}
217
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800218static void clear_connections(struct bsc_data *bsc)
219{
220 struct active_sccp_con *tmp, *con;
221
222 llist_for_each_entry_safe(con, tmp, &bsc->sccp_connections, entry) {
223 free_con(con);
224 }
225
226 bsc->link.clear_queue(&bsc->link);
227}
228
229void bsc_resources_released(struct bsc_data *bsc)
230{
231 bsc_del_timer(&bsc->reset_timeout);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800232}
233
234static void bsc_reset_timeout(void *_data)
235{
236 struct msgb *msg;
237 struct bsc_data *bsc = (struct bsc_data *) _data;
238
239 /* no reset */
240 if (bsc->reset_count > 0) {
241 LOGP(DINP, LOGL_ERROR, "The BSC did not answer the GSM08.08 reset. Restart MTP\n");
242 mtp_link_stop(bsc->link.the_link);
243 clear_connections(bsc);
244 bsc->link.reset(&bsc->link);
245 bsc_resources_released(bsc);
246 return;
247 }
248
249 msg = create_reset();
250 if (!msg) {
251 bsc_schedule_timer(&bsc->reset_timeout, 10, 0);
252 return;
253 }
254
255 ++bsc->reset_count;
256 mtp_link_submit_sccp_data(bsc->link.the_link, 13, msg->l2h, msgb_l2len(msg));
257 msgb_free(msg);
258 bsc_schedule_timer(&bsc->reset_timeout, 20, 0);
259}
260
261/*
262 * We have lost the connection to the MSC. This is tough. We
263 * can not just bring down the MTP link as this will disable
264 * the BTS radio. We will have to do the following:
265 *
266 * 1.) Bring down all open SCCP connections. As this will close
267 * all radio resources
268 * 2.) Bring down all MGCP endpoints
269 * 3.) Clear the connection data.
270 *
271 * To make things worse we need to buffer the BSC messages... atfer
272 * everything has been sent we will try to connect to the MSC again.
273 *
274 * We will have to veriy that all connections are closed properly..
275 * this means we need to parse response message. In the case the
276 * MTP link is going down while we are sending. We will simply
277 * reconnect to the MSC.
278 */
279void release_bsc_resources(struct bsc_data *bsc)
280{
281 struct active_sccp_con *tmp;
282 struct active_sccp_con *con;
283
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800284 bsc_del_timer(&bsc->reset_timeout);
285
286 /* 2. clear the MGCP endpoints */
287 mgcp_reset(bsc);
288
289 /* 1. send BSSMAP Cleanup.. if we have any connection */
290 llist_for_each_entry_safe(con, tmp, &bsc->sccp_connections, entry) {
291 if (!con->has_dst_ref) {
292 free_con(con);
293 continue;
294 }
295
296 struct msgb *msg = create_clear_command(&con->src_ref);
297 if (!msg)
298 continue;
299
300 /* wait for the clear commands */
301 mtp_link_submit_sccp_data(bsc->link.the_link, con->sls, msg->l2h, msgb_l2len(msg));
302 msgb_free(msg);
303 }
304
305 if (llist_empty(&bsc->sccp_connections)) {
306 bsc_resources_released(bsc);
307 } else {
308 /* Send a reset in 20 seconds if we fail to bring everything down */
309 bsc->reset_timeout.cb = bsc_reset_timeout;
310 bsc->reset_timeout.data = bsc;
311 bsc->reset_count = 0;
312 bsc_schedule_timer(&bsc->reset_timeout, 10, 0);
313 }
314
315 /* clear pending messages from the MSC */
Holger Hans Peter Freyther71f4f352010-08-07 02:00:32 +0800316 msc_clear_queue(bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800317}
318
319void bsc_link_down(struct link_data *data)
320{
321 int was_up;
322 struct mtp_link *link = data->the_link;
323
324 link->available = 0;
325 was_up = link->sccp_up;
326 mtp_link_stop(link);
327 clear_connections(data->bsc);
328 mgcp_reset(data->bsc);
329
330 data->clear_queue(data);
331
332 /* clear pending messages from the MSC */
Holger Hans Peter Freyther3e054ee2010-08-07 02:32:44 +0800333 msc_clear_queue(data->bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800334
Holger Hans Peter Freyther7b7c2972010-08-07 05:41:06 +0800335 /* If we have an A link send a reset to the MSC */
336 msc_send_reset(data->bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800337}
338
339void bsc_link_up(struct link_data *data)
340{
341 data->the_link->available = 1;
342
343 /* we have not gone through link down */
Holger Hans Peter Freyther0c95c6a2010-08-07 02:37:43 +0800344 if (data->bsc->msc_link_down) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800345 clear_connections(data->bsc);
346 bsc_resources_released(data->bsc);
347 }
348
349 mtp_link_reset(data->the_link);
350
351 if (flood)
352 start_flood();
353}
354
355/**
356 * update the connection state and helpers below
357 */
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800358static void send_rlc_to_bsc(unsigned int sls, struct sccp_source_reference *src, struct sccp_source_reference *dst)
359{
360 struct msgb *msg;
361
362 msg = create_sccp_rlc(src, dst);
363 if (!msg)
364 return;
365
366 mtp_link_submit_sccp_data(bsc.link.the_link, sls, msg->l2h, msgb_l2len(msg));
367 msgb_free(msg);
368}
369
370static void handle_rlsd(struct sccp_connection_released *rlsd, int from_msc)
371{
372 struct active_sccp_con *con;
373
374 if (from_msc) {
375 /* search for a connection, reverse src/dest for MSC */
376 con = find_con_by_src_dest_ref(&rlsd->destination_local_reference,
377 &rlsd->source_local_reference);
378 if (con) {
379 LOGP(DINP, LOGL_DEBUG, "RLSD conn still alive: local: 0x%x remote: 0x%x\n",
380 sccp_src_ref_to_int(&con->src_ref),
381 sccp_src_ref_to_int(&con->dst_ref));
382 con->released_from_msc = 1;
383 } else {
384 /* send RLC */
385 LOGP(DINP, LOGL_DEBUG, "Sending RLC for MSC: src: 0x%x dst: 0x%x\n",
386 sccp_src_ref_to_int(&rlsd->destination_local_reference),
387 sccp_src_ref_to_int(&rlsd->source_local_reference));
388 msc_send_rlc(&bsc, &rlsd->destination_local_reference,
389 &rlsd->source_local_reference);
390 }
391 } else {
392 unsigned int sls = 13;
393 con = find_con_by_src_dest_ref(&rlsd->source_local_reference,
394 &rlsd->destination_local_reference);
395 if (con) {
396 LOGP(DINP, LOGL_DEBUG, "Timeout on BSC. Sending RLC. src: 0x%x\n",
397 sccp_src_ref_to_int(&rlsd->source_local_reference));
398
399 if (con->released_from_msc)
400 msc_send_rlc(&bsc, &con->src_ref, &con->dst_ref);
401 sls = con->sls;
402 free_con(con);
403 } else {
404 LOGP(DINP, LOGL_ERROR, "Timeout on BSC for unknown connection. src: 0x%x\n",
405 sccp_src_ref_to_int(&rlsd->source_local_reference));
406 }
407
408 /* now send a rlc back to the BSC */
409 send_rlc_to_bsc(sls, &rlsd->destination_local_reference, &rlsd->source_local_reference);
410 }
411}
412
413/**
414 * Update connection state and also send message.....
415 *
416 * RLSD from MSC:
417 * 1.) We don't find the entry in this case we will send a
418 * forged RLC to the MSC and we are done.
419 * 2.) We find an entry in this we will need to register that
420 * we need to send a RLC and we are done for now.
421 * RLSD from BSC:
422 * 1.) This is an error we are ignoring for now.
423 * RLC from BSC:
424 * 1.) We are destroying the connection, we might send a RLC to
425 * the MSC if we are waiting for one.
426 */
Holger Hans Peter Freyther5d930f82010-10-08 23:18:15 +0800427void update_con_state(struct mtp_link *link, int rc, struct sccp_parse_result *res, struct msgb *msg, int from_msc, int sls)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800428{
429 struct active_sccp_con *con;
430 struct sccp_connection_request *cr;
431 struct sccp_connection_confirm *cc;
432 struct sccp_connection_release_complete *rlc;
433 struct sccp_connection_refused *cref;
434
435 /* was the header okay? */
436 if (rc < 0)
437 return;
438
439 /* the header was size checked */
440 switch (msg->l2h[0]) {
441 case SCCP_MSG_TYPE_CR:
442 if (from_msc) {
443 LOGP(DMSC, LOGL_ERROR, "CR from MSC is not handled.\n");
444 return;
445 }
446
447 cr = (struct sccp_connection_request *) msg->l2h;
448 con = find_con_by_src_ref(&cr->source_local_reference);
449 if (con) {
450 LOGP(DINP, LOGL_ERROR, "Duplicate SRC reference for: 0x%x. Reusing\n",
451 sccp_src_ref_to_int(&con->src_ref));
452 free_con(con);
453 }
454
455 con = talloc_zero(NULL, struct active_sccp_con);
456 if (!con) {
457 LOGP(DINP, LOGL_ERROR, "Failed to allocate\n");
458 return;
459 }
460
461 con->src_ref = cr->source_local_reference;
462 con->sls = sls;
Holger Hans Peter Freyther5d930f82010-10-08 23:18:15 +0800463 con->link = link;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800464 llist_add_tail(&con->entry, &bsc.sccp_connections);
465 LOGP(DINP, LOGL_DEBUG, "Adding CR: local ref: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
466 break;
467 case SCCP_MSG_TYPE_CC:
468 if (!from_msc) {
469 LOGP(DINP, LOGL_ERROR, "CC from BSC is not handled.\n");
470 return;
471 }
472
473 cc = (struct sccp_connection_confirm *) msg->l2h;
474 con = find_con_by_src_ref(&cc->destination_local_reference);
475 if (con) {
476 con->dst_ref = cc->source_local_reference;
477 con->has_dst_ref = 1;
478 LOGP(DINP, LOGL_DEBUG, "Updating CC: local: 0x%x remote: 0x%x\n",
479 sccp_src_ref_to_int(&con->src_ref), sccp_src_ref_to_int(&con->dst_ref));
480 return;
481 }
482
483 LOGP(DINP, LOGL_ERROR, "CCed connection can not be found: 0x%x\n",
484 sccp_src_ref_to_int(&cc->destination_local_reference));
485 break;
486 case SCCP_MSG_TYPE_CREF:
487 if (!from_msc) {
488 LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n");
489 return;
490 }
491
492 cref = (struct sccp_connection_refused *) msg->l2h;
493 con = find_con_by_src_ref(&cref->destination_local_reference);
494 if (con) {
495 LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
496 free_con(con);
497 return;
498 }
499
500 LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n");
501 break;
502 case SCCP_MSG_TYPE_RLSD:
503 handle_rlsd((struct sccp_connection_released *) msg->l2h, from_msc);
504 break;
505 case SCCP_MSG_TYPE_RLC:
506 if (from_msc) {
507 LOGP(DINP, LOGL_ERROR, "RLC from MSC is wrong.\n");
508 return;
509 }
510
511 rlc = (struct sccp_connection_release_complete *) msg->l2h;
512 con = find_con_by_src_dest_ref(&rlc->source_local_reference,
513 &rlc->destination_local_reference);
514 if (con) {
515 LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
516 if (con->released_from_msc)
517 msc_send_rlc(&bsc, &con->src_ref, &con->dst_ref);
518 free_con(con);
519 return;
520 }
521
522 LOGP(DINP, LOGL_ERROR, "RLC can not be found. 0x%x 0x%x\n",
523 sccp_src_ref_to_int(&rlc->source_local_reference),
524 sccp_src_ref_to_int(&rlc->destination_local_reference));
525 break;
526 }
527}
528
529static void send_local_rlsd_for_con(void *data)
530{
531 struct msgb *rlsd;
532 struct active_sccp_con *con = (struct active_sccp_con *) data;
533
534 /* try again in three seconds */
535 con->rlc_timeout.data = con;
536 con->rlc_timeout.cb = send_local_rlsd_for_con;
537 bsc_schedule_timer(&con->rlc_timeout, 3, 0);
538
539 /* we send this to the BSC so we need to switch src and dest */
540 rlsd = create_sccp_rlsd(&con->dst_ref, &con->src_ref);
541 if (!rlsd)
542 return;
543
544 ++con->rls_tries;
545 LOGP(DINP, LOGL_DEBUG, "Sending RLSD for 0x%x the %d time.\n",
546 sccp_src_ref_to_int(&con->src_ref), con->rls_tries);
547 mtp_link_submit_sccp_data(bsc.link.the_link, con->sls, rlsd->l2h, msgb_l2len(rlsd));
548 msgb_free(rlsd);
549}
550
551static void send_local_rlsd(struct mtp_link *link, struct sccp_parse_result *res)
552{
553 struct active_sccp_con *con;
554
555 LOGP(DINP, LOGL_DEBUG, "Received GSM Clear Complete. Sending RLSD locally.\n");
556
557 con = find_con_by_dest_ref(res->destination_local_reference);
558 if (!con)
559 return;
560 con->rls_tries = 0;
561 send_local_rlsd_for_con(con);
562}
563
564static void send_reset_ack(struct mtp_link *link, int sls)
565{
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800566 static const uint8_t reset_ack[] = {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800567 0x09, 0x00, 0x03, 0x05, 0x7, 0x02, 0x42, 0xfe,
568 0x02, 0x42, 0xfe, 0x03,
569 0x00, 0x01, 0x31
570 };
571
572 mtp_link_submit_sccp_data(link, sls, reset_ack, sizeof(reset_ack));
573}
574
575static void start_flood()
576{
577 static unsigned int i = 0;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800578 static const uint8_t paging_cmd[] = {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800579 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x0a,
580 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10,
581 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x80, 0x10,
582 0x76, 0x10, 0x77, 0x46, 0x05, 0x1a, 0x01, 0x06 };
583
584 /* change the imsi slightly */
585 if (bsc.link.the_link->sltm_pending) {
586 LOGP(DINP, LOGL_ERROR, "Not sending due clash with SLTM.\n");
587 } else {
588 struct msgb *msg;
589 msg = msgb_alloc_headroom(4096, 128, "paging");
590 if (msg) {
591 LOGP(DINP, LOGL_NOTICE, "Flooding BSC with one paging requests.\n");
592
593 msg->l2h = msgb_put(msg, sizeof(paging_cmd));
594 memcpy(msg->l2h, paging_cmd, msgb_l2len(msg));
595
596 bss_rewrite_header_to_bsc(msg,
597 bsc.link.the_link->opc,
598 bsc.link.the_link->dpc);
599 mtp_link_submit_sccp_data(bsc.link.the_link, i++,
600 msg->l2h, msgb_l2len(msg));
601 msgb_free(msg);
602 }
603 }
604
605 /* try again in five seconds */
606 flood_timer.cb = start_flood;
607 bsc_schedule_timer(&flood_timer, 2, 0);
608}
609
610static void print_usage()
611{
612 printf("Usage: cellmgr_ng\n");
613}
614
615static void sigint()
616{
617 static pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
618 static int handled = 0;
619
620 /* failed to lock */
621 if (pthread_mutex_trylock(&exit_mutex) != 0)
622 return;
623 if (handled)
624 goto out;
625
626 printf("Terminating.\n");
627 handled = 1;
628 if (bsc.setup)
629 bsc.link.shutdown(&bsc.link);
630 exit(0);
631
632out:
633 pthread_mutex_unlock(&exit_mutex);
634}
635
636static void sigusr2()
637{
638 printf("Closing the MSC connection on demand.\n");
Holger Hans Peter Freyther43d9eec2010-08-07 01:54:19 +0800639 msc_close_connection(&bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800640}
641
642static void print_help()
643{
644 printf(" Some useful help...\n");
645 printf(" -h --help this text\n");
646 printf(" -c --config=CFG The config file to use.\n");
647 printf(" -p --pcap=FILE. Write MSUs to the PCAP file.\n");
648 printf(" -c --once. Send the SLTM msg only once.\n");
649 printf(" -f --flood. Send flood of paging requests to the BSC.\n");
Holger Hans Peter Freyther4bbfa272010-09-15 20:53:56 +0800650 printf(" -v --version. Print the version number\n");
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800651}
652
653static void handle_options(int argc, char **argv)
654{
655 while (1) {
656 int option_index = 0, c;
657 static struct option long_options[] = {
658 {"help", 0, 0, 'h'},
659 {"config", 1, 0, 'c'},
660 {"pcap", 1, 0, 'p'},
661 {"flood", 0, 0, 'f'},
Holger Hans Peter Freyther4bbfa272010-09-15 20:53:56 +0800662 {"version", 0, 0, 0},
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800663 {0, 0, 0, 0},
664 };
665
Holger Hans Peter Freyther4bbfa272010-09-15 20:53:56 +0800666 c = getopt_long(argc, argv, "hc:p:fv",
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800667 long_options, &option_index);
668 if (c == -1)
669 break;
670
671 switch (c) {
672 case 'h':
673 print_usage();
674 print_help();
675 exit(0);
676 case 'p':
677 if (bsc.link.pcap_fd >= 0)
678 close(bsc.link.pcap_fd);
679 bsc.link.pcap_fd = open(optarg, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH);
680 if (bsc.link.pcap_fd < 0) {
681 fprintf(stderr, "Failed to open PCAP file.\n");
682 exit(0);
683 }
684 mtp_pcap_write_header(bsc.link.pcap_fd);
685 break;
686 case 'c':
687 config = optarg;
688 break;
689 case 'f':
690 flood = 1;
691 break;
Holger Hans Peter Freyther4bbfa272010-09-15 20:53:56 +0800692 case 'v':
693 printf("This is %s version %s.\n", PACKAGE, VERSION);
694 exit(0);
695 break;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800696 default:
697 fprintf(stderr, "Unknown option.\n");
698 break;
699 }
700 }
701}
702
703static void start_rest(void *start)
704{
705 bsc.setup = 1;
706
Holger Hans Peter Freyther594ee9a2010-11-16 11:03:19 +0100707 if (msc_init(&bsc, 1) != 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800708 fprintf(stderr, "Failed to init MSC part.\n");
709 exit(3);
710 }
711
712 bsc.link.start(&bsc.link);
713}
714
715
716int main(int argc, char **argv)
717{
Holger Hans Peter Freytherfdae5c92010-09-30 01:01:03 +0800718 int rc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800719 INIT_LLIST_HEAD(&bsc.sccp_connections);
720
Holger Hans Peter Freyther7942abc2010-09-30 00:34:46 +0800721 bsc.dpc = 1;
722 bsc.opc = 0;
723 bsc.udp_port = 3456;
724 bsc.udp_ip = NULL;
725 bsc.src_port = 1313;
Holger Hans Peter Freytherb38b33b2010-11-26 21:21:04 +0100726 bsc.ni_ni = MTP_NI_NATION_NET;
727 bsc.ni_spare = 0;
Holger Hans Peter Freyther7942abc2010-09-30 00:34:46 +0800728
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800729 mtp_link_init();
730 thread_init();
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800731
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800732 log_init(&log_info);
733 stderr_target = log_target_create_stderr();
734 log_add_target(stderr_target);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800735
736 /* enable filters */
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800737 log_set_all_filter(stderr_target, 1);
738 log_set_category_filter(stderr_target, DINP, 1, LOGL_INFO);
739 log_set_category_filter(stderr_target, DSCCP, 1, LOGL_INFO);
740 log_set_category_filter(stderr_target, DMSC, 1, LOGL_INFO);
741 log_set_category_filter(stderr_target, DMGCP, 1, LOGL_INFO);
742 log_set_print_timestamp(stderr_target, 1);
743 log_set_use_color(stderr_target, 0);
744
745 sccp_set_log_area(DSCCP);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800746
747 bsc.setup = 0;
748 bsc.msc_address = "127.0.0.1";
749 bsc.link.pcap_fd = -1;
750 bsc.link.udp.reset_timeout = 180;
751 bsc.ping_time = 20;
752 bsc.pong_time = 5;
753 bsc.msc_time = 20;
754
755 handle_options(argc, argv);
756
757 signal(SIGPIPE, SIG_IGN);
758 signal(SIGINT, sigint);
759 signal(SIGUSR2, sigusr2);
760 srand(time(NULL));
761
762 cell_vty_init();
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800763 if (vty_read_config_file(config, NULL) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800764 fprintf(stderr, "Failed to read the VTY config.\n");
765 return -1;
766 }
767
Holger Hans Peter Freytherfdae5c92010-09-30 01:01:03 +0800768 rc = telnet_init(NULL, NULL, 4242);
769 if (rc < 0)
770 return rc;
771
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800772 bsc.link.the_link = mtp_link_alloc();
Holger Hans Peter Freyther7942abc2010-09-30 00:34:46 +0800773 bsc.link.the_link->dpc = bsc.dpc;
774 bsc.link.the_link->opc = bsc.opc;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800775 bsc.link.the_link->link = 0;
Holger Hans Peter Freyther7942abc2010-09-30 00:34:46 +0800776 bsc.link.the_link->sltm_once = bsc.once;
Holger Hans Peter Freytherb38b33b2010-11-26 21:21:04 +0100777 bsc.link.the_link->ni = bsc.ni_ni;
778 bsc.link.the_link->spare = bsc.ni_spare;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800779 bsc.link.bsc = &bsc;
780
Holger Hans Peter Freyther7942abc2010-09-30 00:34:46 +0800781 if (bsc.udp_ip) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800782 LOGP(DINP, LOGL_NOTICE, "Using UDP MTP mode.\n");
783
784 /* setup SNMP first, it is blocking */
Holger Hans Peter Freyther7942abc2010-09-30 00:34:46 +0800785 bsc.link.udp.session = snmp_mtp_session_create(bsc.udp_ip);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800786 if (!bsc.link.udp.session)
787 return -1;
788
789 /* now connect to the transport */
Holger Hans Peter Freyther7942abc2010-09-30 00:34:46 +0800790 if (link_udp_init(&bsc.link, bsc.src_port, bsc.udp_ip, bsc.udp_port) != 0)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800791 return -1;
792
793 /*
794 * We will ask the MTP link to be taken down for two
795 * timeouts of the BSC to make sure we are missing the
796 * SLTM and it begins a reset. Then we will take it up
797 * again and do the usual business.
798 */
799 snmp_mtp_deactivate(bsc.link.udp.session);
800 bsc.start_timer.cb = start_rest;
801 bsc.start_timer.data = &bsc;
802 bsc_schedule_timer(&bsc.start_timer, bsc.link.udp.reset_timeout, 0);
803 LOGP(DMSC, LOGL_NOTICE, "Making sure SLTM will timeout.\n");
804 } else {
805 LOGP(DINP, LOGL_NOTICE, "Using NexusWare C7 input.\n");
806 if (link_c7_init(&bsc.link) != 0)
807 return -1;
808
809 /* give time to things to start*/
810 bsc.start_timer.cb = start_rest;
811 bsc.start_timer.data = &bsc;
812 bsc_schedule_timer(&bsc.start_timer, 30, 0);
813 LOGP(DMSC, LOGL_NOTICE, "Waiting to continue to startup.\n");
814 }
815
816
817 while (1) {
818 bsc_select_main(0);
819 }
820
821 return 0;
822}
823