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