GSM: Add audio frame type for uncompressed 16 bit frame
[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_ms_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(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         class Port *port;
340         class Pgsm_ms *pgsm_ms = NULL;
341         char name[64];
342 //      struct mISDNport *mISDNport;
343
344         /* Special messages */
345         switch (msg_type) {
346         }
347
348         /* find callref */
349         callref = mncc->callref;
350         port = port_first;
351         while(port) {
352                 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
353                         pgsm_ms = (class Pgsm_ms *)port;
354                         if (pgsm_ms->p_g_callref == callref) {
355                                 break;
356                         }
357                 }
358                 port = port->next;
359         }
360
361         if (msg_type == GSM_TCHF_FRAME
362          || msg_type == GSM_BAD_FRAME) {
363                 if (port)
364                         pgsm_ms->frame_receive(arg);
365                 return 0;
366         }
367
368         if (!port) {
369                 struct interface *interface;
370
371                 if (msg_type != MNCC_SETUP_IND)
372                         return(0);
373
374                 interface = getinterfacebyname(gsm_ms->interface_name);
375                 if (!interface) {
376                         struct gsm_mncc *rej;
377
378                         rej = create_mncc(MNCC_REJ_REQ, callref);
379                         rej->fields |= MNCC_F_CAUSE;
380                         rej->cause.coding = 3;
381                         rej->cause.location = 1;
382                         rej->cause.value = 27;
383                         gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
384                         add_trace("cause", "coding", "%d", rej->cause.coding);
385                         add_trace("cause", "location", "%d", rej->cause.location);
386                         add_trace("cause", "value", "%d", rej->cause.value);
387                         add_trace("reason", NULL, "interface %s not found", gsm_ms->interface_name);
388                         end_trace();
389                         send_and_free_mncc(gsm_ms, rej->msg_type, rej);
390                         return 0;
391                 }
392                 /* creating port object, transparent until setup with hdlc */
393                 SPRINT(name, "%s-%d-in", interface->name, 0);
394                 if (!(pgsm_ms = new Pgsm_ms(PORT_TYPE_GSM_MS_IN, name, NULL, interface)))
395                         FATAL("Cannot create Port instance.\n");
396         }
397
398         switch(msg_type) {
399                 case MNCC_SETUP_IND:
400                 pgsm_ms->setup_ind(msg_type, callref, mncc);
401                 break;
402
403                 case MNCC_CALL_PROC_IND:
404                 pgsm_ms->call_proc_ind(msg_type, callref, mncc);
405                 break;
406
407                 case MNCC_ALERT_IND:
408                 pgsm_ms->alert_ind(msg_type, callref, mncc);
409                 break;
410
411                 case MNCC_SETUP_CNF:
412                 pgsm_ms->setup_cnf(msg_type, callref, mncc);
413                 break;
414
415                 case MNCC_SETUP_COMPL_IND:
416                 pgsm_ms->setup_compl_ind(msg_type, callref, mncc);
417                 break;
418
419                 case MNCC_DISC_IND:
420                 pgsm_ms->disc_ind(msg_type, callref, mncc);
421                 break;
422
423                 case MNCC_REL_IND:
424                 case MNCC_REL_CNF:
425                 case MNCC_REJ_IND:
426                 pgsm_ms->rel_ind(msg_type, callref, mncc);
427                 break;
428
429                 case MNCC_NOTIFY_IND:
430                 pgsm_ms->notify_ind(msg_type, callref, mncc);
431                 break;
432
433                 case MNCC_START_DTMF_RSP:
434                 case MNCC_START_DTMF_REJ:
435                 case MNCC_STOP_DTMF_RSP:
436                 pgsm_ms->dtmf_statemachine(mncc);
437                 break;
438
439                 default:
440                 ;
441         }
442         return(0);
443 }
444
445 /* MESSAGE_SETUP */
446 void Pgsm_ms::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
447 {
448         struct lcr_msg *message;
449         struct epoint_list *epointlist;
450         struct gsm_mncc *mncc;
451
452         /* copy setup infos to port */
453         memcpy(&p_callerinfo, &param->setup.callerinfo, sizeof(p_callerinfo));
454         memcpy(&p_dialinginfo, &param->setup.dialinginfo, sizeof(p_dialinginfo));
455         memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
456         memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
457
458         /* no instance */
459         if (!p_g_lcr_gsm || p_g_lcr_gsm->mncc_lfd.fd < 0) {
460                 gsm_trace_header(p_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
461                 add_trace("failure", NULL, "MS %s instance is unavailable", p_g_ms_name);
462                 end_trace();
463                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
464                 message->param.disconnectinfo.cause = 41;
465                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
466                 message_put(message);
467                 new_state(PORT_STATE_RELEASE);
468                 trigger_work(&p_g_delete);
469                 return;
470         }
471         
472         /* no number */
473         if (!p_dialinginfo.id[0]) {
474                 gsm_trace_header(p_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
475                 add_trace("failure", NULL, "No dialed subscriber given.");
476                 end_trace();
477                 message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
478                 message->param.disconnectinfo.cause = 28;
479                 message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
480                 message_put(message);
481                 new_state(PORT_STATE_RELEASE);
482                 trigger_work(&p_g_delete);
483                 return;
484         }
485
486         /* attach only if not already */
487         epointlist = p_epointlist;
488         while(epointlist) {
489                 if (epointlist->epoint_id == epoint_id)
490                         break;
491                 epointlist = epointlist->next;
492         }
493         if (!epointlist)
494                 epointlist_new(epoint_id);
495
496         /* creating l3id */
497         gsm_trace_header(p_interface_name, this, 0, DIRECTION_OUT);
498         p_g_callref = new_callref++;
499         add_trace("callref", "new", "0x%x", p_g_callref);
500         end_trace();
501
502         gsm_trace_header(p_interface_name, this, MNCC_SETUP_REQ, DIRECTION_OUT);
503         mncc = create_mncc(MNCC_SETUP_REQ, p_g_callref);
504         if (!strncasecmp(p_dialinginfo.id, "emerg", 5)) {
505                 mncc->emergency = 1;
506         } else {
507                 /* caller info (only clir) */
508                 switch (p_callerinfo.present) {
509                         case INFO_PRESENT_ALLOWED:
510                         mncc->clir.inv = 1;
511                         break;
512                         default:
513                         mncc->clir.sup = 1;
514                 }
515                 /* dialing information (mandatory) */
516                 mncc->fields |= MNCC_F_CALLED;
517                 mncc->called.type = 0; /* unknown */
518                 mncc->called.plan = 1; /* isdn */
519                 SCPY(mncc->called.number, p_dialinginfo.id);
520                 add_trace("dialing", "number", "%s", mncc->called.number);
521                 
522                 /* bearer capability (mandatory) */
523                 mncc->fields |= MNCC_F_BEARER_CAP;
524                 mncc->bearer_cap.coding = 0;
525                 mncc->bearer_cap.radio = 1;
526                 mncc->bearer_cap.speech_ctm = 0;
527                 mncc->bearer_cap.speech_ver[0] = 0;
528                 mncc->bearer_cap.speech_ver[1] = -1; /* end of list */
529                 switch (p_capainfo.bearer_capa) {
530                         case INFO_BC_DATAUNRESTRICTED:
531                         case INFO_BC_DATARESTRICTED:
532                         mncc->bearer_cap.transfer = 1;
533                         break;
534                         case INFO_BC_SPEECH:
535                         mncc->bearer_cap.transfer = 0;
536                         break;
537                         default:
538                         mncc->bearer_cap.transfer = 2;
539                         break;
540                 }
541                 switch (p_capainfo.bearer_mode) {
542                         case INFO_BMODE_PACKET:
543                         mncc->bearer_cap.mode = 1;
544                         break;
545                         default:
546                         mncc->bearer_cap.mode = 0;
547                         break;
548                 }
549                 /* DTMF supported */
550                 mncc->fields |= MNCC_F_CCCAP;
551                 mncc->cccap.dtmf = 1;
552
553                 /* request keypad from remote */
554                 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
555                 message_put(message);
556         }
557
558         end_trace();
559         send_and_free_mncc(p_g_lcr_gsm, mncc->msg_type, mncc);
560
561         new_state(PORT_STATE_OUT_SETUP);
562
563         message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
564         message_put(message);
565
566         new_state(PORT_STATE_OUT_PROCEEDING);
567
568         p_g_rtp_bridge = 0;
569 }
570
571 void Pgsm_ms::dtmf_statemachine(struct gsm_mncc *mncc)
572 {
573         struct gsm_mncc *dtmf;
574
575         switch (p_g_dtmf_state) {
576         case DTMF_ST_SPACE:
577         case DTMF_ST_IDLE:
578                 /* end of string */
579                 if (!p_g_dtmf[p_g_dtmf_index]) {
580                         PDEBUG(DEBUG_GSM, "done with DTMF\n");
581                         p_g_dtmf_state = DTMF_ST_IDLE;
582                         return;
583                 }
584                 gsm_trace_header(p_interface_name, this, MNCC_START_DTMF_REQ, DIRECTION_OUT);
585                 dtmf = create_mncc(MNCC_START_DTMF_REQ, p_g_callref);
586                 dtmf->keypad = p_g_dtmf[p_g_dtmf_index++];
587                 p_g_dtmf_state = DTMF_ST_START;
588                 PDEBUG(DEBUG_GSM, "start DTMF (keypad %c)\n",
589                         dtmf->keypad);
590                 end_trace();
591                 send_and_free_mncc(p_g_lcr_gsm, dtmf->msg_type, dtmf);
592                 return;
593         case DTMF_ST_START:
594                 if (mncc->msg_type != MNCC_START_DTMF_RSP) {
595                         PDEBUG(DEBUG_GSM, "DTMF was rejected\n");
596                         return;
597                 }
598                 schedule_timer(&p_g_dtmf_timer, 0, 70 * 1000);
599                 p_g_dtmf_state = DTMF_ST_MARK;
600                 PDEBUG(DEBUG_GSM, "DTMF is on\n");
601                 break;
602         case DTMF_ST_MARK:
603                 gsm_trace_header(p_interface_name, this, MNCC_STOP_DTMF_REQ, DIRECTION_OUT);
604                 dtmf = create_mncc(MNCC_STOP_DTMF_REQ, p_g_callref);
605                 p_g_dtmf_state = DTMF_ST_STOP;
606                 end_trace();
607                 send_and_free_mncc(p_g_lcr_gsm, dtmf->msg_type, dtmf);
608                 return;
609         case DTMF_ST_STOP:
610                 schedule_timer(&p_g_dtmf_timer, 0, 120 * 1000);
611                 p_g_dtmf_state = DTMF_ST_SPACE;
612                 PDEBUG(DEBUG_GSM, "DTMF is off\n");
613                 break;
614         }
615 }
616
617 static int dtmf_timeout(struct lcr_timer *timer, void *instance, int index)
618 {
619         class Pgsm_ms *pgsm_ms = (class Pgsm_ms *)instance;
620
621         PDEBUG(DEBUG_GSM, "DTMF timer has fired\n");
622         pgsm_ms->dtmf_statemachine(NULL);
623
624         return 0;
625 }
626
627 /* MESSAGE_DTMF */
628 void Pgsm_ms::message_dtmf(unsigned int epoint_id, int message_id, union parameter *param)
629 {
630         char digit = param->dtmf;
631
632         if (digit >= 'a' && digit <= 'c')
633                 digit = digit - 'a' + 'A';
634         if (!strchr("01234567890*#ABC", digit))
635                 return;
636
637         /* schedule */
638         if (p_g_dtmf_state == DTMF_ST_IDLE) {
639                 p_g_dtmf_index = 0;
640                 p_g_dtmf[0] = '\0';
641         }
642         SCCAT(p_g_dtmf, digit);
643         if (p_g_dtmf_state == DTMF_ST_IDLE)
644                 dtmf_statemachine(NULL);
645 }
646
647 /* MESSAGE_INFORMATION */
648 void Pgsm_ms::message_information(unsigned int epoint_id, int message_id, union parameter *param)
649 {
650         char digit;
651         int i;
652
653         for (i = 0; i < (int)strlen(param->information.id); i++) {
654                 digit = param->information.id[i];
655                 if (digit >= 'a' && digit <= 'c')
656                         digit = digit - 'a' + 'A';
657                 if (!strchr("01234567890*#ABC", digit))
658                         continue;
659
660                 /* schedule */
661                 if (p_g_dtmf_state == DTMF_ST_IDLE) {
662                         p_g_dtmf_index = 0;
663                         p_g_dtmf[0] = '\0';
664                 }
665                 SCCAT(p_g_dtmf, digit);
666                 if (p_g_dtmf_state == DTMF_ST_IDLE)
667                         dtmf_statemachine(NULL);
668         }
669 }
670
671 /*
672  * endpoint sends messages to the port
673  */
674 int Pgsm_ms::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
675 {
676         struct lcr_msg *message;
677
678         if (message_id == MESSAGE_CONNECT) {
679                 /* request keypad from remote */
680                 message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ENABLEKEYPAD);
681                 message_put(message);
682         }
683
684         if (Pgsm::message_epoint(epoint_id, message_id, param))
685                 return(1);
686
687         switch(message_id) {
688                 case MESSAGE_SETUP: /* dial-out command received from epoint */
689                 if (p_state!=PORT_STATE_IDLE)
690                         break;
691                 message_setup(epoint_id, message_id, param);
692                 break;
693
694                 case MESSAGE_DTMF:
695                 message_dtmf(epoint_id, message_id, param);
696                 break;
697
698                 case MESSAGE_INFORMATION:
699                 message_information(epoint_id, message_id, param);
700                 break;
701
702                 default:
703                 PDEBUG(DEBUG_GSM, "Pgsm_ms(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
704         }
705
706         return(1);
707 }
708
709 int gsm_ms_exit(int rc)
710 {
711         /* destroy all instances */
712         while (gsm_ms_first)
713                 gsm_ms_delete(gsm_ms_first->name);
714
715         return rc;
716 }
717
718 int gsm_ms_init(void)
719 {
720         return 0;
721 }
722
723 /* add a new GSM mobile instance */
724 int gsm_ms_new(struct interface *interface)
725 {
726         struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
727
728         while (gsm_ms) {
729                 gsm_ms_p = &gsm_ms->gsm_ms_next;
730                 gsm_ms = gsm_ms->gsm_ms_next;
731         }
732
733         PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is created\n", interface->gsm_ms_name);
734
735         /* create gsm instance */
736         gsm_ms = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
737
738         SCPY(gsm_ms->interface_name, interface->name);
739         gsm_ms->type = LCR_GSM_TYPE_MS;
740         SCPY(gsm_ms->name, interface->gsm_ms_name);
741         gsm_ms->sun.sun_family = AF_UNIX;
742         SPRINT(gsm_ms->sun.sun_path, "/tmp/ms_mncc_%s", gsm_ms->name);
743
744         memset(&gsm_ms->socket_retry, 0, sizeof(gsm_ms->socket_retry));
745         add_timer(&gsm_ms->socket_retry, mncc_socket_retry_cb, gsm_ms, 0);
746
747         /* do the initial connect */
748         mncc_socket_retry_cb(&gsm_ms->socket_retry, gsm_ms, 0);
749
750         *gsm_ms_p = gsm_ms;
751
752         return 0;
753 }
754
755 int gsm_ms_delete(const char *name)
756 {
757         struct lcr_gsm *gsm_ms = gsm_ms_first, **gsm_ms_p = &gsm_ms_first;
758 //      class Port *port;
759 //      class Pgsm_ms *pgsm_ms = NULL;
760
761         PDEBUG(DEBUG_GSM, "GSM: interface for MS '%s' is deleted\n", name);
762
763         while (gsm_ms) {
764                 if (gsm_ms->type == LCR_GSM_TYPE_MS && !strcmp(gsm_ms->name, name))
765                         break;
766                 gsm_ms_p = &gsm_ms->gsm_ms_next;
767                 gsm_ms = gsm_ms->gsm_ms_next;
768         }
769
770         if (!gsm_ms)
771                 return 0;
772
773 /* not needed, because:
774  * - shutdown of interface will destry port instances locally
775  * - closing of socket will make remote socket destroy calls locally
776  */
777 #if 0
778         port = port_first;
779         while(port) {
780                 if ((port->p_type & PORT_CLASS_GSM_MASK) == PORT_CLASS_GSM_MS) {
781                         pgsm_ms = (class Pgsm_ms *)port;
782                         if (pgsm_ms->p_g_lcr_gsm == gsm_ms && pgsm_ms->p_g_callref) {
783                                 struct gsm_mncc *rej;
784
785                                 rej = create_mncc(MNCC_REL_REQ, pgsm_ms->p_g_callref);
786                                 rej->fields |= MNCC_F_CAUSE;
787                                 rej->cause.coding = 3;
788                                 rej->cause.location = 1;
789                                 rej->cause.value = 27;
790                                 gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
791                                 add_trace("cause", "coding", "%d", rej->cause.coding);
792                                 add_trace("cause", "location", "%d", rej->cause.location);
793                                 add_trace("cause", "value", "%d", rej->cause.value);
794                                 end_trace();
795                                 send_and_free_mncc(gsm_ms, rej->msg_type, rej);
796                                 pgsm_ms->new_state(PORT_STATE_RELEASE);
797                                 trigger_work(&pgsm_ms->p_g_delete);
798                         }
799                 }
800         }
801 #endif
802
803         if (gsm_ms->mncc_lfd.fd > -1) {
804                 close(gsm_ms->mncc_lfd.fd);
805                 unregister_fd(&gsm_ms->mncc_lfd);
806         }
807         del_timer(&gsm_ms->socket_retry);
808
809         /* remove instance from list */
810         *gsm_ms_p = gsm_ms->gsm_ms_next;
811         FREE(gsm_ms, sizeof(struct lcr_gsm));
812
813         return 0;
814 }
815
816