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