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