blob: 0df22a1951f62184716a151a6e23ab0932147632 [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 Freyther97f66e22010-07-28 03:32:52 +080031
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080032#include <osmocore/talloc.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080033
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080034#include <osmocom/vty/command.h>
35#include <osmocom/vty/vty.h>
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080036
37#include <openbsc_nat/bssap.h>
38
39#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
50#include <netdb.h>
51
52#ifndef _GNU_SOURCE
53#define _GNU_SOURCE
54#endif
55#include <getopt.h>
56
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080057static struct log_target *stderr_target;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080058static int dpc = 1;
59static int opc = 0;
60
61static char *config = "cellmgr_ng.cfg";
62static int udp_port = 3456;
63static char *udp_ip = NULL;
64static int src_port = 1313;
65static int once = 0;
66static int flood = 0;
67static struct timer_list flood_timer;
68
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +080069static struct vty_app_info vty_info = {
70 .name = "Cellmgr-ng",
71 .version = "0.0.1",
72 .go_parent_cb = NULL,
73};
74
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +080075/*
76 * One SCCP connection.
77 * Use for connection tracking and fixups...
78 */
79struct active_sccp_con {
80 struct llist_head entry;
81
82 struct sccp_source_reference src_ref;
83 struct sccp_source_reference dst_ref;
84
85 int has_dst_ref;
86
87 /* fixup stuff */
88
89 /* We get a RLSD from the MSC and need to send a RLC */
90 int released_from_msc;
91
92 /* timeout for waiting for the RLC */
93 struct timer_list rlc_timeout;
94
95 /* how often did we send a RLSD this */
96 unsigned int rls_tries;
97
98 /* sls id */
99 int sls;
100};
101
102static struct bsc_data bsc;
103
104static void send_reset_ack(struct mtp_link *link, int sls);
105static void bsc_resources_released(struct bsc_data *bsc);
106static void handle_local_sccp(struct mtp_link *link, struct msgb *inp, struct sccp_parse_result *res, int sls);
107static void clear_connections(struct bsc_data *bsc);
108static void send_local_rlsd(struct mtp_link *link, struct sccp_parse_result *res);
109static void start_flood();
110static void cell_vty_init(void);
111
Holger Hans Peter Freyther48f4d632010-08-04 04:51:38 +0800112int link_c7_init(struct link_data *data) __attribute__((__weak__));
113
114int link_c7_init(struct link_data *data)
115{
116 return -1;
117}
118
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800119/* send a RSIP to the MGCP GW */
120static void mgcp_reset(struct bsc_data *bsc)
121{
122 static const char mgcp_reset[] = {
123 "RSIP 1 13@mgw MGCP 1.0\r\n"
124 };
125
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800126 mgcp_forward(bsc, (const uint8_t *) mgcp_reset, strlen(mgcp_reset));
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800127}
128
129/*
130 * methods called from the MTP Level3 part
131 */
132void mtp_link_submit(struct mtp_link *link, struct msgb *msg)
133{
134 bsc.link.write(&bsc.link, msg);
135}
136
137void mtp_link_restart(struct mtp_link *link)
138{
139 LOGP(DINP, LOGL_ERROR, "Need to restart the SS7 link.\n");
140 bsc.link.reset(&bsc.link);
141}
142
143void mtp_link_sccp_down(struct mtp_link *link)
144{
145 msc_clear_queue(&bsc);
146}
147
148void mtp_link_forward_sccp(struct mtp_link *link, struct msgb *_msg, int sls)
149{
150 int rc;
151 struct sccp_parse_result result;
152
153 rc = bss_patch_filter_msg(_msg, &result);
154 if (rc == BSS_FILTER_RESET) {
155 LOGP(DMSC, LOGL_NOTICE, "Filtering BSS Reset from the BSC\n");
156 msc_clear_queue(&bsc);
157 mgcp_reset(&bsc);
158 send_reset_ack(link, sls);
159 return;
160 }
161
162 /* special responder */
163 if (bsc.closing) {
164 if (rc == BSS_FILTER_RESET_ACK && bsc.reset_count > 0) {
165 LOGP(DMSC, LOGL_ERROR, "Received reset ack for closing.\n");
166 clear_connections(&bsc);
167 bsc_resources_released(&bsc);
168 return;
169 }
170
171 if (rc != 0 && rc != BSS_FILTER_RLSD && rc != BSS_FILTER_RLC) {
172 LOGP(DMSC, LOGL_ERROR, "Ignoring unparsable msg during closedown.\n");
173 return;
174 }
175
176 return handle_local_sccp(link, _msg, &result, sls);
177 }
178
179 /* update the connection state */
180 update_con_state(rc, &result, _msg, 0, sls);
181
182 if (rc == BSS_FILTER_CLEAR_COMPL) {
183 send_local_rlsd(link, &result);
184 } else if (rc == BSS_FILTER_RLC || rc == BSS_FILTER_RLSD) {
185 LOGP(DMSC, LOGL_DEBUG, "Not forwarding RLC/RLSD to the MSC.\n");
186 return;
187 }
188
189
190 msc_send_msg(&bsc, rc, &result, _msg);
191}
192
193/*
194 * handle local message in close down mode
195 */
196static void handle_local_sccp(struct mtp_link *link, struct msgb *inpt, struct sccp_parse_result *result, int sls)
197{
198 /* Handle msg with a reject */
199 if (inpt->l2h[0] == SCCP_MSG_TYPE_CR) {
200 struct sccp_connection_request *cr;
201 struct msgb *msg;
202
203 LOGP(DINP, LOGL_NOTICE, "Handling CR localy.\n");
204 cr = (struct sccp_connection_request *) inpt->l2h;
205 msg = create_sccp_refuse(&cr->source_local_reference);
206 if (msg) {
207 mtp_link_submit_sccp_data(link, sls, msg->l2h, msgb_l2len(msg));
208 msgb_free(msg);
209 }
210 return;
211 } else if (inpt->l2h[0] == SCCP_MSG_TYPE_DT1 && result->data_len >= 3) {
212 struct active_sccp_con *con;
213 struct sccp_data_form1 *form1;
214 struct msgb *msg;
215
216 if (inpt->l3h[0] == 0 && inpt->l3h[2] == BSS_MAP_MSG_CLEAR_COMPLETE) {
217 LOGP(DINP, LOGL_DEBUG, "Received Clear Complete. Sending Release.\n");
218
219 form1 = (struct sccp_data_form1 *) inpt->l2h;
220
221 llist_for_each_entry(con, &bsc.sccp_connections, entry) {
222 if (memcmp(&form1->destination_local_reference,
223 &con->dst_ref, sizeof(con->dst_ref)) == 0) {
224 LOGP(DINP, LOGL_DEBUG, "Sending a release request now.\n");
225 msg = create_sccp_rlsd(&con->dst_ref, &con->src_ref);
226 if (msg) {
227 mtp_link_submit_sccp_data(link, con->sls, msg->l2h, msgb_l2len(msg));
228 msgb_free(msg);
229 }
230 return;
231 }
232 }
233
234 LOGP(DINP, LOGL_ERROR, "Could not find connection for the Clear Command.\n");
235 }
236 } else if (inpt->l2h[0] == SCCP_MSG_TYPE_UDT && result->data_len >= 3) {
237 if (inpt->l3h[0] == 0 && inpt->l3h[2] == BSS_MAP_MSG_RESET_ACKNOWLEDGE) {
238 LOGP(DINP, LOGL_NOTICE, "Reset ACK. Connecting to the MSC again.\n");
239 bsc_resources_released(&bsc);
240 return;
241 }
242 }
243
244
245 /* Update the state, maybe the connection was released? */
246 update_con_state(0, result, inpt, 0, sls);
247 if (llist_empty(&bsc.sccp_connections))
248 bsc_resources_released(&bsc);
249 return;
250}
251
252/*
253 * remove data
254 */
255static void free_con(struct active_sccp_con *con)
256{
257 llist_del(&con->entry);
258 bsc_del_timer(&con->rlc_timeout);
259 talloc_free(con);
260}
261
262static void clear_connections(struct bsc_data *bsc)
263{
264 struct active_sccp_con *tmp, *con;
265
266 llist_for_each_entry_safe(con, tmp, &bsc->sccp_connections, entry) {
267 free_con(con);
268 }
269
270 bsc->link.clear_queue(&bsc->link);
271}
272
273void bsc_resources_released(struct bsc_data *bsc)
274{
275 bsc_del_timer(&bsc->reset_timeout);
276 msc_schedule_reconnect(bsc);
277}
278
279static void bsc_reset_timeout(void *_data)
280{
281 struct msgb *msg;
282 struct bsc_data *bsc = (struct bsc_data *) _data;
283
284 /* no reset */
285 if (bsc->reset_count > 0) {
286 LOGP(DINP, LOGL_ERROR, "The BSC did not answer the GSM08.08 reset. Restart MTP\n");
287 mtp_link_stop(bsc->link.the_link);
288 clear_connections(bsc);
289 bsc->link.reset(&bsc->link);
290 bsc_resources_released(bsc);
291 return;
292 }
293
294 msg = create_reset();
295 if (!msg) {
296 bsc_schedule_timer(&bsc->reset_timeout, 10, 0);
297 return;
298 }
299
300 ++bsc->reset_count;
301 mtp_link_submit_sccp_data(bsc->link.the_link, 13, msg->l2h, msgb_l2len(msg));
302 msgb_free(msg);
303 bsc_schedule_timer(&bsc->reset_timeout, 20, 0);
304}
305
306/*
307 * We have lost the connection to the MSC. This is tough. We
308 * can not just bring down the MTP link as this will disable
309 * the BTS radio. We will have to do the following:
310 *
311 * 1.) Bring down all open SCCP connections. As this will close
312 * all radio resources
313 * 2.) Bring down all MGCP endpoints
314 * 3.) Clear the connection data.
315 *
316 * To make things worse we need to buffer the BSC messages... atfer
317 * everything has been sent we will try to connect to the MSC again.
318 *
319 * We will have to veriy that all connections are closed properly..
320 * this means we need to parse response message. In the case the
321 * MTP link is going down while we are sending. We will simply
322 * reconnect to the MSC.
323 */
324void release_bsc_resources(struct bsc_data *bsc)
325{
326 struct active_sccp_con *tmp;
327 struct active_sccp_con *con;
328
329 bsc->closing = 1;
330 bsc_del_timer(&bsc->reset_timeout);
331
332 /* 2. clear the MGCP endpoints */
333 mgcp_reset(bsc);
334
335 /* 1. send BSSMAP Cleanup.. if we have any connection */
336 llist_for_each_entry_safe(con, tmp, &bsc->sccp_connections, entry) {
337 if (!con->has_dst_ref) {
338 free_con(con);
339 continue;
340 }
341
342 struct msgb *msg = create_clear_command(&con->src_ref);
343 if (!msg)
344 continue;
345
346 /* wait for the clear commands */
347 mtp_link_submit_sccp_data(bsc->link.the_link, con->sls, msg->l2h, msgb_l2len(msg));
348 msgb_free(msg);
349 }
350
351 if (llist_empty(&bsc->sccp_connections)) {
352 bsc_resources_released(bsc);
353 } else {
354 /* Send a reset in 20 seconds if we fail to bring everything down */
355 bsc->reset_timeout.cb = bsc_reset_timeout;
356 bsc->reset_timeout.data = bsc;
357 bsc->reset_count = 0;
358 bsc_schedule_timer(&bsc->reset_timeout, 10, 0);
359 }
360
361 /* clear pending messages from the MSC */
362 while (!llist_empty(&bsc->link.the_link->pending_msgs)) {
363 struct msgb *msg = msgb_dequeue(&bsc->link.the_link->pending_msgs);
364 msgb_free(msg);
365 }
366}
367
368void bsc_link_down(struct link_data *data)
369{
370 int was_up;
371 struct mtp_link *link = data->the_link;
372
373 link->available = 0;
374 was_up = link->sccp_up;
375 mtp_link_stop(link);
376 clear_connections(data->bsc);
377 mgcp_reset(data->bsc);
378
379 data->clear_queue(data);
380
381 /* clear pending messages from the MSC */
382 while (!llist_empty(&link->pending_msgs)) {
383 struct msgb *msg = msgb_dequeue(&link->pending_msgs);
384 msgb_free(msg);
385 }
386
387 /* for the case the link is going down while we are trying to reset */
388 if (data->bsc->closing)
389 msc_schedule_reconnect(data->bsc);
390 else if (was_up)
391 msc_send_reset(data->bsc);
392}
393
394void bsc_link_up(struct link_data *data)
395{
396 data->the_link->available = 1;
397
398 /* we have not gone through link down */
399 if (data->bsc->closing) {
400 clear_connections(data->bsc);
401 bsc_resources_released(data->bsc);
402 }
403
404 mtp_link_reset(data->the_link);
405
406 if (flood)
407 start_flood();
408}
409
410/**
411 * update the connection state and helpers below
412 */
413static struct active_sccp_con *find_con_by_dest_ref(struct sccp_source_reference *ref)
414{
415 struct active_sccp_con *con;
416
417 if (!ref) {
418 LOGP(DINP, LOGL_ERROR, "Dest Reference is NULL. No connection found.\n");
419 return NULL;
420 }
421
422 llist_for_each_entry(con, &bsc.sccp_connections, entry) {
423 if (memcmp(&con->dst_ref, ref, sizeof(*ref)) == 0)
424 return con;
425 }
426
427 LOGP(DINP, LOGL_ERROR, "No connection fond with: 0x%x as dest\n", sccp_src_ref_to_int(ref));
428 return NULL;
429}
430
431static struct active_sccp_con *find_con_by_src_ref(struct sccp_source_reference *src_ref)
432{
433 struct active_sccp_con *con;
434
435 /* it is quite normal to not find this one */
436 if (!src_ref)
437 return NULL;
438
439 llist_for_each_entry(con, &bsc.sccp_connections, entry) {
440 if (memcmp(&con->src_ref, src_ref, sizeof(*src_ref)) == 0)
441 return con;
442 }
443
444 return NULL;
445}
446
447static struct active_sccp_con *find_con_by_src_dest_ref(struct sccp_source_reference *src_ref,
448 struct sccp_source_reference *dst_ref)
449{
450 struct active_sccp_con *con;
451
452 llist_for_each_entry(con, &bsc.sccp_connections, entry) {
453 if (memcmp(src_ref, &con->src_ref, sizeof(*src_ref)) == 0 &&
454 memcmp(dst_ref, &con->dst_ref, sizeof(*dst_ref)) == 0) {
455 return con;
456 }
457 }
458
459 return NULL;
460}
461
462unsigned int sls_for_src_ref(struct sccp_source_reference *ref)
463{
464 struct active_sccp_con *con;
465
466 con = find_con_by_src_ref(ref);
467 if (!con)
468 return 13;
469 return con->sls;
470}
471
472static void send_rlc_to_bsc(unsigned int sls, struct sccp_source_reference *src, struct sccp_source_reference *dst)
473{
474 struct msgb *msg;
475
476 msg = create_sccp_rlc(src, dst);
477 if (!msg)
478 return;
479
480 mtp_link_submit_sccp_data(bsc.link.the_link, sls, msg->l2h, msgb_l2len(msg));
481 msgb_free(msg);
482}
483
484static void handle_rlsd(struct sccp_connection_released *rlsd, int from_msc)
485{
486 struct active_sccp_con *con;
487
488 if (from_msc) {
489 /* search for a connection, reverse src/dest for MSC */
490 con = find_con_by_src_dest_ref(&rlsd->destination_local_reference,
491 &rlsd->source_local_reference);
492 if (con) {
493 LOGP(DINP, LOGL_DEBUG, "RLSD conn still alive: local: 0x%x remote: 0x%x\n",
494 sccp_src_ref_to_int(&con->src_ref),
495 sccp_src_ref_to_int(&con->dst_ref));
496 con->released_from_msc = 1;
497 } else {
498 /* send RLC */
499 LOGP(DINP, LOGL_DEBUG, "Sending RLC for MSC: src: 0x%x dst: 0x%x\n",
500 sccp_src_ref_to_int(&rlsd->destination_local_reference),
501 sccp_src_ref_to_int(&rlsd->source_local_reference));
502 msc_send_rlc(&bsc, &rlsd->destination_local_reference,
503 &rlsd->source_local_reference);
504 }
505 } else {
506 unsigned int sls = 13;
507 con = find_con_by_src_dest_ref(&rlsd->source_local_reference,
508 &rlsd->destination_local_reference);
509 if (con) {
510 LOGP(DINP, LOGL_DEBUG, "Timeout on BSC. Sending RLC. src: 0x%x\n",
511 sccp_src_ref_to_int(&rlsd->source_local_reference));
512
513 if (con->released_from_msc)
514 msc_send_rlc(&bsc, &con->src_ref, &con->dst_ref);
515 sls = con->sls;
516 free_con(con);
517 } else {
518 LOGP(DINP, LOGL_ERROR, "Timeout on BSC for unknown connection. src: 0x%x\n",
519 sccp_src_ref_to_int(&rlsd->source_local_reference));
520 }
521
522 /* now send a rlc back to the BSC */
523 send_rlc_to_bsc(sls, &rlsd->destination_local_reference, &rlsd->source_local_reference);
524 }
525}
526
527/**
528 * Update connection state and also send message.....
529 *
530 * RLSD from MSC:
531 * 1.) We don't find the entry in this case we will send a
532 * forged RLC to the MSC and we are done.
533 * 2.) We find an entry in this we will need to register that
534 * we need to send a RLC and we are done for now.
535 * RLSD from BSC:
536 * 1.) This is an error we are ignoring for now.
537 * RLC from BSC:
538 * 1.) We are destroying the connection, we might send a RLC to
539 * the MSC if we are waiting for one.
540 */
541void update_con_state(int rc, struct sccp_parse_result *res, struct msgb *msg, int from_msc, int sls)
542{
543 struct active_sccp_con *con;
544 struct sccp_connection_request *cr;
545 struct sccp_connection_confirm *cc;
546 struct sccp_connection_release_complete *rlc;
547 struct sccp_connection_refused *cref;
548
549 /* was the header okay? */
550 if (rc < 0)
551 return;
552
553 /* the header was size checked */
554 switch (msg->l2h[0]) {
555 case SCCP_MSG_TYPE_CR:
556 if (from_msc) {
557 LOGP(DMSC, LOGL_ERROR, "CR from MSC is not handled.\n");
558 return;
559 }
560
561 cr = (struct sccp_connection_request *) msg->l2h;
562 con = find_con_by_src_ref(&cr->source_local_reference);
563 if (con) {
564 LOGP(DINP, LOGL_ERROR, "Duplicate SRC reference for: 0x%x. Reusing\n",
565 sccp_src_ref_to_int(&con->src_ref));
566 free_con(con);
567 }
568
569 con = talloc_zero(NULL, struct active_sccp_con);
570 if (!con) {
571 LOGP(DINP, LOGL_ERROR, "Failed to allocate\n");
572 return;
573 }
574
575 con->src_ref = cr->source_local_reference;
576 con->sls = sls;
577 llist_add_tail(&con->entry, &bsc.sccp_connections);
578 LOGP(DINP, LOGL_DEBUG, "Adding CR: local ref: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
579 break;
580 case SCCP_MSG_TYPE_CC:
581 if (!from_msc) {
582 LOGP(DINP, LOGL_ERROR, "CC from BSC is not handled.\n");
583 return;
584 }
585
586 cc = (struct sccp_connection_confirm *) msg->l2h;
587 con = find_con_by_src_ref(&cc->destination_local_reference);
588 if (con) {
589 con->dst_ref = cc->source_local_reference;
590 con->has_dst_ref = 1;
591 LOGP(DINP, LOGL_DEBUG, "Updating CC: local: 0x%x remote: 0x%x\n",
592 sccp_src_ref_to_int(&con->src_ref), sccp_src_ref_to_int(&con->dst_ref));
593 return;
594 }
595
596 LOGP(DINP, LOGL_ERROR, "CCed connection can not be found: 0x%x\n",
597 sccp_src_ref_to_int(&cc->destination_local_reference));
598 break;
599 case SCCP_MSG_TYPE_CREF:
600 if (!from_msc) {
601 LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n");
602 return;
603 }
604
605 cref = (struct sccp_connection_refused *) msg->l2h;
606 con = find_con_by_src_ref(&cref->destination_local_reference);
607 if (con) {
608 LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
609 free_con(con);
610 return;
611 }
612
613 LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n");
614 break;
615 case SCCP_MSG_TYPE_RLSD:
616 handle_rlsd((struct sccp_connection_released *) msg->l2h, from_msc);
617 break;
618 case SCCP_MSG_TYPE_RLC:
619 if (from_msc) {
620 LOGP(DINP, LOGL_ERROR, "RLC from MSC is wrong.\n");
621 return;
622 }
623
624 rlc = (struct sccp_connection_release_complete *) msg->l2h;
625 con = find_con_by_src_dest_ref(&rlc->source_local_reference,
626 &rlc->destination_local_reference);
627 if (con) {
628 LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
629 if (con->released_from_msc)
630 msc_send_rlc(&bsc, &con->src_ref, &con->dst_ref);
631 free_con(con);
632 return;
633 }
634
635 LOGP(DINP, LOGL_ERROR, "RLC can not be found. 0x%x 0x%x\n",
636 sccp_src_ref_to_int(&rlc->source_local_reference),
637 sccp_src_ref_to_int(&rlc->destination_local_reference));
638 break;
639 }
640}
641
642static void send_local_rlsd_for_con(void *data)
643{
644 struct msgb *rlsd;
645 struct active_sccp_con *con = (struct active_sccp_con *) data;
646
647 /* try again in three seconds */
648 con->rlc_timeout.data = con;
649 con->rlc_timeout.cb = send_local_rlsd_for_con;
650 bsc_schedule_timer(&con->rlc_timeout, 3, 0);
651
652 /* we send this to the BSC so we need to switch src and dest */
653 rlsd = create_sccp_rlsd(&con->dst_ref, &con->src_ref);
654 if (!rlsd)
655 return;
656
657 ++con->rls_tries;
658 LOGP(DINP, LOGL_DEBUG, "Sending RLSD for 0x%x the %d time.\n",
659 sccp_src_ref_to_int(&con->src_ref), con->rls_tries);
660 mtp_link_submit_sccp_data(bsc.link.the_link, con->sls, rlsd->l2h, msgb_l2len(rlsd));
661 msgb_free(rlsd);
662}
663
664static void send_local_rlsd(struct mtp_link *link, struct sccp_parse_result *res)
665{
666 struct active_sccp_con *con;
667
668 LOGP(DINP, LOGL_DEBUG, "Received GSM Clear Complete. Sending RLSD locally.\n");
669
670 con = find_con_by_dest_ref(res->destination_local_reference);
671 if (!con)
672 return;
673 con->rls_tries = 0;
674 send_local_rlsd_for_con(con);
675}
676
677static void send_reset_ack(struct mtp_link *link, int sls)
678{
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800679 static const uint8_t reset_ack[] = {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800680 0x09, 0x00, 0x03, 0x05, 0x7, 0x02, 0x42, 0xfe,
681 0x02, 0x42, 0xfe, 0x03,
682 0x00, 0x01, 0x31
683 };
684
685 mtp_link_submit_sccp_data(link, sls, reset_ack, sizeof(reset_ack));
686}
687
688static void start_flood()
689{
690 static unsigned int i = 0;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800691 static const uint8_t paging_cmd[] = {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800692 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x0a,
693 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10,
694 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x80, 0x10,
695 0x76, 0x10, 0x77, 0x46, 0x05, 0x1a, 0x01, 0x06 };
696
697 /* change the imsi slightly */
698 if (bsc.link.the_link->sltm_pending) {
699 LOGP(DINP, LOGL_ERROR, "Not sending due clash with SLTM.\n");
700 } else {
701 struct msgb *msg;
702 msg = msgb_alloc_headroom(4096, 128, "paging");
703 if (msg) {
704 LOGP(DINP, LOGL_NOTICE, "Flooding BSC with one paging requests.\n");
705
706 msg->l2h = msgb_put(msg, sizeof(paging_cmd));
707 memcpy(msg->l2h, paging_cmd, msgb_l2len(msg));
708
709 bss_rewrite_header_to_bsc(msg,
710 bsc.link.the_link->opc,
711 bsc.link.the_link->dpc);
712 mtp_link_submit_sccp_data(bsc.link.the_link, i++,
713 msg->l2h, msgb_l2len(msg));
714 msgb_free(msg);
715 }
716 }
717
718 /* try again in five seconds */
719 flood_timer.cb = start_flood;
720 bsc_schedule_timer(&flood_timer, 2, 0);
721}
722
723static void print_usage()
724{
725 printf("Usage: cellmgr_ng\n");
726}
727
728static void sigint()
729{
730 static pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
731 static int handled = 0;
732
733 /* failed to lock */
734 if (pthread_mutex_trylock(&exit_mutex) != 0)
735 return;
736 if (handled)
737 goto out;
738
739 printf("Terminating.\n");
740 handled = 1;
741 if (bsc.setup)
742 bsc.link.shutdown(&bsc.link);
743 exit(0);
744
745out:
746 pthread_mutex_unlock(&exit_mutex);
747}
748
749static void sigusr2()
750{
751 printf("Closing the MSC connection on demand.\n");
752 close(bsc.msc_connection.bfd.fd);
753 bsc_unregister_fd(&bsc.msc_connection.bfd);
754 bsc.msc_connection.bfd.fd = -1;
755 release_bsc_resources(&bsc);
756}
757
758static void print_help()
759{
760 printf(" Some useful help...\n");
761 printf(" -h --help this text\n");
762 printf(" -c --config=CFG The config file to use.\n");
763 printf(" -p --pcap=FILE. Write MSUs to the PCAP file.\n");
764 printf(" -c --once. Send the SLTM msg only once.\n");
765 printf(" -f --flood. Send flood of paging requests to the BSC.\n");
766}
767
768static void handle_options(int argc, char **argv)
769{
770 while (1) {
771 int option_index = 0, c;
772 static struct option long_options[] = {
773 {"help", 0, 0, 'h'},
774 {"config", 1, 0, 'c'},
775 {"pcap", 1, 0, 'p'},
776 {"flood", 0, 0, 'f'},
777 {0, 0, 0, 0},
778 };
779
780 c = getopt_long(argc, argv, "hc:p:f",
781 long_options, &option_index);
782 if (c == -1)
783 break;
784
785 switch (c) {
786 case 'h':
787 print_usage();
788 print_help();
789 exit(0);
790 case 'p':
791 if (bsc.link.pcap_fd >= 0)
792 close(bsc.link.pcap_fd);
793 bsc.link.pcap_fd = open(optarg, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH);
794 if (bsc.link.pcap_fd < 0) {
795 fprintf(stderr, "Failed to open PCAP file.\n");
796 exit(0);
797 }
798 mtp_pcap_write_header(bsc.link.pcap_fd);
799 break;
800 case 'c':
801 config = optarg;
802 break;
803 case 'f':
804 flood = 1;
805 break;
806 default:
807 fprintf(stderr, "Unknown option.\n");
808 break;
809 }
810 }
811}
812
813static void start_rest(void *start)
814{
815 bsc.setup = 1;
816
817 if (msc_init(&bsc) != 0) {
818 fprintf(stderr, "Failed to init MSC part.\n");
819 exit(3);
820 }
821
822 bsc.link.start(&bsc.link);
823}
824
825
826int main(int argc, char **argv)
827{
828 INIT_LLIST_HEAD(&bsc.sccp_connections);
829
830 mtp_link_init();
831 thread_init();
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800832
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800833 log_init(&log_info);
834 stderr_target = log_target_create_stderr();
835 log_add_target(stderr_target);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800836
837 /* enable filters */
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800838 log_set_all_filter(stderr_target, 1);
839 log_set_category_filter(stderr_target, DINP, 1, LOGL_INFO);
840 log_set_category_filter(stderr_target, DSCCP, 1, LOGL_INFO);
841 log_set_category_filter(stderr_target, DMSC, 1, LOGL_INFO);
842 log_set_category_filter(stderr_target, DMGCP, 1, LOGL_INFO);
843 log_set_print_timestamp(stderr_target, 1);
844 log_set_use_color(stderr_target, 0);
845
846 sccp_set_log_area(DSCCP);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800847
848 bsc.setup = 0;
849 bsc.msc_address = "127.0.0.1";
850 bsc.link.pcap_fd = -1;
851 bsc.link.udp.reset_timeout = 180;
852 bsc.ping_time = 20;
853 bsc.pong_time = 5;
854 bsc.msc_time = 20;
855
856 handle_options(argc, argv);
857
858 signal(SIGPIPE, SIG_IGN);
859 signal(SIGINT, sigint);
860 signal(SIGUSR2, sigusr2);
861 srand(time(NULL));
862
863 cell_vty_init();
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800864 if (vty_read_config_file(config, NULL) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800865 fprintf(stderr, "Failed to read the VTY config.\n");
866 return -1;
867 }
868
869 bsc.link.the_link = mtp_link_alloc();
870 bsc.link.the_link->dpc = dpc;
871 bsc.link.the_link->opc = opc;
872 bsc.link.the_link->link = 0;
873 bsc.link.the_link->sltm_once = once;
874 bsc.link.bsc = &bsc;
875
876 if (udp_ip) {
877 LOGP(DINP, LOGL_NOTICE, "Using UDP MTP mode.\n");
878
879 /* setup SNMP first, it is blocking */
880 bsc.link.udp.session = snmp_mtp_session_create(udp_ip);
881 if (!bsc.link.udp.session)
882 return -1;
883
884 /* now connect to the transport */
885 if (link_udp_init(&bsc.link, src_port, udp_ip, udp_port) != 0)
886 return -1;
887
888 /*
889 * We will ask the MTP link to be taken down for two
890 * timeouts of the BSC to make sure we are missing the
891 * SLTM and it begins a reset. Then we will take it up
892 * again and do the usual business.
893 */
894 snmp_mtp_deactivate(bsc.link.udp.session);
895 bsc.start_timer.cb = start_rest;
896 bsc.start_timer.data = &bsc;
897 bsc_schedule_timer(&bsc.start_timer, bsc.link.udp.reset_timeout, 0);
898 LOGP(DMSC, LOGL_NOTICE, "Making sure SLTM will timeout.\n");
899 } else {
900 LOGP(DINP, LOGL_NOTICE, "Using NexusWare C7 input.\n");
901 if (link_c7_init(&bsc.link) != 0)
902 return -1;
903
904 /* give time to things to start*/
905 bsc.start_timer.cb = start_rest;
906 bsc.start_timer.data = &bsc;
907 bsc_schedule_timer(&bsc.start_timer, 30, 0);
908 LOGP(DMSC, LOGL_NOTICE, "Waiting to continue to startup.\n");
909 }
910
911
912 while (1) {
913 bsc_select_main(0);
914 }
915
916 return 0;
917}
918
919/* vty code */
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800920enum cellmgr_node {
921 CELLMGR_NODE = _LAST_OSMOVTY_NODE,
922};
923
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800924static struct cmd_node cell_node = {
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800925 CELLMGR_NODE,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800926 "%s(cellmgr)#",
927 1,
928};
929
930static int config_write_cell()
931{
932 return CMD_SUCCESS;
933}
934
935DEFUN(cfg_cell, cfg_cell_cmd,
936 "cellmgr", "Configure the Cellmgr")
937{
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800938 vty->node = CELLMGR_NODE;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800939 return CMD_SUCCESS;
940}
941
942DEFUN(cfg_net_dpc, cfg_net_dpc_cmd,
943 "mtp dpc DPC_NR",
944 "Set the DPC to be used.")
945{
946 dpc = atoi(argv[0]);
947 return CMD_SUCCESS;
948}
949
950DEFUN(cfg_net_opc, cfg_net_opc_cmd,
951 "mtp opc OPC_NR",
952 "Set the OPC to be used.")
953{
954 opc = atoi(argv[0]);
955 return CMD_SUCCESS;
956}
957
958DEFUN(cfg_udp_dst_ip, cfg_udp_dst_ip_cmd,
959 "udp dest ip IP",
960 "Set the IP when UDP mode is supposed to be used.")
961{
962 struct hostent *hosts;
963 struct in_addr *addr;
964
965 hosts = gethostbyname(argv[0]);
966 if (!hosts || hosts->h_length < 1 || hosts->h_addrtype != AF_INET) {
967 vty_out(vty, "Failed to resolve '%s'%s", argv[0], VTY_NEWLINE);
968 return CMD_WARNING;
969 }
970
971 addr = (struct in_addr *) hosts->h_addr_list[0];
972 udp_ip = talloc_strdup(NULL, inet_ntoa(*addr));
973 return CMD_SUCCESS;
974}
975
976DEFUN(cfg_udp_dst_port, cfg_udp_dst_port_cmd,
977 "udp dest port PORT_NR",
978 "If UDP mode is used specify the UDP dest port")
979{
980 udp_port = atoi(argv[0]);
981 return CMD_SUCCESS;
982}
983
984DEFUN(cfg_udp_src_port, cfg_udp_src_port_cmd,
985 "udp src port PORT_NR",
986 "Set the UDP source port to be used.")
987{
988 src_port = atoi(argv[0]);
989 return CMD_SUCCESS;
990}
991
992DEFUN(cfg_udp_reset, cfg_udp_reset_cmd,
993 "udp reset TIMEOUT",
994 "Set the timeout to take the link down")
995{
996 bsc.link.udp.reset_timeout = atoi(argv[0]);
997 return CMD_SUCCESS;
998}
999
1000DEFUN(cfg_sltm_once, cfg_sltm_once_cmd,
1001 "mtp sltm once (0|1)",
1002 "Send SLTMs until the link is established.")
1003{
1004 once = !!atoi(argv[0]);
1005 return CMD_SUCCESS;
1006}
1007
1008DEFUN(cfg_msc_ip, cfg_msc_ip_cmd,
1009 "msc ip IP",
1010 "Set the MSC IP")
1011{
1012 struct hostent *hosts;
1013 struct in_addr *addr;
1014
1015 hosts = gethostbyname(argv[0]);
1016 if (!hosts || hosts->h_length < 1 || hosts->h_addrtype != AF_INET) {
1017 vty_out(vty, "Failed to resolve '%s'%s", argv[0], VTY_NEWLINE);
1018 return CMD_WARNING;
1019 }
1020
1021 addr = (struct in_addr *) hosts->h_addr_list[0];
1022
1023 bsc.msc_address = talloc_strdup(NULL, inet_ntoa(*addr));
1024 return CMD_SUCCESS;
1025}
1026
1027DEFUN(cfg_msc_ip_dscp, cfg_msc_ip_dscp_cmd,
1028 "msc ip-dscp <0-255>",
1029 "Set the IP DSCP on the A-link\n"
1030 "Set the DSCP in IP packets to the MSC")
1031{
1032 bsc.msc_ip_dscp = atoi(argv[0]);
1033 return CMD_SUCCESS;
1034}
1035
1036ALIAS_DEPRECATED(cfg_msc_ip_dscp, cfg_msc_ip_tos_cmd,
1037 "msc ip-tos <0-255>",
1038 "Set the IP DSCP on the A-link\n"
1039 "Set the DSCP in IP packets to the MSC")
1040
1041DEFUN(cfg_msc_token, cfg_msc_token_cmd,
1042 "msc token TOKEN",
1043 "Set the Token to be used for the MSC")
1044{
1045 bsc.token = talloc_strdup(NULL, argv[0]);
1046 return CMD_SUCCESS;
1047}
1048
1049DEFUN(cfg_ping_time, cfg_ping_time_cmd,
1050 "timeout ping NR",
1051 "Set the PING interval. Negative to disable it")
1052{
1053 bsc.ping_time = atoi(argv[0]);
1054 return CMD_SUCCESS;
1055}
1056
1057DEFUN(cfg_pong_time, cfg_pong_time_cmd,
1058 "timeout pong NR",
1059 "Set the PING interval. Negative to disable it")
1060{
1061 bsc.pong_time = atoi(argv[0]);
1062 return CMD_SUCCESS;
1063}
1064
1065DEFUN(cfg_msc_time, cfg_msc_time_cmd,
1066 "timeout msc NR",
1067 "Set the MSC connect timeout")
1068{
1069 bsc.msc_time = atoi(argv[0]);
1070 return CMD_SUCCESS;
1071}
1072
1073static void cell_vty_init(void)
1074{
1075 cmd_init(1);
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +08001076 vty_init(&vty_info);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001077
1078 install_element(CONFIG_NODE, &cfg_cell_cmd);
1079 install_node(&cell_node, config_write_cell);
1080
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +08001081 install_element(CELLMGR_NODE, &cfg_net_dpc_cmd);
1082 install_element(CELLMGR_NODE, &cfg_net_opc_cmd);
1083 install_element(CELLMGR_NODE, &cfg_udp_dst_ip_cmd);
1084 install_element(CELLMGR_NODE, &cfg_udp_dst_port_cmd);
1085 install_element(CELLMGR_NODE, &cfg_udp_src_port_cmd);
1086 install_element(CELLMGR_NODE, &cfg_udp_reset_cmd);
1087 install_element(CELLMGR_NODE, &cfg_sltm_once_cmd);
1088 install_element(CELLMGR_NODE, &cfg_msc_ip_cmd);
1089 install_element(CELLMGR_NODE, &cfg_msc_token_cmd);
1090 install_element(CELLMGR_NODE, &cfg_msc_ip_dscp_cmd);
1091 install_element(CELLMGR_NODE, &cfg_msc_ip_tos_cmd);
1092 install_element(CELLMGR_NODE, &cfg_ping_time_cmd);
1093 install_element(CELLMGR_NODE, &cfg_pong_time_cmd);
1094 install_element(CELLMGR_NODE, &cfg_msc_time_cmd);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001095}
1096
Holger Hans Peter Freyther8c6b3562010-08-04 05:53:21 +08001097const char *openbsc_copyright = "";