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