Added GSM network support.
authorAndreas Eversberg <andreas@eversberg.eu>
Mon, 11 May 2009 09:07:58 +0000 (11:07 +0200)
committerAndreas Eversberg <andreas@eversberg.eu>
Mon, 11 May 2009 09:07:58 +0000 (11:07 +0200)
This turns LCR into a GSM mobile switching center.
More infos will follow.

30 files changed:
Makefile.am
Makefile.in
README
apppbx.cpp
bootstrap.c [new file with mode: 0644]
bootstrap.h [new file with mode: 0644]
configure
configure.ac
default/gsm.conf [new file with mode: 0644]
default/interface.conf
default/options.conf
dss1.cpp
endpoint.cpp
gsm.cpp [new file with mode: 0644]
gsm.h [new file with mode: 0644]
gsm_audio.c [new file with mode: 0644]
gsm_audio.h [new file with mode: 0644]
gsm_conf.c [new file with mode: 0644]
interface.c
interface.h
lcradmin.c
mISDN.cpp
mISDN.h
main.c
main.h
message.h
options.c
options.h
port.h
route.c

index 7f1b577..61d8a86 100644 (file)
@@ -43,8 +43,18 @@ INSTALLATION_DEFINES = \
  -DLOG_DIR="\"$(LOGdir)\"" \
  -DEXTENSION_DATA="\"$(EXTENSIONdir)\""
 
-INCLUDES = $(all_includes) -I/usr/include/mISDNuser $(INSTALLATION_DEFINES) 
+if ENABLE_GSM
 
+GSM_INCLUDE = -DWITH_GSM
+
+GSM_SOURCE = gsm_audio.c gsm.cpp gsm_conf.c bootstrap.c
+
+GSM_LIB = /usr/local/lib/libgsm.a /usr/local/lib/libbsc.a /usr/local/lib/libvty.a -ldbi -lcrypt
+
+#gsm_audio.po: gsm_audio.c gsm_audio.h
+#      $(CC) -D_GNU_SOURCE -fPIC -c gsm_audio.c -o gsm_audio.po
+
+endif
 
 bin_PROGRAMS = lcradmin gentones genwave
 
@@ -74,7 +84,9 @@ install-exec-hook:
        $(INSTALL) chan_lcr.so $(astmoddir)
 endif
 
-lcr_SOURCES = action.cpp       mISDN.cpp        tones.c \
+INCLUDES = $(all_includes) $(GSM_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
+
+lcr_SOURCES = $(GSM_SOURCE) action.cpp       mISDN.cpp        tones.c \
        action_efi.cpp   crypt.cpp        mail.c           trace.c \
        action_vbox.cpp  dss1.cpp         main.c           \
        vbox.cpp alawulaw.c       endpoint.cpp     interface.c     message.c \
@@ -83,7 +95,8 @@ lcr_SOURCES = action.cpp       mISDN.cpp        tones.c \
        callerid.c       joinremote.cpp  route.c \
        cause.c          socket_server.c
 
-lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread
+lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread $(GSM_LIB)
+
 
 lcradmin_SOURCES = lcradmin.c cause.c options.c
 genextension_SOURCES = genext.c options.c extension.c
@@ -111,6 +124,9 @@ install-data-hook:
        @if test -a $(CONFIGdir)/routing.conf ; then \
                echo "NOTE: routing.conf already exists, not changed." ; else \
                cp -v default/routing.conf $(CONFIGdir) ; fi
+       @if test -a $(CONFIGdir)/gsm.conf ; then \
+               echo "NOTE: gsm.conf already exists, not changed." ; else \
+               cp -v default/gsm.conf $(CONFIGdir) ; fi
        @if test -a $(CONFIGdir)/numbering_int.conf ; then \
                echo "NOTE: numbering_int.conf is obsolete, please use routing." ; fi
        @if test -a $(CONFIGdir)/numbering_ext.conf ; then \
index 9a94335..36fafce 100644 (file)
@@ -75,18 +75,30 @@ gentones_LDADD = $(LDADD)
 genwave_SOURCES = genwave.c
 genwave_OBJECTS = genwave.$(OBJEXT)
 genwave_LDADD = $(LDADD)
-am_lcr_OBJECTS = action.$(OBJEXT) mISDN.$(OBJEXT) tones.$(OBJEXT) \
-       action_efi.$(OBJEXT) crypt.$(OBJEXT) mail.$(OBJEXT) \
-       trace.$(OBJEXT) action_vbox.$(OBJEXT) dss1.$(OBJEXT) \
-       main.$(OBJEXT) vbox.$(OBJEXT) alawulaw.$(OBJEXT) \
-       endpoint.$(OBJEXT) interface.$(OBJEXT) message.$(OBJEXT) \
-       apppbx.$(OBJEXT) endpointapp.$(OBJEXT) join.$(OBJEXT) \
-       options.$(OBJEXT) extension.$(OBJEXT) joinpbx.$(OBJEXT) \
-       port.$(OBJEXT) callerid.$(OBJEXT) joinremote.$(OBJEXT) \
-       route.$(OBJEXT) cause.$(OBJEXT) socket_server.$(OBJEXT)
+am__lcr_SOURCES_DIST = gsm_audio.c gsm.cpp gsm_conf.c bootstrap.c \
+       action.cpp mISDN.cpp tones.c action_efi.cpp crypt.cpp mail.c \
+       trace.c action_vbox.cpp dss1.cpp main.c vbox.cpp alawulaw.c \
+       endpoint.cpp interface.c message.c apppbx.cpp endpointapp.cpp \
+       join.cpp options.c extension.c joinpbx.cpp port.cpp callerid.c \
+       joinremote.cpp route.c cause.c socket_server.c
+@ENABLE_GSM_TRUE@am__objects_1 = gsm_audio.$(OBJEXT) gsm.$(OBJEXT) \
+@ENABLE_GSM_TRUE@      gsm_conf.$(OBJEXT) bootstrap.$(OBJEXT)
+am_lcr_OBJECTS = $(am__objects_1) action.$(OBJEXT) mISDN.$(OBJEXT) \
+       tones.$(OBJEXT) action_efi.$(OBJEXT) crypt.$(OBJEXT) \
+       mail.$(OBJEXT) trace.$(OBJEXT) action_vbox.$(OBJEXT) \
+       dss1.$(OBJEXT) main.$(OBJEXT) vbox.$(OBJEXT) \
+       alawulaw.$(OBJEXT) endpoint.$(OBJEXT) interface.$(OBJEXT) \
+       message.$(OBJEXT) apppbx.$(OBJEXT) endpointapp.$(OBJEXT) \
+       join.$(OBJEXT) options.$(OBJEXT) extension.$(OBJEXT) \
+       joinpbx.$(OBJEXT) port.$(OBJEXT) callerid.$(OBJEXT) \
+       joinremote.$(OBJEXT) route.$(OBJEXT) cause.$(OBJEXT) \
+       socket_server.$(OBJEXT)
 lcr_OBJECTS = $(am_lcr_OBJECTS)
 am__DEPENDENCIES_1 =
-lcr_DEPENDENCIES = $(am__DEPENDENCIES_1)
+@ENABLE_GSM_TRUE@am__DEPENDENCIES_2 = /usr/local/lib/libgsm.a \
+@ENABLE_GSM_TRUE@      /usr/local/lib/libbsc.a \
+@ENABLE_GSM_TRUE@      /usr/local/lib/libvty.a
+lcr_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
 am_lcradmin_OBJECTS = lcradmin.$(OBJEXT) cause.$(OBJEXT) \
        options.$(OBJEXT)
 lcradmin_OBJECTS = $(am_lcradmin_OBJECTS)
@@ -103,7 +115,8 @@ CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
 SOURCES = $(chan_lcr_so_SOURCES) $(genextension_SOURCES) genrc.c \
        gentones.c genwave.c $(lcr_SOURCES) $(lcradmin_SOURCES)
 DIST_SOURCES = $(chan_lcr_so_SOURCES) $(genextension_SOURCES) genrc.c \
-       gentones.c genwave.c $(lcr_SOURCES) $(lcradmin_SOURCES)
+       gentones.c genwave.c $(am__lcr_SOURCES_DIST) \
+       $(lcradmin_SOURCES)
 ETAGS = etags
 CTAGS = ctags
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@@ -142,6 +155,8 @@ ECHO_T = @ECHO_T@
 EGREP = @EGREP@
 ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE = @ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE@
 ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE = @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@
+ENABLE_GSM_FALSE = @ENABLE_GSM_FALSE@
+ENABLE_GSM_TRUE = @ENABLE_GSM_TRUE@
 EXEEXT = @EXEEXT@
 GREP = @GREP@
 INSTALL_DATA = @INSTALL_DATA@
@@ -224,11 +239,14 @@ INSTALLATION_DEFINES = \
  -DLOG_DIR="\"$(LOGdir)\"" \
  -DEXTENSION_DATA="\"$(EXTENSIONdir)\""
 
-INCLUDES = $(all_includes) -I/usr/include/mISDNuser $(INSTALLATION_DEFINES) 
+@ENABLE_GSM_TRUE@GSM_INCLUDE = -DWITH_GSM
+@ENABLE_GSM_TRUE@GSM_SOURCE = gsm_audio.c gsm.cpp gsm_conf.c bootstrap.c
+@ENABLE_GSM_TRUE@GSM_LIB = /usr/local/lib/libgsm.a /usr/local/lib/libbsc.a /usr/local/lib/libvty.a -ldbi -lcrypt
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_SOURCES = 
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDFLAGS = -shared
 @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po
-lcr_SOURCES = action.cpp       mISDN.cpp        tones.c \
+INCLUDES = $(all_includes) $(GSM_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
+lcr_SOURCES = $(GSM_SOURCE) action.cpp       mISDN.cpp        tones.c \
        action_efi.cpp   crypt.cpp        mail.c           trace.c \
        action_vbox.cpp  dss1.cpp         main.c           \
        vbox.cpp alawulaw.c       endpoint.cpp     interface.c     message.c \
@@ -237,7 +255,7 @@ lcr_SOURCES = action.cpp       mISDN.cpp        tones.c \
        callerid.c       joinremote.cpp  route.c \
        cause.c          socket_server.c
 
-lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread
+lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread $(GSM_LIB)
 lcradmin_SOURCES = lcradmin.c cause.c options.c
 genextension_SOURCES = genext.c options.c extension.c
 
@@ -387,6 +405,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/action_vbox.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alawulaw.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apppbx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bootstrap.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callerid.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cause.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypt.Po@am__quote@
@@ -398,6 +417,9 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genrc.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gentones.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genwave.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsm_audio.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsm_conf.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/join.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joinpbx.Po@am__quote@
@@ -764,6 +786,9 @@ install-data-hook:
        @if test -a $(CONFIGdir)/routing.conf ; then \
                echo "NOTE: routing.conf already exists, not changed." ; else \
                cp -v default/routing.conf $(CONFIGdir) ; fi
+       @if test -a $(CONFIGdir)/gsm.conf ; then \
+               echo "NOTE: gsm.conf already exists, not changed." ; else \
+               cp -v default/gsm.conf $(CONFIGdir) ; fi
        @if test -a $(CONFIGdir)/numbering_int.conf ; then \
                echo "NOTE: numbering_int.conf is obsolete, please use routing." ; fi
        @if test -a $(CONFIGdir)/numbering_ext.conf ; then \
diff --git a/README b/README
index 75a8913..a5b5945 100644 (file)
--- a/README
+++ b/README
@@ -487,3 +487,8 @@ Changes after Version 1.4 release
   -> Improved forking
   -> Execution action can now be done on call init or on call hangup.
 
+New release Version 1.5
+- Added GSM network support.
+  -> Requires OpenBSC, GSM codec, and a BS11 base station.
+  -> For more refer to www.linux-call-router.de.
+
index 88694e0..16da68b 100644 (file)
@@ -827,7 +827,6 @@ void EndpointAppPBX::out_setup(void)
 {
        struct dialing_info     dialinginfo;
        class Port              *port;
-//     class pdss1             *pdss1;
        struct port_list        *portlist;
        struct lcr_msg          *message;
        int                     anycall = 0;
@@ -987,9 +986,16 @@ void EndpointAppPBX::out_setup(void)
                        }
                        /* creating INTERNAL port */
                        SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
-                       port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                       if (!mISDNport->gsm)
+                               port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                       else
+#ifdef WITH_GSM
+                               port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+#else
+                               port = NULL;
+#endif
                        if (!port)
-                               FATAL("No memory for DSS1 Port instance\n");
+                               FATAL("No memory for Port instance\n");
                        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
                        memset(&dialinginfo, 0, sizeof(dialinginfo));
                        SCPY(dialinginfo.id, e_dialinginfo.id);
@@ -1104,8 +1110,9 @@ void EndpointAppPBX::out_setup(void)
                                {
                                        /* creating EXTERNAL port*/
                                        SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
-                                       if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode)))
-                                               FATAL("No memory for DSS1 Port instance\n");
+                                               port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                                       if (!port)
+                                               FATAL("No memory for Port instance\n");
                                        earlyb = mISDNport->earlyb;
                                } else
                                {
@@ -1200,8 +1207,16 @@ void EndpointAppPBX::out_setup(void)
                        }
                        /* creating EXTERNAL port*/
                        SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
-                       if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode)))
-                               FATAL("No memory for DSS1 Port instance\n");
+                       if (!mISDNport->gsm)
+                               port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+                       else
+#ifdef WITH_GSM
+                               port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
+#else
+                               port = NULL;
+#endif
+                       if (!port)
+                               FATAL("No memory for Port instance\n");
                        earlyb = mISDNport->earlyb;
                        PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
                        memset(&dialinginfo, 0, sizeof(dialinginfo));
@@ -1215,7 +1230,6 @@ void EndpointAppPBX::out_setup(void)
                                delete port;
                                goto check_anycall_extern;
                        }
-//                     dss1 = (class Pdss1 *)port;
 //printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
                        message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
                        memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
@@ -2103,7 +2117,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
        if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE)
        {
                e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
-               if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) /* external extension answered */
+               if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT || portlist->port_type==PORT_TYPE_GSM_OUT) /* external extension answered */
                {
                        port = find_port_id(portlist->port_id);
                        if (port)
@@ -3626,7 +3640,7 @@ void EndpointAppPBX::pick_join(char *extensions)
                                                        break;
                                                }
                                        }
