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