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