This turns LCR into a GSM mobile switching center.
More infos will follow.
-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
$(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 \
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
@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 \
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)
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)
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@
-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 \
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
@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@
@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@
@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 \
-> 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.
+
{
struct dialing_info dialinginfo;
class Port *port;
-// class pdss1 *pdss1;
struct port_list *portlist;
struct lcr_msg *message;
int anycall = 0;
}
/* 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);
{
/* 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
{
}
/* 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));
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));
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)
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))
{
--- /dev/null
+/* 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
--- /dev/null
+
+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);
+
#! /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>.
#
# 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"
ac_subst_vars='LTLIBOBJS
POW_LIB
LIBOBJS
+ENABLE_GSM_FALSE
+ENABLE_GSM_TRUE
LIBCRYPTO
ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE
ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE
enable_dependency_tracking
with_asterisk
with_ssl
+with_gsm
'
ac_precious_vars='build_alias
host_alias
# 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]...
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
--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
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,
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 $@
# Define the identity of the package.
PACKAGE=lcr
- VERSION=1.4
+ VERSION=1.5
cat >>confdefs.h <<_ACEOF
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
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
# 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
_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'`\\"
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)
# fix warnings from autoconf + automake
AC_GNU_SOURCE
# AC_USE_SYSTEM_EXTENSIONS
-AM_INIT_AUTOMAKE(lcr,1.4)
+AM_INIT_AUTOMAKE(lcr,1.5)
]
)
+# 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])
--- /dev/null
+# 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
+
#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.
#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
+
/*****************************************************************************\
** **
-** PBX4Linux **
+** LCR **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
#include "main.h"
#include "myisdn.h"
// socket mISDN
-#include <sys/socket.h>
+//#include <sys/socket.h>
extern "C" {
}
#include <q931.h>
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 */
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;
/* 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 */
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();
}
/* if channel value is faulty */
- if (channel <= 0)
- {
+ if (channel <= 0) {
add_trace("conclusion", NULL, "illegal reply");
end_trace();
ret = -111; // protocol error
/* 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;
/* 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 */
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
/* 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;
/* 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;
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);
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;
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
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;
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
}
/* 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)
/* 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;
}
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;
}
break; /* found channel */
selchannel = selchannel->next;
}
- if (!channel)
- {
+ if (!channel) {
add_trace("conclusion", NULL, "no channel available");
end_trace();
return(-6); // channel unacceptable
/* 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();
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 */
}
/* caller info */
- switch (calling_present)
- {
+ switch (calling_present) {
case 1:
p_callerinfo.present = INFO_PRESENT_RESTRICTED;
break;
p_callerinfo.present = INFO_PRESENT_ALLOWED;
break;
}
- switch (calling_screen)
- {
+ switch (calling_screen) {
case 0:
p_callerinfo.screen = INFO_SCREEN_USER;
break;
p_callerinfo.screen = INFO_SCREEN_NETWORK;
break;
}
- switch (calling_type)
- {
+ switch (calling_type) {
case -1:
p_callerinfo.ntype = INFO_NTYPE_NOTPRESENT;
break;
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;
p_callerinfo.present2 = INFO_PRESENT_ALLOWED;
break;
}
- switch (calling_screen2)
- {
+ switch (calling_screen2) {
case 0:
p_callerinfo.screen2 = INFO_SCREEN_USER;
break;
p_callerinfo.screen2 = INFO_SCREEN_NETWORK;
break;
}
- switch (calling_type2)
- {
+ switch (calling_type2) {
case -1:
p_callerinfo.ntype2 = INFO_NTYPE_NOTPRESENT;
break;
/* dialing information */
SCAT(p_dialinginfo.id, (char *)keypad);
- switch (called_type)
- {
+ switch (called_type) {
case 0x1:
p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
break;
}
/* redir info */
- switch (redir_present)
- {
+ switch (redir_present) {
case 1:
p_redirinfo.present = INFO_PRESENT_RESTRICTED;
break;
p_redirinfo.present = INFO_PRESENT_ALLOWED;
break;
}
- switch (redir_screen)
- {
+ switch (redir_screen) {
case 0:
p_redirinfo.screen = INFO_SCREEN_USER;
break;
p_redirinfo.screen = INFO_SCREEN_NETWORK;
break;
}
- switch (redir_reason)
- {
+ switch (redir_reason) {
case 1:
p_redirinfo.reason = INFO_REDIR_BUSY;
break;
p_redirinfo.reason = INFO_REDIR_UNKNOWN;
break;
}
- switch (redir_type)
- {
+ switch (redir_type) {
case -1:
p_redirinfo.ntype = INFO_NTYPE_NOTPRESENT;
break;
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;
p_capainfo.bearer_capa = bearer_capability;
break;
}
- switch (bearer_mode)
- {
+ switch (bearer_mode) {
case 2:
p_capainfo.bearer_mode = INFO_BMODE_PACKET;
break;
p_capainfo.bearer_mode = INFO_BMODE_CIRCUIT;
break;
}
- switch (bearer_user)
- {
+ switch (bearer_user) {
case -1:
p_capainfo.bearer_info1 = INFO_INFO1_NONE;
break;
}
/* hlc */
- switch (hlc_hlc)
- {
+ switch (hlc_hlc) {
case -1:
p_capainfo.hlc = INFO_HLC_NONE;
break;
p_capainfo.hlc = hlc_hlc + 0x80;
break;
}
- switch (hlc_exthlc)
- {
+ switch (hlc_exthlc) {
case -1:
p_capainfo.exthlc = INFO_HLC_NONE;
break;
/* 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
end_trace();
SCAT(p_dialinginfo.id, (char *)keypad);
- switch (type)
- {
+ switch (type) {
case 0x1:
p_dialinginfo.ntype = INFO_NTYPE_INTERNATIONAL;
break;
/* 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;
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);
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;
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;
message->param.notifyinfo.present = INFO_PRESENT_ALLOWED;
break;
}
- switch (type)
- {
+ switch (type) {
case -1:
message->param.notifyinfo.ntype = INFO_NTYPE_NOTPRESENT;
break;
/* 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;
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;
message->param.notifyinfo.present = INFO_PRESENT_ALLOWED;
break;
}
- switch (type)
- {
+ switch (type) {
case -1:
message->param.notifyinfo.ntype = INFO_NTYPE_NOTPRESENT;
break;
/* 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;
}
/* connect information */
- switch (present)
- {
+ switch (present) {
case 1:
p_connectinfo.present = INFO_PRESENT_RESTRICTED;
break;
p_connectinfo.present = INFO_PRESENT_ALLOWED;
break;
}
- switch (screen)
- {
+ switch (screen) {
case 0:
p_connectinfo.screen = INFO_SCREEN_USER;
break;
p_connectinfo.screen = INFO_SCREEN_NETWORK;
break;
}
- switch (type)
- {
+ switch (type) {
case -1:
p_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
break;
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);
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();
/* 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;
/* 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;
/* 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);
}
/* 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;
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");
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;
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;
message->param.notifyinfo.present = INFO_PRESENT_ALLOWED;
break;
}
- switch (type)
- {
+ switch (type) {
case -1:
message->param.notifyinfo.ntype = INFO_NTYPE_NOTPRESENT;
break;
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 */
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);
}
dec_ie_channel_id(l3m, &exclusive, &channel);
end_trace();
- if (!p_m_hold)
- {
+ if (!p_m_hold) {
cause = 101; /* incompatible state */
reject:
/* open channel */
ret = seize_bchannel(channel, 1);
- if (ret < 0)
- {
+ if (ret < 0) {
no_channel:
cause = -ret;
goto reject;
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);
/* 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;
}
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;
/* 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();
end_trace();
/* if blocked, release call */
- if (p_m_mISDNport->ifport->block)
- {
+ if (p_m_mISDNport->ifport->block) {
ret = -27;
goto reject;
}
// 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();
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))
/* 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);
{
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;
}
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;
}
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;
}
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;
}
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);
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);
/* 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;
}
// 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);
}
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);
}
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);
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);
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);
/* attach only if not already */
epointlist = p_epointlist;
- while(epointlist)
- {
+ while(epointlist) {
if (epointlist->epoint_id == epoint_id)
break;
epointlist = epointlist->next;
/* 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
/* 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");
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;
type = -1;
break;
}
- switch (p_callerinfo.screen)
- {
+ switch (p_callerinfo.screen) {
case INFO_SCREEN_USER:
screen = 0;
break;
screen = 3;
break;
}
- switch (p_callerinfo.present)
- {
+ switch (p_callerinfo.present) {
case INFO_PRESENT_ALLOWED:
present = 0;
break;
}
/* caller information 2 */
plan2 = 1;
- switch (p_callerinfo.ntype2)
- {
+ switch (p_callerinfo.ntype2) {
case INFO_NTYPE_UNKNOWN:
type2 = 0x0;
break;
type2 = -1;
break;
}
- switch (p_callerinfo.screen2)
- {
+ switch (p_callerinfo.screen2) {
case INFO_SCREEN_USER:
screen2 = 0;
break;
screen2 = 3;
break;
}
- switch (p_callerinfo.present2)
- {
+ switch (p_callerinfo.present2) {
case INFO_PRESENT_ALLOWED:
present2 = 0;
break;
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);
}
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;
type = -1;
break;
}
- switch (p_redirinfo.screen)
- {
+ switch (p_redirinfo.screen) {
case INFO_SCREEN_USER:
screen = 0;
break;
screen = 3;
break;
}
- switch (p_redirinfo.reason)
- {
+ switch (p_redirinfo.reason) {
case INFO_REDIR_BUSY:
reason = 1;
break;
reason = 0;
break;
}
- switch (p_redirinfo.present)
- {
+ switch (p_redirinfo.present) {
case INFO_PRESENT_ALLOWED:
present = 0;
break;
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;
}
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;
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;
type = -1;
break;
}
- switch (param->notifyinfo.present)
- {
+ switch (param->notifyinfo.present) {
case INFO_PRESENT_ALLOWED:
present = 0;
break;
}
}
- 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);
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);
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;
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);
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);
/* 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);
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;
}
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;
type = -1;
break;
}
- switch (param->connectinfo.screen)
- {
+ switch (param->connectinfo.screen) {
case INFO_SCREEN_USER:
screen = 0;
break;
screen = 3;
break;
}
- switch (p_connectinfo.present)
- {
+ switch (p_connectinfo.present) {
case INFO_PRESENT_ALLOWED:
present = 0;
break;
// 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);
}
/* 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);
}
/* 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);
* 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);
* 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 */
#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 */
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
&& 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)
&& 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);
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;
}
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);
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);
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);
&& 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);
&& 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);
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
}
/* 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);
/* 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);
}
/* 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);
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)
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");
--- /dev/null
+/*****************************************************************************\
+** **
+** 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, ¶m->setup.callerinfo, sizeof(p_callerinfo));
+ memcpy(&p_dialinginfo, ¶m->setup.dialinginfo, sizeof(p_dialinginfo));
+ memcpy(&p_capainfo, ¶m->setup.capainfo, sizeof(p_capainfo));
+ memcpy(&p_redirinfo, ¶m->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, ¶m->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;
+}
+
--- /dev/null
+
+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);
+
--- /dev/null
+/*****************************************************************************\
+** **
+** 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);
+}
+
+}
+
--- /dev/null
+
+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);
+
--- /dev/null
+/*****************************************************************************\
+** **
+** 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);
+}
+
+
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;
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
+}
/*
{"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}
};
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 */
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 */
int mode;
int sock, conn;
struct sockaddr_un sock_address;
- const char *ret;
+ const char *ret = "invalid mode";
/* show options */
}
/* 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
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);
mt_assign_pid = pid;
return(0);
}
-
/* queue message, create, if required */
if (!l3m)
{
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;
}
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
}
}
+ /* 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;
}
/* 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
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;
}
/* 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);
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)
extern int entity;
extern int mISDNdevice;
+extern int mISDNsocket;
+
enum {
B_EVENT_USE, /* activate/export bchannel */
B_EVENT_EXPORTREQUEST, /* remote app requests bchannel */
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;
/* 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);
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())
{
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)
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) \
#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
#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"
#include "socket_server.h"
#include "trace.h"
+extern int quit;
extern double now_d;
extern time_t now;
extern struct tm *now_tm;
#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
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];
{
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;
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;
#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
/* 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
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;