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