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