Checking for GSM codec to be installed at configure.
[lcr.git] / gsm_ms.cpp
1 /*****************************************************************************\
2 **                                                                           **
3 ** LCR                                                                       **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** mISDN gsm (MS mode)                                                       **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13 #include "mncc.h"
14
15
16 struct lcr_gsm *gsm_ms_first = NULL;
17
18 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index);
19
20 #define DTMF_ST_IDLE            0       /* no DTMF active */
21 #define DTMF_ST_START           1       /* DTMF started, waiting for resp. */
22 #define DTMF_ST_MARK            2       /* wait tone duration */
23 #define DTMF_ST_STOP            3       /* DTMF stopped, waiting for resp. */
24 #define DTMF_ST_SPACE           4       /* wait space between tones */
25
26 /*
27  * constructor
28  */
29 Pgsm_ms::Pgsm_ms(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)
30 {
31         struct lcr_gsm *gsm_ms = gsm_ms_first;
32         char *ms_name = mISDNport->ifport->gsm_ms_name;
33
34         p_m_g_lcr_gsm = NULL;
35
36         while (gsm_ms) {
37                 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, ms_name)) {
38                         p_m_g_lcr_gsm = gsm_ms;
39                         break;
40                 }
41                 gsm_ms = gsm_ms->gsm_ms_next;
42         }
43
44         p_m_g_dtmf_state = DTMF_ST_IDLE;
45         p_m_g_dtmf_index = 0;
46         p_m_g_dtmf[0] = '\0';
47         memset(&p_m_g_dtmf_timer, 0, sizeof(p_m_g_dtmf_timer));
48         add_timer(&p_m_g_dtmf_timer, dtmf_timeout, this, 0);
49
50         PDEBUG(DEBUG_GSM, "Created new GSMMSPort(%s %s).\n", portname, ms_name);
51 }
52
53 /*
54  * destructor
55  */
56 Pgsm_ms::~Pgsm_ms()
57 {
58         PDEBUG(DEBUG_GSM, "Destroyed GSM MS process(%s).\n", p_name);
59         del_timer(&p_m_g_dtmf_timer);
60 }
61
62 /*
63  * handles all indications
64  */
65 /* SETUP INDICATION */
66 void Pgsm_ms::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
67 {
68         int ret;
69         class Endpoint *epoint;
70         struct lcr_msg *message;
71         int channel;
72         struct gsm_mncc *mode, *proceeding, *frame;
73
74         /* process given callref */
75         l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
76         add_trace("callref", "new", "0x%x", callref);
77         if (p_m_g_callref) {
78                 /* release in case the ID is already in use */
79                 add_trace("error", NULL, "callref already in use");
80                 end_trace();
81                 mncc = create_mncc(MNCC_REJ_REQ, callref);
82                 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
83                 mncc->fields |= MNCC_F_CAUSE;
84                 mncc->cause.coding = 3;
85                 mncc->cause.location = 1;
86                 mncc->cause.value = 47;
87                 add_trace("cause", "coding", "%d", mncc->cause.coding);
88                 add_trace("cause", "location", "%d", mncc->cause.location);
89                 add_trace("cause", "value", "%d", mncc->cause.value);
90                 add_trace("reason", NULL, "callref already in use");
91                 end_trace();
92                 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
93                 new_state(PORT_STATE_RELEASE);
94                 trigger_work(&p_m_g_delete);
95                 return;
96         }
97         p_m_g_callref = callref;
98         end_trace();
99
100         /* if blocked, release call with MT_RELEASE_COMPLETE */
101         if (p_m_mISDNport->ifport->block) {
102                 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
103                 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
104                 mncc->fields |= MNCC_F_CAUSE;
105                 mncc->cause.coding = 3;
106                 mncc->cause.location = 1;
107                 mncc->cause.value = 27;
108                 add_trace("cause", "coding", "%d", mncc->cause.coding);
109                 add_trace("cause", "location", "%d", mncc->cause.location);
110                 add_trace("cause", "value", "%d", mncc->cause.value);
111                 add_trace("reason", NULL, "port is blocked");
112                 end_trace();
113                 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
114                 new_state(PORT_STATE_RELEASE);
115                 trigger_work(&p_m_g_delete);
116                 return;
117         }
118
119         gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_IND, DIRECTION_IN);
120         /* caller information */
121         p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
122         if (mncc->fields & MNCC_F_CALLING) {
123                 switch (mncc->calling.present) {
124                         case 1:
125                         p_callerinfo.present = INFO_PRESENT_RESTRICTED;
126                         break;
127                         case 2:
128                         p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
129                         break;
130                         default:
131                         p_callerinfo.present = INFO_PRESENT_ALLOWED;
132                         break;
133                 }
134                 switch (mncc->calling.screen) {
135                         case 0:
136                         p_callerinfo.screen = INFO_SCREEN_USER;
137                         break;
138                         case 1:
139                         p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
140                         break;
141                         case 2:
142                         p_callerinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
143                         break;
144                         default:
145                         p_callerinfo.screen = INFO_SCREEN_NETWORK;
146                         break;
147                 }
148                 switch (mncc->calling.type) {
149                         case 0x0:
150                         p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
151                         break;
152                         case 0x1:
153                         p_callerinfo.ntype = INFO_NTYPE_INTERNATIONAL;
154                         break;
155                         case 0x2:
156                         p_callerinfo.ntype = INFO_NTYPE_NATIONAL;
157                         break;
158                         case 0x4:
159                         p_callerinfo.ntype = INFO_NTYPE_SUBSCRIBER;
160                         break;
161                         default:
162                         p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
163                         break;
164                 }
165                 SCPY(p_callerinfo.id, mncc->calling.number);
166                 add_trace("calling", "type", "%d", mncc->calling.type);
167                 add_trace("calling", "plan", "%d", mncc->calling.plan);
168                 add_trace("calling", "present", "%d", mncc->calling.present);
169                 add_trace("calling", "screen", "%d", mncc->calling.screen);
170                 add_trace("calling", "number", "%s", mncc->calling.number);
171         }
172         p_callerinfo.isdn_port = p_m_portnum;
173         SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
174         /* dialing information */
175         if (mncc->fields & MNCC_F_CALLED) {
176                 SCAT(p_dialinginfo.id, mncc->called.number);
177                 switch (mncc->called.type) {
178                         case 0x1:
179                         p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
180                         break;
181                         case 0x2:
182                         p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
183                         break;
184                         case 0x4:
185                         p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
186                         break;
187                         default:
188                         p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
189                         break;
190                 }
191                 add_trace("dialing", "type", "%d", mncc->called.type);
192                 add_trace("dialing", "plan", "%d", mncc->called.plan);
193                 add_trace("dialing", "number", "%s", mncc->called.number);
194         }
195         p_dialinginfo.sending_complete = 1;
196         /* redir info */
197         p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
198         if (mncc->fields & MNCC_F_REDIRECTING) {
199                 switch (mncc->redirecting.present) {
200                         case 1:
201                         p_redirinfo.present = INFO_PRESENT_RESTRICTED;
202                         break;
203                         case 2:
204                         p_redirinfo.present = INFO_PRESENT_NOTAVAIL;
205                         break;
206                         default:
207                         p_redirinfo.present = INFO_PRESENT_ALLOWED;
208                         break;
209                 }
210                 switch (mncc->redirecting.screen) {
211                         case 0:
212                         p_redirinfo.screen = INFO_SCREEN_USER;
213                         break;
214                         case 1:
215                         p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_PASSED;
216                         break;
217                         case 2:
218                         p_redirinfo.screen = INFO_SCREEN_USER_VERIFIED_FAILED;
219                         break;
220                         default:
221                         p_redirinfo.screen = INFO_SCREEN_NETWORK;
222                         break;
223                 }
224                 switch (mncc->redirecting.type) {
225                         case 0x0:
226                         p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
227                         break;
228                         case 0x1:
229                         p_redirinfo.ntype = INFO_NTYPE_INTERNATIONAL;
230                         break;
231                         case 0x2:
232                         p_redirinfo.ntype = INFO_NTYPE_NATIONAL;
233                         break;
234                         case 0x4:
235                         p_redirinfo.ntype = INFO_NTYPE_SUBSCRIBER;
236                         break;
237                         default:
238                         p_redirinfo.ntype = INFO_NTYPE_UNKNOWN;
239                         break;
240                 }
241                 SCPY(p_redirinfo.id, mncc->redirecting.number);
242                 add_trace("redir", "type", "%d", mncc->redirecting.type);
243                 add_trace("redir", "plan", "%d", mncc->redirecting.plan);
244                 add_trace("redir", "present", "%d", mncc->redirecting.present);
245                 add_trace("redir", "screen", "%d", mncc->redirecting.screen);
246                 add_trace("redir", "number", "%s", mncc->redirecting.number);
247                 p_redirinfo.isdn_port = p_m_portnum;
248         }
249         /* bearer capability */
250         if (mncc->fields & MNCC_F_BEARER_CAP) {
251                 switch (mncc->bearer_cap.transfer) {
252                         case 1:
253                         p_capainfo.bearer_capa = INFO_BC_DATAUNRESTRICTED;
254                         break;
255                         case 2:
256                         case 3:
257                         p_capainfo.bearer_capa = INFO_BC_AUDIO;
258                         p_capainfo.bearer_info1 = (options.law=='a')?3:2;
259                         break;
260                         default:
261                         p_capainfo.bearer_capa = INFO_BC_SPEECH;
262                         p_capainfo.bearer_info1 = (options.law=='a')?3:2;
263                         break;
264                 }
265                 switch (mncc->bearer_cap.mode) {
266                         case 1:
267                         p_capainfo.bearer_mode = INFO_BMODE_PACKET;
268                         break;
269                         default:
270                         p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
271                         break;
272                 }
273                 add_trace("bearer", "transfer", "%d", mncc->bearer_cap.transfer);
274                 add_trace("bearer", "mode", "%d", mncc->bearer_cap.mode);
275         } else {
276                 p_capainfo.bearer_capa = INFO_BC_SPEECH;
277                 p_capainfo.bearer_info1 = (options.law=='a')?3:2;
278                 p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
279         }
280         /* if packet mode works some day, see dss1.cpp for conditions */
281         p_capainfo.source_mode = B_MODE_TRANSPARENT;
282
283         end_trace();
284
285         /* hunt channel */
286         ret = channel = hunt_bchannel();
287         if (ret < 0)
288                 goto no_channel;
289
290         /* open channel */
291         ret = seize_bchannel(channel, 1);
292         if (ret < 0) {
293                 no_channel:
294                 mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
295                 gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
296                 mncc->fields |= MNCC_F_CAUSE;
297                 mncc->cause.coding = 3;
298                 mncc->cause.location = 1;
299                 mncc->cause.value = 34;
300                 add_trace("cause", "coding", "%d", mncc->cause.coding);
301                 add_trace("cause", "location", "%d", mncc->cause.location);
302                 add_trace("cause", "value", "%d", mncc->cause.value);
303                 add_trace("reason", NULL, "no channel");
304                 end_trace();
305                 send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
306                 new_state(PORT_STATE_RELEASE);
307                 trigger_work(&p_m_g_delete);
308                 return;
309         }
310         bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
311         if (bchannel_open(p_m_b_index))
312                 goto no_channel;
313
314         /* create endpoint */
315         if (p_epointlist)
316                 FATAL("Incoming call but already got an endpoint.\n");
317         if (!(epoint = new Endpoint(p_serial, 0)))
318                 FATAL("No memory for Endpoint instance\n");
319         if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
320                 FATAL("No memory for Endpoint Application instance\n");
321         epointlist_new(epoint->ep_serial);
322
323         /* modify lchan to GSM codec V1 */
324         gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
325         mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
326         mode->lchan_mode = 0x01; /* GSM V1 */
327         add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
328         end_trace();
329         send_and_free_mncc(p_m_g_lcr_gsm, mode->msg_type, mode);
330
331         /* send call proceeding */
332         gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_CONF_REQ, DIRECTION_OUT);
333         proceeding = create_mncc(MNCC_CALL_CONF_REQ, p_m_g_callref);
334         // FIXME: bearer
335         /* DTMF supported */
336         proceeding->fields |= MNCC_F_CCCAP;
337         proceeding->cccap.dtmf = 1;
338         end_trace();
339         send_and_free_mncc(p_m_g_lcr_gsm, proceeding->msg_type, proceeding);
340
341         new_state(PORT_STATE_IN_PROCEEDING);
342
343         if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
344                 gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
345                 end_trace();
346                 frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
347                 send_and_free_mncc(p_m_g_lcr_gsm, frame->msg_type, frame);
348                 p_m_g_tch_connected = 1;
349         }
350
351         /* send setup message to endpoit */
352         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
353         message->param.setup.isdn_port = p_m_portnum;
354         message->param.setup.port_type = p_type;
355 //      message->param.setup.dtmf = 0;
356         memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
357         memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
358         memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
359         SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser.info);
360         message->param.setup.useruser.len = strlen(mncc->useruser.info);
361         message->param.setup.useruser.protocol = mncc->useruser.proto;
362         message_put(message);
363 }
364
365 /*
366  * MS sends message to port
367  */
368 int message_ms(struct lcr_gsm *gsm_ms, int msg_type, void *arg)
369 {
370         struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
371         unsigned int callref = mncc->callref;
372         class Port *port;
373         class Pgsm_ms *pgsm_ms = NULL;
374         char name[64];
375         struct mISDNport *mISDNport;
376
377         /* Special messages */
378         switch (msg_type) {
379         }
380
381         /* find callref */
382         callref = mncc->callref;
383         port = port_first;
384         while(port) {
385                 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
386                         pgsm_ms = (class Pgsm_ms *)port;
387                         if (pgsm_ms->p_m_g_callref == callref) {
388                                 break;
389                         }
390                 }
391                 port = port->next;
392         }
393
394         if (msg_type == GSM_TCHF_FRAME) {
395                 if (port)
396                         pgsm_ms->frame_receive(arg);
397                 return 0;
398         }
399
400         if (!port) {
401                 if (msg_type != MNCC_SETUP_IND)
402                         return(0);
403                 /* find gsm ms port */
404                 mISDNport = mISDNport_first;
405                 while(mISDNport) {
406                         if (mISDNport->gsm_ms && !strcmp(mISDNport->ifport->gsm_ms_name, gsm_ms->name))
407                                 break;
408                         mISDNport = mISDNport->next;
409                 }
410                 if (!mISDNport) {
411                         struct gsm_mncc *rej;
412
413                         rej = create_mncc(MNCC_REJ_REQ, callref);
414                         rej->fields |= MNCC_F_CAUSE;
415                         rej->cause.coding = 3;
416                         rej->cause.location = 1;
417                         rej->cause.value = 27;
418                         gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
419                         add_trace("cause", "coding", "%d", rej->cause.coding);
420                         add_trace("cause", "location", "%d", rej->cause.location);
421                         add_trace("cause", "value", "%d", rej->cause.value);
422                         end_trace();
423                         send_and_free_mncc(gsm_ms, rej->msg_type, rej);
424                         return 0;
425                 }
426                 /* creating port object, transparent until setup with hdlc */
427                 SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
428                 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
429
430                         FATAL("Cannot create Port instance.\n");
431         }
432
433         switch(msg_type) {
434                 case MNCC_SETUP_IND:
435                 pgsm_ms->setup_ind(msg_type, callref, mncc);
436                 break;
437
438                 case MNCC_CALL_PROC_IND:
439                 pgsm_ms->call_proc_ind(msg_type, callref, mncc);
440                 break;
441
442                 case MNCC_ALERT_IND:
443                 pgsm_ms->alert_ind(msg_type, callref, mncc);
444                 break;
445
446                 case MNCC_SETUP_CNF:
447                 pgsm_ms->setup_cnf(msg_type, callref, mncc);
448                 break;
449
450                 case MNCC_SETUP_COMPL_IND:
451                 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
452                 break;
453
454                 case MNCC_DISC_IND:
455                 pgsm_ms->disc_ind(msg_type, callref, mncc);
456                 break;
457
458                 case MNCC_REL_IND:
459                 case MNCC_REL_CNF:
460                 case MNCC_REJ_IND:
461                 pgsm_ms->rel_ind(msg_type, callref, mncc);
462                 break;
463
464                 case MNCC_NOTIFY_IND:
465                 pgsm_ms->notify_ind(msg_type, callref, mncc);
466                 break;
467
468                 case MNCC_START_DTMF_RSP:
469                 case MNCC_START_DTMF_REJ:
470                 case MNCC_STOP_DTMF_RSP:
471                 pgsm_ms->dtmf_statemachine(mncc);
472                 break;
473
474                 default:
475                 ;
476         }
477         return(0);
478 }
479
480 /* MESSAGE_SETUP */
481 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
482 {
483         struct lcr_msg *message;
484         int ret;
485         struct epoint_list *epointlist;
486         struct gsm_mncc *mncc;
487         int channel;
488
489         /* copy setup infos to port */
490         memcpy(&p_callerinfo, &param->setup.callerinfo, sizeof(p_callerinfo));
491         memcpy(&p_dialinginfo, &param->setup.dialinginfo, sizeof(p_dialinginfo));
492         memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
493         memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
494
495         /* no instance */
496         if (!p_m_g_lcr_gsm || p_m_g_lcr_gsm->mncc_lfd.fd < 0) {
497                 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
498                 add_trace("failure", NULL, "MS %s instance is unavailable", p_m_mISDNport->ifport->gsm_ms_name);
499                 end_trace();
500                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
501                 message->param.disconnectinfo.cause = 41;
502                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
503                 message_put(message);
504                 new_state(PORT_STATE_RELEASE);
505                 trigger_work(&p_m_g_delete);
506                 return;
507         }
508         
509         /* no number */
510         if (!p_dialinginfo.id[0]) {
511                 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
512                 add_trace("failure", NULL, "No dialed subscriber given.");
513                 end_trace();
514                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
515                 message->param.disconnectinfo.cause = 28;
516                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
517                 message_put(message);
518                 new_state(PORT_STATE_RELEASE);
519                 trigger_work(&p_m_g_delete);
520                 return;
521         }
522         
523         /* release if port is blocked */
524         if (p_m_mISDNport->ifport->block) {
525                 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
526                 add_trace("failure", NULL, "Port blocked.");
527                 end_trace();
528                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
529                 message->param.disconnectinfo.cause = 27; // temp. unavail.
530                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
531                 message_put(message);
532                 new_state(PORT_STATE_RELEASE);
533                 trigger_work(&p_m_g_delete);
534                 return;
535         }
536
537         /* hunt channel */
538         ret = channel = hunt_bchannel();
539         if (ret < 0)
540                 goto no_channel;
541         /* open channel */
542         ret = seize_bchannel(channel, 1);
543         if (ret < 0) {
544                 no_channel:
545                 gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
546                 add_trace("failure", NULL, "No internal audio channel available.");
547                 end_trace();
548                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
549                 message->param.disconnectinfo.cause = 34;
550                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
551                 message_put(message);
552                 new_state(PORT_STATE_RELEASE);
553                 trigger_work(&p_m_g_delete);
554                 return;
555         }
556         bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
557         if (bchannel_open(p_m_b_index))
558                 goto no_channel;
559
560         /* attach only if not already */
561         epointlist = p_epointlist;
562         while(epointlist) {
563                 if (epointlist->epoint_id == epoint_id)
564                         break;
565                 epointlist = epointlist->next;
566         }
567         if (!epointlist)
568                 epointlist_new(epoint_id);
569
570         /* creating l3id */
571         l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
572         p_m_g_callref = new_callref++;
573         add_trace("callref", "new", "0x%x", p_m_g_callref);
574         end_trace();
575
576         gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
577         mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
578         if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
579                 mncc->emergency = 1;
580         } else {
581                 /* caller info (only clir) */
582                 switch (p_callerinfo.present) {
583                         case INFO_PRESENT_ALLOWED:
584                         mncc->clir.inv = 1;
585                         break;
586                         default:
587                         mncc->clir.sup = 1;
588                 }
589                 /* dialing information (mandatory) */
590                 mncc->fields |= MNCC_F_CALLED;
591                 mncc->called.type = 0; /* unknown */
592                 mncc->called.plan = 1; /* isdn */
593                 SCPY(mncc->called.number, p_dialinginfo.id);
594                 add_trace("dialing", "number", "%s", mncc->called.number);
595                 
596                 /* bearer capability (mandatory) */
597                 mncc->fields |= MNCC_F_BEARER_CAP;
598                 mncc->bearer_cap.coding = 0;
599                 mncc->bearer_cap.radio = 1;
600                 mncc->bearer_cap.speech_ctm = 0;
601                 mncc->bearer_cap.speech_ver[0] = 0;
602                 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
603                 switch (p_capainfo.bearer_capa) {
604                         case INFO_BC_DATAUNRESTRICTED:
605                         case INFO_BC_DATARESTRICTED:
606                         mncc->bearer_cap.transfer = 1;
607                         break;
608                         case INFO_BC_SPEECH:
609                         mncc->bearer_cap.transfer = 0;
610                         break;
611                         default:
612                         mncc->bearer_cap.transfer = 2;
613                         break;
614                 }
615                 switch (p_capainfo.bearer_mode) {
616                         case INFO_BMODE_PACKET:
617                         mncc->bearer_cap.mode = 1;
618                         break;
619                         default:
620                         mncc->bearer_cap.mode = 0;
621                         break;
622                 }
623                 /* DTMF supported */
624                 mncc->fields |= MNCC_F_CCCAP;
625                 mncc->cccap.dtmf = 1;
626
627                 /* request keypad from remote */
628                 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
629                 message_put(message);
630         }
631
632         end_trace();
633         send_and_free_mncc(p_m_g_lcr_gsm, mncc->msg_type, mncc);
634
635         new_state(PORT_STATE_OUT_SETUP);
636
637         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
638         message_put(message);
639
640         new_state(PORT_STATE_OUT_PROCEEDING);
641 }
642
643 void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc)
644 {
645         struct gsm_mncc *dtmf;
646
647         switch (p_m_g_dtmf_state) {
648         case DTMF_ST_SPACE:
649         case DTMF_ST_IDLE:
650                 /* end of string */
651                 if (!p_m_g_dtmf[p_m_g_dtmf_index]) {
652                         PDEBUG(DEBUG_GSM, "done with DTMF\n");
653                         p_m_g_dtmf_state = DTMF_ST_IDLE;
654                         return;
655                 }
656                 gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_REQ, DIRECTION_OUT);
657                 dtmf = create_mncc(MNCC_START_DTMF_REQ, p_m_g_callref);
658                 dtmf->keypad = p_m_g_dtmf[p_m_g_dtmf_index++];
659                 p_m_g_dtmf_state = DTMF_ST_START;
660                 PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n",
661                         dtmf->keypad);
662                 end_trace();
663                 send_and_free_mncc(p_m_g_lcr_gsm, dtmf->msg_type, dtmf);
664                 return;
665         case DTMF_ST_START:
666                 if (mncc->msg_type != MNCC_START_DTMF_RSP) {
667                         PDEBUG(DEBUG_GSM, "DTMF was rejected\n");
668                         return;
669                 }
670                 schedule_timer(&p_m_g_dtmf_timer, 0, 70 * 1000);
671                 p_m_g_dtmf_state = DTMF_ST_MARK;
672                 PDEBUG(DEBUG_GSM, "DTMF is on\n");
673                 break;
674         case DTMF_ST_MARK:
675                 gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT);
676                 dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_m_g_callref);
677                 p_m_g_dtmf_state = DTMF_ST_STOP;
678                 end_trace();
679                 send_and_free_mncc(p_m_g_lcr_gsm, dtmf->msg_type, dtmf);
680                 return;
681         case DTMF_ST_STOP:
682                 schedule_timer(&p_m_g_dtmf_timer, 0, 120 * 1000);
683                 p_m_g_dtmf_state = DTMF_ST_SPACE;
684                 PDEBUG(DEBUG_GSM, "DTMF is off\n");
685                 break;
686         }
687 }
688
689 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index)
690 {
691         class Pgsm_ms *pgsm_ms = (class Pgsm_ms *)instance;
692
693         PDEBUG(DEBUG_GSM, "DTMF timer has fired\n");
694         pgsm_ms->dtmf_statemachine(NULL);
695
696         return 0;
697 }
698
699 /* MESSAGE_DTMF */
700 void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
701 {
702         char digit = param->dtmf;
703
704         if (digit >= 'a' && digit <= 'c')
705                 digit = digit - 'a' + 'A';
706         if (!strchr("01234567890*#ABC", digit))
707                 return;
708
709         /* schedule */
710         if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
711                 p_m_g_dtmf_index = 0;
712                 p_m_g_dtmf[0] = '\0';
713         }
714         SCCAT(p_m_g_dtmf, digit);
715         if (p_m_g_dtmf_state == DTMF_ST_IDLE)
716                 dtmf_statemachine(NULL);
717 }
718
719 /* MESSAGE_INFORMATION */
720 void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union parameter *param)
721 {
722         char digit;
723         int i;
724
725         for (i = 0; i < (int)strlen(param->information.id); i++) {
726                 digit = param->information.id[i];
727                 if (digit >= 'a' && digit <= 'c')
728                         digit = digit - 'a' + 'A';
729                 if (!strchr("01234567890*#ABC", digit))
730                         continue;
731
732                 /* schedule */
733                 if (p_m_g_dtmf_state == DTMF_ST_IDLE) {
734                         p_m_g_dtmf_index = 0;
735                         p_m_g_dtmf[0] = '\0';
736                 }
737                 SCCAT(p_m_g_dtmf, digit);
738                 if (p_m_g_dtmf_state == DTMF_ST_IDLE)
739                         dtmf_statemachine(NULL);
740         }
741 }
742
743 /*
744  * endpoint sends messages to the port
745  */
746 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
747 {
748         struct lcr_msg *message;
749
750         if (message_id == MESSAGE_CONNECT) {
751                 /* request keypad from remote */
752                 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
753                 message_put(message);
754         }
755
756         if (Pgsm::message_epoint(epoint_id, message_id, param))
757                 return(1);
758
759         switch(message_id) {
760                 case MESSAGE_SETUP: /* dial-out command received from epoint */
761                 if (p_state!=PORT_STATE_IDLE)
762                         break;
763                 message_setup(epoint_id, message_id, param);
764                 break;
765
766                 case MESSAGE_DTMF:
767                 message_dtmf(epoint_id, message_id, param);
768                 break;
769
770                 case MESSAGE_INFORMATION:
771                 message_information(epoint_id, message_id, param);
772                 break;
773
774                 default:
775                 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
776         }
777
778         return(1);
779 }
780
781 int gsm_ms_exit(int rc)
782 {
783         /* destroy all instances */
784         while (gsm_ms_first)
785                 gsm_ms_delete(gsm_ms_first->name);
786
787         return rc;
788 }
789
790 int gsm_ms_init(void)
791 {
792         return 0;
793 }
794
795 /* add a new GSM mobile instance */
796 int gsm_ms_new(const char *name)
797 {
798         struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
799
800         while (gsm_ms) {
801                 gsm_ms_p = &gsm_ms->gsm_ms_next;
802                 gsm_ms = gsm_ms->gsm_ms_next;
803         }
804
805         PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", name);
806
807         /* create gsm instance */
808         gsm_ms = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
809
810         gsm_ms->type = LCR_GSM_TYPE_MS;
811         SCPY(gsm_ms->name, name);
812         gsm_ms->sun.sun_family = AF_UNIX;
813         SPRINT(gsm_ms->sun.sun_path, "/tmp/ms_mncc_%s", name);
814
815         memset(&gsm_ms->socket_retry, 0, sizeof(gsm_ms->socket_retry));
816         add_timer(&gsm_ms->socket_retry, mncc_socket_retry_cb, gsm_ms, 0);
817
818         /* do the initial connect */
819         mncc_socket_retry_cb(&gsm_ms->socket_retry, gsm_ms, 0);
820
821         *gsm_ms_p = gsm_ms;
822
823         return 0;
824 }
825
826 int gsm_ms_delete(const char *name)
827 {
828         struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
829 //      class Port *port;
830 //      class Pgsm_ms *pgsm_ms = NULL;
831
832         PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is deleted\n", name);
833
834         while (gsm_ms) {
835                 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, name))
836                         break;
837                 gsm_ms_p = &gsm_ms->gsm_ms_next;
838                 gsm_ms = gsm_ms->gsm_ms_next;
839         }
840
841         if (!gsm_ms)
842                 return 0;
843
844 /* not needed, because:
845  * - shutdown of interface will destry port instances locally
846  * - closing of socket will make remote socket destroy calls locally
847  */
848 #if 0
849         port = port_first;
850         while(port) {
851                 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
852                         pgsm_ms = (class Pgsm_ms *)port;
853                         if (pgsm_ms->p_m_g_lcr_gsm == gsm_ms && pgsm_ms->p_m_g_callref) {
854                                 struct gsm_mncc *rej;
855
856                                 rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_m_g_callref);
857                                 rej->fields |= MNCC_F_CAUSE;
858                                 rej->cause.coding = 3;
859                                 rej->cause.location = 1;
860                                 rej->cause.value = 27;
861                                 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
862                                 add_trace("cause", "coding", "%d", rej->cause.coding);
863                                 add_trace("cause", "location", "%d", rej->cause.location);
864                                 add_trace("cause", "value", "%d", rej->cause.value);
865                                 end_trace();
866                                 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
867                                 pgsm_ms->new_state(PORT_STATE_RELEASE);
868                                 trigger_work(&pgsm_ms->p_m_g_delete);
869                         }
870                 }
871         }
872 #endif
873
874         if (gsm_ms->mncc_lfd.fd > -1) {
875                 close(gsm_ms->mncc_lfd.fd);
876                 unregister_fd(&gsm_ms->mncc_lfd);
877         }
878         del_timer(&gsm_ms->socket_retry);
879
880         /* remove instance from list */
881         *gsm_ms_p = gsm_ms->gsm_ms_next;
882         FREE(gsm_ms, sizeof(struct lcr_gsm));
883
884         return 0;
885 }
886
887