blob: bb15ed9627a43b3c8950660ef2c2ff5b38a1d288 [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 */
Holger Hans Peter Freyther0c95c6a2010-08-07 02:37:43 +0800162 if (bsc.msc_link_down) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800163 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
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800328 bsc_del_timer(&bsc->reset_timeout);
329
330 /* 2. clear the MGCP endpoints */
331 mgcp_reset(bsc);
332
333 /* 1. send BSSMAP Cleanup.. if we have any connection */
334 llist_for_each_entry_safe(con, tmp, &bsc->sccp_connections, entry) {
335 if (!con->has_dst_ref) {
336 free_con(con);
337 continue;
338 }
339
340 struct msgb *msg = create_clear_command(&con->src_ref);
341 if (!msg)
342 continue;
343
344 /* wait for the clear commands */
345 mtp_link_submit_sccp_data(bsc->link.the_link, con->sls, msg->l2h, msgb_l2len(msg));
346 msgb_free(msg);
347 }
348
349 if (llist_empty(&bsc->sccp_connections)) {
350 bsc_resources_released(bsc);
351 } else {
352 /* Send a reset in 20 seconds if we fail to bring everything down */
353 bsc->reset_timeout.cb = bsc_reset_timeout;
354 bsc->reset_timeout.data = bsc;
355 bsc->reset_count = 0;
356 bsc_schedule_timer(&bsc->reset_timeout, 10, 0);
357 }
358
359 /* clear pending messages from the MSC */
Holger Hans Peter Freyther71f4f352010-08-07 02:00:32 +0800360 msc_clear_queue(bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800361}
362
363void bsc_link_down(struct link_data *data)
364{
365 int was_up;
366 struct mtp_link *link = data->the_link;
367
368 link->available = 0;
369 was_up = link->sccp_up;
370 mtp_link_stop(link);
371 clear_connections(data->bsc);
372 mgcp_reset(data->bsc);
373
374 data->clear_queue(data);
375
376 /* clear pending messages from the MSC */
Holger Hans Peter Freyther3e054ee2010-08-07 02:32:44 +0800377 msc_clear_queue(data->bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800378
379 /* for the case the link is going down while we are trying to reset */
Holger Hans Peter Freyther0c95c6a2010-08-07 02:37:43 +0800380 if (data->bsc->msc_link_down)
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800381 msc_schedule_reconnect(data->bsc);
382 else if (was_up)
383 msc_send_reset(data->bsc);
384}
385
386void bsc_link_up(struct link_data *data)
387{
388 data->the_link->available = 1;
389
390 /* we have not gone through link down */
Holger Hans Peter Freyther0c95c6a2010-08-07 02:37:43 +0800391 if (data->bsc->msc_link_down) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800392 clear_connections(data->bsc);
393 bsc_resources_released(data->bsc);
394 }
395
396 mtp_link_reset(data->the_link);
397
398 if (flood)
399 start_flood();
400}
401
402/**
403 * update the connection state and helpers below
404 */
405static struct active_sccp_con *find_con_by_dest_ref(struct sccp_source_reference *ref)
406{
407 struct active_sccp_con *con;
408
409 if (!ref) {
410 LOGP(DINP, LOGL_ERROR, "Dest Reference is NULL. No connection found.\n");
411 return NULL;
412 }
413
414 llist_for_each_entry(con, &bsc.sccp_connections, entry) {
415 if (memcmp(&con->dst_ref, ref, sizeof(*ref)) == 0)
416 return con;
417 }
418
419 LOGP(DINP, LOGL_ERROR, "No connection fond with: 0x%x as dest\n", sccp_src_ref_to_int(ref));
420 return NULL;
421}
422
423static struct active_sccp_con *find_con_by_src_ref(struct sccp_source_reference *src_ref)
424{
425 struct active_sccp_con *con;
426
427 /* it is quite normal to not find this one */
428 if (!src_ref)
429 return NULL;
430
431 llist_for_each_entry(con, &bsc.sccp_connections, entry) {
432 if (memcmp(&con->src_ref, src_ref, sizeof(*src_ref)) == 0)
433 return con;
434 }
435
436 return NULL;
437}
438
439static struct active_sccp_con *find_con_by_src_dest_ref(struct sccp_source_reference *src_ref,
440 struct sccp_source_reference *dst_ref)
441{
442 struct active_sccp_con *con;
443
444 llist_for_each_entry(con, &bsc.sccp_connections, entry) {
445 if (memcmp(src_ref, &con->src_ref, sizeof(*src_ref)) == 0 &&
446 memcmp(dst_ref, &con->dst_ref, sizeof(*dst_ref)) == 0) {
447 return con;
448 }
449 }
450
451 return NULL;
452}
453
454unsigned int sls_for_src_ref(struct sccp_source_reference *ref)
455{
456 struct active_sccp_con *con;
457
458 con = find_con_by_src_ref(ref);
459 if (!con)
460 return 13;
461 return con->sls;
462}
463
464static void send_rlc_to_bsc(unsigned int sls, struct sccp_source_reference *src, struct sccp_source_reference *dst)
465{
466 struct msgb *msg;
467
468 msg = create_sccp_rlc(src, dst);
469 if (!msg)
470 return;
471
472 mtp_link_submit_sccp_data(bsc.link.the_link, sls, msg->l2h, msgb_l2len(msg));
473 msgb_free(msg);
474}
475
476static void handle_rlsd(struct sccp_connection_released *rlsd, int from_msc)
477{
478 struct active_sccp_con *con;
479
480 if (from_msc) {
481 /* search for a connection, reverse src/dest for MSC */
482 con = find_con_by_src_dest_ref(&rlsd->destination_local_reference,
483 &rlsd->source_local_reference);
484 if (con) {
485 LOGP(DINP, LOGL_DEBUG, "RLSD conn still alive: local: 0x%x remote: 0x%x\n",
486 sccp_src_ref_to_int(&con->src_ref),
487 sccp_src_ref_to_int(&con->dst_ref));
488 con->released_from_msc = 1;
489 } else {
490 /* send RLC */
491 LOGP(DINP, LOGL_DEBUG, "Sending RLC for MSC: src: 0x%x dst: 0x%x\n",
492 sccp_src_ref_to_int(&rlsd->destination_local_reference),
493 sccp_src_ref_to_int(&rlsd->source_local_reference));
494 msc_send_rlc(&bsc, &rlsd->destination_local_reference,
495 &rlsd->source_local_reference);
496 }
497 } else {
498 unsigned int sls = 13;
499 con = find_con_by_src_dest_ref(&rlsd->source_local_reference,
500 &rlsd->destination_local_reference);
501 if (con) {
502 LOGP(DINP, LOGL_DEBUG, "Timeout on BSC. Sending RLC. src: 0x%x\n",
503 sccp_src_ref_to_int(&rlsd->source_local_reference));
504
505 if (con->released_from_msc)
506 msc_send_rlc(&bsc, &con->src_ref, &con->dst_ref);
507 sls = con->sls;
508 free_con(con);
509 } else {
510 LOGP(DINP, LOGL_ERROR, "Timeout on BSC for unknown connection. src: 0x%x\n",
511 sccp_src_ref_to_int(&rlsd->source_local_reference));
512 }
513
514 /* now send a rlc back to the BSC */
515 send_rlc_to_bsc(sls, &rlsd->destination_local_reference, &rlsd->source_local_reference);
516 }
517}
518
519/**
520 * Update connection state and also send message.....
521 *
522 * RLSD from MSC:
523 * 1.) We don't find the entry in this case we will send a
524 * forged RLC to the MSC and we are done.
525 * 2.) We find an entry in this we will need to register that
526 * we need to send a RLC and we are done for now.
527 * RLSD from BSC:
528 * 1.) This is an error we are ignoring for now.
529 * RLC from BSC:
530 * 1.) We are destroying the connection, we might send a RLC to
531 * the MSC if we are waiting for one.
532 */
533void update_con_state(int rc, struct sccp_parse_result *res, struct msgb *msg, int from_msc, int sls)
534{
535 struct active_sccp_con *con;
536 struct sccp_connection_request *cr;
537 struct sccp_connection_confirm *cc;
538 struct sccp_connection_release_complete *rlc;
539 struct sccp_connection_refused *cref;
540
541 /* was the header okay? */
542 if (rc < 0)
543 return;
544
545 /* the header was size checked */
546 switch (msg->l2h[0]) {
547 case SCCP_MSG_TYPE_CR:
548 if (from_msc) {
549 LOGP(DMSC, LOGL_ERROR, "CR from MSC is not handled.\n");
550 return;
551 }
552
553 cr = (struct sccp_connection_request *) msg->l2h;
554 con = find_con_by_src_ref(&cr->source_local_reference);
555 if (con) {
556 LOGP(DINP, LOGL_ERROR, "Duplicate SRC reference for: 0x%x. Reusing\n",
557 sccp_src_ref_to_int(&con->src_ref));
558 free_con(con);
559 }
560
561 con = talloc_zero(NULL, struct active_sccp_con);
562 if (!con) {
563 LOGP(DINP, LOGL_ERROR, "Failed to allocate\n");
564 return;
565 }
566
567 con->src_ref = cr->source_local_reference;
568 con->sls = sls;
569 llist_add_tail(&con->entry, &bsc.sccp_connections);
570 LOGP(DINP, LOGL_DEBUG, "Adding CR: local ref: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
571 break;
572 case SCCP_MSG_TYPE_CC:
573 if (!from_msc) {
574 LOGP(DINP, LOGL_ERROR, "CC from BSC is not handled.\n");
575 return;
576 }
577
578 cc = (struct sccp_connection_confirm *) msg->l2h;
579 con = find_con_by_src_ref(&cc->destination_local_reference);
580 if (con) {
581 con->dst_ref = cc->source_local_reference;
582 con->has_dst_ref = 1;
583 LOGP(DINP, LOGL_DEBUG, "Updating CC: local: 0x%x remote: 0x%x\n",
584 sccp_src_ref_to_int(&con->src_ref), sccp_src_ref_to_int(&con->dst_ref));
585 return;
586 }
587
588 LOGP(DINP, LOGL_ERROR, "CCed connection can not be found: 0x%x\n",
589 sccp_src_ref_to_int(&cc->destination_local_reference));
590 break;
591 case SCCP_MSG_TYPE_CREF:
592 if (!from_msc) {
593 LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n");
594 return;
595 }
596
597 cref = (struct sccp_connection_refused *) msg->l2h;
598 con = find_con_by_src_ref(&cref->destination_local_reference);
599 if (con) {
600 LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
601 free_con(con);
602 return;
603 }
604
605 LOGP(DINP, LOGL_ERROR, "CREF from BSC is not handled.\n");
606 break;
607 case SCCP_MSG_TYPE_RLSD:
608 handle_rlsd((struct sccp_connection_released *) msg->l2h, from_msc);
609 break;
610 case SCCP_MSG_TYPE_RLC:
611 if (from_msc) {
612 LOGP(DINP, LOGL_ERROR, "RLC from MSC is wrong.\n");
613 return;
614 }
615
616 rlc = (struct sccp_connection_release_complete *) msg->l2h;
617 con = find_con_by_src_dest_ref(&rlc->source_local_reference,
618 &rlc->destination_local_reference);
619 if (con) {
620 LOGP(DINP, LOGL_DEBUG, "Releasing local: 0x%x\n", sccp_src_ref_to_int(&con->src_ref));
621 if (con->released_from_msc)
622 msc_send_rlc(&bsc, &con->src_ref, &con->dst_ref);
623 free_con(con);
624 return;
625 }
626
627 LOGP(DINP, LOGL_ERROR, "RLC can not be found. 0x%x 0x%x\n",
628 sccp_src_ref_to_int(&rlc->source_local_reference),
629 sccp_src_ref_to_int(&rlc->destination_local_reference));
630 break;
631 }
632}
633
634static void send_local_rlsd_for_con(void *data)
635{
636 struct msgb *rlsd;
637 struct active_sccp_con *con = (struct active_sccp_con *) data;
638
639 /* try again in three seconds */
640 con->rlc_timeout.data = con;
641 con->rlc_timeout.cb = send_local_rlsd_for_con;
642 bsc_schedule_timer(&con->rlc_timeout, 3, 0);
643
644 /* we send this to the BSC so we need to switch src and dest */
645 rlsd = create_sccp_rlsd(&con->dst_ref, &con->src_ref);
646 if (!rlsd)
647 return;
648
649 ++con->rls_tries;
650 LOGP(DINP, LOGL_DEBUG, "Sending RLSD for 0x%x the %d time.\n",
651 sccp_src_ref_to_int(&con->src_ref), con->rls_tries);
652 mtp_link_submit_sccp_data(bsc.link.the_link, con->sls, rlsd->l2h, msgb_l2len(rlsd));
653 msgb_free(rlsd);
654}
655
656static void send_local_rlsd(struct mtp_link *link, struct sccp_parse_result *res)
657{
658 struct active_sccp_con *con;
659
660 LOGP(DINP, LOGL_DEBUG, "Received GSM Clear Complete. Sending RLSD locally.\n");
661
662 con = find_con_by_dest_ref(res->destination_local_reference);
663 if (!con)
664 return;
665 con->rls_tries = 0;
666 send_local_rlsd_for_con(con);
667}
668
669static void send_reset_ack(struct mtp_link *link, int sls)
670{
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800671 static const uint8_t reset_ack[] = {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800672 0x09, 0x00, 0x03, 0x05, 0x7, 0x02, 0x42, 0xfe,
673 0x02, 0x42, 0xfe, 0x03,
674 0x00, 0x01, 0x31
675 };
676
677 mtp_link_submit_sccp_data(link, sls, reset_ack, sizeof(reset_ack));
678}
679
680static void start_flood()
681{
682 static unsigned int i = 0;
Holger Hans Peter Freyther5aa17012010-07-31 04:37:26 +0800683 static const uint8_t paging_cmd[] = {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800684 0x09, 0x00, 0x03, 0x07, 0x0b, 0x04, 0x43, 0x0a,
685 0x00, 0xfe, 0x04, 0x43, 0x5c, 0x00, 0xfe, 0x10,
686 0x00, 0x0e, 0x52, 0x08, 0x08, 0x29, 0x80, 0x10,
687 0x76, 0x10, 0x77, 0x46, 0x05, 0x1a, 0x01, 0x06 };
688
689 /* change the imsi slightly */
690 if (bsc.link.the_link->sltm_pending) {
691 LOGP(DINP, LOGL_ERROR, "Not sending due clash with SLTM.\n");
692 } else {
693 struct msgb *msg;
694 msg = msgb_alloc_headroom(4096, 128, "paging");
695 if (msg) {
696 LOGP(DINP, LOGL_NOTICE, "Flooding BSC with one paging requests.\n");
697
698 msg->l2h = msgb_put(msg, sizeof(paging_cmd));
699 memcpy(msg->l2h, paging_cmd, msgb_l2len(msg));
700
701 bss_rewrite_header_to_bsc(msg,
702 bsc.link.the_link->opc,
703 bsc.link.the_link->dpc);
704 mtp_link_submit_sccp_data(bsc.link.the_link, i++,
705 msg->l2h, msgb_l2len(msg));
706 msgb_free(msg);
707 }
708 }
709
710 /* try again in five seconds */
711 flood_timer.cb = start_flood;
712 bsc_schedule_timer(&flood_timer, 2, 0);
713}
714
715static void print_usage()
716{
717 printf("Usage: cellmgr_ng\n");
718}
719
720static void sigint()
721{
722 static pthread_mutex_t exit_mutex = PTHREAD_MUTEX_INITIALIZER;
723 static int handled = 0;
724
725 /* failed to lock */
726 if (pthread_mutex_trylock(&exit_mutex) != 0)
727 return;
728 if (handled)
729 goto out;
730
731 printf("Terminating.\n");
732 handled = 1;
733 if (bsc.setup)
734 bsc.link.shutdown(&bsc.link);
735 exit(0);
736
737out:
738 pthread_mutex_unlock(&exit_mutex);
739}
740
741static void sigusr2()
742{
743 printf("Closing the MSC connection on demand.\n");
Holger Hans Peter Freyther43d9eec2010-08-07 01:54:19 +0800744 msc_close_connection(&bsc);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800745}
746
747static void print_help()
748{
749 printf(" Some useful help...\n");
750 printf(" -h --help this text\n");
751 printf(" -c --config=CFG The config file to use.\n");
752 printf(" -p --pcap=FILE. Write MSUs to the PCAP file.\n");
753 printf(" -c --once. Send the SLTM msg only once.\n");
754 printf(" -f --flood. Send flood of paging requests to the BSC.\n");
755}
756
757static void handle_options(int argc, char **argv)
758{
759 while (1) {
760 int option_index = 0, c;
761 static struct option long_options[] = {
762 {"help", 0, 0, 'h'},
763 {"config", 1, 0, 'c'},
764 {"pcap", 1, 0, 'p'},
765 {"flood", 0, 0, 'f'},
766 {0, 0, 0, 0},
767 };
768
769 c = getopt_long(argc, argv, "hc:p:f",
770 long_options, &option_index);
771 if (c == -1)
772 break;
773
774 switch (c) {
775 case 'h':
776 print_usage();
777 print_help();
778 exit(0);
779 case 'p':
780 if (bsc.link.pcap_fd >= 0)
781 close(bsc.link.pcap_fd);
782 bsc.link.pcap_fd = open(optarg, O_WRONLY | O_TRUNC | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP| S_IROTH);
783 if (bsc.link.pcap_fd < 0) {
784 fprintf(stderr, "Failed to open PCAP file.\n");
785 exit(0);
786 }
787 mtp_pcap_write_header(bsc.link.pcap_fd);
788 break;
789 case 'c':
790 config = optarg;
791 break;
792 case 'f':
793 flood = 1;
794 break;
795 default:
796 fprintf(stderr, "Unknown option.\n");
797 break;
798 }
799 }
800}
801
802static void start_rest(void *start)
803{
804 bsc.setup = 1;
805
806 if (msc_init(&bsc) != 0) {
807 fprintf(stderr, "Failed to init MSC part.\n");
808 exit(3);
809 }
810
811 bsc.link.start(&bsc.link);
812}
813
814
815int main(int argc, char **argv)
816{
817 INIT_LLIST_HEAD(&bsc.sccp_connections);
818
819 mtp_link_init();
820 thread_init();
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800821
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800822 log_init(&log_info);
823 stderr_target = log_target_create_stderr();
824 log_add_target(stderr_target);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800825
826 /* enable filters */
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800827 log_set_all_filter(stderr_target, 1);
828 log_set_category_filter(stderr_target, DINP, 1, LOGL_INFO);
829 log_set_category_filter(stderr_target, DSCCP, 1, LOGL_INFO);
830 log_set_category_filter(stderr_target, DMSC, 1, LOGL_INFO);
831 log_set_category_filter(stderr_target, DMGCP, 1, LOGL_INFO);
832 log_set_print_timestamp(stderr_target, 1);
833 log_set_use_color(stderr_target, 0);
834
835 sccp_set_log_area(DSCCP);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800836
837 bsc.setup = 0;
838 bsc.msc_address = "127.0.0.1";
839 bsc.link.pcap_fd = -1;
840 bsc.link.udp.reset_timeout = 180;
841 bsc.ping_time = 20;
842 bsc.pong_time = 5;
843 bsc.msc_time = 20;
844
845 handle_options(argc, argv);
846
847 signal(SIGPIPE, SIG_IGN);
848 signal(SIGINT, sigint);
849 signal(SIGUSR2, sigusr2);
850 srand(time(NULL));
851
852 cell_vty_init();
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800853 if (vty_read_config_file(config, NULL) < 0) {
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800854 fprintf(stderr, "Failed to read the VTY config.\n");
855 return -1;
856 }
857
858 bsc.link.the_link = mtp_link_alloc();
859 bsc.link.the_link->dpc = dpc;
860 bsc.link.the_link->opc = opc;
861 bsc.link.the_link->link = 0;
862 bsc.link.the_link->sltm_once = once;
863 bsc.link.bsc = &bsc;
864
865 if (udp_ip) {
866 LOGP(DINP, LOGL_NOTICE, "Using UDP MTP mode.\n");
867
868 /* setup SNMP first, it is blocking */
869 bsc.link.udp.session = snmp_mtp_session_create(udp_ip);
870 if (!bsc.link.udp.session)
871 return -1;
872
873 /* now connect to the transport */
874 if (link_udp_init(&bsc.link, src_port, udp_ip, udp_port) != 0)
875 return -1;
876
877 /*
878 * We will ask the MTP link to be taken down for two
879 * timeouts of the BSC to make sure we are missing the
880 * SLTM and it begins a reset. Then we will take it up
881 * again and do the usual business.
882 */
883 snmp_mtp_deactivate(bsc.link.udp.session);
884 bsc.start_timer.cb = start_rest;
885 bsc.start_timer.data = &bsc;
886 bsc_schedule_timer(&bsc.start_timer, bsc.link.udp.reset_timeout, 0);
887 LOGP(DMSC, LOGL_NOTICE, "Making sure SLTM will timeout.\n");
888 } else {
889 LOGP(DINP, LOGL_NOTICE, "Using NexusWare C7 input.\n");
890 if (link_c7_init(&bsc.link) != 0)
891 return -1;
892
893 /* give time to things to start*/
894 bsc.start_timer.cb = start_rest;
895 bsc.start_timer.data = &bsc;
896 bsc_schedule_timer(&bsc.start_timer, 30, 0);
897 LOGP(DMSC, LOGL_NOTICE, "Waiting to continue to startup.\n");
898 }
899
900
901 while (1) {
902 bsc_select_main(0);
903 }
904
905 return 0;
906}
907
908/* vty code */
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800909enum cellmgr_node {
910 CELLMGR_NODE = _LAST_OSMOVTY_NODE,
911};
912
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800913static struct cmd_node cell_node = {
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800914 CELLMGR_NODE,
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800915 "%s(cellmgr)#",
916 1,
917};
918
919static int config_write_cell()
920{
921 return CMD_SUCCESS;
922}
923
924DEFUN(cfg_cell, cfg_cell_cmd,
925 "cellmgr", "Configure the Cellmgr")
926{
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +0800927 vty->node = CELLMGR_NODE;
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +0800928 return CMD_SUCCESS;
929}
930
931DEFUN(cfg_net_dpc, cfg_net_dpc_cmd,
932 "mtp dpc DPC_NR",
933 "Set the DPC to be used.")
934{
935 dpc = atoi(argv[0]);
936 return CMD_SUCCESS;
937}
938
939DEFUN(cfg_net_opc, cfg_net_opc_cmd,
940 "mtp opc OPC_NR",
941 "Set the OPC to be used.")
942{
943 opc = atoi(argv[0]);
944 return CMD_SUCCESS;
945}
946
947DEFUN(cfg_udp_dst_ip, cfg_udp_dst_ip_cmd,
948 "udp dest ip IP",
949 "Set the IP when UDP mode is supposed to be used.")
950{
951 struct hostent *hosts;
952 struct in_addr *addr;
953
954 hosts = gethostbyname(argv[0]);
955 if (!hosts || hosts->h_length < 1 || hosts->h_addrtype != AF_INET) {
956 vty_out(vty, "Failed to resolve '%s'%s", argv[0], VTY_NEWLINE);
957 return CMD_WARNING;
958 }
959
960 addr = (struct in_addr *) hosts->h_addr_list[0];
961 udp_ip = talloc_strdup(NULL, inet_ntoa(*addr));
962 return CMD_SUCCESS;
963}
964
965DEFUN(cfg_udp_dst_port, cfg_udp_dst_port_cmd,
966 "udp dest port PORT_NR",
967 "If UDP mode is used specify the UDP dest port")
968{
969 udp_port = atoi(argv[0]);
970 return CMD_SUCCESS;
971}
972
973DEFUN(cfg_udp_src_port, cfg_udp_src_port_cmd,
974 "udp src port PORT_NR",
975 "Set the UDP source port to be used.")
976{
977 src_port = atoi(argv[0]);
978 return CMD_SUCCESS;
979}
980
981DEFUN(cfg_udp_reset, cfg_udp_reset_cmd,
982 "udp reset TIMEOUT",
983 "Set the timeout to take the link down")
984{
985 bsc.link.udp.reset_timeout = atoi(argv[0]);
986 return CMD_SUCCESS;
987}
988
989DEFUN(cfg_sltm_once, cfg_sltm_once_cmd,
990 "mtp sltm once (0|1)",
991 "Send SLTMs until the link is established.")
992{
993 once = !!atoi(argv[0]);
994 return CMD_SUCCESS;
995}
996
997DEFUN(cfg_msc_ip, cfg_msc_ip_cmd,
998 "msc ip IP",
999 "Set the MSC IP")
1000{
1001 struct hostent *hosts;
1002 struct in_addr *addr;
1003
1004 hosts = gethostbyname(argv[0]);
1005 if (!hosts || hosts->h_length < 1 || hosts->h_addrtype != AF_INET) {
1006 vty_out(vty, "Failed to resolve '%s'%s", argv[0], VTY_NEWLINE);
1007 return CMD_WARNING;
1008 }
1009
1010 addr = (struct in_addr *) hosts->h_addr_list[0];
1011
1012 bsc.msc_address = talloc_strdup(NULL, inet_ntoa(*addr));
1013 return CMD_SUCCESS;
1014}
1015
1016DEFUN(cfg_msc_ip_dscp, cfg_msc_ip_dscp_cmd,
1017 "msc ip-dscp <0-255>",
1018 "Set the IP DSCP on the A-link\n"
1019 "Set the DSCP in IP packets to the MSC")
1020{
1021 bsc.msc_ip_dscp = atoi(argv[0]);
1022 return CMD_SUCCESS;
1023}
1024
1025ALIAS_DEPRECATED(cfg_msc_ip_dscp, cfg_msc_ip_tos_cmd,
1026 "msc ip-tos <0-255>",
1027 "Set the IP DSCP on the A-link\n"
1028 "Set the DSCP in IP packets to the MSC")
1029
1030DEFUN(cfg_msc_token, cfg_msc_token_cmd,
1031 "msc token TOKEN",
1032 "Set the Token to be used for the MSC")
1033{
1034 bsc.token = talloc_strdup(NULL, argv[0]);
1035 return CMD_SUCCESS;
1036}
1037
1038DEFUN(cfg_ping_time, cfg_ping_time_cmd,
1039 "timeout ping NR",
1040 "Set the PING interval. Negative to disable it")
1041{
1042 bsc.ping_time = atoi(argv[0]);
1043 return CMD_SUCCESS;
1044}
1045
1046DEFUN(cfg_pong_time, cfg_pong_time_cmd,
1047 "timeout pong NR",
1048 "Set the PING interval. Negative to disable it")
1049{
1050 bsc.pong_time = atoi(argv[0]);
1051 return CMD_SUCCESS;
1052}
1053
1054DEFUN(cfg_msc_time, cfg_msc_time_cmd,
1055 "timeout msc NR",
1056 "Set the MSC connect timeout")
1057{
1058 bsc.msc_time = atoi(argv[0]);
1059 return CMD_SUCCESS;
1060}
1061
1062static void cell_vty_init(void)
1063{
1064 cmd_init(1);
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +08001065 vty_init(&vty_info);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001066
1067 install_element(CONFIG_NODE, &cfg_cell_cmd);
1068 install_node(&cell_node, config_write_cell);
1069
Holger Hans Peter Freythercbf7d182010-07-31 05:25:35 +08001070 install_element(CELLMGR_NODE, &cfg_net_dpc_cmd);
1071 install_element(CELLMGR_NODE, &cfg_net_opc_cmd);
1072 install_element(CELLMGR_NODE, &cfg_udp_dst_ip_cmd);
1073 install_element(CELLMGR_NODE, &cfg_udp_dst_port_cmd);
1074 install_element(CELLMGR_NODE, &cfg_udp_src_port_cmd);
1075 install_element(CELLMGR_NODE, &cfg_udp_reset_cmd);
1076 install_element(CELLMGR_NODE, &cfg_sltm_once_cmd);
1077 install_element(CELLMGR_NODE, &cfg_msc_ip_cmd);
1078 install_element(CELLMGR_NODE, &cfg_msc_token_cmd);
1079 install_element(CELLMGR_NODE, &cfg_msc_ip_dscp_cmd);
1080 install_element(CELLMGR_NODE, &cfg_msc_ip_tos_cmd);
1081 install_element(CELLMGR_NODE, &cfg_ping_time_cmd);
1082 install_element(CELLMGR_NODE, &cfg_pong_time_cmd);
1083 install_element(CELLMGR_NODE, &cfg_msc_time_cmd);
Holger Hans Peter Freyther97f66e22010-07-28 03:32:52 +08001084}
1085
Holger Hans Peter Freyther8c6b3562010-08-04 05:53:21 +08001086const char *openbsc_copyright = "";