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