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