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