Fix of vbox announcing bug
[lcr.git] / gsm_bs.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** LCR                                                                       **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** mISDN gsm (BS mode)                                                       **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 #ifndef _GNU_SOURCE
15 #define _GNU_SOURCE
16 #endif
17 extern "C" {
18 #include <getopt.h>
19
20 #include <openbsc/db.h>
21 #include <osmocore/select.h>
22 #include <openbsc/debug.h>
23 #include <openbsc/e1_input.h>
24 #include <osmocore/talloc.h>
25 #include <openbsc/mncc.h>
26 #include <openbsc/trau_frame.h>
27 //#include <osmocom/vty/command.h>
28 struct gsm_network *bsc_gsmnet = 0;
29 extern int ipacc_rtp_direct;
30 extern int bsc_bootstrap_network(int (*mmc_rev)(struct gsm_network *, int, void *),
31                                  const char *cfg_file);
32 extern int bsc_shutdown_net(struct gsm_network *net);
33 void talloc_ctx_init(void);
34 void on_dso_load_token(void);
35 void on_dso_load_rrlp(void);
36 void on_dso_load_ho_dec(void);
37 int bts_model_unknown_init(void);
38 int bts_model_bs11_init(void);
39 int bts_model_nanobts_init(void);
40 static struct log_target *stderr_target;
41
42 /* timer to store statistics */
43 #define DB_SYNC_INTERVAL        60, 0
44 static struct timer_list db_sync_timer;
45
46 /* FIXME: copied from the include file, because it will con compile with C++ */
47 struct vty_app_info {
48         const char *name;
49         const char *version;
50         char *copyright;
51         void *tall_ctx;
52         int (*go_parent_cb)(struct vty *vty);
53 };
54 extern int bsc_vty_go_parent(struct vty *vty);
55 static struct vty_app_info vty_info = {
56         "OpenBSC",
57         PACKAGE_VERSION,
58         NULL,
59         NULL,
60         bsc_vty_go_parent,
61 };
62 void vty_init(struct vty_app_info *app_info);
63 int bsc_vty_init(void);
64
65 }
66
67 /* timer handling */
68 static int _db_store_counter(struct counter *counter, void *data)
69 {
70         return db_store_counter(counter);
71 }
72
73 static void db_sync_timer_cb(void *data)
74 {
75         /* store counters to database and re-schedule */
76         counters_for_each(_db_store_counter, NULL);
77         bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
78 }
79
80 /*
81  * constructor
82  */
83 Pgsm_bs::Pgsm_bs(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : Pgsm(type, mISDNport, portname, settings, channel, exclusive, mode)
84 {
85         p_m_g_instance = gsm->network;
86         PDEBUG(DEBUG_GSM, "Created new GSMBSPort(%s).\n", portname);
87 }
88
89 /*
90  * destructor
91  */
92 Pgsm_bs::~Pgsm_bs()
93 {
94         PDEBUG(DEBUG_GSM, "Destroyed GSM BS process(%s).\n", p_name);
95 }
96
97 /* DTMF INDICATION */
98 void Pgsm_bs::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
99 {
100         struct lcr_msg *message;
101         struct gsm_mncc *resp;
102
103         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
104         add_trace("keypad", NULL, "%c", mncc->keypad);
105         end_trace();
106         SPRINT(p_dialinginfo.id, "%c", mncc->keypad);
107         p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
108
109         /* send resp */
110         gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_RSP, DIRECTION_OUT);
111         add_trace("keypad", NULL, "%c", mncc->keypad);
112         end_trace();
113         resp = create_mncc(MNCC_START_DTMF_RSP, p_m_g_callref);
114         resp->keypad = mncc->keypad;
115         send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
116
117         /* send dialing information */
118         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
119         memcpy(&message->param.information, &p_dialinginfo, sizeof(struct dialing_info));
120         message_put(message);
121 }
122 void Pgsm_bs::stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
123 {
124         struct gsm_mncc *resp;
125
126         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
127         add_trace("keypad", NULL, "%c", mncc->keypad);
128         end_trace();
129
130         /* send resp */
131         gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_RSP, DIRECTION_OUT);
132         add_trace("keypad", NULL, "%c", mncc->keypad);
133         end_trace();
134         resp = create_mncc(MNCC_STOP_DTMF_RSP, p_m_g_callref);
135         resp->keypad = mncc->keypad;
136         send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
137 }
138
139 /* HOLD INDICATION */
140 void Pgsm_bs::hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
141 {
142         struct lcr_msg *message;
143         struct gsm_mncc *resp, *frame;
144
145         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
146         end_trace();
147
148         /* notify the hold of call */
149         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
150         message->param.notifyinfo.notify = INFO_NOTIFY_REMOTE_HOLD;
151         message->param.notifyinfo.local = 1; /* call is held by supplementary service */
152         message_put(message);
153
154         /* acknowledge hold */
155         gsm_trace_header(p_m_mISDNport, this, MNCC_HOLD_CNF, DIRECTION_OUT);
156         end_trace();
157         resp = create_mncc(MNCC_HOLD_CNF, p_m_g_callref);
158         send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
159
160         /* disable audio */
161         if (p_m_g_tch_connected) { /* it should be true */
162                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_DROP, DIRECTION_OUT);
163                 end_trace();
164                 frame = create_mncc(MNCC_FRAME_DROP, p_m_g_callref);
165                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
166                 p_m_g_tch_connected = 0;
167         }
168 }
169
170
171 /* RETRIEVE INDICATION */
172 void Pgsm_bs::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
173 {
174         struct lcr_msg *message;
175         struct gsm_mncc *resp, *frame;
176
177         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
178         end_trace();
179
180         /* notify the retrieve of call */
181         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
182         message->param.notifyinfo.notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
183         message->param.notifyinfo.local = 1; /* call is retrieved by supplementary service */
184         message_put(message);
185
186         /* acknowledge retr */
187         gsm_trace_header(p_m_mISDNport, this, MNCC_RETRIEVE_CNF, DIRECTION_OUT);
188         end_trace();
189         resp = create_mncc(MNCC_RETRIEVE_CNF, p_m_g_callref);
190         send_and_free_mncc(p_m_g_instance, resp->msg_type, resp);
191
192         /* enable audio */
193         if (!p_m_g_tch_connected) { /* it should be true */
194                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
195                 end_trace();
196                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
197                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
198                 p_m_g_tch_connected = 1;
199         }
200 }
201
202 /*
203  * handles all indications
204  */
205 /* SETUP INDICATION */
206 void Pgsm_bs::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
207 {
208         int ret;
209         class Endpoint *epoint;
210         struct lcr_msg *message;
211         int channel;
212         struct gsm_mncc *mode, *proceeding, *frame;
213
214         /* process given callref */
215         l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
216         add_trace("callref", "new", "0x%x", callref);
217         if (p_m_g_callref) {
218                 /* release in case the ID is already in use */
219                 add_trace("error", NULL, "callref already in use");
220                 end_trace();
221                 mncc = create_mncc(MNCC_REJ_REQ, callref);
222                 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
223                 mncc->fields |= MNCC_F_CAUSE;
224                 mncc->cause.coding = 3;
225                 mncc->cause.location = 1;
226                 mncc->cause.value = 47;
227                 add_trace("cause", "coding", "%d", mncc->cause.coding);
228                 add_trace("cause", "location", "%d", mncc->cause.location);
229                 add_trace("cause", "value", "%d", mncc->cause.value);
230                 add_trace("reason", NULL, "callref already in use");
231                 end_trace();
232                 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
233                 new_state(PORT_STATE_RELEASE);
234                 trigger_work(&p_m_g_delete);
235                 return;
236         }
237         p_m_g_callref = callref;
238         end_trace();
239
240         /* if blocked, release call with MT_RELEASE_COMPLETE */
241         if (p_m_mISDNport->ifport->block) {
242                 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
243                 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
244                 mncc->fields |= MNCC_F_CAUSE;
245                 mncc->cause.coding = 3;
246                 mncc->cause.location = 1;
247                 mncc->cause.value = 27;
248                 add_trace("cause", "coding", "%d", mncc->cause.coding);
249                 add_trace("cause", "location", "%d", mncc->cause.location);
250                 add_trace("cause", "value", "%d", mncc->cause.value);
251                 add_trace("reason", NULL, "port is blocked");
252                 end_trace();
253                 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
254                 new_state(PORT_STATE_RELEASE);
255                 trigger_work(&p_m_g_delete);
256                 return;
257         }
258
259         /* caller info */
260         if (mncc->clir.inv)
261                 p_callerinfo.present = INFO_PRESENT_RESTRICTED;
262         else
263                 p_callerinfo.present = INFO_PRESENT_ALLOWED;
264         if (mncc->calling.number[0])
265                 SCPY(p_callerinfo.id, mncc->calling.number);
266         else
267                 p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
268         SCPY(p_callerinfo.imsi, mncc->imsi);
269         p_callerinfo.screen = INFO_SCREEN_NETWORK;
270         p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
271         p_callerinfo.isdn_port = p_m_portnum;
272         SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
273
274         /* dialing information */
275         SCAT(p_dialinginfo.id, mncc->called.number);
276         switch (mncc->called.type) {
277                 case 0x1:
278                 p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
279                 break;
280                 case 0x2:
281                 p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
282                 break;
283                 case 0x4:
284                 p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
285                 break;
286                 default:
287                 p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
288                 break;
289         }
290         if (mncc->emergency) {
291                 SCPY(p_dialinginfo.id, "emergency");
292         }
293         p_dialinginfo.sending_complete = 1;
294
295         /* bearer capability */
296         // todo
297         p_capainfo.bearer_capa = INFO_BC_SPEECH;
298         p_capainfo.bearer_info1 = (options.law=='a')?3:2;
299         p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
300         p_capainfo.source_mode = B_MODE_TRANSPARENT;
301         p_m_g_mode = p_capainfo.source_mode;
302
303         /* useruser */
304
305         /* hunt channel */
306         ret = channel = hunt_bchannel();
307         if (ret < 0)
308                 goto no_channel;
309
310         /* open channel */
311         ret = seize_bchannel(channel, 1);
312         if (ret < 0) {
313                 no_channel:
314                 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
315                 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
316                 mncc->fields |= MNCC_F_CAUSE;
317                 mncc->cause.coding = 3;
318                 mncc->cause.location = 1;
319                 mncc->cause.value = 34;
320                 add_trace("cause", "coding", "%d", mncc->cause.coding);
321                 add_trace("cause", "location", "%d", mncc->cause.location);
322                 add_trace("cause", "value", "%d", mncc->cause.value);
323                 add_trace("reason", NULL, "no channel");
324                 end_trace();
325                 send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
326                 new_state(PORT_STATE_RELEASE);
327                 trigger_work(&p_m_g_delete);
328                 return;
329         }
330         bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
331         if (bchannel_open(p_m_b_index))
332                 goto no_channel;
333
334         /* what infos did we got ... */
335         gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
336         if (p_callerinfo.id[0])
337                 add_trace("calling", "number", "%s", p_callerinfo.id);
338         else
339                 SPRINT(p_callerinfo.id, "imsi-%s", p_callerinfo.imsi);
340         add_trace("calling", "imsi", "%s", p_callerinfo.imsi);
341         add_trace("dialing", "number", "%s", p_dialinginfo.id);
342         end_trace();
343
344         /* create endpoint */
345         if (p_epointlist)
346                 FATAL("Incoming call but already got an endpoint.\n");
347         if (!(epoint = new Endpoint(p_serial, 0)))
348                 FATAL("No memory for Endpoint instance\n");
349         if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
350                 FATAL("No memory for Endpoint Application instance\n");
351         epointlist_new(epoint->ep_serial);
352
353         /* modify lchan to GSM codec V1 */
354         gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
355         mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
356         mode->lchan_mode = 0x01; /* GSM V1 */
357         add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
358         end_trace();
359         send_and_free_mncc(p_m_g_instance, mode->msg_type, mode);
360
361         /* send call proceeding */
362         gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT);
363         proceeding = create_mncc(MNCC_CALL_PROC_REQ, p_m_g_callref);
364         if (p_m_mISDNport->tones) {
365                 proceeding->fields |= MNCC_F_PROGRESS;
366                 proceeding->progress.coding = 3; /* GSM */
367                 proceeding->progress.location = 1;
368                 proceeding->progress.descr = 8;
369                 add_trace("progress", "coding", "%d", proceeding->progress.coding);
370                 add_trace("progress", "location", "%d", proceeding->progress.location);
371                 add_trace("progress", "descr", "%d", proceeding->progress.descr);
372         }
373         end_trace();
374         send_and_free_mncc(p_m_g_instance, proceeding->msg_type, proceeding);
375
376         new_state(PORT_STATE_IN_PROCEEDING);
377
378         if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
379                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
380                 end_trace();
381                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
382                 send_and_free_mncc(p_m_g_instance, frame->msg_type, frame);
383                 p_m_g_tch_connected = 1;
384         }
385
386         /* send setup message to endpoit */
387         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
388         message->param.setup.isdn_port = p_m_portnum;
389         message->param.setup.port_type = p_type;
390 //      message->param.setup.dtmf = 0;
391         memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
392         memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
393         memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
394         SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
395         message->param.setup.useruser.len = strlen(mncc->useruser.info);
396         message->param.setup.useruser.protocol = mncc->useruser.proto;
397         message_put(message);
398 }
399
400 /*
401  * BSC sends message to port
402  */
403 static int message_bsc(struct gsm_network *net, int msg_type, void *arg)
404 {
405         struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
406         unsigned int callref = mncc->callref;
407         class Port *port;
408         class Pgsm_bs *pgsm_bs = NULL;
409         char name[64];
410         struct mISDNport *mISDNport;
411
412         /* Special messages */
413         switch(msg_type) {
414         }
415
416         /* find callref */
417         callref = mncc->callref;
418         port = port_first;
419         while(port) {
420                 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_BS) {
421                         pgsm_bs = (class Pgsm_bs *)port;
422                         if (pgsm_bs->p_m_g_callref == callref) {
423                                 break;
424                         }
425                 }
426                 port = port->next;
427         }
428
429         if (msg_type == GSM_TCHF_FRAME) {
430                 if (port)
431                         pgsm_bs->frame_receive((struct gsm_trau_frame *)arg);
432                 return 0;
433         }
434
435         if (!port) {
436                 if (msg_type != MNCC_SETUP_IND)
437                         return(0);
438                 /* find gsm port */
439                 mISDNport = mISDNport_first;
440                 while(mISDNport) {
441                         if (mISDNport->gsm_bs)
442                                 break;
443                         mISDNport = mISDNport->next;
444                 }
445                 if (!mISDNport) {
446                         struct gsm_mncc *rej;
447
448                         rej = create_mncc(MNCC_REJ_REQ, callref);
449                         rej->fields |= MNCC_F_CAUSE;
450                         rej->cause.coding = 3;
451                         rej->cause.location = 1;
452                         rej->cause.value = 27;
453                         gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
454                         add_trace("cause", "coding", "%d", rej->cause.coding);
455                         add_trace("cause", "location", "%d", rej->cause.location);
456                         add_trace("cause", "value", "%d", rej->cause.value);
457                         end_trace();
458                         send_and_free_mncc(gsm->network, rej->msg_type, rej);
459                         return 0;
460                 }
461                 /* creating port object, transparent until setup with hdlc */
462                 SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
463                 if (!(pgsm_bs = new Pgsm_bs(PORT_TYPE_GSM_BS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
464
465                         FATAL("Cannot create Port instance.\n");
466         }
467
468         switch(msg_type) {
469                 case MNCC_SETUP_IND:
470                 pgsm_bs->setup_ind(msg_type, callref, mncc);
471                 break;
472
473                 case MNCC_START_DTMF_IND:
474                 pgsm_bs->start_dtmf_ind(msg_type, callref, mncc);
475                 break;
476
477                 case MNCC_STOP_DTMF_IND:
478                 pgsm_bs->stop_dtmf_ind(msg_type, callref, mncc);
479                 break;
480
481                 case MNCC_CALL_CONF_IND:
482                 pgsm_bs->call_conf_ind(msg_type, callref, mncc);
483                 break;
484
485                 case MNCC_ALERT_IND:
486                 pgsm_bs->alert_ind(msg_type, callref, mncc);
487                 break;
488
489                 case MNCC_SETUP_CNF:
490                 pgsm_bs->setup_cnf(msg_type, callref, mncc);
491                 break;
492
493                 case MNCC_SETUP_COMPL_IND:
494                 pgsm_bs->setup_compl_ind(msg_type, callref, mncc);
495                 break;
496
497                 case MNCC_DISC_IND:
498                 pgsm_bs->disc_ind(msg_type, callref, mncc);
499                 break;
500
501                 case MNCC_REL_IND:
502                 case MNCC_REL_CNF:
503                 case MNCC_REJ_IND:
504                 pgsm_bs->rel_ind(msg_type, callref, mncc);
505                 break;
506
507                 case MNCC_NOTIFY_IND:
508                 pgsm_bs->notify_ind(msg_type, callref, mncc);
509                 break;
510
511                 case MNCC_HOLD_IND:
512                 pgsm_bs->hold_ind(msg_type, callref, mncc);
513                 break;
514
515                 case MNCC_RETRIEVE_IND:
516                 pgsm_bs->retr_ind(msg_type, callref, mncc);
517                 break;
518
519                 default:
520                 PDEBUG(DEBUG_GSM, "Pgsm_bs(%s) gsm port with (caller id %s) received unhandled nessage: 0x%x\n", pgsm_bs->p_name, pgsm_bs->p_callerinfo.id, msg_type);
521         }
522         return(0);
523 }
524
525 /* MESSAGE_SETUP */
526 void Pgsm_bs::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
527 {
528         struct lcr_msg *message;
529         int ret;
530         struct epoint_list *epointlist;
531         struct gsm_mncc *mncc;
532         int channel;
533
534         /* copy setup infos to port */
535         memcpy(&p_callerinfo, &param->setup.callerinfo, sizeof(p_callerinfo));
536         memcpy(&p_dialinginfo, &param->setup.dialinginfo, sizeof(p_dialinginfo));
537         memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
538         memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
539
540         /* no number */
541         if (!p_dialinginfo.id[0]) {
542                 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
543                 add_trace("failure", NULL, "No dialed subscriber given.");
544                 end_trace();
545                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
546                 message->param.disconnectinfo.cause = 28;
547                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
548                 message_put(message);
549                 new_state(PORT_STATE_RELEASE);
550                 trigger_work(&p_m_g_delete);
551                 return;
552         }
553         
554         /* release if port is blocked */
555         if (p_m_mISDNport->ifport->block) {
556                 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
557                 add_trace("failure", NULL, "Port blocked.");
558                 end_trace();
559                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
560                 message->param.disconnectinfo.cause = 27; // temp. unavail.
561                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
562                 message_put(message);
563                 new_state(PORT_STATE_RELEASE);
564                 trigger_work(&p_m_g_delete);
565                 return;
566         }
567
568         /* hunt channel */
569         ret = channel = hunt_bchannel();
570         if (ret < 0)
571                 goto no_channel;
572         /* open channel */
573         ret = seize_bchannel(channel, 1);
574         if (ret < 0) {
575                 no_channel:
576                 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
577                 add_trace("failure", NULL, "No internal audio channel available.");
578                 end_trace();
579                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
580                 message->param.disconnectinfo.cause = 34;
581                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
582                 message_put(message);
583                 new_state(PORT_STATE_RELEASE);
584                 trigger_work(&p_m_g_delete);
585                 return;
586         }
587         bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
588         if (bchannel_open(p_m_b_index))
589                 goto no_channel;
590
591 //              SCPY(&p_m_tones_dir, param->setup.ext.tones_dir);
592         /* screen outgoing caller id */
593         do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface);
594
595         /* attach only if not already */
596         epointlist = p_epointlist;
597         while(epointlist) {
598                 if (epointlist->epoint_id == epoint_id)
599                         break;
600                 epointlist = epointlist->next;
601         }
602         if (!epointlist)
603                 epointlist_new(epoint_id);
604
605         /* creating l3id */
606         l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
607         p_m_g_callref = new_callref++;
608         add_trace("callref", "new", "0x%x", p_m_g_callref);
609         end_trace();
610
611         gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
612         mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
613         /* caller information */
614         mncc->fields |= MNCC_F_CALLING;
615         mncc->calling.plan = 1;
616         switch (p_callerinfo.ntype) {
617                 case INFO_NTYPE_UNKNOWN:
618                 mncc->calling.type = 0x0;
619                 break;
620                 case INFO_NTYPE_INTERNATIONAL:
621                 mncc->calling.type = 0x1;
622                 break;
623                 case INFO_NTYPE_NATIONAL:
624                 mncc->calling.type = 0x2;
625                 break;
626                 case INFO_NTYPE_SUBSCRIBER:
627                 mncc->calling.type = 0x4;
628                 break;
629                 default: /* INFO_NTYPE_NOTPRESENT */
630                 mncc->fields &= ~MNCC_F_CALLING;
631                 break;
632         }
633         switch (p_callerinfo.screen) {
634                 case INFO_SCREEN_USER:
635                 mncc->calling.screen = 0;
636                 break;
637                 default: /* INFO_SCREEN_NETWORK */
638                 mncc->calling.screen = 3;
639                 break;
640         }
641         switch (p_callerinfo.present) {
642                 case INFO_PRESENT_ALLOWED:
643                 mncc->calling.present = 0;
644                 break;
645                 case INFO_PRESENT_RESTRICTED:
646                 mncc->calling.present = 1;
647                 break;
648                 default: /* INFO_PRESENT_NOTAVAIL */
649                 mncc->calling.present = 2;
650                 break;
651         }
652         if (mncc->fields & MNCC_F_CALLING) {
653                 SCPY(mncc->calling.number, p_callerinfo.id);
654                 add_trace("calling", "type", "%d", mncc->calling.type);
655                 add_trace("calling", "plan", "%d", mncc->calling.plan);
656                 add_trace("calling", "present", "%d", mncc->calling.present);
657                 add_trace("calling", "screen", "%d", mncc->calling.screen);
658                 add_trace("calling", "number", "%s", mncc->calling.number);
659         }
660         /* dialing information */
661         mncc->fields |= MNCC_F_CALLED;
662         if (!strncmp(p_dialinginfo.id, "imsi-", 5)) {
663                 SCPY(mncc->imsi, p_dialinginfo.id+5);
664                 add_trace("dialing", "imsi", "%s", mncc->imsi);
665         } else {
666                 SCPY(mncc->called.number, p_dialinginfo.id);
667                 add_trace("dialing", "number", "%s", mncc->called.number);
668         }
669         
670         /* sending user-user */
671
672         /* redirecting number */
673         mncc->fields |= MNCC_F_REDIRECTING;
674         mncc->redirecting.plan = 1;
675         switch (p_redirinfo.ntype) {
676                 case INFO_NTYPE_UNKNOWN:
677                 mncc->redirecting.type = 0x0;
678                 break;
679                 case INFO_NTYPE_INTERNATIONAL:
680                 mncc->redirecting.type = 0x1;
681                 break;
682                 case INFO_NTYPE_NATIONAL:
683                 mncc->redirecting.type = 0x2;
684                 break;
685                 case INFO_NTYPE_SUBSCRIBER:
686                 mncc->redirecting.type = 0x4;
687                 break;
688                 default: /* INFO_NTYPE_NOTPRESENT */
689                 mncc->fields &= ~MNCC_F_REDIRECTING;
690                 break;
691         }
692         switch (p_redirinfo.screen) {
693                 case INFO_SCREEN_USER:
694                 mncc->redirecting.screen = 0;
695                 break;
696                 default: /* INFO_SCREE_NETWORK */
697                 mncc->redirecting.screen = 3;
698                 break;
699         }
700         switch (p_redirinfo.present) {
701                 case INFO_PRESENT_ALLOWED:
702                 mncc->redirecting.present = 0;
703                 break;
704                 case INFO_PRESENT_RESTRICTED:
705                 mncc->redirecting.present = 1;
706                 break;
707                 default: /* INFO_PRESENT_NOTAVAIL */
708                 mncc->redirecting.present = 2;
709                 break;
710         }
711         /* sending redirecting number only in ntmode */
712         if (mncc->fields & MNCC_F_REDIRECTING) {
713                 SCPY(mncc->redirecting.number, p_redirinfo.id);
714                 add_trace("redir", "type", "%d", mncc->redirecting.type);
715                 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
716                 add_trace("redir", "present", "%d", mncc->redirecting.present);
717                 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
718                 add_trace("redir", "number", "%s", mncc->redirecting.number);
719         }
720         /* bearer capability */
721         //todo
722
723         end_trace();
724         send_and_free_mncc(p_m_g_instance, mncc->msg_type, mncc);
725
726         new_state(PORT_STATE_OUT_SETUP);
727
728         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
729         message_put(message);
730
731         new_state(PORT_STATE_OUT_PROCEEDING);
732 }
733
734 /*
735  * endpoint sends messages to the port
736  */
737 int Pgsm_bs::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
738 {
739         if (Pgsm::message_epoint(epoint_id, message_id, param))
740                 return(1);
741
742         switch(message_id) {
743                 case MESSAGE_SETUP: /* dial-out command received from epoint */
744                 if (p_state!=PORT_STATE_IDLE)
745                         break;
746                 message_setup(epoint_id, message_id, param);
747                 break;
748
749                 default:
750                 PDEBUG(DEBUG_GSM, "Pgsm_bs(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
751         }
752
753         return(1);
754 }
755
756 int gsm_bs_exit(int rc)
757 {
758         /* free gsm instance */
759         if (gsm) {
760                 /* shutdown network */
761                 if (gsm->network)
762                         bsc_shutdown_net((struct gsm_network *)gsm->network);
763                 /* free network */
764 //              if (gsm->network) {
765 //                      free((struct gsm_network *)gsm->network); /* TBD */
766 //              }
767         }
768
769         return(rc);
770 }
771
772 int gsm_bs_init(void)
773 {
774         char hlr[128], cfg[128], filename[128];
775         mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
776         int pcapfd, rc;
777
778         log_init(&log_info);
779         tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
780         talloc_ctx_init();
781         on_dso_load_token();
782         on_dso_load_rrlp();
783         on_dso_load_ho_dec();
784         stderr_target = log_target_create_stderr();
785         log_add_target(stderr_target);
786
787         bts_model_unknown_init();
788         bts_model_bs11_init();
789         bts_model_nanobts_init();
790
791         /* enable filters */
792         log_set_all_filter(stderr_target, 1);
793
794         /* set debug */
795         if (gsm->conf.debug[0])
796                 log_parse_category_mask(stderr_target, gsm->conf.debug);
797
798         /* open pcap file */
799         if (gsm->conf.pcapfile[0]) {
800                 if (gsm->conf.pcapfile[0] == '/')
801                         SCPY(filename, gsm->conf.pcapfile);
802                 else
803                         SPRINT(filename, "%s/%s", CONFIG_DATA, gsm->conf.pcapfile);
804                 pcapfd = open(filename, O_WRONLY|O_TRUNC|O_CREAT, mode);
805                 if (pcapfd < 0) {
806                         PERROR("Failed to open file for pcap\n");
807                         return gsm_exit(-1);
808                 }
809                 e1_set_pcap_fd(pcapfd);
810         }
811
812         /* use RTP proxy for audio streaming */
813         ipacc_rtp_direct = 0;
814
815         /* init database */
816         if (gsm->conf.hlr[0] == '/')
817                 SCPY(hlr, gsm->conf.hlr);
818         else
819                 SPRINT(hlr, "%s/%s", CONFIG_DATA, gsm->conf.hlr);
820         if (db_init(hlr)) {
821                 PERROR("GSM DB: Failed to init database '%s'. Please check the option settings.\n", hlr);
822                 return gsm_exit(-1);
823         }
824         printf("DB: Database initialized.\n");
825         if (db_prepare()) {
826                 PERROR("GSM DB: Failed to prepare database.\n");
827                 return gsm_exit(-1);
828         }
829         printf("DB: Database prepared.\n");
830
831         /* setup the timer */
832         db_sync_timer.cb = db_sync_timer_cb;
833         db_sync_timer.data = NULL;
834         bsc_schedule_timer(&db_sync_timer, DB_SYNC_INTERVAL);
835
836         /* Init VTY */
837         vty_init(&vty_info);
838         bsc_vty_init();
839
840         /* bootstrap network */
841         if (gsm->conf.openbsc_cfg[0] == '/')
842                 SCPY(cfg, gsm->conf.openbsc_cfg);
843         else
844                 SPRINT(cfg, "%s/%s", CONFIG_DATA, gsm->conf.openbsc_cfg);
845         rc = bsc_bootstrap_network(&message_bsc, cfg);
846         if (rc < 0) {
847                 PERROR("Failed to bootstrap GSM network.\n");
848                 return gsm_exit(-1);
849         }
850         gsm->network = bsc_gsmnet;
851
852         return 0;
853 }
854
855 /*
856  * handles bsc select function within LCR's main loop
857  */
858 int handle_gsm_bs(void)
859 {
860         int ret1, ret2;
861
862         ret1 = bsc_upqueue((struct gsm_network *)gsm->network);
863         log_reset_context();
864         ret2 = bsc_select_main(1); /* polling */
865         if (ret1 || ret2)
866                 return 1;
867         return 0;
868 }
869