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