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