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