-                                       if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT)
+                                       if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
                                         && port->p_state==PORT_STATE_OUT_ALERTING)
                                                if (match_list(extensions, eapp->e_ext.number))
                                                {
diff --git a/bootstrap.c b/bootstrap.c
new file mode 100644 (file)
index 0000000..0c309a3
--- /dev/null
@@ -0,0 +1,948 @@
+/* Bootstrapping GSM - taken from bsc_hack.c */
+
+/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
+ * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <getopt.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <openbsc/openbsc.h>
+#include <openbsc/gsm_data.h>
+#include <openbsc/gsm_04_08.h>
+#include <openbsc/db.h>
+#include <openbsc/timer.h>
+#include <openbsc/select.h>
+#include <openbsc/abis_rsl.h>
+#include <openbsc/abis_nm.h>
+#include <openbsc/debug.h>
+#include <openbsc/misdn.h>
+#include <openbsc/telnet_interface.h>
+#include <openbsc/paging.h>
+#include <openbsc/e1_input.h>
+
+/* The following definitions are for OM and NM packets that we cannot yet
+ * generate by code but we just pass on */
+
+// BTS Site Manager, SET ATTRIBUTES
+
+/*
+  Object Class: BTS Site Manager
+  Instance 1: FF
+  Instance 2: FF
+  Instance 3: FF
+SET ATTRIBUTES
+  sAbisExternalTime: 2007/09/08   14:36:11
+  omLAPDRelTimer: 30sec
+  shortLAPDIntTimer: 5sec
+  emergencyTimer1: 10 minutes
+  emergencyTimer2: 0 minutes
+*/
+
+unsigned char msg_1[] = 
+{
+       0xD0, 0x00, 0xFF, 0xFF, 0xFF, 
+               NM_ATT_BS11_ABIS_EXT_TIME, 0x07, 0xD7, 0x09, 0x08, 0x0E, 0x24, 0x0B, 0xCE, 
+               0x02, 0x00, 0x1E, 
+               0xE8, 0x01, 0x05,
+               0x42, 0x02, 0x00, 0x0A, 
+               0x44, 0x02, 0x00, 0x00
+};
+
+// BTS, SET BTS ATTRIBUTES
+
+/*
+  Object Class: BTS
+  BTS relat. Number: 0 
+  Instance 2: FF
+  Instance 3: FF
+SET BTS ATTRIBUTES
+  bsIdentityCode / BSIC:
+    PLMN_colour_code: 7h
+    BS_colour_code:   7h
+  BTS Air Timer T3105: 4  ,unit 10 ms
+  btsIsHopping: FALSE
+  periodCCCHLoadIndication: 1sec
+  thresholdCCCHLoadIndication: 0%
+  cellAllocationNumber: 00h = GSM 900
+  enableInterferenceClass: 00h =  Disabled
+  fACCHQual: 6 (FACCH stealing flags minus 1)
+  intaveParameter: 31 SACCH multiframes
+  interferenceLevelBoundaries:
+    Interference Boundary 1: 0Ah 
+    Interference Boundary 2: 0Fh
+    Interference Boundary 3: 14h
+    Interference Boundary 4: 19h
+    Interference Boundary 5: 1Eh
+  mSTxPwrMax: 11
+      GSM range:     2=39dBm, 15=13dBm, stepsize 2 dBm 
+      DCS1800 range: 0=30dBm, 15=0dBm, stepsize 2 dBm 
+      PCS1900 range: 0=30dBm, 15=0dBm, stepsize 2 dBm 
+                    30=33dBm, 31=32dBm 
+  ny1:
+    Maximum number of repetitions for PHYSICAL INFORMATION message (GSM 04.08): 20
+  powerOutputThresholds:
+    Out Power Fault Threshold:     -10 dB
+    Red Out Power Threshold:       - 6 dB
+    Excessive Out Power Threshold:   5 dB
+  rACHBusyThreshold: -127 dBm 
+  rACHLoadAveragingSlots: 250 ,number of RACH burst periods
+  rfResourceIndicationPeriod: 125  SACCH multiframes 
+  T200:
+    SDCCH:                044 in  5 ms
+    FACCH/Full rate:      031 in  5 ms
+    FACCH/Half rate:      041 in  5 ms
+    SACCH with TCH SAPI0: 090 in 10 ms
+    SACCH with SDCCH:     090 in 10 ms
+    SDCCH with SAPI3:     090 in  5 ms
+    SACCH with TCH SAPI3: 135 in 10 ms
+  tSync: 9000 units of 10 msec
+  tTrau: 9000 units of 10 msec
+  enableUmLoopTest: 00h =  disabled
+  enableExcessiveDistance: 00h =  Disabled
+  excessiveDistance: 64km
+  hoppingMode: 00h = baseband hopping
+  cellType: 00h =  Standard Cell
+  BCCH ARFCN / bCCHFrequency: 1
+*/
+
+unsigned char msg_2[] = 
+{
+       0x41, 0x01, 0x00, 0xFF, 0xFF,
+               NM_ATT_BSIC, 0x3F,
+               NM_ATT_BTS_AIR_TIMER, 0x04,
+               NM_ATT_BS11_BTSLS_HOPPING, 0x00,
+               NM_ATT_CCCH_L_I_P, 0x01,
+               NM_ATT_CCCH_L_T, 0x00,
+               NM_ATT_BS11_CELL_ALLOC_NR, 0x00,
+               NM_ATT_BS11_ENA_INTERF_CLASS, 0x00,
+               NM_ATT_BS11_FACCH_QUAL, 0x06,
+               NM_ATT_INTAVE_PARAM, 0x1F, 
+               NM_ATT_INTERF_BOUND, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x7B,
+               NM_ATT_CCCH_L_T, 0x23,
+               NM_ATT_GSM_TIME, 0x28, 0x00,
+               NM_ATT_ADM_STATE, 0x03,
+               NM_ATT_RACH_B_THRESH, 0x7F,
+               NM_ATT_LDAVG_SLOTS, 0x00, 0xFA,
+               NM_ATT_BS11_RF_RES_IND_PER, 0x7D,
+               NM_ATT_T200, 0x2C, 0x1F, 0x29, 0x5A, 0x5A, 0x5A, 0x87,
+               NM_ATT_BS11_TSYNC, 0x23, 0x28,
+               NM_ATT_BS11_TTRAU, 0x23, 0x28, 
+               NM_ATT_TEST_DUR, 0x01, 0x00,
+               NM_ATT_OUTST_ALARM, 0x01, 0x00,
+               NM_ATT_BS11_EXCESSIVE_DISTANCE, 0x01, 0x40,
+               NM_ATT_BS11_HOPPING_MODE, 0x01, 0x00,
+               NM_ATT_BS11_PLL, 0x01, 0x00, 
+               NM_ATT_BCCH_ARFCN, 0x00, HARDCODED_ARFCN/*0x01*/, 
+};
+
+// Handover Recognition, SET ATTRIBUTES
+
+/*
+Illegal Contents GSM Formatted O&M Msg 
+  Object Class: Handover Recognition
+  BTS relat. Number: 0 
+  Instance 2: FF
+  Instance 3: FF
+SET ATTRIBUTES
+  enableDelayPowerBudgetHO: 00h = Disabled
+  enableDistanceHO: 00h =  Disabled
+  enableInternalInterCellHandover: 00h = Disabled
+  enableInternalIntraCellHandover: 00h =  Disabled
+  enablePowerBudgetHO: 00h = Disabled
+  enableRXLEVHO: 00h =  Disabled
+  enableRXQUALHO: 00h =  Disabled
+  hoAveragingDistance: 8  SACCH multiframes 
+  hoAveragingLev:
+    A_LEV_HO: 8  SACCH multiframes 
+    W_LEV_HO: 1  SACCH multiframes 
+  hoAveragingPowerBudget:  16  SACCH multiframes 
+  hoAveragingQual:
+    A_QUAL_HO: 8  SACCH multiframes 
+    W_QUAL_HO: 2  SACCH multiframes 
+  hoLowerThresholdLevDL: (10 - 110) dBm
+  hoLowerThresholdLevUL: (5 - 110) dBm
+  hoLowerThresholdQualDL: 06h =   6.4% < BER < 12.8%
+  hoLowerThresholdQualUL: 06h =   6.4% < BER < 12.8%
+  hoThresholdLevDLintra : (20 - 110) dBm
+  hoThresholdLevULintra: (20 - 110) dBm
+  hoThresholdMsRangeMax: 20 km 
+  nCell: 06h
+  timerHORequest: 3  ,unit 2 SACCH multiframes 
+*/
+
+unsigned char msg_3[] = 
+{
+       0xD0, 0xA1, 0x00, 0xFF, 0xFF, 
+               0xD0, 0x00,
+               0x64, 0x00,
+               0x67, 0x00,
+               0x68, 0x00,
+               0x6A, 0x00,
+               0x6C, 0x00,
+               0x6D, 0x00,
+               0x6F, 0x08,
+               0x70, 0x08, 0x01,
+               0x71, 0x10, 0x10, 0x10,
+               0x72, 0x08, 0x02,
+               0x73, 0x0A,
+               0x74, 0x05,
+               0x75, 0x06,
+               0x76, 0x06,
+               0x78, 0x14,
+               0x79, 0x14,
+               0x7A, 0x14,
+               0x7D, 0x06,
+               0x92, 0x03, 0x20, 0x01, 0x00,
+               0x45, 0x01, 0x00,
+               0x48, 0x01, 0x00,
+               0x5A, 0x01, 0x00,
+               0x5B, 0x01, 0x05,
+               0x5E, 0x01, 0x1A,
+               0x5F, 0x01, 0x20,
+               0x9D, 0x01, 0x00,
+               0x47, 0x01, 0x00,
+               0x5C, 0x01, 0x64,
+               0x5D, 0x01, 0x1E,
+               0x97, 0x01, 0x20,
+               0xF7, 0x01, 0x3C,
+};
+
+// Power Control, SET ATTRIBUTES
+
+/*
+  Object Class: Power Control
+  BTS relat. Number: 0 
+  Instance 2: FF
+  Instance 3: FF
+SET ATTRIBUTES
+  enableMsPowerControl: 00h =  Disabled
+  enablePowerControlRLFW: 00h =  Disabled
+  pcAveragingLev:
+    A_LEV_PC: 4  SACCH multiframes 
+    W_LEV_PC: 1  SACCH multiframes 
+  pcAveragingQual:
+    A_QUAL_PC: 4  SACCH multiframes 
+    W_QUAL_PC: 2  SACCH multiframes 
+  pcLowerThresholdLevDL: 0Fh
+  pcLowerThresholdLevUL: 0Ah
+  pcLowerThresholdQualDL: 05h =   3.2% < BER <  6.4%
+  pcLowerThresholdQualUL: 05h =   3.2% < BER <  6.4%
+  pcRLFThreshold: 0Ch
+  pcUpperThresholdLevDL: 14h
+  pcUpperThresholdLevUL: 0Fh
+  pcUpperThresholdQualDL: 04h =   1.6% < BER <  3.2%
+  pcUpperThresholdQualUL: 04h =   1.6% < BER <  3.2%
+  powerConfirm: 2  ,unit 2 SACCH multiframes 
+  powerControlInterval: 2  ,unit 2 SACCH multiframes 
+  powerIncrStepSize: 02h = 4 dB
+  powerRedStepSize: 01h = 2 dB
+  radioLinkTimeoutBs: 64  SACCH multiframes 
+  enableBSPowerControl: 00h =  disabled
+*/
+
+unsigned char msg_4[] = 
+{
+       0xD0, 0xA2, 0x00, 0xFF, 0xFF, 
+               NM_ATT_BS11_ENA_MS_PWR_CTRL, 0x00,
+               NM_ATT_BS11_ENA_PWR_CTRL_RLFW, 0x00,
+               0x7E, 0x04, 0x01,
+               0x7F, 0x04, 0x02,
+               0x80, 0x0F,
+               0x81, 0x0A,
+               0x82, 0x05,
+               0x83, 0x05,
+               0x84, 0x0C, 
+               0x85, 0x14, 
+               0x86, 0x0F, 
+               0x87, 0x04,
+               0x88, 0x04,
+               0x89, 0x02,
+               0x8A, 0x02,
+               0x8B, 0x02,
+               0x8C, 0x01,
+               0x8D, 0x40,
+               0x65, 0x01, 0x00 // set to 0x01 to enable BSPowerControl
+};
+
+
+// Transceiver, SET TRX ATTRIBUTES (TRX 0)
+
+/*
+  Object Class: Transceiver
+  BTS relat. Number: 0 
+  Tranceiver number: 0 
+  Instance 3: FF
+SET TRX ATTRIBUTES
+  aRFCNList (HEX):  0001
+  txPwrMaxReduction: 00h =   30dB
+  radioMeasGran: 254  SACCH multiframes 
+  radioMeasRep: 01h =  enabled
+  memberOfEmergencyConfig: 01h =  TRUE
+  trxArea: 00h = TRX doesn't belong to a concentric cell
+*/
+
+unsigned char msg_6[] = 
+{
+       0x44, 0x02, 0x00, 0x00, 0xFF, 
+               NM_ATT_ARFCN_LIST, 0x01, 0x00, HARDCODED_ARFCN /*0x01*/,
+               NM_ATT_RF_MAXPOWR_R, 0x00,
+               NM_ATT_BS11_RADIO_MEAS_GRAN, 0x01, 0xFE, 
+               NM_ATT_BS11_RADIO_MEAS_REP, 0x01, 0x01,
+               NM_ATT_BS11_EMRG_CFG_MEMBER, 0x01, 0x01,
+               NM_ATT_BS11_TRX_AREA, 0x01, 0x00, 
+};
+
+static unsigned char nanobts_attr_bts[] = {
+       NM_ATT_INTERF_BOUND, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73,
+       NM_ATT_INTAVE_PARAM, 0x06,
+       NM_ATT_CONN_FAIL_CRIT, 0x00, 0x02, 0x01, 0x10, 
+       NM_ATT_T200, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21, 0xa8,
+       NM_ATT_MAX_TA, 0x3f,
+       NM_ATT_OVERL_PERIOD, 0x00, 0x01, 10, /* seconds */
+       NM_ATT_CCCH_L_T, 10, /* percent */
+       NM_ATT_CCCH_L_I_P, 1, /* seconds */
+       NM_ATT_RACH_B_THRESH, 0x0a,
+       NM_ATT_LDAVG_SLOTS, 0x03, 0xe8,
+       NM_ATT_BTS_AIR_TIMER, 0x80,
+       NM_ATT_NY1, 0x0a,
+       NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
+       NM_ATT_BSIC, 0x20,
+};
+
+static unsigned char nanobts_attr_radio[] = {
+       NM_ATT_RF_MAXPOWR_R, 0x0c,
+       NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
+};
+
+static unsigned char nanobts_attr_e0[] = {
+       0x85, 0x00,
+       0x81, 0x0b, 0xbb,       /* TCP PORT for RSL */
+};
+
+int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
+                  struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
+{
+       struct gsm_bts *bts;
+       struct gsm_bts_trx *trx;
+       struct gsm_bts_trx_ts *ts;
+
+       /* This is currently only required on nanoBTS */
+
+       switch (evt) {
+       case EVT_STATECHG_OPER:
+               switch (obj_class) {
+               case NM_OC_SITE_MANAGER:
+                       bts = container_of(obj, struct gsm_bts, site_mgr);
+                       if (old_state->operational != 2 && new_state->operational == 2) {
+                               abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
+                       }
+                       break;
+               case NM_OC_BTS:
+                       bts = (struct gsm_bts *)obj;
+                       if (new_state->availability == 5) {
+                               abis_nm_set_bts_attr(bts, nanobts_attr_bts,
+                                                       sizeof(nanobts_attr_bts));
+                               abis_nm_opstart(bts, NM_OC_BTS,
+                                               bts->nr, 0xff, 0xff);
+                               abis_nm_chg_adm_state(bts, NM_OC_BTS,
+                                                     bts->nr, 0xff, 0xff,
+                                                     NM_STATE_UNLOCKED);
+                       }
+                       break;
+               case NM_OC_RADIO_CARRIER:
+                       trx = (struct gsm_bts_trx *)obj;
+                       if (new_state->availability == 3) {
+                               abis_nm_set_radio_attr(trx, nanobts_attr_radio,
+                                                       sizeof(nanobts_attr_radio));
+                               abis_nm_opstart(trx->bts, NM_OC_RADIO_CARRIER,
+                                               trx->bts->nr, trx->nr, 0xff);
+                               abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
+                                                     trx->bts->nr, trx->nr, 0xff,
+                                                     NM_STATE_UNLOCKED);
+                       }
+                       break;
+               case NM_OC_CHANNEL:
+                       ts = (struct gsm_bts_trx_ts *)obj;
+                       trx = (struct gsm_bts_trx *)ts->trx;
+                       if (new_state->availability == 5) {
+                               if (ts->nr == 0 && trx == trx->bts->c0)
+                                       abis_nm_set_channel_attr(ts, NM_CHANC_BCCH_CBCH);
+                               else
+                                       abis_nm_set_channel_attr(ts, NM_CHANC_TCHFull);
+                               abis_nm_opstart(trx->bts, NM_OC_CHANNEL,
+                                               trx->bts->nr, trx->nr, ts->nr);
+                               abis_nm_chg_adm_state(trx->bts, NM_OC_CHANNEL,
+                                                     trx->bts->nr, trx->nr, ts->nr,
+                                                     NM_STATE_UNLOCKED);
+                       }
+                       break;
+               case NM_OC_BASEB_TRANSC:
+                       trx = container_of(obj, struct gsm_bts_trx, bb_transc);
+                       if (new_state->availability == 5) {
+                               abis_nm_ipaccess_msg(trx->bts, 0xe0, NM_OC_BASEB_TRANSC,
+                                                    trx->bts->nr, trx->nr, 0xff,
+                                                    nanobts_attr_e0, sizeof(nanobts_attr_e0));
+                               abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC, 
+                                               trx->bts->nr, trx->nr, 0xff);
+                               abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC, 
+                                                       trx->bts->nr, trx->nr, 0xff,
+                                                       NM_STATE_UNLOCKED);
+                       }
+                       break;
+               }
+               break;
+       case EVT_STATECHG_ADM:
+               DEBUGP(DMM, "Unhandled state change in %s:%d\n", __func__, __LINE__);
+               break;
+       }
+       return 0;
+}
+
+static void bootstrap_om_nanobts(struct gsm_bts *bts)
+{
+       /* We don't do callback based bootstrapping, but event driven (see above) */
+}
+
+static void bootstrap_om_bs11(struct gsm_bts *bts)
+{
+       struct gsm_bts_trx *trx = &bts->trx[0];
+
+       /* stop sending event reports */
+       abis_nm_event_reports(bts, 0);
+
+       /* begin DB transmission */
+       abis_nm_bs11_db_transmission(bts, 1);
+
+       /* end DB transmission */
+       abis_nm_bs11_db_transmission(bts, 0);
+
+       /* Reset BTS Site manager resource */
+       abis_nm_bs11_reset_resource(bts);
+
+       /* begin DB transmission */
+       abis_nm_bs11_db_transmission(bts, 1);
+
+       abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/
+       abis_nm_raw_msg(bts, sizeof(msg_2), msg_2); /* set BTS attr */
+       abis_nm_raw_msg(bts, sizeof(msg_3), msg_3); /* set BTS handover attr */
+       abis_nm_raw_msg(bts, sizeof(msg_4), msg_4); /* set BTS power control attr */
+
+       /* Connect signalling of bts0/trx0 to e1_0/ts1/64kbps */
+       abis_nm_conn_terr_sign(trx, 0, 1, 0xff);
+       set_ts_e1link(&trx->ts[0], 0, 1, 0xff);
+       abis_nm_raw_msg(bts, sizeof(msg_6), msg_6); /* SET TRX ATTRIBUTES */
+
+       /* Use TEI 1 for signalling */
+       abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x01);
+       abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_SDCCH_CBCH);
+
+#ifdef HAVE_TRX1
+       /* TRX 1 */
+       abis_nm_conn_terr_sign(&bts->trx[1], 0, 1, 0xff);
+       /* FIXME: TRX ATTRIBUTE */
+       abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x02);
+#endif
+
+       /* SET CHANNEL ATTRIBUTE TS1 */
+       abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull);
+       /* Connect traffic of bts0/trx0/ts1 to e1_0/ts2/b */
+       set_ts_e1link(&trx->ts[1], 0, 2, 1);
+       abis_nm_conn_terr_traf(&trx->ts[1], 0, 2, 1);
+       
+       /* SET CHANNEL ATTRIBUTE TS2 */
+       abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull);
+       /* Connect traffic of bts0/trx0/ts2 to e1_0/ts2/c */
+       set_ts_e1link(&trx->ts[2], 0, 2, 2);
+       abis_nm_conn_terr_traf(&trx->ts[2], 0, 2, 2);
+
+       /* SET CHANNEL ATTRIBUTE TS3 */
+       abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull);
+       /* Connect traffic of bts0/trx0/ts3 to e1_0/ts2/d */
+       set_ts_e1link(&trx->ts[3], 0, 2, 3);
+       abis_nm_conn_terr_traf(&trx->ts[3], 0, 2, 3);
+
+       /* SET CHANNEL ATTRIBUTE TS4 */
+       abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull);
+       /* Connect traffic of bts0/trx0/ts4 to e1_0/ts3/a */
+       set_ts_e1link(&trx->ts[4], 0, 3, 0);
+       abis_nm_conn_terr_traf(&trx->ts[4], 0, 3, 0);
+
+       /* SET CHANNEL ATTRIBUTE TS5 */
+       abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull);
+       /* Connect traffic of bts0/trx0/ts5 to e1_0/ts3/b */
+       set_ts_e1link(&trx->ts[5], 0, 3, 1);
+       abis_nm_conn_terr_traf(&trx->ts[5], 0, 3, 1);
+
+       /* SET CHANNEL ATTRIBUTE TS6 */
+       abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull);
+       /* Connect traffic of bts0/trx0/ts6 to e1_0/ts3/c */
+       set_ts_e1link(&trx->ts[6], 0, 3, 2);
+       abis_nm_conn_terr_traf(&trx->ts[6], 0, 3, 2);
+
+       /* SET CHANNEL ATTRIBUTE TS7 */
+       abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull);
+       /* Connect traffic of bts0/trx0/ts7 to e1_0/ts3/d */
+       set_ts_e1link(&trx->ts[7], 0, 3, 3);
+       abis_nm_conn_terr_traf(&trx->ts[7], 0, 3, 3);
+
+       /* end DB transmission */
+       abis_nm_bs11_db_transmission(bts, 0);
+
+       /* Reset BTS Site manager resource */
+       abis_nm_bs11_reset_resource(bts);
+
+       /* restart sending event reports */
+       abis_nm_event_reports(bts, 1);
+}
+
+static void bootstrap_om(struct gsm_bts *bts)
+{
+       fprintf(stdout, "bootstrapping OML\n");
+
+       switch (bts->type) {
+       case GSM_BTS_TYPE_BS11:
+               bootstrap_om_bs11(bts);
+               break;
+       case GSM_BTS_TYPE_NANOBTS_900:
+       case GSM_BTS_TYPE_NANOBTS_1800:
+               bootstrap_om_nanobts(bts);
+               break;
+       default:
+               fprintf(stderr, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type);
+       }
+}
+
+static int shutdown_om(struct gsm_bts *bts)
+{
+       /* stop sending event reports */
+       abis_nm_event_reports(bts, 0);
+
+       /* begin DB transmission */
+       abis_nm_bs11_db_transmission(bts, 1);
+
+       /* end DB transmission */
+       abis_nm_bs11_db_transmission(bts, 0);
+
+       /* Reset BTS Site manager resource */
+       abis_nm_bs11_reset_resource(bts);
+
+       return 0;
+}
+
+struct bcch_info {
+       u_int8_t type;
+       u_int8_t len;
+       const u_int8_t *data;
+};
+
+/*
+SYSTEM INFORMATION TYPE 1
+  Cell channel description
+    Format-ID bit map 0
+    CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
+  RACH Control Parameters
+    maximum 7 retransmissions
+    8 slots used to spread transmission
+    cell not barred for access
+    call reestablishment not allowed
+    Access Control Class = 0000
+*/
+static u_int8_t si1[] = {
+       /* header */0x55, 0x06, 0x19,
+       /* ccdesc */0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/,
+       /* rach */0xD5, 0x00, 0x00,
+       /* s1 reset*/0x2B
+};
+
+/*
+ SYSTEM INFORMATION TYPE 2
+  Neighbour Cells Description
+    EXT-IND: Carries the complete BA
+    BA-IND = 0
+    Format-ID bit map 0
+    CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+  NCC permitted (NCC) = FF
+  RACH Control Parameters
+    maximum 7 retransmissions
+    8 slots used to spread transmission
+    cell not barred for access
+    call reestablishment not allowed
+    Access Control Class = 0000
+*/
+static u_int8_t si2[] = {
+       /* header */0x59, 0x06, 0x1A,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       /* ncc */0xFF,
+       /* rach*/0xD5, 0x00, 0x00
+};
+
+/*
+SYSTEM INFORMATION TYPE 3
+  Cell identity = 00001 (1h)
+  Location area identification
+    Mobile Country Code (MCC): 001
+    Mobile Network Code (MNC): 01
+    Location Area Code  (LAC): 00001 (1h)
+  Control Channel Description
+    Attach-detach: MSs in the cell are not allowed to apply IMSI attach /detach
+    0 blocks reserved for access grant
+    1 channel used for CCCH, with SDCCH
+    5 multiframes period for PAGING REQUEST
+    Time-out T3212 = 0
+  Cell Options BCCH
+    Power control indicator: not set
+    MSs shall not use uplink DTX
+    Radio link timeout = 36
+  Cell Selection Parameters
+    Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection
+    max.TX power level MS may use for CCH = 2 <- according to GSM05.05 39dBm (max)
+    Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters
+    Half rate support (NECI): New establishment causes are not supported
+    min.RX signal level for MS = 0
+  RACH Control Parameters
+    maximum 7 retransmissions
+    8 slots used to spread transmission
+    cell not barred for access
+    call reestablishment not allowed
+    Access Control Class = 0000
+  SI 3 Rest Octets
+    Cell Bar Qualify (CBQ): 0
+    Cell Reselect Offset = 0 dB
+    Temporary Offset = 0 dB
+    Penalty Time = 20 s
+    System Information 2ter Indicator (2TI): 0 = not available
+    Early Classmark Sending Control (ECSC):  0 = forbidden
+    Scheduling Information is not sent in SYSTEM INFORMATION TYPE 9 on the BCCH
+*/
+static u_int8_t si3[] = {
+       /* header */0x49, 0x06, 0x1B,
+       /* cell */0x00, 0x01,
+       /* lai  */0x00, 0xF1, 0x10, 0x00, 0x01,
+       /* desc */0x01, 0x03, 0x00,
+       /* option*/0x28,
+       /* selection*/0x62, 0x00,
+       /* rach */0xD5, 0x00, 0x00,
+       /* reset*/0x80, 0x00, 0x00, 0x2B
+};
+
+/*
+SYSTEM INFORMATION TYPE 4
+  Location area identification
+    Mobile Country Code (MCC): 001
+    Mobile Network Code (MNC): 01
+    Location Area Code  (LAC): 00001 (1h)
+  Cell Selection Parameters
+    Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection
+    max.TX power level MS may use for CCH = 2
+    Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters
+    Half rate support (NECI): New establishment causes are not supported
+    min.RX signal level for MS = 0
+  RACH Control Parameters
+    maximum 7 retransmissions
+    8 slots used to spread transmission
+    cell not barred for access
+    call reestablishment not allowed
+    Access Control Class = 0000
+  Channel Description
+    Type = SDCCH/4[2]
+    Timeslot Number: 0
+    Training Sequence Code: 7h
+    ARFCN: 1
+  SI Rest Octets
+    Cell Bar Qualify (CBQ): 0
+    Cell Reselect Offset = 0 dB
+    Temporary Offset = 0 dB
+    Penalty Time = 20 s
+*/
+static u_int8_t si4[] = {
+       /* header */0x41, 0x06, 0x1C,
+       /* lai */0x00, 0xF1, 0x10, 0x00, 0x01,
+       /* sel */0x62, 0x00,
+       /* rach*/0xD5, 0x00, 0x00,
+       /* var */0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/, 0x80, 0x00, 0x00,
+       0x2B, 0x2B, 0x2B
+};
+
+/*
+ SYSTEM INFORMATION TYPE 5
+  Neighbour Cells Description
+    EXT-IND: Carries the complete BA
+    BA-IND = 0
+    Format-ID bit map 0
+    CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+*/
+
+static u_int8_t si5[] = {
+       /* header without l2 len*/0x06, 0x1D,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+// SYSTEM INFORMATION TYPE 6
+
+/*
+SACCH FILLING
+  System Info Type: SYSTEM INFORMATION 6
+  L3 Information (Hex): 06 1E 00 01 xx xx 10 00 01 28 FF
+
+SYSTEM INFORMATION TYPE 6
+  Cell identity = 00001 (1h)
+  Location area identification
+    Mobile Country Code (MCC): 001
+    Mobile Network Code (MNC): 01
+    Location Area Code  (LAC): 00001 (1h)
+  Cell Options SACCH
+    Power control indicator: not set
+    MSs shall not use uplink DTX on a TCH-F. MS shall not use uplink DTX on TCH-H.
+    Radio link timeout = 36
+  NCC permitted (NCC) = FF
+*/
+
+static u_int8_t si6[] = {
+       /* header */0x06, 0x1E,
+       /* cell id*/ 0x00, 0x01,
+       /* lai */ 0x00, 0xF1, 0x10, 0x00, 0x01,
+       /* options */ 0x28,
+       /* ncc */ 0xFF,
+};
+
+
+
+static const struct bcch_info bcch_infos[] = {
+       {
+               RSL_SYSTEM_INFO_1,
+               sizeof(si1),
+               si1,
+       }, {
+               RSL_SYSTEM_INFO_2,
+               sizeof(si2),
+               si2,
+       }, {
+               RSL_SYSTEM_INFO_3,
+               sizeof(si3),
+               si3,
+       }, {
+               RSL_SYSTEM_INFO_4,
+               sizeof(si4),
+               si4,
+       },
+};
+
+static_assert(sizeof(si1) == sizeof(struct gsm48_system_information_type_1), type1)
+static_assert(sizeof(si2) == sizeof(struct gsm48_system_information_type_2), type2)
+static_assert(sizeof(si3) == sizeof(struct gsm48_system_information_type_3), type3)
+static_assert(sizeof(si4) >= sizeof(struct gsm48_system_information_type_4), type4)
+static_assert(sizeof(si5) == sizeof(struct gsm48_system_information_type_5), type5)
+static_assert(sizeof(si6) >= sizeof(struct gsm48_system_information_type_6), type6)
+
+/* set all system information types */
+static int set_system_infos(struct gsm_bts_trx *trx)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) {
+               rsl_bcch_info(trx, bcch_infos[i].type,
+                             bcch_infos[i].data,
+                             bcch_infos[i].len);
+       }
+       rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5));
+       rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6));
+
+       return 0;
+}
+
+/*
+ * Inform anyone...
+ */
+static void bsc_hack_channel_allocated(struct gsm_lchan *lchan) {
+}
+
+/*
+ * Patch the various SYSTEM INFORMATION tables to update
+ * the LAI
+ */
+static void patch_tables(struct gsm_bts *bts)
+{
+       u_int8_t arfcn_low = bts->trx[0].arfcn & 0xff;
+       u_int8_t arfcn_high = (bts->trx[0].arfcn >> 8) & 0x0f;
+       /* covert the raw packet to the struct */
+       struct gsm48_system_information_type_3 *type_3 =
+               (struct gsm48_system_information_type_3*)&si3;
+       struct gsm48_system_information_type_4 *type_4 =
+               (struct gsm48_system_information_type_4*)&si4;
+       struct gsm48_system_information_type_6 *type_6 =
+               (struct gsm48_system_information_type_6*)&si6;
+       struct gsm48_loc_area_id lai;
+
+       gsm0408_generate_lai(&lai, bts->network->country_code,
+                               bts->network->network_code, bts->location_area_code);
+
+       /* assign the MCC and MNC */
+       type_3->lai = lai;
+       type_4->lai = lai;
+       type_6->lai = lai;
+
+       /* patch ARFCN into BTS Attributes */
+       msg_2[74] &= 0xf0;
+       msg_2[74] |= arfcn_high;
+       msg_2[75] = arfcn_low;
+       nanobts_attr_bts[42] &= 0xf0;
+       nanobts_attr_bts[42] |= arfcn_high;
+       nanobts_attr_bts[43] = arfcn_low;
+
+       /* patch ARFCN into TRX Attributes */
+       msg_6[7] &= 0xf0;
+       msg_6[7] |= arfcn_high;
+       msg_6[8] = arfcn_low;
+       nanobts_attr_radio[5] &= 0xf0;
+       nanobts_attr_radio[5] |= arfcn_high;
+       nanobts_attr_radio[6] = arfcn_low;
+
+       type_4->data[2] &= 0xf0;
+       type_4->data[2] |= arfcn_high;
+       type_4->data[3] = arfcn_low;
+
+       /* patch Control Channel Description 10.5.2.11 */
+       type_3->control_channel_desc = bts->chan_desc;
+}
+
+
+static void bootstrap_rsl(struct gsm_bts_trx *trx)
+{
+       fprintf(stdout, "bootstrapping RSL MCC=%u MNC=%u\n", trx->bts->network->country_code, trx->bts->network->network_code);
+       set_system_infos(trx);
+}
+
+void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
+{
+       switch (event) {
+       case EVT_E1_TEI_UP:
+               switch (type) {
+               case E1INP_SIGN_OML:
+                       bootstrap_om(trx->bts);
+                       break;
+               case E1INP_SIGN_RSL:
+                       bootstrap_rsl(trx);
+                       break;
+               default:
+                       break;
+               }
+               break;
+       case EVT_E1_TEI_DN:
+               fprintf(stderr, "Lost some E1 TEI link\n");
+               /* FIXME: deal with TEI or L1 link loss */
+               break;
+       default:
+               break;
+       }
+}
+
+void *bootstrap_network(int (*mncc_recv)(void *, int, void *),int bts_type, int mcc, int mnc, int lac, int arfcn, int cardnr, int release_l2, char *name_short, char *name_long, char *hlr, int allow_all)
+{
+       struct gsm_bts *bts;
+       struct gsm_network *gsmnet;
+
+       /* open database */
+       if (db_init(hlr)) {
+               fprintf(stderr, "DB: Failed to init HLR database '%s'. Please check the option settings.\n", hlr);
+               return NULL;
+       }        
+       if (db_prepare()) {
+               fprintf(stderr, "DB: Failed to prepare database.\n");
+               return NULL;
+       }
+
+       /* seed the PRNG for TMSI */
+       srand(time(NULL));
+
+       /* initialize our data structures */
+       gsmnet = gsm_network_init(1, (gsm_bts_type)bts_type, mcc, mnc, mncc_recv);
+       if (!gsmnet)
+               return 0;
+
+       gsmnet->name_long = name_long;
+       gsmnet->name_short = name_short;
+       bts = &gsmnet->bts[0];
+       bts->location_area_code = lac;
+       bts->trx[0].arfcn = arfcn;
+
+       /* Control Channel Description */
+       memset(&bts->chan_desc, 0, sizeof(struct gsm48_control_channel_descr));
+       bts->chan_desc.att = 1;
+       bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
+       bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
+       bts->chan_desc.t3212 = 0;
+
+       patch_tables(bts);
+
+       paging_init(bts);
+       bts->paging.channel_allocated = bsc_hack_channel_allocated;
+
+       telnet_init(gsmnet, 4242);
+
+       /* E1 mISDN input setup */
+       if (bts_type == GSM_BTS_TYPE_BS11) {
+               if (e1_config(bts, cardnr, release_l2))
+                       return NULL;
+       } else {
+               if (ia_config(bts))
+                       return NULL;
+       }
+
+       if (allow_all)
+               gsm0408_allow_everyone(1);
+
+       return gsmnet;
+}
+
+int shutdown_net(void *network)
+{
+       struct gsm_network *net = (struct gsm_network *)network;
+       unsigned int i;
+       for (i = 0; i < net->num_bts; i++) {
+               int rc;
+               rc = shutdown_om(&net->bts[i]);
+               if (rc < 0)
+                       return rc;
+       }
+
+       return 0;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/bootstrap.h b/bootstrap.h
new file mode 100644 (file)
index 0000000..515774b
--- /dev/null
@@ -0,0 +1,4 @@
+
+void *bootstrap_network(int (*mncc_recv)(void *, int, void *),int bts_type, int mcc, int mnc, int lac, int arfcn, int cardnr, int release_l2, char *name_short, char *name_long, char *hlr, int allow_all);
+int shutdown_net(void *network);
+
index bc2f8b2..beb24a9 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.63 for lcr 1.4.
+# Generated by GNU Autoconf 2.63 for lcr 1.5.
 #
 # Report bugs to <andreas@eversberg.eu>.
 #
@@ -596,8 +596,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='lcr'
 PACKAGE_TARNAME='lcr'
-PACKAGE_VERSION='1.4'
-PACKAGE_STRING='lcr 1.4'
+PACKAGE_VERSION='1.5'
+PACKAGE_STRING='lcr 1.5'
 PACKAGE_BUGREPORT='andreas@eversberg.eu'
 
 ac_unique_file="main.c"
@@ -640,6 +640,8 @@ ac_includes_default="\
 ac_subst_vars='LTLIBOBJS
 POW_LIB
 LIBOBJS
+ENABLE_GSM_FALSE
+ENABLE_GSM_TRUE
 LIBCRYPTO
 ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE
 ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE
@@ -732,6 +734,7 @@ enable_option_checking
 enable_dependency_tracking
 with_asterisk
 with_ssl
+with_gsm
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1297,7 +1300,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures lcr 1.4 to adapt to many kinds of systems.
+\`configure' configures lcr 1.5 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1363,7 +1366,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of lcr 1.4:";;
+     short | recursive ) echo "Configuration of lcr 1.5:";;
    esac
   cat <<\_ACEOF
 
@@ -1382,6 +1385,8 @@ Optional Packages:
 
   --with-ssl              compile with ssl support (libcrypto) [default=check]
 
+  --with-gsm              compile with OpenBSC support (libbsc) [default=no]
+
 
 Some influential environment variables:
   CC          C compiler command
@@ -1461,7 +1466,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-lcr configure 1.4
+lcr configure 1.5
 generated by GNU Autoconf 2.63
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1475,7 +1480,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by lcr $as_me 1.4, which was
+It was created by lcr $as_me 1.5, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   $ $0 $@
@@ -4033,7 +4038,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE=lcr
- VERSION=1.4
+ VERSION=1.5
 
 
 cat >>confdefs.h <<_ACEOF
@@ -6253,6 +6258,27 @@ fi
 fi
 
 
+# check for gsm
+
+# Check whether --with-gsm was given.
+if test "${with_gsm+set}" = set; then
+  withval=$with_gsm;
+else
+  with_gsm=no
+fi
+
+
+
+
+if test "x$with_gsm" != "xno" ; then
+  ENABLE_GSM_TRUE=
+  ENABLE_GSM_FALSE='#'
+else
+  ENABLE_GSM_TRUE='#'
+  ENABLE_GSM_FALSE=
+fi
+
+
 # Checks for libraries.
 
 { $as_echo "$as_me:$LINENO: checking for main in -lm" >&5
@@ -9756,6 +9782,13 @@ $as_echo "$as_me: error: conditional \"ENABLE_ASTERISK_CHANNEL_DRIVER\" was neve
 Usually this means the macro was only invoked conditionally." >&2;}
    { (exit 1); exit 1; }; }
 fi
+if test -z "${ENABLE_GSM_TRUE}" && test -z "${ENABLE_GSM_FALSE}"; then
+  { { $as_echo "$as_me:$LINENO: error: conditional \"ENABLE_GSM\" was never defined.
+Usually this means the macro was only invoked conditionally." >&5
+$as_echo "$as_me: error: conditional \"ENABLE_GSM\" was never defined.
+Usually this means the macro was only invoked conditionally." >&2;}
+   { (exit 1); exit 1; }; }
+fi
 
 : ${CONFIG_STATUS=./config.status}
 ac_write_fail=0
@@ -10078,7 +10111,7 @@ exec 6>&1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by lcr $as_me 1.4, which was
+This file was extended by lcr $as_me 1.5, which was
 generated by GNU Autoconf 2.63.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -10141,7 +10174,7 @@ Report bugs to <bug-autoconf@gnu.org>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-lcr config.status 1.4
+lcr config.status 1.5
 configured by $0, generated by GNU Autoconf 2.63,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 
index e1d3db6..bbd770f 100644 (file)
@@ -24,7 +24,7 @@ dnl    Boston, MA 02110-1301, USA.
 dnl This keeps being the first instruction.
 dnl Change the 2nd argument if the version increases
 dnl 1st + 2nd argument is used for distribution package name
-AC_INIT(lcr, 1.4, andreas@eversberg.eu)
+AC_INIT(lcr, 1.5, andreas@eversberg.eu)
 AC_PREREQ(2.59)
 AC_CONFIG_SRCDIR([main.c])
 AM_CONFIG_HEADER(config.h)
@@ -32,7 +32,7 @@ AM_CONFIG_HEADER(config.h)
 # fix warnings from autoconf + automake
 AC_GNU_SOURCE
 # AC_USE_SYSTEM_EXTENSIONS
-AM_INIT_AUTOMAKE(lcr,1.4)
+AM_INIT_AUTOMAKE(lcr,1.5)
 
 
 
@@ -95,6 +95,16 @@ AS_IF([test "x$with_ssl" != xno],
       ]
      )
 
+# check for gsm
+AC_ARG_WITH([gsm],
+       [AS_HELP_STRING([--with-gsm],
+                       [compile with OpenBSC support (libbsc) @<:@default=no@:>@])
+       ],
+       [],
+       [with_gsm=no])
+
+AM_CONDITIONAL(ENABLE_GSM, test "x$with_gsm" != "xno" )
+
 # Checks for libraries.
 AC_CHECK_LIB([m], [main])
 AC_CHECK_LIB([ncurses], [main])
diff --git a/default/gsm.conf b/default/gsm.conf
new file mode 100644 (file)
index 0000000..b7d7bac
--- /dev/null
@@ -0,0 +1,74 @@
+# LCR GSM options
+#################
+
+# Enable debugging of OpenBSC library.
+# Refer to OpenBSC project for debugging options.
+# By default, debugging is turned off.
+#debug DRLL:DCC:DMM:DRR:DRSL:DNM
+
+# Two Loopback interfaces for audio transfer between OpenBSC and mISDN.
+# The first interface must provide B-channelis for each call mobile call.
+# The seond interface links them to LCR.
+# Use 30 B-channels unless you need more due to many TRXs.
+# -> Load with: "modprobe mISDN_l1loop pri=1 nchannel=30"
+# By default "mISDN_l1loop.1" and "mISDN_l1loop.2" is used.
+#interface-bsc mISDN_l1loop.1
+#interface-lcr mISDN_l1loop.2
+
+# GSM network names.
+# This name is presented to the mobile station.
+# By default 'LCR' is used.
+#long-name Linux-Call-Router
+#short-name LCR
+
+# Give the GSM country code.
+# The country code is different from the PSTN country code. E.g Germany uses
+# 262 instead of 49. Use this for IMSI catching.
+# This will override the default value of 1 = 'test country';
+#mcc 001
+
+# Give the GSM network code.
+# The network code is different from the PSTN network codes. Change this if
+# you run different test networks in the same locations.
+# This will override the default value of 1 = 'test network';
+#mnc 01
+
+# Give the location area code.
+# The location area code is not known to the author of LCR. Don't change it!
+#lac 1
+
+# Give database of Home Location Register (HLR)
+# HLR stores all subscribers. It will be used to grant access to the network.
+# It is an Sqlite3 database. Refer to OpenBSC project for handling.
+# The database is located at /usr/local/lcr by default.
+#hlr hlr.sqlite3
+
+# Authorization of unknown subscribers.
+# To allow all subscribers to access the network, use this option.
+# By default, subscribers are only accepted if allowed in the HLR
+allow-all
+
+# To keep layer 2 connection to BS11 when quitting, use this option.
+# It is only usefull for developing. TRX will stay on.
+# Warning: Keeping layer 2 link may prevent emergency calls. (See below)
+# Layer 2 will only be kept, if lcr was killed manually.
+#keep-l2
+
+# You must define a list of your BTS'.
+# Usage: 'bts bs11 <card> <frequency> [<frequency 2>]
+#  The keyword 'bts' is used to specify a BTS. Multiple BTS' may be defined.
+#  The 'bs11' keyword specifies a BS11 BTS connected to an E1 card.
+#  The frequency is given for the first TRX (tranceiver).
+#  In case of a second tranceiver, give frequency 2.
+bts bs11 9 123
+
+# Shutdown on emergency calls:
+# This option will prevent a shutdown if an emergency call is received. In
+# case of an emergency, a mobile phone may log onto you GSM network and may
+# use it to set up an emergency call.
+# The received emergency call will have 'emergency' as dialed number. But this
+# number can't be dialed on PSTN networks without chaning.
+# If you disable shutdown, be sure to provide routing of emergency calls to
+# emergency facility. If you can't do that, don't touch it!
+#no-emergency-shutdown
+
index 51cc036..8f1dc6b 100644 (file)
 #portnum 0
 #dialmax 20
 
+
+# A special case for GSM interface.
+# Don't remove/change the settings, they will cause undefined behaviour
+# of LCR. The actual interface is defined in gsm.conf.
+# You may add 'extension' and 'mns' keywords to turn all your subscribers
+# in you GSM network to internal 'extensions'.
+# The MSN numbers will equal the subscriber number.
+#[GSM]
+#gsm
+#nt
+#layer1hold no
+#layer2hold no
+#tones yes
+#earlyb no
+#channel-in free
+#channel-out any
+
+
 # Hint: Enter "lcr interface" for quick help on interface options.
 
 
index dfa3b34..a020f62 100644 (file)
@@ -11,6 +11,7 @@
 #define DEBUG_BCHANNEL         0x0008
 #define DEBUG_PORT     0x0100
 #define DEBUG_ISDN     0x0110
+#define DEBUG_GSM      0x0120
 #define DEBUG_VBOX     0x0180
 #define DEBUG_EPOINT   0x0200
 #define DEBUG_JOIN     0x0400
 # Rights must have 0 in front, if octal values above are used.
 #socketrights 0700
 
+# Enable GSM network capability.
+# This option turns LCR into a GSM network. Additional options are specified
+# in 'gsm.conf'. You also need openbsc at compile time and of yourse -
+# a base station transceiver. For more refer to LCR home page.
+#
+# !!! DANGER !!!
+# Running a GSM network may disturb other networks and may be prossecuted by
+# law of your country.
+# Running a GSM network may prevent mobile users from making EMERGENCY CALLS.
+# Be sure to allow emergency calls to be routed to emergency facilities.
+#
+#gsm
+
index b7ff80c..c8adb27 100644 (file)
--- a/dss1.cpp
+++ b/dss1.cpp
@@ -1,6 +1,6 @@
 /*****************************************************************************\
 **                                                                           **
-** PBX4Linux                                                                 **
+** LCR                                                                       **
 **                                                                           **
 **---------------------------------------------------------------------------**
 ** Copyright: Andreas Eversberg                                              **
@@ -12,7 +12,7 @@
 #include "main.h"
 #include "myisdn.h"
 // socket mISDN
-#include <sys/socket.h>
+//#include <sys/socket.h>
 extern "C" {
 }
 #include <q931.h>
@@ -81,8 +81,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                exclusive = 0;
        
        /* select scenario */
-       if (p_m_b_channel && p_m_b_exclusive)
-       {
+       if (p_m_b_channel && p_m_b_exclusive) {
                /*** we gave an exclusive channel (or if we are done) ***/
 
                /* if not first reply, we are done */
@@ -94,8 +93,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                add_trace("channel", "reply", (channel>=0)?"%d":"(none)", channel);
 
                /* if give channel not accepted or not equal */
-               if (channel!=-1 && p_m_b_channel!=channel)
-               {
+               if (channel!=-1 && p_m_b_channel!=channel) {
                        add_trace("conclusion", NULL, "forced channel not accepted");
                        end_trace();
                        ret = -44;
@@ -109,8 +107,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                /* activate our exclusive channel */
                bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
        } else
-       if (p_m_b_channel)
-       {
+       if (p_m_b_channel) {
                /*** we gave a non-exclusive channel ***/
 
                /* if not first reply, we are done */
@@ -122,8 +119,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                add_trace("channel", "reply", (channel>=0)?"%d":"(none)", channel);
 
                /* if channel was accepted as given */
-               if (channel==-1 || p_m_b_channel==channel)
-               {
+               if (channel==-1 || p_m_b_channel==channel) {
                        add_trace("conclusion", NULL, "channel was accepted as given");
                        add_trace("connect", "channel", "%d", p_m_b_channel);
                        end_trace();
@@ -133,8 +129,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                }
 
                /* if channel value is faulty */
-               if (channel <= 0)
-               {
+               if (channel <= 0) {
                        add_trace("conclusion", NULL, "illegal reply");
                        end_trace();
                        ret = -111; // protocol error
@@ -144,8 +139,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                /* if channel was not accepted, try to get it */
                ret = seize_bchannel(channel, 1); // exclusively
                add_trace("channel", "available", ret<0?"no":"yes");
-               if (ret < 0)
-               {
+               if (ret < 0) {
                        add_trace("conclusion", NULL, "replied channel not available");
                        end_trace();
                        goto channelerror;
@@ -157,8 +151,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                /* activate channel given by remote */
                bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
        } else
-       if (p_m_b_reserve)
-       {
+       if (p_m_b_reserve) {
                /*** we sent 'any channel acceptable' ***/
 
                /* if not first reply, we are done */
@@ -169,8 +162,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                add_trace("channel", "request", "any");
                add_trace("channel", "reply", (channel>=0)?"%d":"(none)", channel);
                /* if no channel was replied */
-               if (channel <= 0)
-               {
+               if (channel <= 0) {
                        add_trace("conclusion", NULL, "no channel, protocol error");
                        end_trace();
                        ret = -111; // protocol error
@@ -180,8 +172,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                /* we will see, if our received channel is available */
                ret = seize_bchannel(channel, 1); // exclusively
                add_trace("channel", "available", ret<0?"no":"yes");
-               if (ret < 0)
-               {
+               if (ret < 0) {
                        add_trace("conclusion", NULL, "replied channel not available");
                        end_trace();
                        goto channelerror;
@@ -192,24 +183,20 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
 
                /* activate channel given by remote */
                bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
-       } else
-       {
+       } else {
                /*** we sent 'no channel available' ***/
 
                /* if not the first reply, but a connect, we are forced */
-               if (cmd==MT_CONNECT && p_state!=PORT_STATE_OUT_SETUP)
-               {
+               if (cmd==MT_CONNECT && p_state!=PORT_STATE_OUT_SETUP) {
                        chan_trace_header(p_m_mISDNport, this, "CHANNEL SELECTION (connect)", DIRECTION_NONE);
                        add_trace("channel", "request", "no-channel");
                        add_trace("channel", "reply", (channel>=0)?"%d%s":"(none)", channel, exclusive?" (forced)":"");
-                       if (channel > 0)
-                       {
+                       if (channel > 0) {
                                goto use_from_connect;
                        }
                        ret = seize_bchannel(CHANNEL_ANY, 0); // any channel
                        add_trace("channel", "available", ret<0?"no":"yes");
-                       if (ret < 0)
-                       {
+                       if (ret < 0) {
                                add_trace("conclusion", NULL, "no channel available during call-waiting");
                                end_trace();
                                goto channelerror;
@@ -232,8 +219,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                add_trace("channel", "request", "no-channel");
                add_trace("channel", "reply", (channel>=0)?"%d":"(none)", channel);
                /* if first reply has no channel, we are done */
-               if (channel <= 0)
-               {
+               if (channel <= 0) {
                        add_trace("conclusion", NULL, "no channel until connect");
                        end_trace();
                        return(0);
@@ -243,8 +229,7 @@ int Pdss1::received_first_reply_to_setup(unsigned int cmd, int channel, int excl
                use_from_connect:
                ret = seize_bchannel(channel, exclusive);
                add_trace("channel", "available", ret<0?"no":"yes");
-               if (ret < 0)
-               {
+               if (ret < 0) {
                        add_trace("conclusion", NULL, "replied channel not available");
                        end_trace();
                        goto channelerror;
@@ -291,8 +276,7 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
                add_trace("channel", "request", "no-channel");
        else
                add_trace("channel", "request", (channel>0)?"%d%s":"any", channel, exclusive?" (forced)":"");
-       if (channel==CHANNEL_NO && p_type==PORT_TYPE_DSS1_TE_IN)
-       {
+       if (channel==CHANNEL_NO && p_type==PORT_TYPE_DSS1_TE_IN) {
                add_trace("conclusion", NULL, "incoming call-waiting not supported for TE-mode");
                end_trace();
                return(-6); // channel unacceptable
@@ -300,20 +284,17 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
        if (channel <= 0) /* not given, no channel, whatever.. */
                channel = CHANNEL_ANY; /* any channel */
        add_trace("channel", "reserved", "%d", p_m_mISDNport->b_reserved);
-       if (p_m_mISDNport->b_reserved >= p_m_mISDNport->b_num) // of out chan..
-       {
+       if (p_m_mISDNport->b_reserved >= p_m_mISDNport->b_num) { // of out chan..
                add_trace("conclusion", NULL, "all channels are reserved");
                end_trace();
                return(-34); // no channel
        }
        if (channel == CHANNEL_ANY)
                goto get_from_list;
-       if (channel > 0)
-       {
+       if (channel > 0) {
                /* check for given channel in selection list */
                selchannel = ifport->in_channel;
-               while(selchannel)
-               {
+               while(selchannel) {
                        if (selchannel->channel == channel || selchannel->channel == CHANNEL_FREE)
                                break;
                        selchannel = selchannel->next;
@@ -322,19 +303,16 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
                        channel = 0;
 
                /* exclusive channel requests must be in the list */
-               if (exclusive)
-               {
+               if (exclusive) {
                        /* no exclusive channel */
-                       if (!channel)
-                       {
+                       if (!channel) {
                                add_trace("conclusion", NULL, "exclusively requested channel not in list");
                                end_trace();
                                return(-6); // channel unacceptable
                        }
                        /* get index for channel */
                        i = channel-1-(channel>=17);
-                       if (i < 0 || i >= p_m_mISDNport->b_num || channel == 16)
-                       {
+                       if (i < 0 || i >= p_m_mISDNport->b_num || channel == 16) {
                                add_trace("conclusion", NULL, "exclusively requested channel outside interface range");
                                end_trace();
                                return(-6); // channel unacceptable
@@ -348,12 +326,10 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
                }
 
                /* requested channels in list will be used */
-               if (channel)
-               {
+               if (channel) {
                        /* get index for channel */
                        i = channel-1-(channel>=17);
-                       if (i < 0 || i >= p_m_mISDNport->b_num || channel == 16)
-                       {
+                       if (i < 0 || i >= p_m_mISDNport->b_num || channel == 16) {
                                add_trace("info", NULL, "requested channel %d outside interface range", channel);
                        } else /* if inside range (else) check if available */
                        if (p_m_mISDNport->b_port[i] == NULL)
@@ -365,20 +341,16 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
                /* check for first free channel in list */
                channel = 0;
                selchannel = ifport->in_channel;
-               while(selchannel)
-               {
-                       switch(selchannel->channel)
-                       {
+               while(selchannel) {
+                       switch(selchannel->channel) {
                                case CHANNEL_FREE: /* free channel */
                                add_trace("hunting", "channel", "free");
                                if (p_m_mISDNport->b_reserved >= p_m_mISDNport->b_num)
                                        break; /* all channel in use or reserverd */
                                /* find channel */
                                i = 0;
-                               while(i < p_m_mISDNport->b_num)
-                               {
-                                       if (p_m_mISDNport->b_port[i] == NULL)
-                                       {
+                               while(i < p_m_mISDNport->b_num) {
+                                       if (p_m_mISDNport->b_port[i] == NULL) {
                                                channel = i+1+(i>=15);
                                                break;
                                        }
@@ -393,8 +365,7 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
                                i = selchannel->channel-1-(selchannel->channel>=17);
                                if (i >= p_m_mISDNport->b_num)
                                        break; /* channel not in port */
-                               if (p_m_mISDNport->b_port[i] == NULL)
-                               {
+                               if (p_m_mISDNport->b_port[i] == NULL) {
                                        channel = selchannel->channel;
                                        break;
                                }
@@ -404,8 +375,7 @@ int Pdss1::hunt_bchannel(int channel, int exclusive)
                                break; /* found channel */
                        selchannel = selchannel->next;
                }
-               if (!channel)
-               {
+               if (!channel) {
                        add_trace("conclusion", NULL, "no channel available");
                        end_trace();
                        return(-6); // channel unacceptable
@@ -441,8 +411,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        /* process given callref */
        l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
        add_trace("callref", "new", "0x%x", pid);
-       if (p_m_d_l3id)
-       {
+       if (p_m_d_l3id) {
                /* release in case the ID is already in use */
                add_trace("error", NULL, "callref already in use");
                end_trace();
@@ -476,8 +445,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        end_trace();
 
        /* if blocked, release call with MT_RELEASE_COMPLETE */
-       if (p_m_mISDNport->ifport->block)
-       {
+       if (p_m_mISDNport->ifport->block) {
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_COMPLETE_REQ, DIRECTION_OUT);
                enc_ie_cause(l3m, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, 27); /* temporary unavailable */
@@ -490,8 +458,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        }
 
        /* caller info */
-       switch (calling_present)
-       {
+       switch (calling_present) {
                case 1:
                p_callerinfo.present = INFO_PRESENT_RESTRICTED;
                break;
@@ -502,8 +469,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_callerinfo.present = INFO_PRESENT_ALLOWED;
                break;
        }
-       switch (calling_screen)
-       {
+       switch (calling_screen) {
                case 0:
                p_callerinfo.screen = INFO_SCREEN_USER;
                break;
@@ -511,8 +477,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_callerinfo.screen = INFO_SCREEN_NETWORK;
                break;
        }
-       switch (calling_type)
-       {
+       switch (calling_type) {
                case -1:
                p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
                break;
@@ -536,8 +501,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
 
        /* caller info2 */
-       switch (calling_present2)
-       {
+       switch (calling_present2) {
                case 1:
                p_callerinfo.present2 = INFO_PRESENT_RESTRICTED;
                break;
@@ -548,8 +512,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_callerinfo.present2 = INFO_PRESENT_ALLOWED;
                break;
        }
-       switch (calling_screen2)
-       {
+       switch (calling_screen2) {
                case 0:
                p_callerinfo.screen2 = INFO_SCREEN_USER;
                break;
@@ -557,8 +520,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_callerinfo.screen2 = INFO_SCREEN_NETWORK;
                break;
        }
-       switch (calling_type2)
-       {
+       switch (calling_type2) {
                case -1:
                p_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
                break;
@@ -581,8 +543,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 
        /* dialing information */
        SCAT(p_dialinginfo.id, (char *)keypad);
-       switch (called_type)
-       {
+       switch (called_type) {
                case 0x1:
                p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
                break;
@@ -598,8 +559,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        }
 
        /* redir info */
-       switch (redir_present)
-       {
+       switch (redir_present) {
                case 1:
                p_redirinfo.present = INFO_PRESENT_RESTRICTED;
                break;
@@ -610,8 +570,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_redirinfo.present = INFO_PRESENT_ALLOWED;
                break;
        }
-       switch (redir_screen)
-       {
+       switch (redir_screen) {
                case 0:
                p_redirinfo.screen = INFO_SCREEN_USER;
                break;
@@ -619,8 +578,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_redirinfo.screen = INFO_SCREEN_NETWORK;
                break;
        }
-       switch (redir_reason)
-       {
+       switch (redir_reason) {
                case 1:
                p_redirinfo.reason = INFO_REDIR_BUSY;
                break;
@@ -640,8 +598,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_redirinfo.reason = INFO_REDIR_UNKNOWN;
                break;
        }
-       switch (redir_type)
-       {
+       switch (redir_type) {
                case -1:
                p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
                break;
@@ -664,8 +621,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        p_redirinfo.isdn_port = p_m_portnum;
 
        /* bearer capability */
-       switch (bearer_capability)
-       {
+       switch (bearer_capability) {
                case -1:
                p_capainfo.bearer_capa = INFO_BC_AUDIO;
                bearer_user = (options.law=='a')?3:2;
@@ -674,8 +630,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_capainfo.bearer_capa = bearer_capability;
                break;
        }
-       switch (bearer_mode)
-       {
+       switch (bearer_mode) {
                case 2:
                p_capainfo.bearer_mode = INFO_BMODE_PACKET;
                break;
@@ -683,8 +638,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
                break;
        }
-       switch (bearer_user)
-       {
+       switch (bearer_user) {
                case -1:
                p_capainfo.bearer_info1 = INFO_INFO1_NONE;
                break;
@@ -694,8 +648,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        }
 
        /* hlc */
-       switch (hlc_hlc)
-       {
+       switch (hlc_hlc) {
                case -1:
                p_capainfo.hlc = INFO_HLC_NONE;
                break;
@@ -703,8 +656,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_capainfo.hlc = hlc_hlc + 0x80;
                break;
        }
-       switch (hlc_exthlc)
-       {
+       switch (hlc_exthlc) {
                case -1:
                p_capainfo.exthlc = INFO_HLC_NONE;
                break;
@@ -729,8 +681,7 @@ void Pdss1::setup_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 
        /* open channel */
        ret = seize_bchannel(channel, 1);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                no_channel:
                /*
                 * NOTE: we send MT_RELEASE_COMPLETE to "REJECT" the channel
@@ -788,8 +739,7 @@ void Pdss1::information_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l
        end_trace();
 
        SCAT(p_dialinginfo.id, (char *)keypad);
-       switch (type)
-       {
+       switch (type) {
                case 0x1:
                p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
                break;
@@ -829,8 +779,7 @@ void Pdss1::setup_acknowledge_ind(unsigned int cmd, unsigned int pid, struct l3_
 
        /* process channel */
        ret = received_first_reply_to_setup(cmd, channel, exclusive);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.cause = -ret;
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
@@ -846,10 +795,9 @@ void Pdss1::setup_acknowledge_ind(unsigned int cmd, unsigned int pid, struct l3_
        new_state(PORT_STATE_OUT_OVERLAP);
 
        number = p_m_d_queue;
-       while (number[0]) /* as long we have something to dial */
-       {
-               if (max > strlen(number) || max == 0)
-                       max = strlen(number);
+       while (number[0]) { /* as long we have something to dial */
+               if (max > (int)strlen(number) || max == 0)
+                       max = (int)strlen(number);
       
                nl3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
@@ -879,8 +827,7 @@ void Pdss1::proceeding_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
        end_trace();
 
        ret = received_first_reply_to_setup(cmd, channel, exclusive);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.cause = -ret;
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
@@ -898,16 +845,14 @@ void Pdss1::proceeding_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                notify |= 0x80;
        else
                notify = 0;
-       if (type >= 0 || notify)
-       {
+       if (type >= 0 || notify) {
                if (!notify && type >= 0)
                        notify = 251;
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
                message->param.notifyinfo.notify = notify;
                SCPY(message->param.notifyinfo.id, redir);
                /* redirection number */
-               switch (present)
-               {
+               switch (present) {
                        case 1:
                        message->param.notifyinfo.present = INFO_PRESENT_RESTRICTED;
                        break;
@@ -918,8 +863,7 @@ void Pdss1::proceeding_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                        message->param.notifyinfo.present = INFO_PRESENT_ALLOWED;
                        break;
                }
-               switch (type)
-               {
+               switch (type) {
                        case -1:
                        message->param.notifyinfo.ntype = INFO_NTYPE_NOTPRESENT;
                        break;
@@ -960,8 +904,7 @@ void Pdss1::alerting_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 
        /* process channel */
        ret = received_first_reply_to_setup(cmd, channel, exclusive);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.cause = -ret;
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
@@ -979,15 +922,13 @@ void Pdss1::alerting_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                notify |= 0x80;
        else
                notify = 0;
-       if (type >= 0 || notify)
-       {
+       if (type >= 0 || notify) {
                if (!notify && type >= 0)
                        notify = 251;
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
                message->param.notifyinfo.notify = notify;
                SCPY(message->param.notifyinfo.id, redir);
-               switch (present)
-               {
+               switch (present) {
                        case 1:
                        message->param.notifyinfo.present = INFO_PRESENT_RESTRICTED;
                        break;
@@ -998,8 +939,7 @@ void Pdss1::alerting_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                        message->param.notifyinfo.present = INFO_PRESENT_ALLOWED;
                        break;
                }
-               switch (type)
-               {
+               switch (type) {
                        case -1:
                        message->param.notifyinfo.ntype = INFO_NTYPE_NOTPRESENT;
                        break;
@@ -1041,8 +981,7 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        /* select channel */
        bchannel_before = p_m_b_channel;
        ret = received_first_reply_to_setup(cmd, channel, exclusive);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.cause = -ret;
                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
@@ -1053,8 +992,7 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        }
 
        /* connect information */
-       switch (present)
-       {
+       switch (present) {
                case 1:
                p_connectinfo.present = INFO_PRESENT_RESTRICTED;
                break;
@@ -1065,8 +1003,7 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_connectinfo.present = INFO_PRESENT_ALLOWED;
                break;
        }
-       switch (screen)
-       {
+       switch (screen) {
                case 0:
                p_connectinfo.screen = INFO_SCREEN_USER;
                break;
@@ -1074,8 +1011,7 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                p_connectinfo.screen = INFO_SCREEN_NETWORK;
                break;
        }
-       switch (type)
-       {
+       switch (type) {
                case -1:
                p_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
                break;
@@ -1096,8 +1032,7 @@ void Pdss1::connect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        SCPY(p_connectinfo.interface, p_m_mISDNport->ifport->interface->name);
 
        /* only in nt-mode we send connect ack. in te-mode it is done by stack itself or optional */
-       if (p_m_d_ntmode)
-       {
+       if (p_m_d_ntmode) {
                /* send connect acknowledge */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_CONNECT_RES, DIRECTION_OUT);
@@ -1133,8 +1068,7 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                cause = 16;
 
        /* release if remote sends us no tones */
-       if (!p_m_mISDNport->earlyb)
-       {
+       if (!p_m_mISDNport->earlyb) {
                l3_msg *l3m;
 
                l3m = create_l3msg();
@@ -1147,8 +1081,7 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
                /* sending release to endpoint */
                if (location == LOCATION_PRIVATE_LOCAL)
                        location = LOCATION_PRIVATE_REMOTE;
-               while(p_epointlist)
-               {
+               while(p_epointlist) {
                        message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
                        message->param.disconnectinfo.cause = cause;
                        message->param.disconnectinfo.location = location;
@@ -1165,16 +1098,14 @@ void Pdss1::disconnect_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3
        /* sending disconnect to active endpoint and release to inactive endpoints */
        if (location == LOCATION_PRIVATE_LOCAL)
                location = LOCATION_PRIVATE_REMOTE;
-       if (ACTIVE_EPOINT(p_epointlist))
-       {
+       if (ACTIVE_EPOINT(p_epointlist)) {
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_DISCONNECT);
                message->param.disconnectinfo.location = location;
                message->param.disconnectinfo.cause = cause;
                SCAT(message->param.disconnectinfo.display, (char *)display);
                message_put(message);
        }
-       while(INACTIVE_EPOINT(p_epointlist))
-       {
+       while(INACTIVE_EPOINT(p_epointlist)) {
                message = message_create(p_serial, INACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.location = location;
                message->param.disconnectinfo.cause = cause;
@@ -1193,8 +1124,7 @@ void Pdss1::disconnect_ind_i(unsigned int cmd, unsigned int pid, struct l3_msg *
 
        /* cause */
        l1l2l3_trace_header(p_m_mISDNport, this, L3_DISCONNECT_IND, DIRECTION_IN);
-       if (p_m_d_collect_cause > 0)
-       {
+       if (p_m_d_collect_cause > 0) {
                add_trace("old-cause", "location", "%d", p_m_d_collect_location);
                add_trace("old-cause", "value", "%d", p_m_d_collect_cause);
        }
@@ -1228,8 +1158,7 @@ void Pdss1::release_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        /* sending release to endpoint */
        if (location == LOCATION_PRIVATE_LOCAL)
                location = LOCATION_PRIVATE_REMOTE;
-       while(p_epointlist)
-       {
+       while(p_epointlist) {
                message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.cause = cause;
                message->param.disconnectinfo.location = location;
@@ -1260,12 +1189,10 @@ void Pdss1::release_complete_ind(unsigned int cmd, unsigned int pid, struct l3_m
        
        l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_COMPLETE_IND, DIRECTION_IN);
        /* in case layer 2 is down during setup, we send cause 27 loc 5 */
-       if (p_state == PORT_STATE_OUT_SETUP && p_m_mISDNport->l1link == 0)
-       {
+       if (p_state == PORT_STATE_OUT_SETUP && p_m_mISDNport->l1link == 0) {
                cause = 27;
                location = 5;
-       } else
-       {
+       } else {
                dec_ie_cause(l3m, &location, &cause);
                if (p_m_mISDNport->l1link < 0)
                        add_trace("layer 1", NULL, "unknown");
@@ -1280,8 +1207,7 @@ void Pdss1::release_complete_ind(unsigned int cmd, unsigned int pid, struct l3_m
                cause = 16;
 
        /* sending release to endpoint */
-       while(p_epointlist)
-       {
+       while(p_epointlist) {
                message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
                message->param.disconnectinfo.cause = cause;
                message->param.disconnectinfo.location = location;
@@ -1324,8 +1250,7 @@ void Pdss1::notify_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        message->param.notifyinfo.notify = notify;
        SCPY(message->param.notifyinfo.id, (char *)notifyid);
        /* redirection number */
-       switch (present)
-       {
+       switch (present) {
                case 1:
                message->param.notifyinfo.present = INFO_PRESENT_RESTRICTED;
                break;
@@ -1336,8 +1261,7 @@ void Pdss1::notify_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                message->param.notifyinfo.present = INFO_PRESENT_ALLOWED;
                break;
        }
-       switch (type)
-       {
+       switch (type) {
                case -1:
                message->param.notifyinfo.ntype = INFO_NTYPE_NOTPRESENT;
                break;
@@ -1369,8 +1293,7 @@ void Pdss1::hold_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        l1l2l3_trace_header(p_m_mISDNport, this, L3_HOLD_IND, DIRECTION_IN);
        end_trace();
 
-       if (!ACTIVE_EPOINT(p_epointlist) || p_m_hold)
-       {
+       if (!ACTIVE_EPOINT(p_epointlist) || p_m_hold) {
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_HOLD_REJECT_REQ, DIRECTION_OUT);
                enc_ie_cause(l3m, (p_m_mISDNport->locally)?LOCATION_PRIVATE_LOCAL:LOCATION_PRIVATE_REMOTE, p_m_hold?101:31); /* normal unspecified / incompatible state */
@@ -1397,8 +1320,7 @@ void Pdss1::hold_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        p_m_hold = 1;
 #if 0
        epoint = find_epoint_id(ACTIVE_EPOINT(p_epointlist));
-       if (epoint && p_m_d_ntmode)
-       {
+       if (epoint && p_m_d_ntmode) {
                p_m_timeout = p_settings.tout_hold;
                time(&p_m_timer);
        }
@@ -1423,8 +1345,7 @@ void Pdss1::retrieve_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        dec_ie_channel_id(l3m, &exclusive, &channel);
        end_trace();
 
-       if (!p_m_hold)
-       {
+       if (!p_m_hold) {
                cause = 101; /* incompatible state */
                reject:
 
@@ -1450,8 +1371,7 @@ void Pdss1::retrieve_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 
        /* open channel */
        ret = seize_bchannel(channel, 1);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                no_channel:
                cause = -ret;
                goto reject;
@@ -1483,8 +1403,7 @@ void Pdss1::suspend_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        dec_ie_call_id(l3m, callid, &len);
        end_trace();
 
-       if (!ACTIVE_EPOINT(p_epointlist))
-       {
+       if (!ACTIVE_EPOINT(p_epointlist)) {
                reject:
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_SUSPEND_REJECT_REQ, DIRECTION_OUT);
@@ -1499,13 +1418,10 @@ void Pdss1::suspend_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 
        /* check if call id is in use */
        epoint = epoint_first;
-       while(epoint)
-       {
-               if (epoint->ep_park)
-               {
+       while(epoint) {
+               if (epoint->ep_park) {
                        if (epoint->ep_park_len == len)
-                       if (!memcmp(epoint->ep_park_callid, callid, len))
-                       {
+                       if (!memcmp(epoint->ep_park_callid, callid, len)) {
                                ret = -84; /* call id in use */
                                goto reject;
                        }
@@ -1526,8 +1442,7 @@ void Pdss1::suspend_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        drop_bchannel();
 
        /* sending suspend to endpoint */
-       while (p_epointlist)
-       {
+       while (p_epointlist) {
                message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_SUSPEND);
                memcpy(message->param.parkinfo.callid, callid, sizeof(message->param.parkinfo.callid));
                message->param.parkinfo.len = len;
@@ -1559,8 +1474,7 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        /* process given callref */
        l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
        add_trace("callref", "new", "0x%x", pid);
-       if (p_m_d_l3id)
-       {
+       if (p_m_d_l3id) {
                /* release is case the ID is already in use */
                add_trace("error", NULL, "callref already in use");
                end_trace();
@@ -1583,8 +1497,7 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
        end_trace();
 
        /* if blocked, release call */
-       if (p_m_mISDNport->ifport->block)
-       {
+       if (p_m_mISDNport->ifport->block) {
                ret = -27;
                goto reject;
        }
@@ -1604,8 +1517,7 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 // mode (if hdlc parked) to be done. never mind, this is almost never requested
        /* open channel */
        ret = seize_bchannel(channel, 1);
-       if (ret < 0)
-       {
+       if (ret < 0) {
                no_channel:
                reject:
                l3m = create_l3msg();
@@ -1626,10 +1538,8 @@ void Pdss1::resume_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                FATAL("Incoming resume but already got an endpoint.\n");
        ret = -85; /* no call suspended */
        epoint = epoint_first;
-       while(epoint)
-       {
-               if (epoint->ep_park)
-               {
+       while(epoint) {
+               if (epoint->ep_park) {
                        ret = -83; /* suspended call exists, but this not */
                        if (epoint->ep_park_len == len)
                        if (!memcmp(epoint->ep_park_callid, callid, len))
@@ -1688,9 +1598,6 @@ void Pdss1::facility_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 /* CC_PROGRESS INDICATION */
 void Pdss1::progress_ind(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 {
-       unsigned char facil[256];
-       int facil_len;
-       struct lcr_msg *message;
        int coding, location, progress;
 
        l1l2l3_trace_header(p_m_mISDNport, this, L3_PROGRESS_IND, DIRECTION_IN);
@@ -1707,16 +1614,13 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 {
        int timer = 0;
 
-       switch (cmd)
-       {
+       switch (cmd) {
                case MT_TIMEOUT:
-               if (!l3m->cause)
-               {
+               if (!l3m->cause) {
                        PERROR("Pdss1(%s) timeout without cause.\n", p_name);
                        break;
                }
-               if (l3m->cause[0] != 5)
-               {
+               if (l3m->cause[0] != 5) {
                        PERROR("Pdss1(%s) expecting timeout with timer diagnostic. (got len=%d)\n", p_name, l3m->cause[0]);
                        break;
                }
@@ -1741,8 +1645,7 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                break;
 
                case MT_SETUP_ACKNOWLEDGE:
-               if (p_state != PORT_STATE_OUT_SETUP)
-               {
+               if (p_state != PORT_STATE_OUT_SETUP) {
                        PDEBUG(DEBUG_ISDN, "Pdss1(%s) received setup_acknowledge, but we are not in outgoing setup state, IGNORING.\n", p_name);
                        break;
                }
@@ -1751,8 +1654,7 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
 
                case MT_CALL_PROCEEDING:
                if (p_state != PORT_STATE_OUT_SETUP
-                && p_state != PORT_STATE_OUT_OVERLAP)
-               {
+                && p_state != PORT_STATE_OUT_OVERLAP) {
                        PDEBUG(DEBUG_ISDN, "Pdss1(%s) received proceeding, but we are not in outgoing setup OR overlap state, IGNORING.\n", p_name);
                        break;
                }
@@ -1762,8 +1664,7 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                case MT_ALERTING:
                if (p_state != PORT_STATE_OUT_SETUP
                 && p_state != PORT_STATE_OUT_OVERLAP
-                && p_state != PORT_STATE_OUT_PROCEEDING)
-               {
+                && p_state != PORT_STATE_OUT_PROCEEDING) {
                        PDEBUG(DEBUG_ISDN, "Pdss1(%s) received alerting, but we are not in outgoing setup OR overlap OR proceeding state, IGNORING.\n", p_name);
                        break;
                }
@@ -1774,14 +1675,12 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                if (p_state != PORT_STATE_OUT_SETUP
                 && p_state != PORT_STATE_OUT_OVERLAP
                 && p_state != PORT_STATE_OUT_PROCEEDING
-                && p_state != PORT_STATE_OUT_ALERTING)
-               {
+                && p_state != PORT_STATE_OUT_ALERTING) {
                        PDEBUG(DEBUG_ISDN, "Pdss1(%s) received alerting, but we are not in outgoing setup OR overlap OR proceeding OR ALERTING state, IGNORING.\n", p_name);
                        break;
                }
                connect_ind(cmd, pid, l3m);
-               if (p_m_d_notify_pending)
-               {
+               if (p_m_d_notify_pending) {
                        /* send pending notify message during connect */
                        message_notify(ACTIVE_EPOINT(p_epointlist), p_m_d_notify_pending->type, &p_m_d_notify_pending->param);
                        message_free(p_m_d_notify_pending);
@@ -1792,8 +1691,7 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                case MT_CONNECT_ACKNOWLEDGE:
                if (p_state == PORT_STATE_CONNECT_WAITING)
                        new_state(PORT_STATE_CONNECT);
-               if (p_m_d_notify_pending)
-               {
+               if (p_m_d_notify_pending) {
                        /* send pending notify message during connect-ack */
                        message_notify(ACTIVE_EPOINT(p_epointlist), p_m_d_notify_pending->type, &p_m_d_notify_pending->param);
                        message_free(p_m_d_notify_pending);
@@ -1855,16 +1753,13 @@ void Pdss1::message_isdn(unsigned int cmd, unsigned int pid, struct l3_msg *l3m)
                /* sending release to endpoint in case we still have an endpoint
                 * this is because we don't get any response if a release_complete is received (or a release in release state)
                 */
-               while(p_epointlist) // only if not already released
-               {
+               while(p_epointlist) { // only if not already released
                        struct lcr_msg *message;
                        message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
-                       if (p_m_d_collect_cause)
-                       {
+                       if (p_m_d_collect_cause) {
                                message->param.disconnectinfo.cause = p_m_d_collect_cause;
                                message->param.disconnectinfo.location = p_m_d_collect_location;
-                       } else
-                       {
+                       } else {
                                message->param.disconnectinfo.cause = CAUSE_NOUSER;
                                message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
                        }
@@ -1888,41 +1783,34 @@ void Pdss1::new_state(int state)
 //     class Endpoint *epoint;
 
        /* set timeout */
-       if (state == PORT_STATE_IN_OVERLAP)
-       {
+       if (state == PORT_STATE_IN_OVERLAP) {
                p_m_timeout = p_m_mISDNport->ifport->tout_dialing;
                time(&p_m_timer);
        }
-       if (state != p_state)
-       {
+       if (state != p_state) {
                if (state == PORT_STATE_IN_SETUP
                 || state == PORT_STATE_OUT_SETUP
                 || state == PORT_STATE_IN_OVERLAP
-                || state == PORT_STATE_OUT_OVERLAP)
-               {
+                || state == PORT_STATE_OUT_OVERLAP) {
                        p_m_timeout = p_m_mISDNport->ifport->tout_setup;
                        time(&p_m_timer);
                }
                if (state == PORT_STATE_IN_PROCEEDING
-                || state == PORT_STATE_OUT_PROCEEDING)
-               {
+                || state == PORT_STATE_OUT_PROCEEDING) {
                        p_m_timeout = p_m_mISDNport->ifport->tout_proceeding;
                        time(&p_m_timer);
                }
                if (state == PORT_STATE_IN_ALERTING
-                || state == PORT_STATE_OUT_ALERTING)
-               {
+                || state == PORT_STATE_OUT_ALERTING) {
                        p_m_timeout = p_m_mISDNport->ifport->tout_alerting;
                        time(&p_m_timer);
                }
                if (state == PORT_STATE_CONNECT
-                || state == PORT_STATE_CONNECT_WAITING)
-               {
+                || state == PORT_STATE_CONNECT_WAITING) {
                        p_m_timeout = 0;
                }
                if (state == PORT_STATE_IN_DISCONNECT
-                || state == PORT_STATE_OUT_DISCONNECT)
-               {
+                || state == PORT_STATE_OUT_DISCONNECT) {
                        p_m_timeout = p_m_mISDNport->ifport->tout_disconnect;
                        time(&p_m_timer);
                }
@@ -1943,8 +1831,7 @@ int Pdss1::handler(void)
                return(ret);
 
        /* handle destruction */
-       if (p_m_delete && p_m_d_l3id==0)
-       {
+       if (p_m_delete && p_m_d_l3id==0) {
                delete this;
                return(-1);
        }
@@ -1964,10 +1851,9 @@ void Pdss1::message_information(unsigned int epoint_id, int message_id, union pa
        char *number = param->information.id;
        int max = p_m_mISDNport->ifport->dialmax;
 
-       while (number[0]) /* as long we have something to dial */
-       {
-               if (max > strlen(number) || max == 0)
-                       max = strlen(number);
+       while (number[0]) { /* as long we have something to dial */
+               if (max > (int)strlen(number) || max == 0)
+                       max = (int)strlen(number);
       
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
@@ -1999,8 +1885,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        int max = p_m_mISDNport->ifport->dialmax;
 
        /* release if port is blocked */
-       if (p_m_mISDNport->ifport->block)
-       {
+       if (p_m_mISDNport->ifport->block) {
                struct lcr_msg *message;
 
                message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_RELEASE);
@@ -2023,13 +1908,11 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface);
 
        /* only display at connect state: this case happens if endpoint is in connected mode */
-       if (p_state==PORT_STATE_CONNECT)
-       {
+       if (p_state==PORT_STATE_CONNECT) {
                if (p_type!=PORT_TYPE_DSS1_NT_OUT
                 && p_type!=PORT_TYPE_DSS1_NT_IN)
                        return;
-               if (p_callerinfo.display[0])
-               {
+               if (p_callerinfo.display[0]) {
                        /* sending information */
                        l3m = create_l3msg();
                        l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
@@ -2043,8 +1926,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
 
        /* attach only if not already */
        epointlist = p_epointlist;
-       while(epointlist)
-       {
+       while(epointlist) {
                if (epointlist->epoint_id == epoint_id)
                        break;
                epointlist = epointlist->next;
@@ -2054,8 +1936,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
 
        /* get channel */
        exclusive = 0;
-       if (p_m_b_channel)
-       {
+       if (p_m_b_channel) {
                channel = p_m_b_channel;
                exclusive = p_m_b_exclusive;
        } else
@@ -2069,8 +1950,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        /* see MT_ASSIGN notes at do_layer3() */
        mt_assign_pid = 0;
        ret = p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_ASSIGN, 0, NULL);
-       if (mt_assign_pid == 0 || ret < 0)
-       {
+       if (mt_assign_pid == 0 || ret < 0) {
                struct lcr_msg *message;
 
                add_trace("callref", NULL, "no free id");
@@ -2093,13 +1973,10 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        l1l2l3_trace_header(p_m_mISDNport, this, L3_SETUP_REQ, DIRECTION_OUT);
        /* channel information */
        if (channel >= 0) /* it should */
-       {
                enc_ie_channel_id(l3m, exclusive, channel);
-       }
        /* caller information */
        plan = 1;
-       switch (p_callerinfo.ntype)
-       {
+       switch (p_callerinfo.ntype) {
                case INFO_NTYPE_UNKNOWN:
                type = 0x0;
                break;
@@ -2116,8 +1993,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                type = -1;
                break;
        }
-       switch (p_callerinfo.screen)
-       {
+       switch (p_callerinfo.screen) {
                case INFO_SCREEN_USER:
                screen = 0;
                break;
@@ -2125,8 +2001,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                screen = 3;
                break;
        }
-       switch (p_callerinfo.present)
-       {
+       switch (p_callerinfo.present) {
                case INFO_PRESENT_ALLOWED:
                present = 0;
                break;
@@ -2139,8 +2014,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        }
        /* caller information 2 */
        plan2 = 1;
-       switch (p_callerinfo.ntype2)
-       {
+       switch (p_callerinfo.ntype2) {
                case INFO_NTYPE_UNKNOWN:
                type2 = 0x0;
                break;
@@ -2157,8 +2031,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                type2 = -1;
                break;
        }
-       switch (p_callerinfo.screen2)
-       {
+       switch (p_callerinfo.screen2) {
                case INFO_SCREEN_USER:
                screen2 = 0;
                break;
@@ -2166,8 +2039,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                screen2 = 3;
                break;
        }
-       switch (p_callerinfo.present2)
-       {
+       switch (p_callerinfo.present2) {
                case INFO_PRESENT_ALLOWED:
                present2 = 0;
                break;
@@ -2181,10 +2053,9 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        if (type >= 0)
                enc_ie_calling_pn(l3m, type, plan, present, screen, (unsigned char *)p_callerinfo.id, type2, plan2, present2, screen2, (unsigned char *)p_callerinfo.id2);
        /* dialing information */
-       if (p_dialinginfo.id[0]) /* only if we have something to dial */
-       {
-               if (max > strlen(p_dialinginfo.id) || max == 0)
-                       max = strlen(p_dialinginfo.id);
+       if (p_dialinginfo.id[0]) { /* only if we have something to dial */
+               if (max > (int)strlen(p_dialinginfo.id) || max == 0)
+                       max = (int)strlen(p_dialinginfo.id);
                enc_ie_called_pn(l3m, 0, 1, (unsigned char *)p_dialinginfo.id, max);
                SCPY(p_m_d_queue, p_dialinginfo.id + max);
        }
@@ -2192,14 +2063,12 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        if (p_dialinginfo.sending_complete)
                enc_ie_complete(l3m, 1);
        /* sending user-user */
-       if (param->setup.useruser.len)
-       {
+       if (param->setup.useruser.len) {
                enc_ie_useruser(l3m, param->setup.useruser.protocol, param->setup.useruser.data, param->setup.useruser.len);
        }
        /* redirecting number */
        plan = 1;
-       switch (p_redirinfo.ntype)
-       {
+       switch (p_redirinfo.ntype) {
                case INFO_NTYPE_UNKNOWN:
                type = 0x0;
                break;
@@ -2216,8 +2085,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                type = -1;
                break;
        }
-       switch (p_redirinfo.screen)
-       {
+       switch (p_redirinfo.screen) {
                case INFO_SCREEN_USER:
                screen = 0;
                break;
@@ -2225,8 +2093,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                screen = 3;
                break;
        }
-       switch (p_redirinfo.reason)
-       {
+       switch (p_redirinfo.reason) {
                case INFO_REDIR_BUSY:
                reason = 1;
                break;
@@ -2246,8 +2113,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
                reason = 0;
                break;
        }
-       switch (p_redirinfo.present)
-       {
+       switch (p_redirinfo.present) {
                case INFO_PRESENT_ALLOWED:
                present = 0;
                break;
@@ -2267,8 +2133,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        capability = p_capainfo.bearer_capa;
        mode = p_capainfo.bearer_mode;
        rate = (mode==INFO_BMODE_CIRCUIT)?0x10:0x00;
-       switch (p_capainfo.bearer_info1)
-       {
+       switch (p_capainfo.bearer_info1) {
                case INFO_INFO1_NONE:
                user = -1;
                break;
@@ -2278,8 +2143,7 @@ void Pdss1::message_setup(unsigned int epoint_id, int message_id, union paramete
        }
        enc_ie_bearer(l3m, coding, capability, mode, rate, -1, user);
        /* hlc */
-       if (p_capainfo.hlc)
-       {
+       if (p_capainfo.hlc) {
                coding = 0;
                interpretation = 4;
                presentation = 1;
@@ -2333,11 +2197,9 @@ void Pdss1::message_notify(unsigned int epoint_id, int message_id, union paramet
                notify = param->notifyinfo.notify & 0x7f;
        else
                notify = -1;
-       if (notify >= 0)
-       {
+       if (notify >= 0) {
                plan = 1;
-               switch (param->notifyinfo.ntype)
-               {
+               switch (param->notifyinfo.ntype) {
                        case INFO_NTYPE_UNKNOWN:
                        type = 0;
                        break;
@@ -2354,8 +2216,7 @@ void Pdss1::message_notify(unsigned int epoint_id, int message_id, union paramet
                        type = -1;
                        break;
                }
-               switch (param->notifyinfo.present)
-               {
+               switch (param->notifyinfo.present) {
                        case INFO_PRESENT_ALLOWED:
                        present = 0;
                        break;
@@ -2368,23 +2229,19 @@ void Pdss1::message_notify(unsigned int epoint_id, int message_id, union paramet
                }
        }
 
-       if (notify<0 && !param->notifyinfo.display[0])
-       {
+       if (notify<0 && !param->notifyinfo.display[0]) {
                /* nothing to notify, nothing to display */
                return;
        }
 
-       if (notify >= 0)
-       {
-               if (p_state!=PORT_STATE_CONNECT && p_state!=PORT_STATE_IN_PROCEEDING && p_state!=PORT_STATE_IN_ALERTING)
-               {
+       if (notify >= 0) {
+               if (p_state!=PORT_STATE_CONNECT && p_state!=PORT_STATE_IN_PROCEEDING && p_state!=PORT_STATE_IN_ALERTING) {
                        /* queue notification */
                        if (p_m_d_notify_pending)
                                message_free(p_m_d_notify_pending);
                        p_m_d_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
                        memcpy(&p_m_d_notify_pending->param, param, sizeof(union parameter));
-               } else
-               {
+               } else {
                        /* sending notification */
                        l3m = create_l3msg();
                        l1l2l3_trace_header(p_m_mISDNport, this, L3_NOTIFY_REQ, DIRECTION_OUT);
@@ -2397,8 +2254,7 @@ void Pdss1::message_notify(unsigned int epoint_id, int message_id, union paramet
                        end_trace();
                        p_m_mISDNport->ml3->to_layer3(p_m_mISDNport->ml3, MT_NOTIFY, p_m_d_l3id, l3m);
                }
-       } else if (p_m_d_ntmode || p_m_d_tespecial)
-       {
+       } else if (p_m_d_ntmode || p_m_d_tespecial) {
                /* sending information */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
@@ -2414,8 +2270,7 @@ void Pdss1::message_overlap(unsigned int epoint_id, int message_id, union parame
        l3_msg *l3m;
 
        /* in case of sending complete, we proceed */
-       if (p_dialinginfo.sending_complete)
-       {
+       if (p_dialinginfo.sending_complete) {
                PDEBUG(DEBUG_ISDN, "sending proceeding instead of setup_acknowledge, because address is complete.\n");
                message_proceeding(epoint_id, message_id, param);
                return;
@@ -2468,8 +2323,7 @@ void Pdss1::message_alerting(unsigned int epoint_id, int message_id, union param
        l3_msg *l3m;
 
        /* NT-MODE in setup state we must send PROCEEDING first */
-       if (p_m_d_ntmode && p_state==PORT_STATE_IN_SETUP)
-       {
+       if (p_m_d_ntmode && p_state==PORT_STATE_IN_SETUP) {
                /* sending proceeding */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_PROCEEDING_REQ, DIRECTION_OUT);
@@ -2512,8 +2366,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
        class Endpoint *epoint;
 
        /* NT-MODE in setup state we must send PROCEEDING first */
-       if (p_m_d_ntmode && p_state==PORT_STATE_IN_SETUP)
-       {
+       if (p_m_d_ntmode && p_state==PORT_STATE_IN_SETUP) {
                /* sending proceeding */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_PROCEEDING_REQ, DIRECTION_OUT);
@@ -2531,8 +2384,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
 
        /* only display at connect state */
        if (p_state == PORT_STATE_CONNECT)
-       if (p_connectinfo.display[0])
-       {
+       if (p_connectinfo.display[0]) {
                /* sending information */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_INFORMATION_REQ, DIRECTION_OUT);
@@ -2543,8 +2395,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
                return;
        }
 
-       if (p_state!=PORT_STATE_IN_SETUP && p_state!=PORT_STATE_IN_OVERLAP && p_state!=PORT_STATE_IN_PROCEEDING && p_state!=PORT_STATE_IN_ALERTING)
-       {
+       if (p_state!=PORT_STATE_IN_SETUP && p_state!=PORT_STATE_IN_OVERLAP && p_state!=PORT_STATE_IN_PROCEEDING && p_state!=PORT_STATE_IN_ALERTING) {
                /* connect command only possible in setup, proceeding or alerting state */
                return;
        }
@@ -2554,8 +2405,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
        l1l2l3_trace_header(p_m_mISDNport, this, L3_CONNECT_REQ, DIRECTION_OUT);
        /* connect information */
        plan = 1;
-       switch (p_connectinfo.ntype)
-       {
+       switch (p_connectinfo.ntype) {
                case INFO_NTYPE_UNKNOWN:
                type = 0x0;
                break;
@@ -2572,8 +2422,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
                type = -1;
                break;
        }
-       switch (param->connectinfo.screen)
-       {
+       switch (param->connectinfo.screen) {
                case INFO_SCREEN_USER:
                screen = 0;
                break;
@@ -2581,8 +2430,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
                screen = 3;
                break;
        }
-       switch (p_connectinfo.present)
-       {
+       switch (p_connectinfo.present) {
                case INFO_PRESENT_ALLOWED:
                present = 0;
                break;
@@ -2602,8 +2450,7 @@ void Pdss1::message_connect(unsigned int epoint_id, int message_id, union parame
 //     if (p_connectinfo.name[0] && (p_m_d_ntmode || p_m_d_tespecial))
 //             enc_facility_centrex(&connect->FACILITY, dmsg, (unsigned char *)p_connectinfo.name, 0);
        /* date & time */
-       if (p_m_d_ntmode || p_m_d_tespecial)
-       {
+       if (p_m_d_ntmode || p_m_d_tespecial) {
                epoint = find_epoint_id(epoint_id);
                enc_ie_date(l3m, now, p_settings.no_seconds);
        }
@@ -2627,11 +2474,9 @@ void Pdss1::message_disconnect(unsigned int epoint_id, int message_id, union par
 
        /* we reject during incoming setup when we have no tones. also if we are in outgoing setup state */
 //     if ((p_state==PORT_STATE_IN_SETUP && !p_m_mISDNport->tones)
-if (/*  ||*/ p_state==PORT_STATE_OUT_SETUP)
-       {
+if (/*  ||*/ p_state==PORT_STATE_OUT_SETUP) {
                /* sending release to endpoint */
-               while(p_epointlist)
-               {
+               while(p_epointlist) {
                        message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
                        memcpy(&message->param, param, sizeof(union parameter));
                        message_put(message);
@@ -2651,8 +2496,7 @@ if (/*     ||*/ p_state==PORT_STATE_OUT_SETUP)
        }
 
        /* workarround: NT-MODE in setup state we must send PROCEEDING first to make it work */
-       if (p_state==PORT_STATE_IN_SETUP)
-       {
+       if (p_state==PORT_STATE_IN_SETUP) {
                /* sending proceeding */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_PROCEEDING_REQ, DIRECTION_OUT);
@@ -2702,8 +2546,7 @@ void Pdss1::message_release(unsigned int epoint_id, int message_id, union parame
         * this means that the endpoint doesnt require audio anymore
         */
        if (p_state == PORT_STATE_IN_DISCONNECT
-        || p_state == PORT_STATE_OUT_DISCONNECT)
-       {
+        || p_state == PORT_STATE_OUT_DISCONNECT) {
                /* sending release */
                l3m = create_l3msg();
                l1l2l3_trace_header(p_m_mISDNport, this, L3_RELEASE_REQ, DIRECTION_OUT);
@@ -2723,8 +2566,7 @@ void Pdss1::message_release(unsigned int epoint_id, int message_id, union parame
         * also on outgoing call setup, we send a release complete, BUT this is not conform. (i don't know any other way)
         */
        if (p_state==PORT_STATE_IN_SETUP
-        || p_state==PORT_STATE_OUT_SETUP)
-       {
+        || p_state==PORT_STATE_OUT_SETUP) {
 //#warning remove me
 //PDEBUG(DEBUG_LOG, "JOLLY sending release complete %d\n", p_serial);
                /* sending release complete */
@@ -2744,8 +2586,7 @@ void Pdss1::message_release(unsigned int epoint_id, int message_id, union parame
 #if 0
 wirklich erst proceeding?:
        /* NT-MODE in setup state we must send PROCEEDING first */
-       if (p_m_d_ntmode && p_state==PORT_STATE_IN_SETUP)
-       {
+       if (p_m_d_ntmode && p_state==PORT_STATE_IN_SETUP) {
                CALL_PROCEEDING_t *proceeding;
 
                /* sending proceeding */
@@ -2800,15 +2641,13 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
        if (PmISDN::message_epoint(epoint_id, message_id, param))
                return(1);
 
-       switch(message_id)
-       {
+       switch(message_id) {
                case MESSAGE_INFORMATION: /* overlap dialing */
                if (p_type==PORT_TYPE_DSS1_NT_OUT
                 && p_state!=PORT_STATE_OUT_OVERLAP
                 && p_state!=PORT_STATE_CONNECT
                 && p_state!=PORT_STATE_OUT_DISCONNECT
-                && p_state!=PORT_STATE_IN_DISCONNECT)
-               {
+                && p_state!=PORT_STATE_IN_DISCONNECT) {
                        break;
                }
                if (p_type==PORT_TYPE_DSS1_TE_OUT
@@ -2817,8 +2656,7 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
                 && p_state!=PORT_STATE_OUT_ALERTING
                 && p_state!=PORT_STATE_CONNECT
                 && p_state!=PORT_STATE_OUT_DISCONNECT
-                && p_state!=PORT_STATE_IN_DISCONNECT)
-               {
+                && p_state!=PORT_STATE_IN_DISCONNECT) {
                        break;
                }
                if ((p_type==PORT_TYPE_DSS1_NT_IN || p_type==PORT_TYPE_DSS1_TE_IN)
@@ -2828,8 +2666,7 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
                 && p_state!=PORT_STATE_CONNECT
                 && p_state!=PORT_STATE_CONNECT_WAITING
                 && p_state!=PORT_STATE_OUT_DISCONNECT
-                && p_state!=PORT_STATE_IN_DISCONNECT)
-               {
+                && p_state!=PORT_STATE_IN_DISCONNECT) {
                        break;
                }
                message_information(epoint_id, message_id, param);
@@ -2837,8 +2674,7 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
 
                case MESSAGE_SETUP: /* dial-out command received from epoint */
                if (p_state!=PORT_STATE_IDLE
-                && p_state!=PORT_STATE_CONNECT)
-               {
+                && p_state!=PORT_STATE_CONNECT) {
                        PERROR("Pdss1(%s) ignoring setup because isdn port is not in idle state (or connected for sending display info).\n", p_name);
                        break;
                }
@@ -2856,8 +2692,7 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
                break;
 
                case MESSAGE_OVERLAP: /* more information is needed */
-               if (p_state!=PORT_STATE_IN_SETUP)
-               {
+               if (p_state!=PORT_STATE_IN_SETUP) {
                        break;
                }
                message_overlap(epoint_id, message_id, param);
@@ -2865,13 +2700,11 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
 
                case MESSAGE_PROCEEDING: /* call of endpoint is proceeding */
                if (p_state!=PORT_STATE_IN_SETUP
-                && p_state!=PORT_STATE_IN_OVERLAP)
-               {
+                && p_state!=PORT_STATE_IN_OVERLAP) {
                        break;
                }
                message_proceeding(epoint_id, message_id, param);
-               if (p_m_d_notify_pending)
-               {
+               if (p_m_d_notify_pending) {
                        /* send pending notify message during connect */
                        message_notify(ACTIVE_EPOINT(p_epointlist), p_m_d_notify_pending->type, &p_m_d_notify_pending->param);
                        message_free(p_m_d_notify_pending);
@@ -2882,13 +2715,11 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
                case MESSAGE_ALERTING: /* call of endpoint is ringing */
                if (p_state!=PORT_STATE_IN_SETUP
                 && p_state!=PORT_STATE_IN_OVERLAP
-                && p_state!=PORT_STATE_IN_PROCEEDING)
-               {
+                && p_state!=PORT_STATE_IN_PROCEEDING) {
                        break;
                }
                message_alerting(epoint_id, message_id, param);
-               if (p_m_d_notify_pending)
-               {
+               if (p_m_d_notify_pending) {
                        /* send pending notify message during connect */
                        message_notify(ACTIVE_EPOINT(p_epointlist), p_m_d_notify_pending->type, &p_m_d_notify_pending->param);
                        message_free(p_m_d_notify_pending);
@@ -2901,13 +2732,11 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
                 && p_state!=PORT_STATE_IN_OVERLAP
                 && p_state!=PORT_STATE_IN_PROCEEDING
                 && p_state!=PORT_STATE_IN_ALERTING
-                && !(p_state==PORT_STATE_CONNECT && p_m_d_ntmode))
-               {
+                && !(p_state==PORT_STATE_CONNECT && p_m_d_ntmode)) {
                        break;
                }
                message_connect(epoint_id, message_id, param);
-               if (p_m_d_notify_pending)
-               {
+               if (p_m_d_notify_pending) {
                        /* send pending notify message during connect */
                        message_notify(ACTIVE_EPOINT(p_epointlist), p_m_d_notify_pending->type, &p_m_d_notify_pending->param);
                        message_free(p_m_d_notify_pending);
@@ -2925,16 +2754,14 @@ int Pdss1::message_epoint(unsigned int epoint_id, int message_id, union paramete
                 && p_state!=PORT_STATE_OUT_PROCEEDING
                 && p_state!=PORT_STATE_OUT_ALERTING
                 && p_state!=PORT_STATE_CONNECT
-                && p_state!=PORT_STATE_CONNECT_WAITING)
-               {
+                && p_state!=PORT_STATE_CONNECT_WAITING) {
                        break;
                }
                message_disconnect(epoint_id, message_id, param);
                break;
 
                case MESSAGE_RELEASE: /* release isdn port */
-               if (p_state==PORT_STATE_RELEASE)
-               {
+               if (p_state==PORT_STATE_RELEASE) {
                        break;
                }
                message_release(epoint_id, message_id, param);
@@ -2960,30 +2787,24 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
 
        PDEBUG(DEBUG_ISDN, "cmd(0x%x) pid(0x%x)\n", cmd, pid);
 
-       if (pid == 0)
-       {
+       if (pid == 0) {
                PDEBUG(DEBUG_ISDN, "ignoring dummy process from phone.\n");
                return(0);
        }
 
        /* find Port object of type ISDN */
        port = port_first;
-       while(port)
-       {
+       while(port) {
                /* are we ISDN ? */
-               if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1)
-               {
+               if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1) {
                        pdss1 = (class Pdss1 *)port;
                        /* check out correct stack and id */
-                       if (pdss1->p_m_mISDNport == mISDNport)
-                       {
-                               if (pdss1->p_m_d_l3id & MISDN_PID_CR_FLAG)
-                               {
+                       if (pdss1->p_m_mISDNport == mISDNport) {
+                               if (pdss1->p_m_d_l3id & MISDN_PID_CR_FLAG) {
                                        /* local callref, so match value only */
                                        if ((pdss1->p_m_d_l3id & MISDN_PID_CRVAL_MASK) == (pid & MISDN_PID_CRVAL_MASK))
                                                break; // found
-                               } else
-                               {
+                               } else {
                                        /* remote callref, ref + channel id */
                                        if (pdss1->p_m_d_l3id == pid)
                                                break; // found
@@ -2994,10 +2815,8 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
        }
 
        /* aktueller prozess */
-       if (port)
-       {
-               if (cmd == MT_ASSIGN)
-               {
+       if (port) {
+               if (cmd == MT_ASSIGN) {
                        /* stack gives us new layer 3 id (during connect) */
                        l1l2l3_trace_header(mISDNport, pdss1, L3_NEW_L3ID_IND, DIRECTION_IN);
                        add_trace("callref", "old", "0x%x", pdss1->p_m_d_l3id);
@@ -3014,11 +2833,9 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
                /* if process id is master process, but a child disconnects */
                if (mISDNport->ntmode
                 && (pid & MISDN_PID_CRTYPE_MASK) != MISDN_PID_MASTER
-                && (pdss1->p_m_d_l3id & MISDN_PID_CRTYPE_MASK) == MISDN_PID_MASTER)
-               {
+                && (pdss1->p_m_d_l3id & MISDN_PID_CRTYPE_MASK) == MISDN_PID_MASTER) {
                        if (cmd == MT_DISCONNECT
-                        || cmd == MT_RELEASE)
-                       {
+                        || cmd == MT_RELEASE) {
                                /* send special indication for child disconnect */
                                pdss1->disconnect_ind_i(cmd, pid, l3m);
                                return(0);
@@ -3039,8 +2856,7 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
        }
 
        /* d-message */
-       switch(cmd)
-       {
+       switch(cmd) {
                case MT_SETUP:
                /* creating port object, transparent until setup with hdlc */
                SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
@@ -3073,10 +2889,8 @@ int stack2manager(struct mISDNport *mISDNport, unsigned int cmd, unsigned int pi
                default:
                PERROR("unhandled message: cmd(0x%x) pid(0x%x)\n", cmd, pid);
                port = port_first;
-               while(port)
-               {
-                       if (port->p_type == PORT_TYPE_DSS1_NT_IN || port->p_type == PORT_TYPE_DSS1_NT_OUT)
-                       {
+               while(port) {
+                       if (port->p_type == PORT_TYPE_DSS1_NT_IN || port->p_type == PORT_TYPE_DSS1_NT_OUT) {
                                pdss1 = (class Pdss1 *)port;
                                /* check out correct stack */
                                if (pdss1->p_m_mISDNport == mISDNport)
index 1dce9f1..e9c680f 100644 (file)
@@ -67,7 +67,7 @@ Endpoint::Endpoint(unsigned int port_id, unsigned int join_id)
                port = find_port_id(port_id);
                if (port)
                {
-                       if ((port->p_type&PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1)
+                       if ((port->p_type&PORT_CLASS_MASK) == PORT_CLASS_mISDN)
                                earlyb = ((class PmISDN *)port)->p_m_mISDNport->earlyb;
                        if (!portlist_new(port_id, port->p_type, earlyb))
                                FATAL("No memory for portlist.\n");
diff --git a/gsm.cpp b/gsm.cpp
new file mode 100644 (file)
index 0000000..f2519f5
--- /dev/null
+++ b/gsm.cpp
@@ -0,0 +1,1614 @@
+/*****************************************************************************\
+**                                                                           **
+** LCR                                                                       **
+**                                                                           **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg                                              **
+**                                                                           **
+** mISDN gsm                                                                 **
+**                                                                           **
+\*****************************************************************************/ 
+
+#include "main.h"
+extern "C" {
+#include "openbsc/openbsc.h"
+#include "openbsc/mncc.h"
+#include "openbsc/trau_frame.h"
+#include "bootstrap.h"
+#include "gsm_audio.h"
+
+#undef AF_ISDN
+#undef PF_ISDN
+extern  int     AF_ISDN;
+#define PF_ISDN AF_ISDN
+}
+
+struct lcr_gsm *gsm = NULL;
+
+static unsigned int new_callref = 1;
+
+
+/*
+ * create and send mncc message
+ */
+static struct gsm_mncc *create_mncc(int msg_type, unsigned int callref)
+{
+       struct gsm_mncc *mncc;
+
+       mncc = (struct gsm_mncc *)MALLOC(sizeof(struct gsm_mncc));
+       mncc->msg_type = msg_type;
+       mncc->callref = callref;
+       return (mncc);
+}
+static int send_and_free_mncc(void *net, unsigned int msg_type, void *data)
+{
+       int ret;
+
+       ret = mncc_send(net, msg_type, data);
+       free(data);
+
+       return ret;
+}
+
+
+/*
+ * constructor
+ */
+Pgsm::Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode) : PmISDN(type, mISDNport, portname, settings, channel, exclusive, mode)
+{
+       p_callerinfo.itype = (mISDNport->ifport->interface->extension)?INFO_ITYPE_ISDN_EXTENSION:INFO_ITYPE_ISDN;
+       p_m_g_callref = 0;
+       p_m_g_mode = 0;
+       p_m_g_gsm_b_sock = -1;
+       p_m_g_gsm_b_index = -1;
+       p_m_g_gsm_b_active = 0;
+       p_m_g_notify_pending = NULL;
+       p_m_g_decoder = gsm_audio_create();
+       p_m_g_encoder = gsm_audio_create();
+       if (!p_m_g_encoder || !p_m_g_decoder) {
+               PERROR("Failed to create GSM audio codec instance\n");
+               p_m_delete = 1;
+       }
+       p_m_g_rxpos = 0;
+       p_m_g_tch_connected = 0;
+
+       PDEBUG(DEBUG_GSM, "Created new mISDNPort(%s).\n", portname);
+}
+
+/*
+ * destructor
+ */
+Pgsm::~Pgsm()
+{
+       PDEBUG(DEBUG_GSM, "Destroyed GSM process(%s).\n", p_name);
+
+       /* remove queued message */
+       if (p_m_g_notify_pending)
+               message_free(p_m_g_notify_pending);
+
+       /* close audio transfer socket */
+       if (p_m_g_gsm_b_sock > -1)
+               bchannel_close();
+
+       /* close codec */
+       if (p_m_g_encoder)
+               gsm_audio_destroy(p_m_g_encoder);
+       if (p_m_g_decoder)
+               gsm_audio_destroy(p_m_g_decoder);
+}
+
+
+/* close bsc side bchannel */
+void Pgsm::bchannel_close(void)
+{
+       if (p_m_g_gsm_b_sock > -1)
+               close(p_m_g_gsm_b_sock);
+       p_m_g_gsm_b_sock = -1;
+       p_m_g_gsm_b_index = -1;
+       p_m_g_gsm_b_active = 0;
+}
+
+/* open bsc side bchannel */
+int Pgsm::bchannel_open(int index)
+{
+       int ret;
+       unsigned int on = 1;
+       struct sockaddr_mISDN addr;
+       struct mISDNhead act;
+
+       if (p_m_g_gsm_b_sock > -1) {
+               PERROR("Socket already created for index %d\n", index);
+               return(-EIO);
+       }
+
+       /* open socket */
+       ret = p_m_g_gsm_b_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_B_RAW);
+       if (ret < 0) {
+               PERROR("Failed to open bchannel-socket for index %d\n", index);
+               bchannel_close();
+               return(ret);
+       }
+       
+       /* set nonblocking io */
+       ret = ioctl(p_m_g_gsm_b_sock, FIONBIO, &on);
+       if (ret < 0) {
+               PERROR("Failed to set bchannel-socket index %d into nonblocking IO\n", index);
+               bchannel_close();
+               return(ret);
+       }
+
+       /* bind socket to bchannel */
+       addr.family = AF_ISDN;
+       addr.dev = gsm->gsm_port;
+       addr.channel = index+1+(index>15);
+       ret = bind(p_m_g_gsm_b_sock, (struct sockaddr *)&addr, sizeof(addr));
+       if (ret < 0) {
+               PERROR("Failed to bind bchannel-socket for index %d\n", index);
+               bchannel_close();
+               return(ret);
+       }
+       /* activate bchannel */
+       PDEBUG(DEBUG_GSM, "Activating GSM side channel index %i.\n", index);
+       act.prim = PH_ACTIVATE_REQ; 
+       act.id = 0;
+       ret = sendto(p_m_g_gsm_b_sock, &act, MISDN_HEADER_LEN, 0, NULL, 0);
+       if (ret < 0) {
+               PERROR("Failed to activate index %d\n", index);
+               bchannel_close();
+               return(ret);
+       }
+
+       p_m_g_gsm_b_index = index;
+
+       return(0);
+}
+
+/* receive from bchannel */
+void Pgsm::bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len)
+{
+       int i, j, k;
+       unsigned char frame[33];
+       struct decoded_trau_frame tf;
+
+       /* encoder init failed */
+       if (!p_m_g_encoder)
+               return;
+
+       /* (currently) not connected, so don't flood tch! */
+       if (!p_m_g_tch_connected)
+               return;
+
+       /* write to rx buffer */
+       while(len--) {
+               p_m_g_rxdata[p_m_g_rxpos++] = audio_law_to_s32[*data++];
+               if (p_m_g_rxpos == 160) {
+                       p_m_g_rxpos = 0;
+
+                       /* encode data */
+                       gsm_audio_encode(p_m_g_encoder, p_m_g_rxdata, frame);
+
+                       /* set c-bits and t-bits */
+                       tf.c_bits[0] = 1;
+                       tf.c_bits[1] = 1;
+                       tf.c_bits[2] = 1;
+                       tf.c_bits[3] = 0;
+                       tf.c_bits[4] = 0;
+                       memset(&tf.c_bits[5], 0, 6);
+                       memset(&tf.c_bits[11], 1, 10);
+                       memset(&tf.t_bits[0], 1, 4);
+
+                       /* reassemble d-bits */
+                       i = 0;
+                       j = 0;
+                       k = 0;
+                       while(i < 260) {
+                               tf.d_bits[i] = (frame[j] >> k) & 1;
+                               if (++k == 8) {
+                                       k = 0;
+                                       j++;
+                               }
+                               i++;
+                       }
+
+                       trau_send(&tf);
+               }
+       }
+}
+
+/* transmit to bchannel */
+void Pgsm::bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len)
+{
+       unsigned char buf[MISDN_HEADER_LEN+len];
+       struct mISDNhead *hh = (struct mISDNhead *)buf;
+       int ret;
+
+       if (!p_m_g_gsm_b_active)
+               return;
+
+       /* make and send frame */
+       hh->prim = PH_DATA_REQ;
+       hh->id = 0;
+       memcpy(buf+MISDN_HEADER_LEN, data, len);
+       ret = sendto(p_m_g_gsm_b_sock, buf, MISDN_HEADER_LEN+len, 0, NULL, 0);
+       if (ret <= 0)
+               PERROR("Failed to send to socket index %d\n", index);
+}
+
+void Pgsm::trau_send(void *_tf)
+{
+       struct decoded_trau_frame *tf = (struct decoded_trau_frame *)_tf;
+       unsigned char data[sizeof(struct gsm_trau_frame) + sizeof(struct decoded_trau_frame)];
+       struct gsm_trau_frame *frame = (struct gsm_trau_frame *)data;
+       
+       frame->msg_type = GSM_TRAU_FRAME;
+       frame->callref = p_m_g_callref;
+       memcpy(frame->data, tf, sizeof(struct decoded_trau_frame));
+       mncc_send(gsm->network, frame->msg_type, frame);
+}
+
+
+void Pgsm::trau_receive(void *_frame)
+{
+       struct gsm_trau_frame *frm = (struct gsm_trau_frame *)_frame;
+       struct decoded_trau_frame *tf = (struct decoded_trau_frame *)frm->data;
+//struct decoded_trau_frame *tf = (struct decoded_trau_frame *)_frame;
+       unsigned char frame[33];
+       signed short samples[160];
+       unsigned char data[160];
+       int i, j, k;
+
+       if (!p_m_g_decoder)
+               return;
+
+//     printf("got trau %d %d %d %d %d\n", tf->c_bits[0], tf->c_bits[1], tf->c_bits[2], tf->c_bits[3], tf->c_bits[4]);
+       if (tf->c_bits[0]!=0 || tf->c_bits[1]!=0 || tf->c_bits[2]!=0 || tf->c_bits[3]!=1 || tf->c_bits[4]!=0)
+               PERROR("illegal trau (C1-C5) %d %d %d %d %d\n", tf->c_bits[0], tf->c_bits[1], tf->c_bits[2], tf->c_bits[3], tf->c_bits[4]);
+
+       /* set GSM_MAGIC */
+       memset(&frame, 0, sizeof(frame));
+//     frame[0] = 0xd << 4;
+
+       /* reassemble bits */
+       i = 0;
+       j = 0;
+       k = 0;
+       while(i < 260) {
+               if (tf->d_bits[i] > 1)
+                       PERROR("fix!\n");
+               frame[j] |= (tf->d_bits[i] << k);
+               if (++k == 8) {
+                       k = 0;
+                       j++;
+               }
+               i++;
+       }
+       
+       /* decode */
+       gsm_audio_decode(p_m_g_decoder, frame, samples);
+       for (i = 0; i < 160; i++) {
+               data[i] = audio_s16_to_law[samples[i] & 0xffff];
+       }
+
+       /* send */
+       bchannel_send(PH_DATA_REQ, 0, data, 160);
+}
+
+
+/*
+ * create trace
+ **/
+static void gsm_trace_header(struct mISDNport *mISDNport, class PmISDN *port, unsigned int msg_type, int direction)
+{
+       char msgtext[64];
+
+       /* select message and primitive text */
+       SCPY(msgtext, get_mncc_name(msg_type));
+
+       /* add direction */
+       if (direction == DIRECTION_OUT)
+               SCAT(msgtext, " MSC->BSC");
+       else
+               SCAT(msgtext, " MSC<-BSC");
+
+       /* init trace with given values */
+       start_trace(mISDNport?mISDNport->portnum:-1,
+                   mISDNport?(mISDNport->ifport?mISDNport->ifport->interface:NULL):NULL,
+                   port?numberrize_callerinfo(port->p_callerinfo.id, port->p_callerinfo.ntype, options.national, options.international):NULL,
+                   port?port->p_dialinginfo.id:NULL,
+                   direction,
+                   CATEGORY_CH,
+                   port?port->p_serial:0,
+                   msgtext);
+}
+
+
+
+/* select bchannel */
+int Pgsm::hunt_bchannel(void)
+{
+       int channel;
+       int i;
+
+       chan_trace_header(p_m_mISDNport, this, "CHANNEL SELECTION (setup)", DIRECTION_NONE);
+       add_trace("channel", "reserved", "%d", p_m_mISDNport->b_reserved);
+       if (p_m_mISDNport->b_reserved >= p_m_mISDNport->b_num) { // of out chan..
+               add_trace("conclusion", NULL, "all channels are reserved");
+               end_trace();
+               return(-34); // no channel
+       }
+       /* find channel */
+       i = 0;
+       channel = 0;
+       while(i < p_m_mISDNport->b_num) {
+               if (p_m_mISDNport->b_port[i] == NULL) {
+                       channel = i+1+(i>=15);
+                       break;
+               }
+               i++;
+       }
+       if (!channel) {
+               add_trace("conclusion", NULL, "no channel available");
+               end_trace();
+               return(-6); // channel unacceptable
+       }
+       add_trace("conclusion", NULL, "channel available");
+       add_trace("connect", "channel", "%d", channel);
+       end_trace();
+       return(channel);
+}
+
+
+/*
+ * handles all indications
+ */
+/* SETUP INDICATION */
+void Pgsm::setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       int ret;
+       class Endpoint *epoint;
+       struct lcr_msg *message;
+       int channel;
+       struct gsm_mncc *mode, *proceeding, *frame;
+
+       /* emergency shutdown */
+       printf("%d %d\n", mncc->emergency, !gsm->conf.noemergshut);
+       if (mncc->emergency && !gsm->conf.noemergshut) {
+               start_trace(p_m_mISDNport->portnum,
+                       p_m_mISDNport->ifport->interface,
+                       NULL,
+                       NULL,
+                       DIRECTION_NONE,
+                       CATEGORY_CH,
+                       0,
+                       "EMERGENCY SHUTDOWN (due to received emergency call)");
+               end_trace();
+               quit = 1;
+       }
+       /* process given callref */
+       l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_IND, DIRECTION_IN);
+       add_trace("callref", "new", "0x%x", callref);
+       if (p_m_g_callref) {
+               /* release in case the ID is already in use */
+               add_trace("error", NULL, "callref already in use");
+               end_trace();
+               gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
+               add_trace("cause", "location", "1");
+               add_trace("cause", "value", "47");
+               add_trace("reason", NULL, "callref already in use");
+               end_trace();
+               mncc = create_mncc(MNCC_REJ_REQ, callref);
+               mncc->cause = 1;
+               mncc->cause_location = 1;
+               mncc->cause_value = 47;
+               send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+               new_state(PORT_STATE_RELEASE);
+               p_m_delete = 1;
+               return;
+       }
+       p_m_g_callref = callref;
+       end_trace();
+
+       /* if blocked, release call with MT_RELEASE_COMPLETE */
+       if (p_m_mISDNport->ifport->block) {
+               gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
+               add_trace("cause", "location", "1");
+               add_trace("cause", "value", "27");
+               add_trace("reason", NULL, "port blocked");
+               end_trace();
+               mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
+               mncc->cause = 1;
+               mncc->cause_location = 1;
+               mncc->cause_value = 27;
+               send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+               new_state(PORT_STATE_RELEASE);
+               p_m_delete = 1;
+               return;
+       }
+
+       /* caller info */
+       if (mncc->clir_inv)
+               p_callerinfo.present = INFO_PRESENT_RESTRICTED;
+       else
+               p_callerinfo.present = INFO_PRESENT_ALLOWED;
+       if (mncc->calling_number[0])
+               SCPY(p_callerinfo.id, mncc->calling_number);
+       else
+               p_callerinfo.present = INFO_PRESENT_NOTAVAIL;
+       p_callerinfo.screen = INFO_SCREEN_NETWORK;
+       p_callerinfo.ntype = INFO_NTYPE_UNKNOWN;
+       p_callerinfo.isdn_port = p_m_portnum;
+       SCPY(p_callerinfo.interface, p_m_mISDNport->ifport->interface->name);
+
+       /* dialing information */
+       SCAT(p_dialinginfo.id, mncc->called_number);
+       switch (mncc->called_type) {
+               case 0x1:
+               p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
+               break;
+               case 0x2:
+               p_dialinginfo.ntype = INFO_NTYPE_NATIONAL;
+               break;
+               case 0x4:
+               p_dialinginfo.ntype = INFO_NTYPE_SUBSCRIBER;
+               break;
+               default:
+               p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
+               break;
+       }
+       if (mncc->emergency) {
+               SCPY(p_dialinginfo.id, "emergency");
+       }
+       p_dialinginfo.sending_complete = 1;
+
+       /* bearer capability */
+       // todo
+       p_capainfo.bearer_capa = INFO_BC_SPEECH;
+       p_capainfo.bearer_info1 = (options.law=='a')?3:2;
+       p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
+       p_capainfo.source_mode = B_MODE_TRANSPARENT;
+       p_m_g_mode = p_capainfo.source_mode;
+
+       /* useruser */
+
+       /* hunt channel */
+       ret = channel = hunt_bchannel();
+       if (ret < 0)
+               goto no_channel;
+
+       /* open channel */
+       ret = seize_bchannel(channel, 1);
+       if (ret < 0) {
+               no_channel:
+               gsm_trace_header(p_m_mISDNport, this, MNCC_REJ_REQ, DIRECTION_OUT);
+               add_trace("cause", "location", "1");
+               add_trace("cause", "value", "34");
+               add_trace("reason", NULL, "no channel");
+               end_trace();
+               mncc = create_mncc(MNCC_REJ_REQ, p_m_g_callref);
+               mncc->cause = 1;
+               mncc->cause_location = 1;
+               mncc->cause_value = 34;
+               send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+               new_state(PORT_STATE_RELEASE);
+               p_m_delete = 1;
+               return;
+       }
+       bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
+       if (bchannel_open(p_m_b_index))
+               goto no_channel;
+
+       /* what infos did we got ... */
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       add_trace("subscr", "number", "%s", p_callerinfo.id);
+       add_trace("dialing", "number", "%s", p_dialinginfo.id);
+       end_trace();
+
+       /* create endpoint */
+       if (p_epointlist)
+               FATAL("Incoming call but already got an endpoint.\n");
+       if (!(epoint = new Endpoint(p_serial, 0)))
+               FATAL("No memory for Endpoint instance\n");
+       if (!(epoint->ep_app = new DEFAULT_ENDPOINT_APP(epoint, 0))) //incoming
+               FATAL("No memory for Endpoint Application instance\n");
+       epointlist_new(epoint->ep_serial);
+
+       /* modify lchan to GSM codec V1 */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
+       end_trace();
+       mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
+       mode->lchan_mode = 0x01; /* GSM V1 */
+       add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
+       send_and_free_mncc(gsm->network, mode->msg_type, mode);
+
+       /* send call proceeding */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_CALL_PROC_REQ, DIRECTION_OUT);
+       proceeding = create_mncc(MNCC_CALL_PROC_REQ, p_m_g_callref);
+       if (p_m_mISDNport->tones) {
+               proceeding->progress = 1;
+               proceeding->progress_coding = 3; /* GSM */
+               proceeding->progress_location = 1;
+               proceeding->progress_descr = 8;
+               add_trace("progress", "coding", "%d", proceeding->progress_coding);
+               add_trace("progress", "location", "%d", proceeding->progress_location);
+               add_trace("progress", "descr", "%d", proceeding->progress_descr);
+       }
+       send_and_free_mncc(gsm->network, proceeding->msg_type, proceeding);
+       end_trace();
+
+       new_state(PORT_STATE_IN_PROCEEDING);
+
+       if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
+               gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
+               end_trace();
+               frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
+               send_and_free_mncc(gsm->network, frame->msg_type, frame);
+               p_m_g_tch_connected = 1;
+       }
+
+       /* send setup message to endpoit */
+       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_SETUP);
+       message->param.setup.isdn_port = p_m_portnum;
+       message->param.setup.port_type = p_type;
+//     message->param.setup.dtmf = 0;
+       memcpy(&message->param.setup.dialinginfo, &p_dialinginfo, sizeof(struct dialing_info));
+       memcpy(&message->param.setup.callerinfo, &p_callerinfo, sizeof(struct caller_info));
+       memcpy(&message->param.setup.capainfo, &p_capainfo, sizeof(struct capa_info));
+       SCPY((char *)message->param.setup.useruser.data, (char *)mncc->useruser_info);
+       message->param.setup.useruser.len = strlen(mncc->useruser_info);
+       message->param.setup.useruser.protocol = mncc->useruser_proto;
+       message_put(message);
+}
+
+/* DTMF INDICATION */
+void Pgsm::start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct lcr_msg *message;
+       struct gsm_mncc *resp;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       add_trace("keypad", NULL, "%c", mncc->keypad);
+       end_trace();
+       SPRINT(p_dialinginfo.id, "%c", mncc->keypad);
+       p_dialinginfo.ntype = INFO_NTYPE_UNKNOWN;
+
+       /* send resp */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_START_DTMF_RSP, DIRECTION_OUT);
+       add_trace("keypad", NULL, "%c", mncc->keypad);
+       end_trace();
+       resp = create_mncc(MNCC_START_DTMF_RSP, p_m_g_callref);
+       resp->keypad = mncc->keypad;
+       send_and_free_mncc(gsm->network, resp->msg_type, resp);
+
+       /* send dialing information */
+       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_INFORMATION);
+       memcpy(&message->param.information, &p_dialinginfo, sizeof(struct dialing_info));
+       message_put(message);
+}
+void Pgsm::stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct gsm_mncc *resp;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       add_trace("keypad", NULL, "%c", mncc->keypad);
+       end_trace();
+
+       /* send resp */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_STOP_DTMF_RSP, DIRECTION_OUT);
+       add_trace("keypad", NULL, "%c", mncc->keypad);
+       end_trace();
+       resp = create_mncc(MNCC_STOP_DTMF_RSP, p_m_g_callref);
+       resp->keypad = mncc->keypad;
+       send_and_free_mncc(gsm->network, resp->msg_type, resp);
+}
+
+/* PROCEEDING INDICATION */
+void Pgsm::call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct gsm_mncc *mode;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       if (mncc->cause) {
+               add_trace("cause", "location", "%", mncc->cause_location);
+               add_trace("cause", "value", "%", mncc->cause_value);
+       }
+       end_trace();
+
+       /* modify lchan to GSM codec V1 */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_LCHAN_MODIFY, DIRECTION_OUT);
+       end_trace();
+       mode = create_mncc(MNCC_LCHAN_MODIFY, p_m_g_callref);
+       mode->lchan_mode = 0x01; /* GSM V1 */
+       add_trace("mode", NULL, "0x%02x", mode->lchan_mode);
+       send_and_free_mncc(gsm->network, mode->msg_type, mode);
+
+}
+
+/* ALERTING INDICATION */
+void Pgsm::alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct lcr_msg *message;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       end_trace();
+
+       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_ALERTING);
+       message_put(message);
+
+       new_state(PORT_STATE_OUT_ALERTING);
+
+}
+
+/* CONNECT INDICATION */
+void Pgsm::setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct gsm_mncc *resp, *frame;
+       struct lcr_msg *message;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       end_trace();
+
+       /* send resp */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_COMPL_REQ, DIRECTION_OUT);
+       resp = create_mncc(MNCC_SETUP_COMPL_REQ, p_m_g_callref);
+       end_trace();
+       send_and_free_mncc(gsm->network, resp->msg_type, resp);
+
+       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_CONNECT);
+       message_put(message);
+
+       new_state(PORT_STATE_CONNECT);
+
+       if (!p_m_g_tch_connected) { /* only if ... */
+               gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
+               end_trace();
+               frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
+               send_and_free_mncc(gsm->network, frame->msg_type, frame);
+               p_m_g_tch_connected = 1;
+       }
+}
+
+/* CONNECT ACK INDICATION */
+void Pgsm::setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct gsm_mncc *frame;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       end_trace();
+
+       new_state(PORT_STATE_CONNECT);
+
+       if (!p_m_g_tch_connected) { /* only if ... */
+               gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
+               end_trace();
+               frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
+               send_and_free_mncc(gsm->network, frame->msg_type, frame);
+               p_m_g_tch_connected = 1;
+       }
+}
+
+/* DISCONNECT INDICATION */
+void Pgsm::disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct lcr_msg *message;
+       int cause = 16, location = 0;
+       struct gsm_mncc *resp;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       if (mncc->cause) {
+               location = mncc->cause_location;
+               cause = mncc->cause_value;
+               add_trace("cause", "location", "%d", location);
+               add_trace("cause", "value", "%d", cause);
+       }
+       end_trace();
+
+       /* send release */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
+       add_trace("cause", "location", "%d", 1);
+       add_trace("cause", "value", "%d", cause);
+       end_trace();
+       resp = create_mncc(MNCC_REL_REQ, p_m_g_callref);
+       resp->cause = 1;
+       resp->cause_location = 1;
+       resp->cause_value = cause;
+       send_and_free_mncc(gsm->network, resp->msg_type, resp);
+
+       /* sending release to endpoint */
+       while(p_epointlist) {
+               message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+               message->param.disconnectinfo.cause = cause;
+               message->param.disconnectinfo.location = location;
+               message_put(message);
+               /* remove epoint */
+               free_epointlist(p_epointlist);
+       }
+       new_state(PORT_STATE_RELEASE);
+       p_m_delete = 1;
+}
+
+/* CC_RELEASE INDICATION */
+void Pgsm::rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       int location = 0, cause = 16;
+       struct lcr_msg *message;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       if (mncc->cause) {
+               location = mncc->cause_location;
+               cause = mncc->cause_value;
+               add_trace("cause", "location", "%d", location);
+               add_trace("cause", "value", "%d", cause);
+       }
+       end_trace();
+
+       /* sending release to endpoint */
+       while(p_epointlist) {
+               message = message_create(p_serial, p_epointlist->epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+               message->param.disconnectinfo.cause = cause;
+               message->param.disconnectinfo.location = location;
+               message_put(message);
+               /* remove epoint */
+               free_epointlist(p_epointlist);
+       }
+       new_state(PORT_STATE_RELEASE);
+       p_m_delete = 1;
+}
+
+/* NOTIFY INDICATION */
+void Pgsm::notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       end_trace();
+}
+
+
+/* HOLD INDICATION */
+void Pgsm::hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct lcr_msg *message;
+       struct gsm_mncc *resp, *frame;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       end_trace();
+
+       /* notify the hold of call */
+       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
+       message->param.notifyinfo.notify = INFO_NOTIFY_REMOTE_HOLD;
+       message->param.notifyinfo.local = 1; /* call is held by supplementary service */
+       message_put(message);
+
+       /* acknowledge hold */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_HOLD_CNF, DIRECTION_OUT);
+       end_trace();
+       resp = create_mncc(MNCC_HOLD_CNF, p_m_g_callref);
+       send_and_free_mncc(gsm->network, resp->msg_type, resp);
+
+       /* disable audio */
+       if (p_m_g_tch_connected) { /* it should be true */
+               gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_DROP, DIRECTION_OUT);
+               end_trace();
+               frame = create_mncc(MNCC_FRAME_DROP, p_m_g_callref);
+               send_and_free_mncc(gsm->network, frame->msg_type, frame);
+               p_m_g_tch_connected = 0;
+       }
+}
+
+
+/* RETRIEVE INDICATION */
+void Pgsm::retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc)
+{
+       struct lcr_msg *message;
+       struct gsm_mncc *resp, *frame;
+
+       gsm_trace_header(p_m_mISDNport, this, msg_type, DIRECTION_IN);
+       end_trace();
+
+       /* notify the retrieve of call */
+       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_NOTIFY);
+       message->param.notifyinfo.notify = INFO_NOTIFY_REMOTE_RETRIEVAL;
+       message->param.notifyinfo.local = 1; /* call is retrieved by supplementary service */
+       message_put(message);
+
+       /* acknowledge retr */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_RETRIEVE_CNF, DIRECTION_OUT);
+       end_trace();
+       resp = create_mncc(MNCC_RETRIEVE_CNF, p_m_g_callref);
+       send_and_free_mncc(gsm->network, resp->msg_type, resp);
+
+       /* enable audio */
+       if (!p_m_g_tch_connected) { /* it should be true */
+               gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
+               end_trace();
+               frame = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
+               send_and_free_mncc(gsm->network, frame->msg_type, frame);
+               p_m_g_tch_connected = 1;
+       }
+}
+
+/*
+ * BSC sends message to port
+ */
+static int message_bcs(void *net, int msg_type, void *arg)
+{
+       struct gsm_mncc *mncc = (struct gsm_mncc *)arg;
+       unsigned int callref = mncc->callref;
+       class Port *port;
+       class Pgsm *pgsm = NULL;
+       char name[64];
+       struct mISDNport *mISDNport;
+
+       /* Special messages */
+       switch(msg_type) {
+       }
+
+       /* find callref */
+       callref = mncc->callref;
+       port = port_first;
+       while(port) {
+               if ((port->p_type & PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_GSM) {
+                       pgsm = (class Pgsm *)port;
+                       if (pgsm->p_m_g_callref == callref) {
+                               break;
+                       }
+               }
+               port = port->next;
+       }
+
+       if (msg_type == GSM_TRAU_FRAME) {
+               if (port)
+                       pgsm->trau_receive((struct gsm_trau_frame *)arg);
+               return 0;
+       }
+
+       if (!port) {
+               if (msg_type != MNCC_SETUP_IND)
+                       return(0);
+               /* find gsm port */
+               mISDNport = mISDNport_first;
+               while(mISDNport) {
+                       if (mISDNport->gsm)
+                               break;
+                       mISDNport = mISDNport->next;
+               }
+               if (!mISDNport) {
+                       struct gsm_mncc *rej;
+
+                       gsm_trace_header(NULL, NULL, MNCC_REJ_REQ, DIRECTION_OUT);
+                       add_trace("cause", "location", "1");
+                       add_trace("cause", "value", "27");
+                       add_trace("reason", NULL, "GSM port not loaded");
+                       end_trace();
+                       rej = create_mncc(MNCC_REJ_REQ, callref);
+                       rej->cause = 1;
+                       rej->cause_location = 1;
+                       rej->cause_value = 27;
+                       send_and_free_mncc(gsm->network, rej->msg_type, rej);
+                       return 0;
+               }
+               /* creating port object, transparent until setup with hdlc */
+               SPRINT(name, "%s-%d-in", mISDNport->ifport->interface->name, mISDNport->portnum);
+               if (!(pgsm = new Pgsm(PORT_TYPE_GSM_IN, mISDNport, name, NULL, 0, 0, B_MODE_TRANSPARENT)))
+
+                       FATAL("Cannot create Port instance.\n");
+       }
+
+       switch(msg_type) {
+               case MNCC_SETUP_IND:
+               pgsm->setup_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_START_DTMF_IND:
+               pgsm->start_dtmf_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_STOP_DTMF_IND:
+               pgsm->stop_dtmf_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_CALL_CONF_IND:
+               pgsm->call_conf_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_ALERT_IND:
+               pgsm->alert_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_SETUP_CNF:
+               pgsm->setup_cnf(msg_type, callref, mncc);
+               break;
+
+               case MNCC_SETUP_COMPL_IND:
+               pgsm->setup_compl_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_DISC_IND:
+               pgsm->disc_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_REL_IND:
+               case MNCC_REL_CNF:
+               pgsm->rel_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_NOTIFY_IND:
+               pgsm->notify_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_HOLD_IND:
+               pgsm->hold_ind(msg_type, callref, mncc);
+               break;
+
+               case MNCC_RETRIEVE_IND:
+               pgsm->retr_ind(msg_type, callref, mncc);
+               break;
+
+               default:
+               PDEBUG(DEBUG_GSM, "Pgsm(%s) gsm port with (caller id %s) received unhandled nessage: 0x%x\n", pgsm->p_name, pgsm->p_callerinfo.id, msg_type);
+       }
+       return(0);
+}
+
+/* MESSAGE_SETUP */
+void Pgsm::message_setup(unsigned int epoint_id, int message_id, union parameter *param)
+{
+       struct lcr_msg *message;
+       int ret;
+       struct epoint_list *epointlist;
+       struct gsm_mncc *mncc;
+       int channel;
+
+       /* copy setup infos to port */
+       memcpy(&p_callerinfo, &param->setup.callerinfo, sizeof(p_callerinfo));
+       memcpy(&p_dialinginfo, &param->setup.dialinginfo, sizeof(p_dialinginfo));
+       memcpy(&p_capainfo, &param->setup.capainfo, sizeof(p_capainfo));
+       memcpy(&p_redirinfo, &param->setup.redirinfo, sizeof(p_redirinfo));
+
+       /* no number */
+       if (!p_dialinginfo.id[0]) {
+               gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
+               add_trace("failure", NULL, "No dialed subscriber given.");
+               end_trace();
+               message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+               message->param.disconnectinfo.cause = 28;
+               message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+               message_put(message);
+               new_state(PORT_STATE_RELEASE);
+               p_m_delete = 1;
+               return;
+       }
+       
+       /* release if port is blocked */
+       if (p_m_mISDNport->ifport->block) {
+               gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
+               add_trace("failure", NULL, "Port blocked.");
+               end_trace();
+               message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+               message->param.disconnectinfo.cause = 27; // temp. unavail.
+               message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+               message_put(message);
+               new_state(PORT_STATE_RELEASE);
+               p_m_delete = 1;
+               return;
+       }
+
+       /* hunt channel */
+       ret = channel = hunt_bchannel();
+       if (ret < 0)
+               goto no_channel;
+       /* open channel */
+       ret = seize_bchannel(channel, 1);
+       if (ret < 0) {
+               no_channel:
+               gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
+               add_trace("failure", NULL, "No internal audio channel available.");
+               end_trace();
+               message = message_create(p_serial, epoint_id, PORT_TO_EPOINT, MESSAGE_RELEASE);
+               message->param.disconnectinfo.cause = 34;
+               message->param.disconnectinfo.location = LOCATION_PRIVATE_LOCAL;
+               message_put(message);
+               new_state(PORT_STATE_RELEASE);
+               p_m_delete = 1;
+               return;
+       }
+       bchannel_event(p_m_mISDNport, p_m_b_index, B_EVENT_USE);
+       if (bchannel_open(p_m_b_index))
+               goto no_channel;
+
+//             SCPY(&p_m_tones_dir, param->setup.ext.tones_dir);
+       /* screen outgoing caller id */
+       do_screen(1, p_callerinfo.id, sizeof(p_callerinfo.id), &p_callerinfo.ntype, &p_callerinfo.present, p_m_mISDNport->ifport->interface);
+       do_screen(1, p_callerinfo.id2, sizeof(p_callerinfo.id2), &p_callerinfo.ntype2, &p_callerinfo.present2, p_m_mISDNport->ifport->interface);
+
+       /* attach only if not already */
+       epointlist = p_epointlist;
+       while(epointlist) {
+               if (epointlist->epoint_id == epoint_id)
+                       break;
+               epointlist = epointlist->next;
+       }
+       if (!epointlist)
+               epointlist_new(epoint_id);
+
+       /* creating l3id */
+       l1l2l3_trace_header(p_m_mISDNport, this, L3_NEW_L3ID_REQ, DIRECTION_OUT);
+       p_m_g_callref = new_callref++;
+       add_trace("callref", "new", "0x%x", p_m_g_callref);
+       end_trace();
+
+       gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_REQ, DIRECTION_OUT);
+       mncc = create_mncc(MNCC_SETUP_REQ, p_m_g_callref);
+       /* caller information */
+       mncc->calling = 1;
+       mncc->calling_plan = 1;
+       switch (p_callerinfo.ntype) {
+               case INFO_NTYPE_UNKNOWN:
+               mncc->calling_type = 0x0;
+               break;
+               case INFO_NTYPE_INTERNATIONAL:
+               mncc->calling_type = 0x1;
+               break;
+               case INFO_NTYPE_NATIONAL:
+               mncc->calling_type = 0x2;
+               break;
+               case INFO_NTYPE_SUBSCRIBER:
+               mncc->calling_type = 0x4;
+               break;
+               default: /* INFO_NTYPE_NOTPRESENT */
+               mncc->calling = 0;
+               break;
+       }
+       switch (p_callerinfo.screen) {
+               case INFO_SCREEN_USER:
+               mncc->calling_screen = 0;
+               break;
+               default: /* INFO_SCREEN_NETWORK */
+               mncc->calling_screen = 3;
+               break;
+       }
+       switch (p_callerinfo.present) {
+               case INFO_PRESENT_ALLOWED:
+               mncc->calling_present = 0;
+               break;
+               case INFO_PRESENT_RESTRICTED:
+               mncc->calling_present = 1;
+               break;
+               default: /* INFO_PRESENT_NOTAVAIL */
+               mncc->calling_present = 2;
+               break;
+       }
+       if (mncc->calling) {
+               SCPY(mncc->calling_number, p_callerinfo.id);
+               add_trace("calling", "type", "%d", mncc->calling_type);
+               add_trace("calling", "plan", "%d", mncc->calling_plan);
+               add_trace("calling", "present", "%d", mncc->calling_present);
+               add_trace("calling", "screen", "%d", mncc->calling_screen);
+               add_trace("calling", "number", "%s", mncc->calling_number);
+       }
+       /* dialing information */
+       mncc->called = 1;
+       SCPY(mncc->called_number, p_dialinginfo.id);
+       add_trace("dialing", "number", "%s", mncc->calling_number);
+       
+       /* sending user-user */
+
+       /* redirecting number */
+       mncc->redirecting = 1;
+       mncc->redirecting_plan = 1;
+       switch (p_redirinfo.ntype) {
+               case INFO_NTYPE_UNKNOWN:
+               mncc->redirecting_type = 0x0;
+               break;
+               case INFO_NTYPE_INTERNATIONAL:
+               mncc->redirecting_type = 0x1;
+               break;
+               case INFO_NTYPE_NATIONAL:
+               mncc->redirecting_type = 0x2;
+               break;
+               case INFO_NTYPE_SUBSCRIBER:
+               mncc->redirecting_type = 0x4;
+               break;
+               default: /* INFO_NTYPE_NOTPRESENT */
+               mncc->redirecting = 0;
+               break;
+       }
+       switch (p_redirinfo.screen) {
+               case INFO_SCREEN_USER:
+               mncc->redirecting_screen = 0;
+               break;
+               default: /* INFO_SCREE_NETWORK */
+               mncc->redirecting_screen = 3;
+               break;
+       }
+       switch (p_redirinfo.present) {
+               case INFO_PRESENT_ALLOWED:
+               mncc->redirecting_present = 0;
+               break;
+               case INFO_PRESENT_RESTRICTED:
+               mncc->redirecting_present = 1;
+               break;
+               default: /* INFO_PRESENT_NOTAVAIL */
+               mncc->redirecting_present = 2;
+               break;
+       }
+       /* sending redirecting number only in ntmode */
+       if (mncc->redirecting) {
+               SCPY(mncc->redirecting_number, p_redirinfo.id);
+               add_trace("redir", "type", "%d", mncc->redirecting_type);
+               add_trace("redir", "plan", "%d", mncc->redirecting_plan);
+               add_trace("redir", "present", "%d", mncc->redirecting_present);
+               add_trace("redir", "screen", "%d", mncc->redirecting_screen);
+               add_trace("redir", "number", "%s", mncc->redirecting_number);
+       }
+       /* bearer capability */
+       //todo
+
+       send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+       end_trace();
+
+       new_state(PORT_STATE_OUT_SETUP);
+
+       message = message_create(p_serial, ACTIVE_EPOINT(p_epointlist), PORT_TO_EPOINT, MESSAGE_PROCEEDING);
+       message_put(message);
+
+       new_state(PORT_STATE_OUT_PROCEEDING);
+}
+
+/* MESSAGE_NOTIFY */
+void Pgsm::message_notify(unsigned int epoint_id, int message_id, union parameter *param)
+{
+       struct gsm_mncc *mncc;
+       int notify;
+
+       printf("if = %d\n", param->notifyinfo.notify);
+       if (param->notifyinfo.notify>INFO_NOTIFY_NONE) {
+               notify = param->notifyinfo.notify & 0x7f;
+               if (p_state!=PORT_STATE_CONNECT /*&& p_state!=PORT_STATE_IN_PROCEEDING*/ && p_state!=PORT_STATE_IN_ALERTING) {
+                       /* queue notification */
+                       if (p_m_g_notify_pending)
+                               message_free(p_m_g_notify_pending);
+                       p_m_g_notify_pending = message_create(ACTIVE_EPOINT(p_epointlist), p_serial, EPOINT_TO_PORT, message_id);
+                       memcpy(&p_m_g_notify_pending->param, param, sizeof(union parameter));
+               } else {
+                       /* sending notification */
+                       gsm_trace_header(p_m_mISDNport, this, MNCC_NOTIFY_REQ, DIRECTION_OUT);
+                       add_trace("notify", NULL, "%d", notify);
+                       end_trace();
+                       mncc = create_mncc(MNCC_NOTIFY_REQ, p_m_g_callref);
+                       mncc->notify = notify;
+                       send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+               }
+       }
+}
+
+/* MESSAGE_ALERTING */
+void Pgsm::message_alerting(unsigned int epoint_id, int message_id, union parameter *param)
+{
+       struct gsm_mncc *mncc;
+
+       /* send alert */
+       gsm_trace_header(p_m_mISDNport, this, MNCC_ALERT_REQ, DIRECTION_OUT);
+       mncc = create_mncc(MNCC_ALERT_REQ, p_m_g_callref);
+       if (p_m_mISDNport->tones) {
+               mncc->progress = 1;
+               mncc->progress_coding = 3; /* GSM */
+               mncc->progress_location = 1;
+               mncc->progress_descr = 8;
+               add_trace("progress", "coding", "%d", mncc->progress_coding);
+               add_trace("progress", "location", "%d", mncc->progress_location);
+               add_trace("progress", "descr", "%d", mncc->progress_descr);
+       }
+       send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+       end_trace();
+
+       new_state(PORT_STATE_IN_ALERTING);
+
+       if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
+               gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
+               end_trace();
+               mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
+               send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+               p_m_g_tch_connected = 1;
+       }
+}
+
+/* MESSAGE_CONNECT */
+void Pgsm::message_connect(unsigned int epoint_id, int message_id, union parameter *param)
+{
+       struct gsm_mncc *mncc;
+
+       /* copy connected information */
+       memcpy(&p_connectinfo, &param->connectinfo, sizeof(p_connectinfo));
+       /* screen outgoing caller id */
+       do_screen(1, p_connectinfo.id, sizeof(p_connectinfo.id), &p_connectinfo.ntype, &p_connectinfo.present, p_m_mISDNport->ifport->interface);
+
+       /* send connect */
+       mncc = create_mncc(MNCC_SETUP_RSP, p_m_g_callref);
+       gsm_trace_header(p_m_mISDNport, this, MNCC_SETUP_RSP, DIRECTION_OUT);
+       /* caller information */
+       mncc->connected = 1;
+       mncc->connected_plan = 1;
+       switch (p_callerinfo.ntype) {
+               case INFO_NTYPE_UNKNOWN:
+               mncc->connected_type = 0x0;
+               break;
+               case INFO_NTYPE_INTERNATIONAL:
+               mncc->connected_type = 0x1;
+               break;
+               case INFO_NTYPE_NATIONAL:
+               mncc->connected_type = 0x2;
+               break;
+               case INFO_NTYPE_SUBSCRIBER:
+               mncc->connected_type = 0x4;
+               break;
+               default: /* INFO_NTYPE_NOTPRESENT */
+               mncc->connected = 0;
+               break;
+       }
+       switch (p_callerinfo.screen) {
+               case INFO_SCREEN_USER:
+               mncc->connected_screen = 0;
+               break;
+               default: /* INFO_SCREEN_NETWORK */
+               mncc->connected_screen = 3;
+               break;
+       }
+       switch (p_callerinfo.present) {
+               case INFO_PRESENT_ALLOWED:
+               mncc->connected_present = 0;
+               break;
+               case INFO_PRESENT_RESTRICTED:
+               mncc->connected_present = 1;
+               break;
+               default: /* INFO_PRESENT_NOTAVAIL */
+               mncc->connected_present = 2;
+               break;
+       }
+       if (mncc->connected) {
+               SCPY(mncc->connected_number, p_connectinfo.id);
+               add_trace("connected", "type", "%d", mncc->connected_type);
+               add_trace("connected", "plan", "%d", mncc->connected_plan);
+               add_trace("connected", "present", "%d", mncc->connected_present);
+               add_trace("connected", "screen", "%d", mncc->connected_screen);
+               add_trace("connected", "number", "%s", mncc->connected_number);
+       }
+       end_trace();
+       send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+
+       new_state(PORT_STATE_CONNECT_WAITING);
+}
+
+/* MESSAGE_DISCONNECT */
+void Pgsm::message_disconnect(unsigned int epoint_id, int message_id, union parameter *param)
+{
+       struct gsm_mncc *mncc;
+
+       /* send disconnect */
+       mncc = create_mncc(MNCC_DISC_REQ, p_m_g_callref);
+       gsm_trace_header(p_m_mISDNport, this, MNCC_DISC_REQ, DIRECTION_OUT);
+       if (p_m_mISDNport->tones) {
+               mncc->progress = 1;
+               mncc->progress_coding = 3; /* GSM */
+               mncc->progress_location = 1;
+               mncc->progress_descr = 8;
+               add_trace("progress", "coding", "%d", mncc->progress_coding);
+               add_trace("progress", "location", "%d", mncc->progress_location);
+               add_trace("progress", "descr", "%d", mncc->progress_descr);
+       }
+       mncc->cause = 1;
+       mncc->cause_location = param->disconnectinfo.location;
+       mncc->cause_value = param->disconnectinfo.cause;
+       add_trace("cause", "location", "%d", mncc->cause_location);
+       add_trace("cause", "value", "%d", mncc->cause_value);
+       end_trace();
+       send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+
+       new_state(PORT_STATE_OUT_DISCONNECT);
+
+       if (p_m_mISDNport->tones && !p_m_g_tch_connected) { /* only if ... */
+               gsm_trace_header(p_m_mISDNport, this, MNCC_FRAME_RECV, DIRECTION_OUT);
+               end_trace();
+               mncc = create_mncc(MNCC_FRAME_RECV, p_m_g_callref);
+               send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+               p_m_g_tch_connected = 1;
+       }
+}
+
+
+/* MESSAGE_RELEASE */
+void Pgsm::message_release(unsigned int epoint_id, int message_id, union parameter *param)
+{
+       struct gsm_mncc *mncc;
+
+       /* send release */
+       mncc = create_mncc(MNCC_REL_REQ, p_m_g_callref);
+       gsm_trace_header(p_m_mISDNport, this, MNCC_REL_REQ, DIRECTION_OUT);
+       mncc->cause = 1;
+       mncc->cause_location = param->disconnectinfo.location;
+       mncc->cause_value = param->disconnectinfo.cause;
+       add_trace("cause", "location", "%d", mncc->cause_location);
+       add_trace("cause", "value", "%d", mncc->cause_value);
+       end_trace();
+       send_and_free_mncc(gsm->network, mncc->msg_type, mncc);
+
+       new_state(PORT_STATE_RELEASE);
+       p_m_delete = 1;
+       return;
+}
+
+
+/*
+ * endpoint sends messages to the port
+ */
+int Pgsm::message_epoint(unsigned int epoint_id, int message_id, union parameter *param)
+{
+       if (PmISDN::message_epoint(epoint_id, message_id, param))
+               return(1);
+
+       switch(message_id) {
+               case MESSAGE_SETUP: /* dial-out command received from epoint */
+               if (p_state!=PORT_STATE_IDLE)
+                       break;
+               message_setup(epoint_id, message_id, param);
+               break;
+
+               case MESSAGE_NOTIFY: /* display and notifications */
+               message_notify(epoint_id, message_id, param);
+               break;
+
+//             case MESSAGE_FACILITY: /* facility message */
+//             message_facility(epoint_id, message_id, param);
+//             break;
+
+               case MESSAGE_PROCEEDING: /* message not handles */
+               break;
+
+               case MESSAGE_ALERTING: /* call of endpoint is ringing */
+               if (p_state!=PORT_STATE_IN_PROCEEDING)
+                       break;
+               message_alerting(epoint_id, message_id, param);
+               if (p_m_g_notify_pending) {
+                       /* send pending notify message during connect */
+                       message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
+                       message_free(p_m_g_notify_pending);
+                       p_m_g_notify_pending = NULL;
+               }
+               break;
+
+               case MESSAGE_CONNECT: /* call of endpoint is connected */
+               if (p_state!=PORT_STATE_IN_PROCEEDING
+                && p_state!=PORT_STATE_IN_ALERTING)
+                       break;
+               message_connect(epoint_id, message_id, param);
+               if (p_m_g_notify_pending) {
+                       /* send pending notify message during connect */
+                       message_notify(ACTIVE_EPOINT(p_epointlist), p_m_g_notify_pending->type, &p_m_g_notify_pending->param);
+                       message_free(p_m_g_notify_pending);
+                       p_m_g_notify_pending = NULL;
+               }
+               break;
+
+               case MESSAGE_DISCONNECT: /* call has been disconnected */
+               if (p_state!=PORT_STATE_IN_PROCEEDING
+                && p_state!=PORT_STATE_IN_ALERTING
+                && p_state!=PORT_STATE_OUT_SETUP
+                && p_state!=PORT_STATE_OUT_OVERLAP
+                && p_state!=PORT_STATE_OUT_PROCEEDING
+                && p_state!=PORT_STATE_OUT_ALERTING
+                && p_state!=PORT_STATE_CONNECT
+                && p_state!=PORT_STATE_CONNECT_WAITING)
+                       break;
+               message_disconnect(epoint_id, message_id, param);
+               break;
+
+               case MESSAGE_RELEASE: /* release isdn port */
+               if (p_state==PORT_STATE_RELEASE)
+                       break;
+               message_release(epoint_id, message_id, param);
+               break;
+
+               default:
+               PDEBUG(DEBUG_GSM, "Pgsm(%s) gsm port with (caller id %s) received unhandled nessage: %d\n", p_name, p_callerinfo.id, message_id);
+       }
+
+       return(1);
+}
+
+
+/*
+ * handler
+ */
+int Pgsm::handler(void)
+{
+       int ret;
+       int work = 0;
+       unsigned char buffer[2048+MISDN_HEADER_LEN];
+       struct mISDNhead *hh = (struct mISDNhead *)buffer;
+
+       if ((ret = PmISDN::handler()))
+               return(ret);
+
+       /* handle destruction */
+       if (p_m_delete) {
+               delete this;
+               return(-1);
+       }
+
+       /* handle message from bchannel */
+       if (p_m_g_gsm_b_sock > -1) {
+               ret = recv(p_m_g_gsm_b_sock, buffer, sizeof(buffer), 0);
+               if (ret >= (int)MISDN_HEADER_LEN) {
+                       switch(hh->prim) {
+                               /* we don't care about confirms, we use rx data to sync tx */
+                               case PH_DATA_CNF:
+                               break;
+                               /* we receive audio data, we respond to it AND we send tones */
+                               case PH_DATA_IND:
+                               bchannel_receive(hh, buffer+MISDN_HEADER_LEN, ret-MISDN_HEADER_LEN);
+                               break;
+                               case PH_ACTIVATE_IND:
+                               p_m_g_gsm_b_active = 1;
+                               break;
+                               case PH_DEACTIVATE_IND:
+                               p_m_g_gsm_b_active = 0;
+                               break;
+                       }
+                       work = 1;
+               } else {
+                       if (ret < 0 && errno != EWOULDBLOCK)
+                               PERROR("Read from GSM port, index %d failed with return code %d\n", ret);
+               }
+       }
+
+       return(work);
+}
+
+
+/*
+ * handles bsc select function within LCR's main loop
+ */
+int handle_gsm(void)
+{
+       int ret1, ret2;
+
+       ret1 = bsc_upqueue(gsm->network);
+       ret2 = bsc_select_main(1); /* polling */
+       if (ret1 || ret2)
+               return 1;
+       return 0;
+}
+
+static void gsm_sock_close(void)
+{
+       if (gsm->gsm_sock > -1)
+               close(gsm->gsm_sock);
+       gsm->gsm_sock = -1;
+}
+
+static int gsm_sock_open(char *portname)
+{
+       int ret;
+       int cnt;
+       unsigned long on = 1;
+       struct sockaddr_mISDN addr;
+       struct mISDN_devinfo devinfo;
+       int pri, bri;
+
+       /* check port counts */
+       ret = ioctl(mISDNsocket, IMGETCOUNT, &cnt);
+       if (ret < 0) {
+               fprintf(stderr, "Cannot get number of mISDN devices. (ioctl IMGETCOUNT failed ret=%d)\n", ret);
+               return(ret);
+       }
+
+       if (cnt <= 0) {
+               PERROR_RUNTIME("Found no card. Please be sure to load card drivers.\n");
+               return -EIO;
+       }
+       gsm->gsm_port = mISDN_getportbyname(mISDNsocket, cnt, portname);
+       if (gsm->gsm_port < 0) {
+               PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname);
+               return gsm->gsm_port;
+       }
+       /* get protocol */
+       bri = pri = 0;
+       devinfo.id = gsm->gsm_port;
+       ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
+       if (ret < 0) {
+               PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", gsm->gsm_port, ret);
+               return ret;
+       }
+       if (devinfo.Dprotocols & (1 << ISDN_P_TE_S0)) {
+               bri = 1;
+       }
+       if (devinfo.Dprotocols & (1 << ISDN_P_TE_E1)) {
+               pri = 1;
+       }
+       if (!pri && !pri) {
+               PERROR_RUNTIME("GSM port %d does not support TE PRI or TE BRI.\n", gsm->gsm_port);
+       }
+       /* open socket */
+       if ((gsm->gsm_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_TE_S0)) < 0) {
+               PERROR_RUNTIME("GSM port %d failed to open socket.\n", gsm->gsm_port);
+               gsm_sock_close();
+               return gsm->gsm_sock;
+       }
+       /* set nonblocking io */
+       if ((ret = ioctl(gsm->gsm_sock, FIONBIO, &on)) < 0) {
+               PERROR_RUNTIME("GSM port %d failed to set socket into nonblocking io.\n", gsm->gsm_port);
+               gsm_sock_close();
+               return ret;
+       }
+       /* bind socket to dchannel */
+       memset(&addr, 0, sizeof(addr));
+       addr.family = AF_ISDN;
+       addr.dev = gsm->gsm_port;
+       addr.channel = 0;
+       if ((ret = bind(gsm->gsm_sock, (struct sockaddr *)&addr, sizeof(addr))) < 0) {
+               PERROR_RUNTIME("GSM port %d failed to bind socket. (name = %s errno=%d)\n", gsm->gsm_port, portname, errno);
+               gsm_sock_close();
+               return (ret);
+       }
+
+       return 0;
+}
+
+
+int gsm_exit(int rc)
+{
+       /* free gsm instance */
+       if (gsm) {
+               if (gsm->gsm_sock > -1)
+                       gsm_sock_close();
+               /* shutdown network */
+               if (gsm->network)
+                       shutdown_net(gsm->network);
+               /* free network */
+               if (gsm->network) {
+                       free(gsm->network); /* TBD */
+               }
+               free(gsm);
+               gsm = NULL;
+       }
+
+       return(rc);
+}
+
+int gsm_init(void)
+{
+       char hlr[128];
+
+       /* create gsm instance */
+       gsm = (struct lcr_gsm *)MALLOC(sizeof(struct lcr_gsm));
+       gsm->gsm_sock = -1;
+
+       /* parse options */
+       if (!gsm_conf(&gsm->conf)) {
+               PERROR("%s", gsm_conf_error);
+               return gsm_exit(-EINVAL);
+       }
+
+       /* init database */
+       if (gsm->conf.hlr[0] == '/')
+               SCPY(hlr, gsm->conf.hlr);
+       else
+               SPRINT(hlr, "%s/%s", CONFIG_DATA, gsm->conf.hlr);
+
+       // TODO multiple base stations
+       if (gsm->conf.numbts < 1 || gsm->conf.numbts > 1) {
+               PERROR("Expecting exactly one BTS. You defined %d.\n", gsm->conf.numbts);
+               return gsm_exit(-1);
+       }
+       /* bootstrap network */
+       gsm->network = bootstrap_network(&message_bcs, gsm->conf.bts[0].type, gsm->conf.mcc, gsm->conf.mnc, gsm->conf.lac, gsm->conf.bts[0].frequency[0], gsm->conf.bts[0].card, !gsm->conf.keep_l2, gsm->conf.short_name, gsm->conf.long_name, hlr, gsm->conf.allow_all);
+       if (!gsm->network) {
+               PERROR("Failed to bootstrap GSM network.\n");
+               return gsm_exit(-1);
+       }
+       /* open gsm loop interface */
+       if (gsm_sock_open(gsm->conf.interface_bsc)) {
+               return gsm_exit(-1);
+       }
+
+       return 0;
+}
+
diff --git a/gsm.h b/gsm.h
new file mode 100644 (file)
index 0000000..61676de
--- /dev/null
+++ b/gsm.h
@@ -0,0 +1,89 @@
+
+struct bts_conf {
+       int type;                       /* type of BTS */
+       int card;                       /* E1 card number of BS11 BTS */
+       int numtrx;                     /* up to 8 TRXs */
+       int frequency[8];               /* up to 8 frequencies for TRXs */
+};
+
+struct gsm_conf {
+       char debug[128];                /* debug info */
+       char interface_bsc[64];         /* loopback interface BSC side */
+       char interface_lcr[64];         /* loopback interface LCR side */
+       char short_name[64];            /* short network name */
+       char long_name[64];             /* long network name */
+       int mcc;                        /* mobile country code */
+       int mnc;                        /* mobile network code */
+       int lac;                        /* location area code */
+       char hlr[64];                   /* database name */
+       int allow_all;                  /* accept unknown subscribers */
+       int keep_l2;                    /* keep layer 2 after exit */
+       int numbts;                     /* number of BTS' */
+       struct bts_conf bts[8];         /* configure BTS' */
+       int noemergshut;                /* don't shut down on emergency */
+};
+
+struct lcr_gsm {
+       void            *network;       /* OpenBSC network handle */
+       struct gsm_conf conf;           /* gsm.conf options */
+       int             gsm_sock;       /* loopback interface BSC side */
+       int             gsm_port;       /* loopback interface port number */
+};
+
+extern struct lcr_gsm *gsm;
+
+/* GSM port class */
+class Pgsm : public PmISDN
+{
+       public:
+       Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode);
+       ~Pgsm();
+
+       unsigned int p_m_g_callref; /* ref by OpenBSC */
+       unsigned int p_m_g_mode; /* data/transparent mode */
+       int p_m_g_gsm_b_sock; /* gsm bchannel socket */
+       int p_m_g_gsm_b_index; /* gsm bchannel socket index to use */
+       int p_m_g_gsm_b_active; /* gsm bchannel socket is activated */
+       struct lcr_msg *p_m_g_notify_pending;   /* queue for NOTIFY if not connected */
+       void *p_m_g_encoder, *p_m_g_decoder;    /* gsm handle */
+       signed short p_m_g_rxdata[160]; /* receive audio buffer */
+       int p_m_g_rxpos; /* position in audio buffer 0..159 */
+       int p_m_g_tch_connected; /* indicates if audio is connected */
+
+       void bchannel_close(void);
+       int bchannel_open(int index);
+       void bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len);
+       void bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len);
+
+       void trau_send(void *_tf);
+       void trau_receive(void *_frame);
+
+       int hunt_bchannel(void);
+       void setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *gsm);
+       void alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
+       void message_setup(unsigned int epoint_id, int message_id, union parameter *param);
+       void message_notify(unsigned int epoint_id, int message_id, union parameter *param);
+       void message_alerting(unsigned int epoint_id, int message_id, union parameter *param);
+       void message_connect(unsigned int epoint_id, int message_id, union parameter *param);
+       void message_disconnect(unsigned int epoint_id, int message_id, union parameter *param);
+       void message_release(unsigned int epoint_id, int message_id, union parameter *param);
+       int message_epoint(unsigned int epoint_id, int message_id, union parameter *param);
+       int handler(void);
+};
+
+extern char *gsm_conf_error;
+int gsm_conf(struct gsm_conf *gsm_conf);
+int handle_gsm(void);
+int gsm_exit(int rc);
+int gsm_init(void);
+
diff --git a/gsm_audio.c b/gsm_audio.c
new file mode 100644 (file)
index 0000000..751f354
--- /dev/null
@@ -0,0 +1,54 @@
+/*****************************************************************************\
+**                                                                           **
+** LCR                                                                       **
+**                                                                           **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg                                              **
+**                                                                           **
+** gsm audio                                                                 **
+**                                                                           **
+\*****************************************************************************/ 
+
+extern "C" {
+#include "/usr/local/include/gsm.h"
+
+
+/* create gsm instance */
+void *gsm_audio_create(void)
+{
+       int value = 1;
+       gsm handle;
+
+       handle = gsm_create();
+       if (handle)
+               gsm_option(handle, GSM_OPT_WAV49, &value);
+
+       return handle;
+}
+
+/* free gsm instance */
+void gsm_audio_destroy(void *arg)
+{
+       gsm_destroy((gsm)arg);
+}
+
+/* decode frame into samples, return error */
+int gsm_audio_decode(void *arg, unsigned char *frame, signed short *samples)
+{
+       int value = 0;
+
+       gsm_option((gsm)arg, GSM_OPT_FRAME_INDEX, &value);
+       return gsm_decode((gsm)arg, (gsm_byte *)frame, (gsm_signal *)samples);
+}
+
+/* encode samples into frame */
+void gsm_audio_encode(void *arg, signed short *samples, unsigned char *frame)
+{
+       int value = 0;
+       
+       gsm_option((gsm)arg, GSM_OPT_FRAME_INDEX, &value);
+       gsm_encode((gsm)arg, (gsm_signal *)samples, (gsm_byte *)frame);
+}
+
+}
+
diff --git a/gsm_audio.h b/gsm_audio.h
new file mode 100644 (file)
index 0000000..04a6d77
--- /dev/null
@@ -0,0 +1,6 @@
+
+void *gsm_audio_create(void);
+void gsm_audio_destroy(void *arg);
+int gsm_audio_decode(void *arg, unsigned char *frame, signed short *samples);
+void gsm_audio_encode(void *arg, signed short *samples, unsigned char *frame);
+
diff --git a/gsm_conf.c b/gsm_conf.c
new file mode 100644 (file)
index 0000000..8898cf2
--- /dev/null
@@ -0,0 +1,280 @@
+/*****************************************************************************\
+**                                                                           **
+** PBX4Linux                                                                 **
+**                                                                           **
+**---------------------------------------------------------------------------**
+** Copyright: Andreas Eversberg                                              **
+**                                                                           **
+** reading options.conf and filling structure                                **
+**                                                                           **
+\*****************************************************************************/ 
+
+#include "main.h"
+#include "openbsc/openbsc.h"
+
+
+char *gsm_conf_error = "";
+
+/* read options
+ *
+ * read options from options.conf
+ */
+int gsm_conf(struct gsm_conf *gsm_conf)
+{
+       FILE *fp=NULL;
+       char filename[128];
+       char *p;
+       char option[32];
+       char params[11][256];
+       int pnum;
+       unsigned int line,i;
+       char buffer[256];
+
+       /* set defaults */
+       SCPY(gsm_conf->debug, "");
+       SCPY(gsm_conf->interface_bsc, "mISDN_l1loop.1");
+       SCPY(gsm_conf->interface_lcr, "mISDN_l1loop.2");
+       SCPY(gsm_conf->short_name, "LCR");
+       SCPY(gsm_conf->long_name, "Linux-Call-Router");
+       gsm_conf->mcc = 1;
+       gsm_conf->mnc = 1;
+       gsm_conf->lac = 1;
+       SCPY(gsm_conf->hlr, "hlr.sqlite3");
+       gsm_conf->allow_all = 0;
+       gsm_conf->keep_l2 = 0;
+       gsm_conf->numbts = 0;
+       //gsm_conf->bts[xx]
+       gsm_conf->noemergshut = 0;
+
+       SPRINT(filename, "%s/gsm.conf", CONFIG_DATA);
+
+       if (!(fp=fopen(filename,"r")))
+       {
+               SPRINT(gsm_conf_error, "Cannot open %s\n",filename);
+               return(0);
+       }
+
+       line=0;
+       while((fgets(buffer,sizeof(buffer),fp)))
+       {
+               line++;
+               buffer[sizeof(buffer)-1]=0;
+               if (buffer[0]) buffer[strlen(buffer)-1]=0;
+               p=buffer;
+
+               while(*p <= 32) /* skip spaces */
+               {
+                       if (*p == 0)
+                               break;
+                       p++;
+               }
+               if (*p==0 || *p=='#') /* ignore comments and empty line */
+                       continue;
+
+               option[0]=0;
+               i=0; /* read option */
+               while(*p > 32)
+               {
+                       if (i+1 >= sizeof(option))
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): option too long.\n",filename,line);
+                               goto error;
+                       }
+                       option[i+1] = '\0';
+                       option[i++] = *p++;
+               }
+
+               while(*p <= 32) /* skip spaces */
+               {
+                       if (*p == 0)
+                               break;
+                       p++;
+               }
+
+               params[0][0] = 0;
+               pnum = 0;
+               while(*p!=0 && *p!='#' && pnum < 10) /* param */
+               {
+                       i=0; /* read param */
+                       while(*p > 32)
+                       {
+                               if (i+1 >= sizeof(params[pnum]))
+                               {
+                                       SPRINT(gsm_conf_error, "Error in %s (line %d): param too long.\n",filename,line);
+                                       goto error;
+                               }
+                               params[pnum][i+1] = '\0';
+                               params[pnum][i++] = *p++;
+                       }
+                       while(*p <= 32) /* skip spaces */
+                       {
+                               if (*p == 0)
+                                       break;
+                               p++;
+                       }
+                       pnum++;
+                       params[pnum][0] = 0;
+               }
+
+               /* at this point we have option and param */
+
+               /* check option */
+               if (!strcmp(option,"debug"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option);
+                               goto error;
+                       }
+                       SCPY(gsm_conf->debug, params[0]);
+
+               } else
+               if (!strcmp(option,"interface-bsc"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       SCPY(gsm_conf->interface_bsc, params[0]);
+
+               } else
+               if (!strcmp(option,"interface-lcr"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       SCPY(gsm_conf->interface_lcr, params[0]);
+
+               } else
+               if (!strcmp(option,"short-name"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       SCPY(gsm_conf->short_name, params[0]);
+
+               } else
+               if (!strcmp(option,"long-name"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       SCPY(gsm_conf->long_name, params[0]);
+
+               } else
+               if (!strcmp(option,"mcc"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       gsm_conf->mcc = atoi(params[0]);
+
+               } else
+               if (!strcmp(option,"mnc"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       gsm_conf->mnc = atoi(params[0]);
+
+               } else
+               if (!strcmp(option,"lac"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       gsm_conf->lac = atoi(params[0]);
+
+               } else
+               if (!strcmp(option,"hlr"))
+               {
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
+                               goto error;
+                       }
+                       SCPY(gsm_conf->hlr, params[0]);
+
+               } else
+               if (!strcmp(option,"allow-all"))
+               {
+                       gsm_conf->allow_all = 1;
+               } else
+               if (!strcmp(option,"keep-l2"))
+               {
+                       gsm_conf->keep_l2 = 1;
+
+               } else
+               if (!strcmp(option,"no-mergency-shutdown"))
+               {
+                       gsm_conf->noemergshut = 1;
+               } else
+               if (!strcmp(option,"bts"))
+               {
+                       if (gsm_conf->numbts == 8)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): too many BTS defined.\n",filename,line);
+                               goto error;
+                       }
+                       if (params[0][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter <bts-type> for option %s missing.\n",filename,line,option);
+                               goto error;
+                       }
+                       if (params[1][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter <card number> for option %s missing.\n",filename,line,option);
+                               goto error;
+                       }
+                       if (params[2][0]==0)
+                       {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): parameter <frequency> for option %s missing.\n",filename,line,option);
+                               goto error;
+                       }
+                       if (!strcmp(params[0], "bs11"))
+                       {
+                               gsm_conf->bts[gsm_conf->numbts].type = GSM_BTS_TYPE_BS11;
+                       } else {
+                               SPRINT(gsm_conf_error, "Error in %s (line %d): unknown BTS type '%s'.\n",filename,line,params[0]);
+                               goto error;
+                       }
+                       gsm_conf->bts[gsm_conf->numbts].card = atoi(params[1]);
+                       gsm_conf->bts[gsm_conf->numbts].numtrx = 0;
+                       while (params[gsm_conf->bts[gsm_conf->numbts].numtrx+2][0])
+                       {
+                               if (gsm_conf->bts[gsm_conf->numbts].numtrx == 8)
+                               {
+                                       SPRINT(gsm_conf_error, "Error in %s (line %d): too many frequencies defined.\n",filename,line);
+                                       goto error;
+                               }
+                               gsm_conf->bts[gsm_conf->numbts].frequency[gsm_conf->bts[gsm_conf->numbts].numtrx++] = atoi(params[gsm_conf->bts[gsm_conf->numbts].numtrx+2]);
+                       }
+                       gsm_conf->numbts++;
+               } else
+               {
+                       SPRINT(gsm_conf_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option);
+                       goto error;
+               }
+       }
+
+       if (fp) fclose(fp);
+       return(1);
+error:
+       if (fp) fclose(fp);
+       return(0);
+}
+
+
index 28ad88c..613614a 100644 (file)
@@ -342,6 +342,12 @@ static int inter_portname(struct interface *interface, char *filename, int line,
                                SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
                                return(-1);
                        }
+                       /* check for use as GSM */
+                       if (ifport->gsm)
+                       {
+                               SPRINT(interface_error, "Error in %s (line %d): Interface already used for GSM.\n", filename, line);
+                               return(-1);
+                       }
                        ifport = ifport->next;
                }
                searchif = searchif->next;
@@ -943,6 +949,48 @@ static int inter_dialmax(struct interface *interface, char *filename, int line,
        ifport->dialmax = atoi(value);
        return(0);
 }
+static int inter_gsm(struct interface *interface, char *filename, int line, char *parameter, char *value)
+{
+#ifndef WITH_GSM
+       SPRINT(interface_error, "Error in %s (line %d): GSM not compiled in.\n", filename, line);
+       return(-1);
+#else
+       struct interface_port *ifport;
+       struct interface *searchif;
+
+       /* check gsm */
+       if (!gsm)
+       {
+               SPRINT(interface_error, "Error in %s (line %d): GSM is not activated.\n", filename, line);
+               return(-1);
+       }
+       searchif = interface_newlist;
+       while(searchif)
+       {
+               ifport = searchif->ifport;
+               while(ifport)
+               {
+                       if (ifport->gsm)
+                       {
+                               SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses gsm\n", filename, line, value);
+                               return(-1);
+                       }
+                       ifport = ifport->next;
+               }
+               searchif = searchif->next;
+       }
+
+       /* set portname */
+       if (inter_portname(interface, filename, line, "portname", gsm->conf.interface_lcr))
+               return(-1);
+       /* goto end of chain again to set gsmflag*/
+       ifport = interface->ifport;
+       while(ifport->next)
+               ifport = ifport->next;
+       ifport->gsm = 1;
+       return(0);
+#endif
+}
 
 
 /*
@@ -1061,6 +1109,11 @@ struct interface_param interface_param[] = {
        {"dialmax", &inter_dialmax, "<digits>",
        "Limits the number of digits in setup/information message."},
 
+       {"gsm", &inter_gsm, "",
+       "Sets up GSM interface for using OpenBSC.\n"
+       "This interface must be a loopback interface. The second loopback interface\n"
+       "must be assigned to OpenBSC"},
+
        {NULL, NULL, NULL, NULL}
 };
 
@@ -1412,7 +1465,7 @@ void load_port(struct interface_port *ifport)
        struct mISDNport *mISDNport;
 
        /* open new port */
-       mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface);
+       mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface, ifport->gsm);
        if (mISDNport)
        {
                /* link port */
index a467a71..e459b5b 100644 (file)
@@ -51,6 +51,7 @@ struct interface_port {
        int                     tespecial; /* special TE-mode behavior */
        int                     l1hold; /* hold layer 1 (1=on, 0=off) */
        int                     l2hold; /* hold layer 2 (1=force, -1=disable, 0=default) */
+       int                     gsm; /* interface is an GSM interface */
        int                     channel_force; /* forces channel by protocol */
        int                     nodtmf; /* disables DTMF */
        struct select_channel   *out_channel; /* list of channels to select */
index b8b9ac3..12bfa74 100644 (file)
@@ -1836,7 +1836,7 @@ int main(int argc, char *argv[])
        int mode;
        int sock, conn;
        struct sockaddr_un sock_address;
-       const char *ret;
+       const char *ret = "invalid mode";
 
 
        /* show options */
index 2cbd39f..57c942e 100644 (file)
--- a/mISDN.cpp
+++ b/mISDN.cpp
@@ -1947,106 +1947,109 @@ int mISDN_handler(void)
                }
 
                /* handle queued up-messages (d-channel) */
-               while ((mb = mdequeue(&mISDNport->upqueue)))
+               if (!mISDNport->gsm)
                {
-                       l3m = &mb->l3;
-                       switch(l3m->type)
+                       while ((mb = mdequeue(&mISDNport->upqueue)))
                        {
-                               case MPH_ACTIVATE_IND:
-                               if (mISDNport->l1link != 1)
+                               l3m = &mb->l3;
+                               switch(l3m->type)
                                {
-                                       l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
-                                       end_trace();
-                                       mISDNport->l1link = 1;
-                               }
-                               break;
-       
-                               case MPH_DEACTIVATE_IND:
-                               if (mISDNport->l1link != 0)
-                               {
-                                       l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
-                                       end_trace();
-                                       mISDNport->l1link = 0;
-                               }
-                               break;
-
-                               case MPH_INFORMATION_IND:
-                               PDEBUG(DEBUG_ISDN, "Received MPH_INFORMATION_IND for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
-                               switch (l3m->pid)
-                               {
-                                       case L1_SIGNAL_LOS_ON:
-                                       mISDNport->los = 1;
-                                       break;
-                                       case L1_SIGNAL_LOS_OFF:
-                                       mISDNport->los = 0;
-                                       break;
-                                       case L1_SIGNAL_AIS_ON:
-                                       mISDNport->ais = 1;
-                                       break;
-                                       case L1_SIGNAL_AIS_OFF:
-                                       mISDNport->ais = 0;
-                                       break;
-                                       case L1_SIGNAL_RDI_ON:
-                                       mISDNport->rdi = 1;
-                                       break;
-                                       case L1_SIGNAL_RDI_OFF:
-                                       mISDNport->rdi = 0;
-                                       break;
-                                       case L1_SIGNAL_SLIP_TX:
-                                       mISDNport->slip_tx++;
+                                       case MPH_ACTIVATE_IND:
+                                       if (mISDNport->l1link != 1)
+                                       {
+                                               l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
+                                               end_trace();
+                                               mISDNport->l1link = 1;
+                                       }
                                        break;
-                                       case L1_SIGNAL_SLIP_RX:
-                                       mISDNport->slip_rx++;
+               
+                                       case MPH_DEACTIVATE_IND:
+                                       if (mISDNport->l1link != 0)
+                                       {
+                                               l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
+                                               end_trace();
+                                               mISDNport->l1link = 0;
+                                       }
                                        break;
-                               }
-                               break;
 
-                               case MT_L2ESTABLISH:
-                               l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
-                               add_trace("tei", NULL, "%d", l3m->pid);
-                               end_trace();
-                               mISDNport->l2link = 1;
-                               if (l3m->pid < 128)
-                                       mISDNport->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
-                               if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127)
-                               {
-                                       if (mISDNport->l2establish)
+                                       case MPH_INFORMATION_IND:
+                                       PDEBUG(DEBUG_ISDN, "Received MPH_INFORMATION_IND for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
+                                       switch (l3m->pid)
                                        {
-                                               mISDNport->l2establish = 0;
-                                               PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
+                                               case L1_SIGNAL_LOS_ON:
+                                               mISDNport->los = 1;
+                                               break;
+                                               case L1_SIGNAL_LOS_OFF:
+                                               mISDNport->los = 0;
+                                               break;
+                                               case L1_SIGNAL_AIS_ON:
+                                               mISDNport->ais = 1;
+                                               break;
+                                               case L1_SIGNAL_AIS_OFF:
+                                               mISDNport->ais = 0;
+                                               break;
+                                               case L1_SIGNAL_RDI_ON:
+                                               mISDNport->rdi = 1;
+                                               break;
+                                               case L1_SIGNAL_RDI_OFF:
+                                               mISDNport->rdi = 0;
+                                               break;
+                                               case L1_SIGNAL_SLIP_TX:
+                                               mISDNport->slip_tx++;
+                                               break;
+                                               case L1_SIGNAL_SLIP_RX:
+                                               mISDNport->slip_rx++;
+                                               break;
                                        }
-                               }
-                               break;
+                                       break;
 
-                               case MT_L2RELEASE:
-                               if (l3m->pid < 128)
-                                       mISDNport->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
-                               if (!mISDNport->l2establish)
-                               {
-                                       l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
+                                       case MT_L2ESTABLISH:
+                                       l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
                                        add_trace("tei", NULL, "%d", l3m->pid);
                                        end_trace();
-                                       /* down if not nt-ptmp */ 
-                                       if (!mISDNport->ntmode || mISDNport->ptp)
-                                               mISDNport->l2link = 0;
-                               }
-                               if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127)
-                               {
-                                       if (!mISDNport->l2establish && mISDNport->l2hold)
+                                       mISDNport->l2link = 1;
+                                       if (l3m->pid < 128)
+                                               mISDNport->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
+                                       if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127)
                                        {
-                                               PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
-                                               time(&mISDNport->l2establish);
-                                               mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
+                                               if (mISDNport->l2establish)
+                                               {
+                                                       mISDNport->l2establish = 0;
+                                                       PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
+                                               }
                                        }
-                               }
-                               break;
+                                       break;
 
-                               default:
-                               /* l3-data is sent to LCR */
-                               stack2manager(mISDNport, l3m->type, l3m->pid, l3m);
+                                       case MT_L2RELEASE:
+                                       if (l3m->pid < 128)
+                                               mISDNport->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
+                                       if (!mISDNport->l2establish)
+                                       {
+                                               l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
+                                               add_trace("tei", NULL, "%d", l3m->pid);
+                                               end_trace();
+                                               /* down if not nt-ptmp */ 
+                                               if (!mISDNport->ntmode || mISDNport->ptp)
+                                                       mISDNport->l2link = 0;
+                                       }
+                                       if (!mISDNport->gsm && (!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127)
+                                       {
+                                               if (!mISDNport->l2establish && mISDNport->l2hold)
+                                               {
+                                                       PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
+                                                       time(&mISDNport->l2establish);
+                                                       mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
+                                               }
+                                       }
+                                       break;
+
+                                       default:
+                                       /* l3-data is sent to LCR */
+                                       stack2manager(mISDNport, l3m->type, l3m->pid, l3m);
+                               }
+                               /* free message */
+                               free_l3_msg(l3m);
                        }
-                       /* free message */
-                       free_l3_msg(l3m);
                }
 
 #if 0
@@ -2062,7 +2065,7 @@ int mISDN_handler(void)
                        if (now-mISDNport->l2establish > 5)
                        {
                                mISDNport->l2establish = 0;
-                               if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode))
+                               if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode))
                                {
 
                                        PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
@@ -2109,7 +2112,6 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
                mt_assign_pid = pid;
                return(0);
        }
-       
        /* queue message, create, if required */
        if (!l3m)
        {
@@ -2124,11 +2126,32 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
        return 0;
 }
 
+int mISDN_getportbyname(int sock, int cnt, char *portname)
+{
+       struct mISDN_devinfo devinfo;
+       int port = 0, ret;
+
+       /* resolve name */
+       while (port < cnt)
+       {
+               devinfo.id = port;
+               ret = ioctl(sock, IMGETDEVINFO, &devinfo);
+               if (ret < 0)
+                       return ret;
+               if (!strcasecmp(devinfo.name, portname))
+                       break;
+               port++;
+       }
+       if (port == cnt)
+               return -EIO;
+
+       return (port);
+}
 
 /*
  * global function to add a new card (port)
  */
-struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface)
+struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm)
 {
        int ret;
        struct mISDNport *mISDNport, **mISDNportp;
@@ -2154,24 +2177,13 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
        }
        if (port < 0)
        {
-               /* resolve name */
-               port = 0;
-               while (port < cnt)
+               port = mISDN_getportbyname(mISDNsocket, cnt, portname);
+               if (port < 0)
                {
-                       devinfo.id = port;
-                       ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
-                       if (ret < 0)
-                       {
-                               PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", port, ret);
-                               return(NULL);
-                       }
-                       if (!strcasecmp(devinfo.name, portname))
-                               break;
-                       port++;
-               }
-               if (port == cnt)
-               {
-                       PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", portname);
+                       if (gsm)
+                               PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname);
+                       else
+                               PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", portname);
                        return(NULL);
                }
                // note: 'port' has still the port number
@@ -2274,14 +2286,48 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
                }
        }
 
+       /* check for continous channelmap with no bchannel on slot 16 */
+       if (test_channelmap(0, devinfo.channelmap))
+       {
+               PERROR_RUNTIME("Port %d provides channel 0, but we cannot access it!\n", port);
+               return(NULL);
+       }
+       i = 1;
+       while(i < (int)devinfo.nrbchan + 1)
+       {
+               if (i == 16) {
+                       if (test_channelmap(i, devinfo.channelmap))
+                       {
+                               PERROR("Port %d provides bchannel 16. Pleas upgrade mISDN, if this port is mISDN loopback interface.\n", port);
+                               return(NULL);
+                       }
+               } else
+               {
+                       if (!test_channelmap(i, devinfo.channelmap))
+                       {
+                               PERROR_RUNTIME("Port %d has no channel on slot %d!\n", port, i);
+                               return(NULL);
+                       }
+               }
+               i++;
+       }
 
        /* add mISDNport structure */
        mISDNportp = &mISDNport_first;
        while(*mISDNportp)
                mISDNportp = &((*mISDNportp)->next);
        mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
-       mISDNport->l1link = -1;
-       mISDNport->l2link = -1;
+       if (gsm)
+       {
+               /* gsm audio is always active */
+               mISDNport->l1link = 1;
+               mISDNport->l2link = 1;
+       } else
+       {
+               mISDNport->l1link = -1;
+               mISDNport->l2link = -1;
+       }
+       mISDNport->gsm = gsm;
        pmemuse++;
        *mISDNportp = mISDNport;
 
@@ -2307,7 +2353,6 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
        }
                
        /* allocate ressources of port */
-       /* open layer 3 and init upqueue */
        protocol = (nt)?L3_PROTOCOL_DSS1_NET:L3_PROTOCOL_DSS1_USER;
        prop = (1 << MISDN_FLG_L2_CLEAN);
        if (ptp) // ptp forced
@@ -2318,41 +2363,65 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
               prop |= (1 << MISDN_FLG_L1_HOLD);
        if (l2hold) // supports layer 2 hold
               prop |= (1 << MISDN_FLG_L2_HOLD);
-       /* queue must be initializes, because l3-thread may send messages during open_layer3() */
-       mqueue_init(&mISDNport->upqueue);
-       mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
-       if (!mISDNport->ml3)
+       /* open layer 3 and init upqueue */
+       if (gsm)
        {
-               mqueue_purge(&mISDNport->upqueue);
-               PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
-               start_trace(port,
-                       interface,
-                       NULL,
-                       NULL,
-                       DIRECTION_NONE,
-                       CATEGORY_CH,
-                       0,
-                       "PORT (open failed)");
-               end_trace();
-               mISDNport_close(mISDNport);
-               return(NULL);
-       }
+               unsigned long on = 1;
+               struct sockaddr_mISDN addr;
 
-#if 0
-       /* if ntmode, establish L1 to send the tei removal during start */
-       if (mISDNport->ntmode)
-       {
-               iframe_t act;
-               /* L1 */
-               act.prim = PH_ACTIVATE | REQUEST; 
-               act.addr = mISDNport->upper_id | FLG_MSG_DOWN;
-               printf("UPPER ID 0x%x, addr 0x%x\n",mISDNport->upper_id, act.addr);
-               act.dinfo = 0;
-               act.len = 0;
-               mISDN_write(mISDNdevice, &act, mISDN_HEADER_LEN+act.len, TIMEOUT_1SEC);
-               usleep(10000); /* to be sure, that l1 is up */
+               if (devinfo.nrbchan < 8)
+               {
+                       PERROR_RUNTIME("GSM port %d must have at least 8 b-channels.\n", port);
+                       mISDNport_close(mISDNport);
+                       return(NULL);
+               }
+
+               if ((mISDNport->lcr_sock = socket(PF_ISDN, SOCK_DGRAM, ISDN_P_NT_S0)) < 0)
+               {
+                       PERROR_RUNTIME("GSM port %d failed to open socket.\n", port);
+                       mISDNport_close(mISDNport);
+                       return(NULL);
+               }
+               /* set nonblocking io */
+               if (ioctl(mISDNport->lcr_sock, FIONBIO, &on) < 0)
+               {
+                       PERROR_RUNTIME("GSM port %d failed to set socket into nonblocking io.\n", port);
+                       mISDNport_close(mISDNport);
+                       return(NULL);
+               }
+               /* bind socket to dchannel */
+               memset(&addr, 0, sizeof(addr));
+               addr.family = AF_ISDN;
+               addr.dev = port;
+               addr.channel = 0;
+               if (bind(mISDNport->lcr_sock, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+               {
+                       PERROR_RUNTIME("GSM port %d failed to bind socket. (errno %d)\n", port, errno);
+                       mISDNport_close(mISDNport);
+                       return(NULL);
+               }
+       } else
+       {
+               /* queue must be initializes, because l3-thread may send messages during open_layer3() */
+               mqueue_init(&mISDNport->upqueue);
+               mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
+               if (!mISDNport->ml3)
+               {
+                       mqueue_purge(&mISDNport->upqueue);
+                       PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
+                       start_trace(port,
+                               interface,
+                               NULL,
+                               NULL,
+                               DIRECTION_NONE,
+                               CATEGORY_CH,
+                               0,
+                               "PORT (open failed)");
+                       end_trace();
+                       mISDNport_close(mISDNport);
+                       return(NULL);
+               }
        }
-#endif
 
        SCPY(mISDNport->name, devinfo.name);
        mISDNport->b_num = devinfo.nrbchan;
@@ -2373,7 +2442,7 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
        }
 
        /* if ptp, pull up the link */
-       if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode))
+       if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode))
        {
                mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
                l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
@@ -2465,13 +2534,22 @@ void mISDNport_close(struct mISDNport *mISDNport)
                i++;
        }
 
-       /* close layer 3, if open and purge upqueue */
-       if (mISDNport->ml3)
+       /* close layer 3, if open */
+       if (!mISDNport->gsm && mISDNport->ml3)
        {
                close_layer3(mISDNport->ml3);
-               mqueue_purge(&mISDNport->upqueue);
        }
 
+       /* close gsm socket, if open */
+       if (mISDNport->gsm && mISDNport->lcr_sock > -1)
+       {
+               close(mISDNport->lcr_sock);
+       }
+
+       /* purge upqueue */
+       if (!mISDNport->gsm)
+               mqueue_purge(&mISDNport->upqueue);
+
        /* remove from list */
        mISDNportp = &mISDNport_first;
        while(*mISDNportp)
diff --git a/mISDN.h b/mISDN.h
index 90f686b..4f1e596 100644 (file)
--- a/mISDN.h
+++ b/mISDN.h
@@ -15,6 +15,8 @@
 extern int entity;
 extern int mISDNdevice;
 
+extern int mISDNsocket;
+
 enum {
        B_EVENT_USE,            /* activate/export bchannel */
        B_EVENT_EXPORTREQUEST,  /* remote app requests bchannel */
@@ -61,6 +63,10 @@ struct mISDNport {
        unsigned int b_remote_ref[128]; /* the ref currently exported */
        int locally; /* local causes are sent as local causes not remote */
        int los, ais, rdi, slip_rx, slip_tx;
+
+       /* gsm */
+       int gsm; /* this is the (only) GSM interface */
+       int lcr_sock; /* socket of loopback on LCR side */
 };
 extern mISDNport *mISDNport_first;
 
@@ -82,7 +88,8 @@ calls with no bchannel (call waiting, call on hold).
 /* mISDN none-object functions */
 int mISDN_initialize(void);
 void mISDN_deinitialize(void);
-struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface);
+int mISDN_getportbyname(int sock, int cnt, char *portname);
+struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm);
 void mISDNport_close_all(void);
 void mISDNport_close(struct mISDNport *mISDNport);
 void mISDN_port_reorder(void);
diff --git a/main.c b/main.c
index 51da4a1..522b214 100644 (file)
--- a/main.c
+++ b/main.c
@@ -394,6 +394,21 @@ int main(int argc, char *argv[])
                goto free;
        }
 
+#ifdef WITH_GSM
+       /* handle gsm */
+       if (options.gsm && gsm_init())
+       {
+               fprintf(stderr, "GSM initialization failed.\n");
+               goto free;
+       }
+#else
+       if (options.gsm)
+       {
+               fprintf(stderr, "GSM is enabled, but not compiled. Use --with-gsm while configure!\n");
+               goto free;
+       }
+#endif
+
        /* read interfaces and open ports */
        if (!read_interfaces())
        {
@@ -614,6 +629,15 @@ BUDETECT
                        all_idle = 0;
 BUDETECT
 
+#ifdef WITH_GSM
+               /* handle gsm */
+               if (options.gsm)
+                       while(handle_gsm())
+                               all_idle = 0;
+#endif
+
+BUDETECT
+
 #if 0
                /* check for child to exit (eliminate zombies) */
                if (waitpid(-1, NULL, WNOHANG) > 0)
@@ -746,6 +770,12 @@ free:
        if (created_misdn)
                mISDN_deinitialize();
 
+#ifdef WITH_GSM
+       /* free gsm */
+       if (options.gsm)
+               gsm_exit(0);
+#endif
+
        /* display memory leak */
 #define MEMCHECK(a, b) \
        if (b) \
diff --git a/main.h b/main.h
index 427b39c..0b9f754 100644 (file)
--- a/main.h
+++ b/main.h
@@ -67,6 +67,7 @@ void debug(const char *function, int line, const char *prefix, char *buffer);
 #define DEBUG_BCHANNEL         0x0008
 #define DEBUG_PORT     0x0100
 #define DEBUG_ISDN     0x0110
+#define DEBUG_GSM      0x0120
 //#define DEBUG_KNOCK  0x0140
 #define DEBUG_VBOX     0x0180
 #define DEBUG_EPOINT   0x0200
@@ -147,6 +148,9 @@ extern "C" {
 #include "port.h"
 #include "mISDN.h"
 #include "dss1.h"
+#ifdef WITH_GSM
+#include "gsm.h"
+#endif
 #include "vbox.h"
 #include "join.h"
 #include "joinpbx.h"
@@ -158,6 +162,7 @@ extern "C" {
 #include "socket_server.h"
 #include "trace.h"
 
+extern int quit;
 extern double now_d;
 extern time_t now;
 extern struct tm *now_tm;
index 7ac4a84..9fc01b2 100644 (file)
--- a/message.h
+++ b/message.h
@@ -12,7 +12,7 @@
 #define ISDN_TRANSMIT  256 // samples
 
 enum { /* interface types */
-       INFO_ITYPE_ISDN,
+       INFO_ITYPE_ISDN, /* call from external */
        INFO_ITYPE_ISDN_EXTENSION, /* call from internal extension */
        INFO_ITYPE_CHAN,
        INFO_ITYPE_VBOX
index 160a8a8..b76059e 100644 (file)
--- a/options.c
+++ b/options.c
@@ -31,7 +31,8 @@ struct options options = {
        0,                              /* by default use priority 0 */
        "lcr@your.machine",             /* source mail adress */
        "/var/tmp",                     /* path of lock files */
-       0700                            /* rights of lcr admin socket */
+       0700,                           /* rights of lcr admin socket */
+       0                               /* enable gsm */
 };
 
 char options_error[256];
@@ -249,6 +250,10 @@ int read_options(void)
                {
                        options.socketrights = strtol(param, NULL, 0);
                } else
+               if (!strcmp(option,"gsm"))
+               {
+                       options.gsm = 1;
+               } else
                {
                        SPRINT(options_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option);
                        goto error;
index 976aaba..872ac7d 100644 (file)
--- a/options.h
+++ b/options.h
@@ -28,6 +28,8 @@ struct options {
        char    email[128];             /* source email address */
        char    lock[128];              /* path of lock files */
        int     socketrights;           /* rights of lcr admin socket */
+
+       int     gsm;                    /* enable gsm support */
 };     
 
 extern struct options options;
diff --git a/port.h b/port.h
index 3a1a930..be2598f 100644 (file)
--- a/port.h
+++ b/port.h
@@ -17,6 +17,7 @@
 #define PORT_CLASS_mISDN       0x0100
 #define PORT_CLASS_MASK                0xff00
 #define PORT_CLASS_mISDN_DSS1  0x0110
+#define PORT_CLASS_mISDN_GSM   0x0120
 #define PORT_CLASS_mISDN_MASK  0xfff0
        /* nt-mode */
 #define        PORT_TYPE_DSS1_NT_IN    0x0111
@@ -24,6 +25,9 @@
        /* te-mode */
 #define        PORT_TYPE_DSS1_TE_IN    0x0113
 #define        PORT_TYPE_DSS1_TE_OUT   0x0114
+       /* gsm */
+#define        PORT_TYPE_GSM_IN        0x0121
+#define        PORT_TYPE_GSM_OUT       0x0122
        /* answering machine */
 #define        PORT_TYPE_VBOX_OUT      0x0311
 
diff --git a/route.c b/route.c
index 017a55c..da59e98 100644 (file)
--- a/route.c
+++ b/route.c
@@ -2022,7 +2022,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
 
                                case MATCH_PORT:
                                if (ea_endpoint->ep_portlist)
-                               if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
+                               if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_MASK) != PORT_CLASS_mISDN)
                                        break;
                                integer = e_callerinfo.isdn_port;
                                goto match_integer;