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