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