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