Added GSM network support.

This turns LCR into a GSM mobile switching center.
More infos will follow.
This commit is contained in:
Andreas Eversberg 2009-05-11 11:07:58 +02:00
parent 64143650bc
commit 20a671d768
30 changed files with 3770 additions and 567 deletions

View File

@ -43,8 +43,18 @@ INSTALLATION_DEFINES = \
-DLOG_DIR="\"$(LOGdir)\"" \
-DEXTENSION_DATA="\"$(EXTENSIONdir)\""
INCLUDES = $(all_includes) -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
if ENABLE_GSM
GSM_INCLUDE = -DWITH_GSM
GSM_SOURCE = gsm_audio.c gsm.cpp gsm_conf.c bootstrap.c
GSM_LIB = /usr/local/lib/libgsm.a /usr/local/lib/libbsc.a /usr/local/lib/libvty.a -ldbi -lcrypt
#gsm_audio.po: gsm_audio.c gsm_audio.h
# $(CC) -D_GNU_SOURCE -fPIC -c gsm_audio.c -o gsm_audio.po
endif
bin_PROGRAMS = lcradmin gentones genwave
@ -74,7 +84,9 @@ install-exec-hook:
$(INSTALL) chan_lcr.so $(astmoddir)
endif
lcr_SOURCES = action.cpp mISDN.cpp tones.c \
INCLUDES = $(all_includes) $(GSM_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
lcr_SOURCES = $(GSM_SOURCE) action.cpp mISDN.cpp tones.c \
action_efi.cpp crypt.cpp mail.c trace.c \
action_vbox.cpp dss1.cpp main.c \
vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \
@ -83,7 +95,8 @@ lcr_SOURCES = action.cpp mISDN.cpp tones.c \
callerid.c joinremote.cpp route.c \
cause.c socket_server.c
lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread
lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread $(GSM_LIB)
lcradmin_SOURCES = lcradmin.c cause.c options.c
genextension_SOURCES = genext.c options.c extension.c
@ -111,6 +124,9 @@ install-data-hook:
@if test -a $(CONFIGdir)/routing.conf ; then \
echo "NOTE: routing.conf already exists, not changed." ; else \
cp -v default/routing.conf $(CONFIGdir) ; fi
@if test -a $(CONFIGdir)/gsm.conf ; then \
echo "NOTE: gsm.conf already exists, not changed." ; else \
cp -v default/gsm.conf $(CONFIGdir) ; fi
@if test -a $(CONFIGdir)/numbering_int.conf ; then \
echo "NOTE: numbering_int.conf is obsolete, please use routing." ; fi
@if test -a $(CONFIGdir)/numbering_ext.conf ; then \

View File

@ -75,18 +75,30 @@ gentones_LDADD = $(LDADD)
genwave_SOURCES = genwave.c
genwave_OBJECTS = genwave.$(OBJEXT)
genwave_LDADD = $(LDADD)
am_lcr_OBJECTS = action.$(OBJEXT) mISDN.$(OBJEXT) tones.$(OBJEXT) \
action_efi.$(OBJEXT) crypt.$(OBJEXT) mail.$(OBJEXT) \
trace.$(OBJEXT) action_vbox.$(OBJEXT) dss1.$(OBJEXT) \
main.$(OBJEXT) vbox.$(OBJEXT) alawulaw.$(OBJEXT) \
endpoint.$(OBJEXT) interface.$(OBJEXT) message.$(OBJEXT) \
apppbx.$(OBJEXT) endpointapp.$(OBJEXT) join.$(OBJEXT) \
options.$(OBJEXT) extension.$(OBJEXT) joinpbx.$(OBJEXT) \
port.$(OBJEXT) callerid.$(OBJEXT) joinremote.$(OBJEXT) \
route.$(OBJEXT) cause.$(OBJEXT) socket_server.$(OBJEXT)
am__lcr_SOURCES_DIST = gsm_audio.c gsm.cpp gsm_conf.c bootstrap.c \
action.cpp mISDN.cpp tones.c action_efi.cpp crypt.cpp mail.c \
trace.c action_vbox.cpp dss1.cpp main.c vbox.cpp alawulaw.c \
endpoint.cpp interface.c message.c apppbx.cpp endpointapp.cpp \
join.cpp options.c extension.c joinpbx.cpp port.cpp callerid.c \
joinremote.cpp route.c cause.c socket_server.c
@ENABLE_GSM_TRUE@am__objects_1 = gsm_audio.$(OBJEXT) gsm.$(OBJEXT) \
@ENABLE_GSM_TRUE@ gsm_conf.$(OBJEXT) bootstrap.$(OBJEXT)
am_lcr_OBJECTS = $(am__objects_1) action.$(OBJEXT) mISDN.$(OBJEXT) \
tones.$(OBJEXT) action_efi.$(OBJEXT) crypt.$(OBJEXT) \
mail.$(OBJEXT) trace.$(OBJEXT) action_vbox.$(OBJEXT) \
dss1.$(OBJEXT) main.$(OBJEXT) vbox.$(OBJEXT) \
alawulaw.$(OBJEXT) endpoint.$(OBJEXT) interface.$(OBJEXT) \
message.$(OBJEXT) apppbx.$(OBJEXT) endpointapp.$(OBJEXT) \
join.$(OBJEXT) options.$(OBJEXT) extension.$(OBJEXT) \
joinpbx.$(OBJEXT) port.$(OBJEXT) callerid.$(OBJEXT) \
joinremote.$(OBJEXT) route.$(OBJEXT) cause.$(OBJEXT) \
socket_server.$(OBJEXT)
lcr_OBJECTS = $(am_lcr_OBJECTS)
am__DEPENDENCIES_1 =
lcr_DEPENDENCIES = $(am__DEPENDENCIES_1)
@ENABLE_GSM_TRUE@am__DEPENDENCIES_2 = /usr/local/lib/libgsm.a \
@ENABLE_GSM_TRUE@ /usr/local/lib/libbsc.a \
@ENABLE_GSM_TRUE@ /usr/local/lib/libvty.a
lcr_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2)
am_lcradmin_OBJECTS = lcradmin.$(OBJEXT) cause.$(OBJEXT) \
options.$(OBJEXT)
lcradmin_OBJECTS = $(am_lcradmin_OBJECTS)
@ -103,7 +115,8 @@ CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \
SOURCES = $(chan_lcr_so_SOURCES) $(genextension_SOURCES) genrc.c \
gentones.c genwave.c $(lcr_SOURCES) $(lcradmin_SOURCES)
DIST_SOURCES = $(chan_lcr_so_SOURCES) $(genextension_SOURCES) genrc.c \
gentones.c genwave.c $(lcr_SOURCES) $(lcradmin_SOURCES)
gentones.c genwave.c $(am__lcr_SOURCES_DIST) \
$(lcradmin_SOURCES)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
@ -142,6 +155,8 @@ ECHO_T = @ECHO_T@
EGREP = @EGREP@
ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE = @ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE@
ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE = @ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@
ENABLE_GSM_FALSE = @ENABLE_GSM_FALSE@
ENABLE_GSM_TRUE = @ENABLE_GSM_TRUE@
EXEEXT = @EXEEXT@
GREP = @GREP@
INSTALL_DATA = @INSTALL_DATA@
@ -224,11 +239,14 @@ INSTALLATION_DEFINES = \
-DLOG_DIR="\"$(LOGdir)\"" \
-DEXTENSION_DATA="\"$(EXTENSIONdir)\""
INCLUDES = $(all_includes) -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
@ENABLE_GSM_TRUE@GSM_INCLUDE = -DWITH_GSM
@ENABLE_GSM_TRUE@GSM_SOURCE = gsm_audio.c gsm.cpp gsm_conf.c bootstrap.c
@ENABLE_GSM_TRUE@GSM_LIB = /usr/local/lib/libgsm.a /usr/local/lib/libbsc.a /usr/local/lib/libvty.a -ldbi -lcrypt
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_SOURCES =
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDFLAGS = -shared
@ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE@chan_lcr_so_LDADD = chan_lcr.po bchannel.po options.po callerid.po
lcr_SOURCES = action.cpp mISDN.cpp tones.c \
INCLUDES = $(all_includes) $(GSM_INCLUDE) -Wall -I/usr/include/mISDNuser $(INSTALLATION_DEFINES)
lcr_SOURCES = $(GSM_SOURCE) action.cpp mISDN.cpp tones.c \
action_efi.cpp crypt.cpp mail.c trace.c \
action_vbox.cpp dss1.cpp main.c \
vbox.cpp alawulaw.c endpoint.cpp interface.c message.c \
@ -237,7 +255,7 @@ lcr_SOURCES = action.cpp mISDN.cpp tones.c \
callerid.c joinremote.cpp route.c \
cause.c socket_server.c
lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread
lcr_LDADD = $(LIBCRYPTO) -lmisdn -lpthread $(GSM_LIB)
lcradmin_SOURCES = lcradmin.c cause.c options.c
genextension_SOURCES = genext.c options.c extension.c
@ -387,6 +405,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/action_vbox.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/alawulaw.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/apppbx.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bootstrap.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/callerid.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cause.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crypt.Po@am__quote@
@ -398,6 +417,9 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genrc.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gentones.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/genwave.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsm.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsm_audio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsm_conf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/join.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/joinpbx.Po@am__quote@
@ -764,6 +786,9 @@ install-data-hook:
@if test -a $(CONFIGdir)/routing.conf ; then \
echo "NOTE: routing.conf already exists, not changed." ; else \
cp -v default/routing.conf $(CONFIGdir) ; fi
@if test -a $(CONFIGdir)/gsm.conf ; then \
echo "NOTE: gsm.conf already exists, not changed." ; else \
cp -v default/gsm.conf $(CONFIGdir) ; fi
@if test -a $(CONFIGdir)/numbering_int.conf ; then \
echo "NOTE: numbering_int.conf is obsolete, please use routing." ; fi
@if test -a $(CONFIGdir)/numbering_ext.conf ; then \

5
README
View File

@ -487,3 +487,8 @@ Changes after Version 1.4 release
-> Improved forking
-> Execution action can now be done on call init or on call hangup.
New release Version 1.5
- Added GSM network support.
-> Requires OpenBSC, GSM codec, and a BS11 base station.
-> For more refer to www.linux-call-router.de.

View File

@ -827,7 +827,6 @@ void EndpointAppPBX::out_setup(void)
{
struct dialing_info dialinginfo;
class Port *port;
// class pdss1 *pdss1;
struct port_list *portlist;
struct lcr_msg *message;
int anycall = 0;
@ -987,9 +986,16 @@ void EndpointAppPBX::out_setup(void)
}
/* creating INTERNAL port */
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
if (!mISDNport->gsm)
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
else
#ifdef WITH_GSM
port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
#else
port = NULL;
#endif
if (!port)
FATAL("No memory for DSS1 Port instance\n");
FATAL("No memory for Port instance\n");
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) got port %s\n", ea_endpoint->ep_serial, port->p_name);
memset(&dialinginfo, 0, sizeof(dialinginfo));
SCPY(dialinginfo.id, e_dialinginfo.id);
@ -1104,8 +1110,9 @@ void EndpointAppPBX::out_setup(void)
{
/* creating EXTERNAL port*/
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode)))
FATAL("No memory for DSS1 Port instance\n");
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
if (!port)
FATAL("No memory for Port instance\n");
earlyb = mISDNport->earlyb;
} else
{
@ -1200,8 +1207,16 @@ void EndpointAppPBX::out_setup(void)
}
/* creating EXTERNAL port*/
SPRINT(portname, "%s-%d-out", mISDNport->ifport->interface->name, mISDNport->portnum);
if (!(port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode)))
FATAL("No memory for DSS1 Port instance\n");
if (!mISDNport->gsm)
port = new Pdss1((mISDNport->ntmode)?PORT_TYPE_DSS1_NT_OUT:PORT_TYPE_DSS1_TE_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
else
#ifdef WITH_GSM
port = new Pgsm(PORT_TYPE_GSM_OUT, mISDNport, portname, &port_settings, channel, mISDNport->ifport->channel_force, mode);
#else
port = NULL;
#endif
if (!port)
FATAL("No memory for Port instance\n");
earlyb = mISDNport->earlyb;
PDEBUG(DEBUG_EPOINT, "EPOINT(%d) created port %s\n", ea_endpoint->ep_serial, port->p_name);
memset(&dialinginfo, 0, sizeof(dialinginfo));
@ -1215,7 +1230,6 @@ void EndpointAppPBX::out_setup(void)
delete port;
goto check_anycall_extern;
}
// dss1 = (class Pdss1 *)port;
//printf("EXTERNAL caller=%s,id=%s,dial=%s\n", param.setup.networkid, param.setup.callerinfo.id, param.setup.dialinginfo.id);
message = message_create(ea_endpoint->ep_serial, portlist->port_id, EPOINT_TO_PORT, MESSAGE_SETUP);
memcpy(&message->param.setup.dialinginfo, &dialinginfo, sizeof(struct dialing_info));
@ -2103,7 +2117,7 @@ void EndpointAppPBX::port_connect(struct port_list *portlist, int message_type,
if ((e_connectinfo.id[0]=='\0' || (e_connectinfo.present==INFO_PRESENT_RESTRICTED && !e_ext.anon_ignore))&& e_ext.colp==COLP_FORCE)
{
e_connectinfo.ntype = INFO_NTYPE_NOTPRESENT;
if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT) /* external extension answered */
if (portlist->port_type==PORT_TYPE_DSS1_TE_OUT || portlist->port_type==PORT_TYPE_DSS1_NT_OUT || portlist->port_type==PORT_TYPE_GSM_OUT) /* external extension answered */
{
port = find_port_id(portlist->port_id);
if (port)
@ -3626,7 +3640,7 @@ void EndpointAppPBX::pick_join(char *extensions)
break;
}
}
if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT)
if ((port->p_type==PORT_TYPE_DSS1_NT_OUT || port->p_type==PORT_TYPE_DSS1_TE_OUT || port->p_type==PORT_TYPE_GSM_OUT)
&& port->p_state==PORT_STATE_OUT_ALERTING)
if (match_list(extensions, eapp->e_ext.number))
{

948
bootstrap.c Normal file
View File

@ -0,0 +1,948 @@
/* Bootstrapping GSM - taken from bsc_hack.c */
/* (C) 2008-2009 by Harald Welte <laforge@gnumonks.org>
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
* All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <getopt.h>
#ifdef __cplusplus
extern "C" {
#endif
#include <openbsc/openbsc.h>
#include <openbsc/gsm_data.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/db.h>
#include <openbsc/timer.h>
#include <openbsc/select.h>
#include <openbsc/abis_rsl.h>
#include <openbsc/abis_nm.h>
#include <openbsc/debug.h>
#include <openbsc/misdn.h>
#include <openbsc/telnet_interface.h>
#include <openbsc/paging.h>
#include <openbsc/e1_input.h>
/* The following definitions are for OM and NM packets that we cannot yet
* generate by code but we just pass on */
// BTS Site Manager, SET ATTRIBUTES
/*
Object Class: BTS Site Manager
Instance 1: FF
Instance 2: FF
Instance 3: FF
SET ATTRIBUTES
sAbisExternalTime: 2007/09/08 14:36:11
omLAPDRelTimer: 30sec
shortLAPDIntTimer: 5sec
emergencyTimer1: 10 minutes
emergencyTimer2: 0 minutes
*/
unsigned char msg_1[] =
{
0xD0, 0x00, 0xFF, 0xFF, 0xFF,
NM_ATT_BS11_ABIS_EXT_TIME, 0x07, 0xD7, 0x09, 0x08, 0x0E, 0x24, 0x0B, 0xCE,
0x02, 0x00, 0x1E,
0xE8, 0x01, 0x05,
0x42, 0x02, 0x00, 0x0A,
0x44, 0x02, 0x00, 0x00
};
// BTS, SET BTS ATTRIBUTES
/*
Object Class: BTS
BTS relat. Number: 0
Instance 2: FF
Instance 3: FF
SET BTS ATTRIBUTES
bsIdentityCode / BSIC:
PLMN_colour_code: 7h
BS_colour_code: 7h
BTS Air Timer T3105: 4 ,unit 10 ms
btsIsHopping: FALSE
periodCCCHLoadIndication: 1sec
thresholdCCCHLoadIndication: 0%
cellAllocationNumber: 00h = GSM 900
enableInterferenceClass: 00h = Disabled
fACCHQual: 6 (FACCH stealing flags minus 1)
intaveParameter: 31 SACCH multiframes
interferenceLevelBoundaries:
Interference Boundary 1: 0Ah
Interference Boundary 2: 0Fh
Interference Boundary 3: 14h
Interference Boundary 4: 19h
Interference Boundary 5: 1Eh
mSTxPwrMax: 11
GSM range: 2=39dBm, 15=13dBm, stepsize 2 dBm
DCS1800 range: 0=30dBm, 15=0dBm, stepsize 2 dBm
PCS1900 range: 0=30dBm, 15=0dBm, stepsize 2 dBm
30=33dBm, 31=32dBm
ny1:
Maximum number of repetitions for PHYSICAL INFORMATION message (GSM 04.08): 20
powerOutputThresholds:
Out Power Fault Threshold: -10 dB
Red Out Power Threshold: - 6 dB
Excessive Out Power Threshold: 5 dB
rACHBusyThreshold: -127 dBm
rACHLoadAveragingSlots: 250 ,number of RACH burst periods
rfResourceIndicationPeriod: 125 SACCH multiframes
T200:
SDCCH: 044 in 5 ms
FACCH/Full rate: 031 in 5 ms
FACCH/Half rate: 041 in 5 ms
SACCH with TCH SAPI0: 090 in 10 ms
SACCH with SDCCH: 090 in 10 ms
SDCCH with SAPI3: 090 in 5 ms
SACCH with TCH SAPI3: 135 in 10 ms
tSync: 9000 units of 10 msec
tTrau: 9000 units of 10 msec
enableUmLoopTest: 00h = disabled
enableExcessiveDistance: 00h = Disabled
excessiveDistance: 64km
hoppingMode: 00h = baseband hopping
cellType: 00h = Standard Cell
BCCH ARFCN / bCCHFrequency: 1
*/
unsigned char msg_2[] =
{
0x41, 0x01, 0x00, 0xFF, 0xFF,
NM_ATT_BSIC, 0x3F,
NM_ATT_BTS_AIR_TIMER, 0x04,
NM_ATT_BS11_BTSLS_HOPPING, 0x00,
NM_ATT_CCCH_L_I_P, 0x01,
NM_ATT_CCCH_L_T, 0x00,
NM_ATT_BS11_CELL_ALLOC_NR, 0x00,
NM_ATT_BS11_ENA_INTERF_CLASS, 0x00,
NM_ATT_BS11_FACCH_QUAL, 0x06,
NM_ATT_INTAVE_PARAM, 0x1F,
NM_ATT_INTERF_BOUND, 0x0A, 0x0F, 0x14, 0x19, 0x1E, 0x7B,
NM_ATT_CCCH_L_T, 0x23,
NM_ATT_GSM_TIME, 0x28, 0x00,
NM_ATT_ADM_STATE, 0x03,
NM_ATT_RACH_B_THRESH, 0x7F,
NM_ATT_LDAVG_SLOTS, 0x00, 0xFA,
NM_ATT_BS11_RF_RES_IND_PER, 0x7D,
NM_ATT_T200, 0x2C, 0x1F, 0x29, 0x5A, 0x5A, 0x5A, 0x87,
NM_ATT_BS11_TSYNC, 0x23, 0x28,
NM_ATT_BS11_TTRAU, 0x23, 0x28,
NM_ATT_TEST_DUR, 0x01, 0x00,
NM_ATT_OUTST_ALARM, 0x01, 0x00,
NM_ATT_BS11_EXCESSIVE_DISTANCE, 0x01, 0x40,
NM_ATT_BS11_HOPPING_MODE, 0x01, 0x00,
NM_ATT_BS11_PLL, 0x01, 0x00,
NM_ATT_BCCH_ARFCN, 0x00, HARDCODED_ARFCN/*0x01*/,
};
// Handover Recognition, SET ATTRIBUTES
/*
Illegal Contents GSM Formatted O&M Msg
Object Class: Handover Recognition
BTS relat. Number: 0
Instance 2: FF
Instance 3: FF
SET ATTRIBUTES
enableDelayPowerBudgetHO: 00h = Disabled
enableDistanceHO: 00h = Disabled
enableInternalInterCellHandover: 00h = Disabled
enableInternalIntraCellHandover: 00h = Disabled
enablePowerBudgetHO: 00h = Disabled
enableRXLEVHO: 00h = Disabled
enableRXQUALHO: 00h = Disabled
hoAveragingDistance: 8 SACCH multiframes
hoAveragingLev:
A_LEV_HO: 8 SACCH multiframes
W_LEV_HO: 1 SACCH multiframes
hoAveragingPowerBudget: 16 SACCH multiframes
hoAveragingQual:
A_QUAL_HO: 8 SACCH multiframes
W_QUAL_HO: 2 SACCH multiframes
hoLowerThresholdLevDL: (10 - 110) dBm
hoLowerThresholdLevUL: (5 - 110) dBm
hoLowerThresholdQualDL: 06h = 6.4% < BER < 12.8%
hoLowerThresholdQualUL: 06h = 6.4% < BER < 12.8%
hoThresholdLevDLintra : (20 - 110) dBm
hoThresholdLevULintra: (20 - 110) dBm
hoThresholdMsRangeMax: 20 km
nCell: 06h
timerHORequest: 3 ,unit 2 SACCH multiframes
*/
unsigned char msg_3[] =
{
0xD0, 0xA1, 0x00, 0xFF, 0xFF,
0xD0, 0x00,
0x64, 0x00,
0x67, 0x00,
0x68, 0x00,
0x6A, 0x00,
0x6C, 0x00,
0x6D, 0x00,
0x6F, 0x08,
0x70, 0x08, 0x01,
0x71, 0x10, 0x10, 0x10,
0x72, 0x08, 0x02,
0x73, 0x0A,
0x74, 0x05,
0x75, 0x06,
0x76, 0x06,
0x78, 0x14,
0x79, 0x14,
0x7A, 0x14,
0x7D, 0x06,
0x92, 0x03, 0x20, 0x01, 0x00,
0x45, 0x01, 0x00,
0x48, 0x01, 0x00,
0x5A, 0x01, 0x00,
0x5B, 0x01, 0x05,
0x5E, 0x01, 0x1A,
0x5F, 0x01, 0x20,
0x9D, 0x01, 0x00,
0x47, 0x01, 0x00,
0x5C, 0x01, 0x64,
0x5D, 0x01, 0x1E,
0x97, 0x01, 0x20,
0xF7, 0x01, 0x3C,
};
// Power Control, SET ATTRIBUTES
/*
Object Class: Power Control
BTS relat. Number: 0
Instance 2: FF
Instance 3: FF
SET ATTRIBUTES
enableMsPowerControl: 00h = Disabled
enablePowerControlRLFW: 00h = Disabled
pcAveragingLev:
A_LEV_PC: 4 SACCH multiframes
W_LEV_PC: 1 SACCH multiframes
pcAveragingQual:
A_QUAL_PC: 4 SACCH multiframes
W_QUAL_PC: 2 SACCH multiframes
pcLowerThresholdLevDL: 0Fh
pcLowerThresholdLevUL: 0Ah
pcLowerThresholdQualDL: 05h = 3.2% < BER < 6.4%
pcLowerThresholdQualUL: 05h = 3.2% < BER < 6.4%
pcRLFThreshold: 0Ch
pcUpperThresholdLevDL: 14h
pcUpperThresholdLevUL: 0Fh
pcUpperThresholdQualDL: 04h = 1.6% < BER < 3.2%
pcUpperThresholdQualUL: 04h = 1.6% < BER < 3.2%
powerConfirm: 2 ,unit 2 SACCH multiframes
powerControlInterval: 2 ,unit 2 SACCH multiframes
powerIncrStepSize: 02h = 4 dB
powerRedStepSize: 01h = 2 dB
radioLinkTimeoutBs: 64 SACCH multiframes
enableBSPowerControl: 00h = disabled
*/
unsigned char msg_4[] =
{
0xD0, 0xA2, 0x00, 0xFF, 0xFF,
NM_ATT_BS11_ENA_MS_PWR_CTRL, 0x00,
NM_ATT_BS11_ENA_PWR_CTRL_RLFW, 0x00,
0x7E, 0x04, 0x01,
0x7F, 0x04, 0x02,
0x80, 0x0F,
0x81, 0x0A,
0x82, 0x05,
0x83, 0x05,
0x84, 0x0C,
0x85, 0x14,
0x86, 0x0F,
0x87, 0x04,
0x88, 0x04,
0x89, 0x02,
0x8A, 0x02,
0x8B, 0x02,
0x8C, 0x01,
0x8D, 0x40,
0x65, 0x01, 0x00 // set to 0x01 to enable BSPowerControl
};
// Transceiver, SET TRX ATTRIBUTES (TRX 0)
/*
Object Class: Transceiver
BTS relat. Number: 0
Tranceiver number: 0
Instance 3: FF
SET TRX ATTRIBUTES
aRFCNList (HEX): 0001
txPwrMaxReduction: 00h = 30dB
radioMeasGran: 254 SACCH multiframes
radioMeasRep: 01h = enabled
memberOfEmergencyConfig: 01h = TRUE
trxArea: 00h = TRX doesn't belong to a concentric cell
*/
unsigned char msg_6[] =
{
0x44, 0x02, 0x00, 0x00, 0xFF,
NM_ATT_ARFCN_LIST, 0x01, 0x00, HARDCODED_ARFCN /*0x01*/,
NM_ATT_RF_MAXPOWR_R, 0x00,
NM_ATT_BS11_RADIO_MEAS_GRAN, 0x01, 0xFE,
NM_ATT_BS11_RADIO_MEAS_REP, 0x01, 0x01,
NM_ATT_BS11_EMRG_CFG_MEMBER, 0x01, 0x01,
NM_ATT_BS11_TRX_AREA, 0x01, 0x00,
};
static unsigned char nanobts_attr_bts[] = {
NM_ATT_INTERF_BOUND, 0x55, 0x5b, 0x61, 0x67, 0x6d, 0x73,
NM_ATT_INTAVE_PARAM, 0x06,
NM_ATT_CONN_FAIL_CRIT, 0x00, 0x02, 0x01, 0x10,
NM_ATT_T200, 0x1e, 0x24, 0x24, 0xa8, 0x34, 0x21, 0xa8,
NM_ATT_MAX_TA, 0x3f,
NM_ATT_OVERL_PERIOD, 0x00, 0x01, 10, /* seconds */
NM_ATT_CCCH_L_T, 10, /* percent */
NM_ATT_CCCH_L_I_P, 1, /* seconds */
NM_ATT_RACH_B_THRESH, 0x0a,
NM_ATT_LDAVG_SLOTS, 0x03, 0xe8,
NM_ATT_BTS_AIR_TIMER, 0x80,
NM_ATT_NY1, 0x0a,
NM_ATT_BCCH_ARFCN, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
NM_ATT_BSIC, 0x20,
};
static unsigned char nanobts_attr_radio[] = {
NM_ATT_RF_MAXPOWR_R, 0x0c,
NM_ATT_ARFCN_LIST, 0x00, 0x02, HARDCODED_ARFCN >> 8, HARDCODED_ARFCN & 0xff,
};
static unsigned char nanobts_attr_e0[] = {
0x85, 0x00,
0x81, 0x0b, 0xbb, /* TCP PORT for RSL */
};
int nm_state_event(enum nm_evt evt, u_int8_t obj_class, void *obj,
struct gsm_nm_state *old_state, struct gsm_nm_state *new_state)
{
struct gsm_bts *bts;
struct gsm_bts_trx *trx;
struct gsm_bts_trx_ts *ts;
/* This is currently only required on nanoBTS */
switch (evt) {
case EVT_STATECHG_OPER:
switch (obj_class) {
case NM_OC_SITE_MANAGER:
bts = container_of(obj, struct gsm_bts, site_mgr);
if (old_state->operational != 2 && new_state->operational == 2) {
abis_nm_opstart(bts, NM_OC_SITE_MANAGER, 0xff, 0xff, 0xff);
}
break;
case NM_OC_BTS:
bts = (struct gsm_bts *)obj;
if (new_state->availability == 5) {
abis_nm_set_bts_attr(bts, nanobts_attr_bts,
sizeof(nanobts_attr_bts));
abis_nm_opstart(bts, NM_OC_BTS,
bts->nr, 0xff, 0xff);
abis_nm_chg_adm_state(bts, NM_OC_BTS,
bts->nr, 0xff, 0xff,
NM_STATE_UNLOCKED);
}
break;
case NM_OC_RADIO_CARRIER:
trx = (struct gsm_bts_trx *)obj;
if (new_state->availability == 3) {
abis_nm_set_radio_attr(trx, nanobts_attr_radio,
sizeof(nanobts_attr_radio));
abis_nm_opstart(trx->bts, NM_OC_RADIO_CARRIER,
trx->bts->nr, trx->nr, 0xff);
abis_nm_chg_adm_state(trx->bts, NM_OC_RADIO_CARRIER,
trx->bts->nr, trx->nr, 0xff,
NM_STATE_UNLOCKED);
}
break;
case NM_OC_CHANNEL:
ts = (struct gsm_bts_trx_ts *)obj;
trx = (struct gsm_bts_trx *)ts->trx;
if (new_state->availability == 5) {
if (ts->nr == 0 && trx == trx->bts->c0)
abis_nm_set_channel_attr(ts, NM_CHANC_BCCH_CBCH);
else
abis_nm_set_channel_attr(ts, NM_CHANC_TCHFull);
abis_nm_opstart(trx->bts, NM_OC_CHANNEL,
trx->bts->nr, trx->nr, ts->nr);
abis_nm_chg_adm_state(trx->bts, NM_OC_CHANNEL,
trx->bts->nr, trx->nr, ts->nr,
NM_STATE_UNLOCKED);
}
break;
case NM_OC_BASEB_TRANSC:
trx = container_of(obj, struct gsm_bts_trx, bb_transc);
if (new_state->availability == 5) {
abis_nm_ipaccess_msg(trx->bts, 0xe0, NM_OC_BASEB_TRANSC,
trx->bts->nr, trx->nr, 0xff,
nanobts_attr_e0, sizeof(nanobts_attr_e0));
abis_nm_opstart(trx->bts, NM_OC_BASEB_TRANSC,
trx->bts->nr, trx->nr, 0xff);
abis_nm_chg_adm_state(trx->bts, NM_OC_BASEB_TRANSC,
trx->bts->nr, trx->nr, 0xff,
NM_STATE_UNLOCKED);
}
break;
}
break;
case EVT_STATECHG_ADM:
DEBUGP(DMM, "Unhandled state change in %s:%d\n", __func__, __LINE__);
break;
}
return 0;
}
static void bootstrap_om_nanobts(struct gsm_bts *bts)
{
/* We don't do callback based bootstrapping, but event driven (see above) */
}
static void bootstrap_om_bs11(struct gsm_bts *bts)
{
struct gsm_bts_trx *trx = &bts->trx[0];
/* stop sending event reports */
abis_nm_event_reports(bts, 0);
/* begin DB transmission */
abis_nm_bs11_db_transmission(bts, 1);
/* end DB transmission */
abis_nm_bs11_db_transmission(bts, 0);
/* Reset BTS Site manager resource */
abis_nm_bs11_reset_resource(bts);
/* begin DB transmission */
abis_nm_bs11_db_transmission(bts, 1);
abis_nm_raw_msg(bts, sizeof(msg_1), msg_1); /* set BTS SiteMgr attr*/
abis_nm_raw_msg(bts, sizeof(msg_2), msg_2); /* set BTS attr */
abis_nm_raw_msg(bts, sizeof(msg_3), msg_3); /* set BTS handover attr */
abis_nm_raw_msg(bts, sizeof(msg_4), msg_4); /* set BTS power control attr */
/* Connect signalling of bts0/trx0 to e1_0/ts1/64kbps */
abis_nm_conn_terr_sign(trx, 0, 1, 0xff);
set_ts_e1link(&trx->ts[0], 0, 1, 0xff);
abis_nm_raw_msg(bts, sizeof(msg_6), msg_6); /* SET TRX ATTRIBUTES */
/* Use TEI 1 for signalling */
abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x01);
abis_nm_set_channel_attr(&trx->ts[0], NM_CHANC_SDCCH_CBCH);
#ifdef HAVE_TRX1
/* TRX 1 */
abis_nm_conn_terr_sign(&bts->trx[1], 0, 1, 0xff);
/* FIXME: TRX ATTRIBUTE */
abis_nm_establish_tei(bts, 0, 0, 1, 0xff, 0x02);
#endif
/* SET CHANNEL ATTRIBUTE TS1 */
abis_nm_set_channel_attr(&trx->ts[1], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts1 to e1_0/ts2/b */
set_ts_e1link(&trx->ts[1], 0, 2, 1);
abis_nm_conn_terr_traf(&trx->ts[1], 0, 2, 1);
/* SET CHANNEL ATTRIBUTE TS2 */
abis_nm_set_channel_attr(&trx->ts[2], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts2 to e1_0/ts2/c */
set_ts_e1link(&trx->ts[2], 0, 2, 2);
abis_nm_conn_terr_traf(&trx->ts[2], 0, 2, 2);
/* SET CHANNEL ATTRIBUTE TS3 */
abis_nm_set_channel_attr(&trx->ts[3], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts3 to e1_0/ts2/d */
set_ts_e1link(&trx->ts[3], 0, 2, 3);
abis_nm_conn_terr_traf(&trx->ts[3], 0, 2, 3);
/* SET CHANNEL ATTRIBUTE TS4 */
abis_nm_set_channel_attr(&trx->ts[4], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts4 to e1_0/ts3/a */
set_ts_e1link(&trx->ts[4], 0, 3, 0);
abis_nm_conn_terr_traf(&trx->ts[4], 0, 3, 0);
/* SET CHANNEL ATTRIBUTE TS5 */
abis_nm_set_channel_attr(&trx->ts[5], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts5 to e1_0/ts3/b */
set_ts_e1link(&trx->ts[5], 0, 3, 1);
abis_nm_conn_terr_traf(&trx->ts[5], 0, 3, 1);
/* SET CHANNEL ATTRIBUTE TS6 */
abis_nm_set_channel_attr(&trx->ts[6], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts6 to e1_0/ts3/c */
set_ts_e1link(&trx->ts[6], 0, 3, 2);
abis_nm_conn_terr_traf(&trx->ts[6], 0, 3, 2);
/* SET CHANNEL ATTRIBUTE TS7 */
abis_nm_set_channel_attr(&trx->ts[7], NM_CHANC_TCHFull);
/* Connect traffic of bts0/trx0/ts7 to e1_0/ts3/d */
set_ts_e1link(&trx->ts[7], 0, 3, 3);
abis_nm_conn_terr_traf(&trx->ts[7], 0, 3, 3);
/* end DB transmission */
abis_nm_bs11_db_transmission(bts, 0);
/* Reset BTS Site manager resource */
abis_nm_bs11_reset_resource(bts);
/* restart sending event reports */
abis_nm_event_reports(bts, 1);
}
static void bootstrap_om(struct gsm_bts *bts)
{
fprintf(stdout, "bootstrapping OML\n");
switch (bts->type) {
case GSM_BTS_TYPE_BS11:
bootstrap_om_bs11(bts);
break;
case GSM_BTS_TYPE_NANOBTS_900:
case GSM_BTS_TYPE_NANOBTS_1800:
bootstrap_om_nanobts(bts);
break;
default:
fprintf(stderr, "Unable to bootstrap OML: Unknown BTS type %d\n", bts->type);
}
}
static int shutdown_om(struct gsm_bts *bts)
{
/* stop sending event reports */
abis_nm_event_reports(bts, 0);
/* begin DB transmission */
abis_nm_bs11_db_transmission(bts, 1);
/* end DB transmission */
abis_nm_bs11_db_transmission(bts, 0);
/* Reset BTS Site manager resource */
abis_nm_bs11_reset_resource(bts);
return 0;
}
struct bcch_info {
u_int8_t type;
u_int8_t len;
const u_int8_t *data;
};
/*
SYSTEM INFORMATION TYPE 1
Cell channel description
Format-ID bit map 0
CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01
RACH Control Parameters
maximum 7 retransmissions
8 slots used to spread transmission
cell not barred for access
call reestablishment not allowed
Access Control Class = 0000
*/
static u_int8_t si1[] = {
/* header */0x55, 0x06, 0x19,
/* ccdesc */0x04 /*0x00*/, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*0x01*/,
/* rach */0xD5, 0x00, 0x00,
/* s1 reset*/0x2B
};
/*
SYSTEM INFORMATION TYPE 2
Neighbour Cells Description
EXT-IND: Carries the complete BA
BA-IND = 0
Format-ID bit map 0
CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
NCC permitted (NCC) = FF
RACH Control Parameters
maximum 7 retransmissions
8 slots used to spread transmission
cell not barred for access
call reestablishment not allowed
Access Control Class = 0000
*/
static u_int8_t si2[] = {
/* header */0x59, 0x06, 0x1A,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* ncc */0xFF,
/* rach*/0xD5, 0x00, 0x00
};
/*
SYSTEM INFORMATION TYPE 3
Cell identity = 00001 (1h)
Location area identification
Mobile Country Code (MCC): 001
Mobile Network Code (MNC): 01
Location Area Code (LAC): 00001 (1h)
Control Channel Description
Attach-detach: MSs in the cell are not allowed to apply IMSI attach /detach
0 blocks reserved for access grant
1 channel used for CCCH, with SDCCH
5 multiframes period for PAGING REQUEST
Time-out T3212 = 0
Cell Options BCCH
Power control indicator: not set
MSs shall not use uplink DTX
Radio link timeout = 36
Cell Selection Parameters
Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection
max.TX power level MS may use for CCH = 2 <- according to GSM05.05 39dBm (max)
Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters
Half rate support (NECI): New establishment causes are not supported
min.RX signal level for MS = 0
RACH Control Parameters
maximum 7 retransmissions
8 slots used to spread transmission
cell not barred for access
call reestablishment not allowed
Access Control Class = 0000
SI 3 Rest Octets
Cell Bar Qualify (CBQ): 0
Cell Reselect Offset = 0 dB
Temporary Offset = 0 dB
Penalty Time = 20 s
System Information 2ter Indicator (2TI): 0 = not available
Early Classmark Sending Control (ECSC): 0 = forbidden
Scheduling Information is not sent in SYSTEM INFORMATION TYPE 9 on the BCCH
*/
static u_int8_t si3[] = {
/* header */0x49, 0x06, 0x1B,
/* cell */0x00, 0x01,
/* lai */0x00, 0xF1, 0x10, 0x00, 0x01,
/* desc */0x01, 0x03, 0x00,
/* option*/0x28,
/* selection*/0x62, 0x00,
/* rach */0xD5, 0x00, 0x00,
/* reset*/0x80, 0x00, 0x00, 0x2B
};
/*
SYSTEM INFORMATION TYPE 4
Location area identification
Mobile Country Code (MCC): 001
Mobile Network Code (MNC): 01
Location Area Code (LAC): 00001 (1h)
Cell Selection Parameters
Cell reselect hysteresis = 6 dB RXLEV hysteresis for LA re-selection
max.TX power level MS may use for CCH = 2
Additional Reselect Parameter Indication (ACS) = only SYSTEM INFO 4: The SI rest octets, if present, shall be used to derive the value of PI and possibly C2 parameters
Half rate support (NECI): New establishment causes are not supported
min.RX signal level for MS = 0
RACH Control Parameters
maximum 7 retransmissions
8 slots used to spread transmission
cell not barred for access
call reestablishment not allowed
Access Control Class = 0000
Channel Description
Type = SDCCH/4[2]
Timeslot Number: 0
Training Sequence Code: 7h
ARFCN: 1
SI Rest Octets
Cell Bar Qualify (CBQ): 0
Cell Reselect Offset = 0 dB
Temporary Offset = 0 dB
Penalty Time = 20 s
*/
static u_int8_t si4[] = {
/* header */0x41, 0x06, 0x1C,
/* lai */0x00, 0xF1, 0x10, 0x00, 0x01,
/* sel */0x62, 0x00,
/* rach*/0xD5, 0x00, 0x00,
/* var */0x64, 0x30, 0xE0, HARDCODED_ARFCN/*0x01*/, 0x80, 0x00, 0x00,
0x2B, 0x2B, 0x2B
};
/*
SYSTEM INFORMATION TYPE 5
Neighbour Cells Description
EXT-IND: Carries the complete BA
BA-IND = 0
Format-ID bit map 0
CA-ARFCN Bit 124...001 (Hex): 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
*/
static u_int8_t si5[] = {
/* header without l2 len*/0x06, 0x1D,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
// SYSTEM INFORMATION TYPE 6
/*
SACCH FILLING
System Info Type: SYSTEM INFORMATION 6
L3 Information (Hex): 06 1E 00 01 xx xx 10 00 01 28 FF
SYSTEM INFORMATION TYPE 6
Cell identity = 00001 (1h)
Location area identification
Mobile Country Code (MCC): 001
Mobile Network Code (MNC): 01
Location Area Code (LAC): 00001 (1h)
Cell Options SACCH
Power control indicator: not set
MSs shall not use uplink DTX on a TCH-F. MS shall not use uplink DTX on TCH-H.
Radio link timeout = 36
NCC permitted (NCC) = FF
*/
static u_int8_t si6[] = {
/* header */0x06, 0x1E,
/* cell id*/ 0x00, 0x01,
/* lai */ 0x00, 0xF1, 0x10, 0x00, 0x01,
/* options */ 0x28,
/* ncc */ 0xFF,
};
static const struct bcch_info bcch_infos[] = {
{
RSL_SYSTEM_INFO_1,
sizeof(si1),
si1,
}, {
RSL_SYSTEM_INFO_2,
sizeof(si2),
si2,
}, {
RSL_SYSTEM_INFO_3,
sizeof(si3),
si3,
}, {
RSL_SYSTEM_INFO_4,
sizeof(si4),
si4,
},
};
static_assert(sizeof(si1) == sizeof(struct gsm48_system_information_type_1), type1)
static_assert(sizeof(si2) == sizeof(struct gsm48_system_information_type_2), type2)
static_assert(sizeof(si3) == sizeof(struct gsm48_system_information_type_3), type3)
static_assert(sizeof(si4) >= sizeof(struct gsm48_system_information_type_4), type4)
static_assert(sizeof(si5) == sizeof(struct gsm48_system_information_type_5), type5)
static_assert(sizeof(si6) >= sizeof(struct gsm48_system_information_type_6), type6)
/* set all system information types */
static int set_system_infos(struct gsm_bts_trx *trx)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(bcch_infos); i++) {
rsl_bcch_info(trx, bcch_infos[i].type,
bcch_infos[i].data,
bcch_infos[i].len);
}
rsl_sacch_filling(trx, RSL_SYSTEM_INFO_5, si5, sizeof(si5));
rsl_sacch_filling(trx, RSL_SYSTEM_INFO_6, si6, sizeof(si6));
return 0;
}
/*
* Inform anyone...
*/
static void bsc_hack_channel_allocated(struct gsm_lchan *lchan) {
}
/*
* Patch the various SYSTEM INFORMATION tables to update
* the LAI
*/
static void patch_tables(struct gsm_bts *bts)
{
u_int8_t arfcn_low = bts->trx[0].arfcn & 0xff;
u_int8_t arfcn_high = (bts->trx[0].arfcn >> 8) & 0x0f;
/* covert the raw packet to the struct */
struct gsm48_system_information_type_3 *type_3 =
(struct gsm48_system_information_type_3*)&si3;
struct gsm48_system_information_type_4 *type_4 =
(struct gsm48_system_information_type_4*)&si4;
struct gsm48_system_information_type_6 *type_6 =
(struct gsm48_system_information_type_6*)&si6;
struct gsm48_loc_area_id lai;
gsm0408_generate_lai(&lai, bts->network->country_code,
bts->network->network_code, bts->location_area_code);
/* assign the MCC and MNC */
type_3->lai = lai;
type_4->lai = lai;
type_6->lai = lai;
/* patch ARFCN into BTS Attributes */
msg_2[74] &= 0xf0;
msg_2[74] |= arfcn_high;
msg_2[75] = arfcn_low;
nanobts_attr_bts[42] &= 0xf0;
nanobts_attr_bts[42] |= arfcn_high;
nanobts_attr_bts[43] = arfcn_low;
/* patch ARFCN into TRX Attributes */
msg_6[7] &= 0xf0;
msg_6[7] |= arfcn_high;
msg_6[8] = arfcn_low;
nanobts_attr_radio[5] &= 0xf0;
nanobts_attr_radio[5] |= arfcn_high;
nanobts_attr_radio[6] = arfcn_low;
type_4->data[2] &= 0xf0;
type_4->data[2] |= arfcn_high;
type_4->data[3] = arfcn_low;
/* patch Control Channel Description 10.5.2.11 */
type_3->control_channel_desc = bts->chan_desc;
}
static void bootstrap_rsl(struct gsm_bts_trx *trx)
{
fprintf(stdout, "bootstrapping RSL MCC=%u MNC=%u\n", trx->bts->network->country_code, trx->bts->network->network_code);
set_system_infos(trx);
}
void input_event(int event, enum e1inp_sign_type type, struct gsm_bts_trx *trx)
{
switch (event) {
case EVT_E1_TEI_UP:
switch (type) {
case E1INP_SIGN_OML:
bootstrap_om(trx->bts);
break;
case E1INP_SIGN_RSL:
bootstrap_rsl(trx);
break;
default:
break;
}
break;
case EVT_E1_TEI_DN:
fprintf(stderr, "Lost some E1 TEI link\n");
/* FIXME: deal with TEI or L1 link loss */
break;
default:
break;
}
}
void *bootstrap_network(int (*mncc_recv)(void *, int, void *),int bts_type, int mcc, int mnc, int lac, int arfcn, int cardnr, int release_l2, char *name_short, char *name_long, char *hlr, int allow_all)
{
struct gsm_bts *bts;
struct gsm_network *gsmnet;
/* open database */
if (db_init(hlr)) {
fprintf(stderr, "DB: Failed to init HLR database '%s'. Please check the option settings.\n", hlr);
return NULL;
}
if (db_prepare()) {
fprintf(stderr, "DB: Failed to prepare database.\n");
return NULL;
}
/* seed the PRNG for TMSI */
srand(time(NULL));
/* initialize our data structures */
gsmnet = gsm_network_init(1, (gsm_bts_type)bts_type, mcc, mnc, mncc_recv);
if (!gsmnet)
return 0;
gsmnet->name_long = name_long;
gsmnet->name_short = name_short;
bts = &gsmnet->bts[0];
bts->location_area_code = lac;
bts->trx[0].arfcn = arfcn;
/* Control Channel Description */
memset(&bts->chan_desc, 0, sizeof(struct gsm48_control_channel_descr));
bts->chan_desc.att = 1;
bts->chan_desc.ccch_conf = RSL_BCCH_CCCH_CONF_1_C;
bts->chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5;
bts->chan_desc.t3212 = 0;
patch_tables(bts);
paging_init(bts);
bts->paging.channel_allocated = bsc_hack_channel_allocated;
telnet_init(gsmnet, 4242);
/* E1 mISDN input setup */
if (bts_type == GSM_BTS_TYPE_BS11) {
if (e1_config(bts, cardnr, release_l2))
return NULL;
} else {
if (ia_config(bts))
return NULL;
}
if (allow_all)
gsm0408_allow_everyone(1);
return gsmnet;
}
int shutdown_net(void *network)
{
struct gsm_network *net = (struct gsm_network *)network;
unsigned int i;
for (i = 0; i < net->num_bts; i++) {
int rc;
rc = shutdown_om(&net->bts[i]);
if (rc < 0)
return rc;
}
return 0;
}
#ifdef __cplusplus
}
#endif

4
bootstrap.h Normal file
View File

@ -0,0 +1,4 @@
void *bootstrap_network(int (*mncc_recv)(void *, int, void *),int bts_type, int mcc, int mnc, int lac, int arfcn, int cardnr, int release_l2, char *name_short, char *name_long, char *hlr, int allow_all);
int shutdown_net(void *network);

53
configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.63 for lcr 1.4.
# Generated by GNU Autoconf 2.63 for lcr 1.5.
#
# Report bugs to <andreas@eversberg.eu>.
#
@ -596,8 +596,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
# Identity of this package.
PACKAGE_NAME='lcr'
PACKAGE_TARNAME='lcr'
PACKAGE_VERSION='1.4'
PACKAGE_STRING='lcr 1.4'
PACKAGE_VERSION='1.5'
PACKAGE_STRING='lcr 1.5'
PACKAGE_BUGREPORT='andreas@eversberg.eu'
ac_unique_file="main.c"
@ -640,6 +640,8 @@ ac_includes_default="\
ac_subst_vars='LTLIBOBJS
POW_LIB
LIBOBJS
ENABLE_GSM_FALSE
ENABLE_GSM_TRUE
LIBCRYPTO
ENABLE_ASTERISK_CHANNEL_DRIVER_FALSE
ENABLE_ASTERISK_CHANNEL_DRIVER_TRUE
@ -732,6 +734,7 @@ enable_option_checking
enable_dependency_tracking
with_asterisk
with_ssl
with_gsm
'
ac_precious_vars='build_alias
host_alias
@ -1297,7 +1300,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures lcr 1.4 to adapt to many kinds of systems.
\`configure' configures lcr 1.5 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1363,7 +1366,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of lcr 1.4:";;
short | recursive ) echo "Configuration of lcr 1.5:";;
esac
cat <<\_ACEOF
@ -1382,6 +1385,8 @@ Optional Packages:
--with-ssl compile with ssl support (libcrypto) [default=check]
--with-gsm compile with OpenBSC support (libbsc) [default=no]
Some influential environment variables:
CC C compiler command
@ -1461,7 +1466,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
lcr configure 1.4
lcr configure 1.5
generated by GNU Autoconf 2.63
Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@ -1475,7 +1480,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by lcr $as_me 1.4, which was
It was created by lcr $as_me 1.5, which was
generated by GNU Autoconf 2.63. Invocation command line was
$ $0 $@
@ -4033,7 +4038,7 @@ fi
# Define the identity of the package.
PACKAGE=lcr
VERSION=1.4
VERSION=1.5
cat >>confdefs.h <<_ACEOF
@ -6253,6 +6258,27 @@ fi
fi
# check for gsm
# Check whether --with-gsm was given.
if test "${with_gsm+set}" = set; then
withval=$with_gsm;
else
with_gsm=no
fi
if test "x$with_gsm" != "xno" ; then
ENABLE_GSM_TRUE=
ENABLE_GSM_FALSE='#'
else
ENABLE_GSM_TRUE='#'
ENABLE_GSM_FALSE=
fi
# Checks for libraries.
{ $as_echo "$as_me:$LINENO: checking for main in -lm" >&5
@ -9756,6 +9782,13 @@ $as_echo "$as_me: error: conditional \"ENABLE_ASTERISK_CHANNEL_DRIVER\" was neve
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
if test -z "${ENABLE_GSM_TRUE}" && test -z "${ENABLE_GSM_FALSE}"; then
{ { $as_echo "$as_me:$LINENO: error: conditional \"ENABLE_GSM\" was never defined.
Usually this means the macro was only invoked conditionally." >&5
$as_echo "$as_me: error: conditional \"ENABLE_GSM\" was never defined.
Usually this means the macro was only invoked conditionally." >&2;}
{ (exit 1); exit 1; }; }
fi
: ${CONFIG_STATUS=./config.status}
ac_write_fail=0
@ -10078,7 +10111,7 @@ exec 6>&1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by lcr $as_me 1.4, which was
This file was extended by lcr $as_me 1.5, which was
generated by GNU Autoconf 2.63. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -10141,7 +10174,7 @@ Report bugs to <bug-autoconf@gnu.org>."
_ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_version="\\
lcr config.status 1.4
lcr config.status 1.5
configured by $0, generated by GNU Autoconf 2.63,
with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"

View File

@ -24,7 +24,7 @@ dnl Boston, MA 02110-1301, USA.
dnl This keeps being the first instruction.
dnl Change the 2nd argument if the version increases
dnl 1st + 2nd argument is used for distribution package name
AC_INIT(lcr, 1.4, andreas@eversberg.eu)
AC_INIT(lcr, 1.5, andreas@eversberg.eu)
AC_PREREQ(2.59)
AC_CONFIG_SRCDIR([main.c])
AM_CONFIG_HEADER(config.h)
@ -32,7 +32,7 @@ AM_CONFIG_HEADER(config.h)
# fix warnings from autoconf + automake
AC_GNU_SOURCE
# AC_USE_SYSTEM_EXTENSIONS
AM_INIT_AUTOMAKE(lcr,1.4)
AM_INIT_AUTOMAKE(lcr,1.5)
@ -95,6 +95,16 @@ AS_IF([test "x$with_ssl" != xno],
]
)
# check for gsm
AC_ARG_WITH([gsm],
[AS_HELP_STRING([--with-gsm],
[compile with OpenBSC support (libbsc) @<:@default=no@:>@])
],
[],
[with_gsm=no])
AM_CONDITIONAL(ENABLE_GSM, test "x$with_gsm" != "xno" )
# Checks for libraries.
AC_CHECK_LIB([m], [main])
AC_CHECK_LIB([ncurses], [main])

74
default/gsm.conf Normal file
View File

@ -0,0 +1,74 @@
# LCR GSM options
#################
# Enable debugging of OpenBSC library.
# Refer to OpenBSC project for debugging options.
# By default, debugging is turned off.
#debug DRLL:DCC:DMM:DRR:DRSL:DNM
# Two Loopback interfaces for audio transfer between OpenBSC and mISDN.
# The first interface must provide B-channelis for each call mobile call.
# The seond interface links them to LCR.
# Use 30 B-channels unless you need more due to many TRXs.
# -> Load with: "modprobe mISDN_l1loop pri=1 nchannel=30"
# By default "mISDN_l1loop.1" and "mISDN_l1loop.2" is used.
#interface-bsc mISDN_l1loop.1
#interface-lcr mISDN_l1loop.2
# GSM network names.
# This name is presented to the mobile station.
# By default 'LCR' is used.
#long-name Linux-Call-Router
#short-name LCR
# Give the GSM country code.
# The country code is different from the PSTN country code. E.g Germany uses
# 262 instead of 49. Use this for IMSI catching.
# This will override the default value of 1 = 'test country';
#mcc 001
# Give the GSM network code.
# The network code is different from the PSTN network codes. Change this if
# you run different test networks in the same locations.
# This will override the default value of 1 = 'test network';
#mnc 01
# Give the location area code.
# The location area code is not known to the author of LCR. Don't change it!
#lac 1
# Give database of Home Location Register (HLR)
# HLR stores all subscribers. It will be used to grant access to the network.
# It is an Sqlite3 database. Refer to OpenBSC project for handling.
# The database is located at /usr/local/lcr by default.
#hlr hlr.sqlite3
# Authorization of unknown subscribers.
# To allow all subscribers to access the network, use this option.
# By default, subscribers are only accepted if allowed in the HLR
allow-all
# To keep layer 2 connection to BS11 when quitting, use this option.
# It is only usefull for developing. TRX will stay on.
# Warning: Keeping layer 2 link may prevent emergency calls. (See below)
# Layer 2 will only be kept, if lcr was killed manually.
#keep-l2
# You must define a list of your BTS'.
# Usage: 'bts bs11 <card> <frequency> [<frequency 2>]
# The keyword 'bts' is used to specify a BTS. Multiple BTS' may be defined.
# The 'bs11' keyword specifies a BS11 BTS connected to an E1 card.
# The frequency is given for the first TRX (tranceiver).
# In case of a second tranceiver, give frequency 2.
bts bs11 9 123
# Shutdown on emergency calls:
# This option will prevent a shutdown if an emergency call is received. In
# case of an emergency, a mobile phone may log onto you GSM network and may
# use it to set up an emergency call.
# The received emergency call will have 'emergency' as dialed number. But this
# number can't be dialed on PSTN networks without chaning.
# If you disable shutdown, be sure to provide routing of emergency calls to
# emergency facility. If you can't do that, don't touch it!
#no-emergency-shutdown

View File

@ -136,6 +136,24 @@
#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.

View File

@ -11,6 +11,7 @@
#define DEBUG_BCHANNEL 0x0008
#define DEBUG_PORT 0x0100
#define DEBUG_ISDN 0x0110
#define DEBUG_GSM 0x0120
#define DEBUG_VBOX 0x0180
#define DEBUG_EPOINT 0x0200
#define DEBUG_JOIN 0x0400
@ -96,3 +97,16 @@
# 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

564
dss1.cpp

File diff suppressed because it is too large Load Diff

View File

@ -67,7 +67,7 @@ Endpoint::Endpoint(unsigned int port_id, unsigned int join_id)
port = find_port_id(port_id);
if (port)
{
if ((port->p_type&PORT_CLASS_mISDN_MASK) == PORT_CLASS_mISDN_DSS1)
if ((port->p_type&PORT_CLASS_MASK) == PORT_CLASS_mISDN)
earlyb = ((class PmISDN *)port)->p_m_mISDNport->earlyb;
if (!portlist_new(port_id, port->p_type, earlyb))
FATAL("No memory for portlist.\n");

1614
gsm.cpp Normal file

File diff suppressed because it is too large Load Diff

89
gsm.h Normal file
View File

@ -0,0 +1,89 @@
struct bts_conf {
int type; /* type of BTS */
int card; /* E1 card number of BS11 BTS */
int numtrx; /* up to 8 TRXs */
int frequency[8]; /* up to 8 frequencies for TRXs */
};
struct gsm_conf {
char debug[128]; /* debug info */
char interface_bsc[64]; /* loopback interface BSC side */
char interface_lcr[64]; /* loopback interface LCR side */
char short_name[64]; /* short network name */
char long_name[64]; /* long network name */
int mcc; /* mobile country code */
int mnc; /* mobile network code */
int lac; /* location area code */
char hlr[64]; /* database name */
int allow_all; /* accept unknown subscribers */
int keep_l2; /* keep layer 2 after exit */
int numbts; /* number of BTS' */
struct bts_conf bts[8]; /* configure BTS' */
int noemergshut; /* don't shut down on emergency */
};
struct lcr_gsm {
void *network; /* OpenBSC network handle */
struct gsm_conf conf; /* gsm.conf options */
int gsm_sock; /* loopback interface BSC side */
int gsm_port; /* loopback interface port number */
};
extern struct lcr_gsm *gsm;
/* GSM port class */
class Pgsm : public PmISDN
{
public:
Pgsm(int type, struct mISDNport *mISDNport, char *portname, struct port_settings *settings, int channel, int exclusive, int mode);
~Pgsm();
unsigned int p_m_g_callref; /* ref by OpenBSC */
unsigned int p_m_g_mode; /* data/transparent mode */
int p_m_g_gsm_b_sock; /* gsm bchannel socket */
int p_m_g_gsm_b_index; /* gsm bchannel socket index to use */
int p_m_g_gsm_b_active; /* gsm bchannel socket is activated */
struct lcr_msg *p_m_g_notify_pending; /* queue for NOTIFY if not connected */
void *p_m_g_encoder, *p_m_g_decoder; /* gsm handle */
signed short p_m_g_rxdata[160]; /* receive audio buffer */
int p_m_g_rxpos; /* position in audio buffer 0..159 */
int p_m_g_tch_connected; /* indicates if audio is connected */
void bchannel_close(void);
int bchannel_open(int index);
void bchannel_receive(struct mISDNhead *hh, unsigned char *data, int len);
void bchannel_send(unsigned int prim, unsigned int id, unsigned char *data, int len);
void trau_send(void *_tf);
void trau_receive(void *_frame);
int hunt_bchannel(void);
void setup_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void start_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void stop_dtmf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void call_conf_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *gsm);
void alert_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void setup_cnf(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void setup_compl_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void disc_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void rel_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void notify_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void hold_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void retr_ind(unsigned int msg_type, unsigned int callref, struct gsm_mncc *mncc);
void message_setup(unsigned int epoint_id, int message_id, union parameter *param);
void message_notify(unsigned int epoint_id, int message_id, union parameter *param);
void message_alerting(unsigned int epoint_id, int message_id, union parameter *param);
void message_connect(unsigned int epoint_id, int message_id, union parameter *param);
void message_disconnect(unsigned int epoint_id, int message_id, union parameter *param);
void message_release(unsigned int epoint_id, int message_id, union parameter *param);
int message_epoint(unsigned int epoint_id, int message_id, union parameter *param);
int handler(void);
};
extern char *gsm_conf_error;
int gsm_conf(struct gsm_conf *gsm_conf);
int handle_gsm(void);
int gsm_exit(int rc);
int gsm_init(void);

54
gsm_audio.c Normal file
View File

@ -0,0 +1,54 @@
/*****************************************************************************\
** **
** LCR **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** gsm audio **
** **
\*****************************************************************************/
extern "C" {
#include "/usr/local/include/gsm.h"
/* create gsm instance */
void *gsm_audio_create(void)
{
int value = 1;
gsm handle;
handle = gsm_create();
if (handle)
gsm_option(handle, GSM_OPT_WAV49, &value);
return handle;
}
/* free gsm instance */
void gsm_audio_destroy(void *arg)
{
gsm_destroy((gsm)arg);
}
/* decode frame into samples, return error */
int gsm_audio_decode(void *arg, unsigned char *frame, signed short *samples)
{
int value = 0;
gsm_option((gsm)arg, GSM_OPT_FRAME_INDEX, &value);
return gsm_decode((gsm)arg, (gsm_byte *)frame, (gsm_signal *)samples);
}
/* encode samples into frame */
void gsm_audio_encode(void *arg, signed short *samples, unsigned char *frame)
{
int value = 0;
gsm_option((gsm)arg, GSM_OPT_FRAME_INDEX, &value);
gsm_encode((gsm)arg, (gsm_signal *)samples, (gsm_byte *)frame);
}
}

6
gsm_audio.h Normal file
View File

@ -0,0 +1,6 @@
void *gsm_audio_create(void);
void gsm_audio_destroy(void *arg);
int gsm_audio_decode(void *arg, unsigned char *frame, signed short *samples);
void gsm_audio_encode(void *arg, signed short *samples, unsigned char *frame);

280
gsm_conf.c Normal file
View File

@ -0,0 +1,280 @@
/*****************************************************************************\
** **
** PBX4Linux **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** reading options.conf and filling structure **
** **
\*****************************************************************************/
#include "main.h"
#include "openbsc/openbsc.h"
char *gsm_conf_error = "";
/* read options
*
* read options from options.conf
*/
int gsm_conf(struct gsm_conf *gsm_conf)
{
FILE *fp=NULL;
char filename[128];
char *p;
char option[32];
char params[11][256];
int pnum;
unsigned int line,i;
char buffer[256];
/* set defaults */
SCPY(gsm_conf->debug, "");
SCPY(gsm_conf->interface_bsc, "mISDN_l1loop.1");
SCPY(gsm_conf->interface_lcr, "mISDN_l1loop.2");
SCPY(gsm_conf->short_name, "LCR");
SCPY(gsm_conf->long_name, "Linux-Call-Router");
gsm_conf->mcc = 1;
gsm_conf->mnc = 1;
gsm_conf->lac = 1;
SCPY(gsm_conf->hlr, "hlr.sqlite3");
gsm_conf->allow_all = 0;
gsm_conf->keep_l2 = 0;
gsm_conf->numbts = 0;
//gsm_conf->bts[xx]
gsm_conf->noemergshut = 0;
SPRINT(filename, "%s/gsm.conf", CONFIG_DATA);
if (!(fp=fopen(filename,"r")))
{
SPRINT(gsm_conf_error, "Cannot open %s\n",filename);
return(0);
}
line=0;
while((fgets(buffer,sizeof(buffer),fp)))
{
line++;
buffer[sizeof(buffer)-1]=0;
if (buffer[0]) buffer[strlen(buffer)-1]=0;
p=buffer;
while(*p <= 32) /* skip spaces */
{
if (*p == 0)
break;
p++;
}
if (*p==0 || *p=='#') /* ignore comments and empty line */
continue;
option[0]=0;
i=0; /* read option */
while(*p > 32)
{
if (i+1 >= sizeof(option))
{
SPRINT(gsm_conf_error, "Error in %s (line %d): option too long.\n",filename,line);
goto error;
}
option[i+1] = '\0';
option[i++] = *p++;
}
while(*p <= 32) /* skip spaces */
{
if (*p == 0)
break;
p++;
}
params[0][0] = 0;
pnum = 0;
while(*p!=0 && *p!='#' && pnum < 10) /* param */
{
i=0; /* read param */
while(*p > 32)
{
if (i+1 >= sizeof(params[pnum]))
{
SPRINT(gsm_conf_error, "Error in %s (line %d): param too long.\n",filename,line);
goto error;
}
params[pnum][i+1] = '\0';
params[pnum][i++] = *p++;
}
while(*p <= 32) /* skip spaces */
{
if (*p == 0)
break;
p++;
}
pnum++;
params[pnum][0] = 0;
}
/* at this point we have option and param */
/* check option */
if (!strcmp(option,"debug"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line,option);
goto error;
}
SCPY(gsm_conf->debug, params[0]);
} else
if (!strcmp(option,"interface-bsc"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
SCPY(gsm_conf->interface_bsc, params[0]);
} else
if (!strcmp(option,"interface-lcr"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
SCPY(gsm_conf->interface_lcr, params[0]);
} else
if (!strcmp(option,"short-name"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
SCPY(gsm_conf->short_name, params[0]);
} else
if (!strcmp(option,"long-name"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
SCPY(gsm_conf->long_name, params[0]);
} else
if (!strcmp(option,"mcc"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
gsm_conf->mcc = atoi(params[0]);
} else
if (!strcmp(option,"mnc"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
gsm_conf->mnc = atoi(params[0]);
} else
if (!strcmp(option,"lac"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
gsm_conf->lac = atoi(params[0]);
} else
if (!strcmp(option,"hlr"))
{
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter for option %s missing.\n",filename,line, option);
goto error;
}
SCPY(gsm_conf->hlr, params[0]);
} else
if (!strcmp(option,"allow-all"))
{
gsm_conf->allow_all = 1;
} else
if (!strcmp(option,"keep-l2"))
{
gsm_conf->keep_l2 = 1;
} else
if (!strcmp(option,"no-mergency-shutdown"))
{
gsm_conf->noemergshut = 1;
} else
if (!strcmp(option,"bts"))
{
if (gsm_conf->numbts == 8)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): too many BTS defined.\n",filename,line);
goto error;
}
if (params[0][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter <bts-type> for option %s missing.\n",filename,line,option);
goto error;
}
if (params[1][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter <card number> for option %s missing.\n",filename,line,option);
goto error;
}
if (params[2][0]==0)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): parameter <frequency> for option %s missing.\n",filename,line,option);
goto error;
}
if (!strcmp(params[0], "bs11"))
{
gsm_conf->bts[gsm_conf->numbts].type = GSM_BTS_TYPE_BS11;
} else {
SPRINT(gsm_conf_error, "Error in %s (line %d): unknown BTS type '%s'.\n",filename,line,params[0]);
goto error;
}
gsm_conf->bts[gsm_conf->numbts].card = atoi(params[1]);
gsm_conf->bts[gsm_conf->numbts].numtrx = 0;
while (params[gsm_conf->bts[gsm_conf->numbts].numtrx+2][0])
{
if (gsm_conf->bts[gsm_conf->numbts].numtrx == 8)
{
SPRINT(gsm_conf_error, "Error in %s (line %d): too many frequencies defined.\n",filename,line);
goto error;
}
gsm_conf->bts[gsm_conf->numbts].frequency[gsm_conf->bts[gsm_conf->numbts].numtrx++] = atoi(params[gsm_conf->bts[gsm_conf->numbts].numtrx+2]);
}
gsm_conf->numbts++;
} else
{
SPRINT(gsm_conf_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option);
goto error;
}
}
if (fp) fclose(fp);
return(1);
error:
if (fp) fclose(fp);
return(0);
}

View File

@ -342,6 +342,12 @@ static int inter_portname(struct interface *interface, char *filename, int line,
SPRINT(interface_error, "Error in %s (line %d): port '%s' already used above.\n", filename, line, value);
return(-1);
}
/* check for use as GSM */
if (ifport->gsm)
{
SPRINT(interface_error, "Error in %s (line %d): Interface already used for GSM.\n", filename, line);
return(-1);
}
ifport = ifport->next;
}
searchif = searchif->next;
@ -943,6 +949,48 @@ static int inter_dialmax(struct interface *interface, char *filename, int line,
ifport->dialmax = atoi(value);
return(0);
}
static int inter_gsm(struct interface *interface, char *filename, int line, char *parameter, char *value)
{
#ifndef WITH_GSM
SPRINT(interface_error, "Error in %s (line %d): GSM not compiled in.\n", filename, line);
return(-1);
#else
struct interface_port *ifport;
struct interface *searchif;
/* check gsm */
if (!gsm)
{
SPRINT(interface_error, "Error in %s (line %d): GSM is not activated.\n", filename, line);
return(-1);
}
searchif = interface_newlist;
while(searchif)
{
ifport = searchif->ifport;
while(ifport)
{
if (ifport->gsm)
{
SPRINT(interface_error, "Error in %s (line %d): port '%s' already uses gsm\n", filename, line, value);
return(-1);
}
ifport = ifport->next;
}
searchif = searchif->next;
}
/* set portname */
if (inter_portname(interface, filename, line, "portname", gsm->conf.interface_lcr))
return(-1);
/* goto end of chain again to set gsmflag*/
ifport = interface->ifport;
while(ifport->next)
ifport = ifport->next;
ifport->gsm = 1;
return(0);
#endif
}
/*
@ -1061,6 +1109,11 @@ struct interface_param interface_param[] = {
{"dialmax", &inter_dialmax, "<digits>",
"Limits the number of digits in setup/information message."},
{"gsm", &inter_gsm, "",
"Sets up GSM interface for using OpenBSC.\n"
"This interface must be a loopback interface. The second loopback interface\n"
"must be assigned to OpenBSC"},
{NULL, NULL, NULL, NULL}
};
@ -1412,7 +1465,7 @@ void load_port(struct interface_port *ifport)
struct mISDNport *mISDNport;
/* open new port */
mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface);
mISDNport = mISDNport_open(ifport->portnum, ifport->portname, ifport->ptp, ifport->nt, ifport->tespecial, ifport->l1hold, ifport->l2hold, ifport->interface, ifport->gsm);
if (mISDNport)
{
/* link port */

View File

@ -51,6 +51,7 @@ struct interface_port {
int tespecial; /* special TE-mode behavior */
int l1hold; /* hold layer 1 (1=on, 0=off) */
int l2hold; /* hold layer 2 (1=force, -1=disable, 0=default) */
int gsm; /* interface is an GSM interface */
int channel_force; /* forces channel by protocol */
int nodtmf; /* disables DTMF */
struct select_channel *out_channel; /* list of channels to select */

View File

@ -1836,7 +1836,7 @@ int main(int argc, char *argv[])
int mode;
int sock, conn;
struct sockaddr_un sock_address;
const char *ret;
const char *ret = "invalid mode";
/* show options */

370
mISDN.cpp
View File

@ -1947,106 +1947,109 @@ int mISDN_handler(void)
}
/* handle queued up-messages (d-channel) */
while ((mb = mdequeue(&mISDNport->upqueue)))
if (!mISDNport->gsm)
{
l3m = &mb->l3;
switch(l3m->type)
while ((mb = mdequeue(&mISDNport->upqueue)))
{
case MPH_ACTIVATE_IND:
if (mISDNport->l1link != 1)
l3m = &mb->l3;
switch(l3m->type)
{
l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
end_trace();
mISDNport->l1link = 1;
}
break;
case MPH_DEACTIVATE_IND:
if (mISDNport->l1link != 0)
{
l1l2l3_trace_header(mISDNport, NULL, L1_DEACTIVATE_IND, DIRECTION_IN);
end_trace();
mISDNport->l1link = 0;
}
break;
case MPH_INFORMATION_IND:
PDEBUG(DEBUG_ISDN, "Received MPH_INFORMATION_IND for port %d (%s).\n", mISDNport->portnum, mISDNport->ifport->interface->name);
switch (l3m->pid)
{
case L1_SIGNAL_LOS_ON:
mISDNport->los = 1;
break;
case L1_SIGNAL_LOS_OFF:
mISDNport->los = 0;
break;
case L1_SIGNAL_AIS_ON:
mISDNport->ais = 1;
break;
case L1_SIGNAL_AIS_OFF:
mISDNport->ais = 0;
break;
case L1_SIGNAL_RDI_ON:
mISDNport->rdi = 1;
break;
case L1_SIGNAL_RDI_OFF:
mISDNport->rdi = 0;
break;
case L1_SIGNAL_SLIP_TX:
mISDNport->slip_tx++;
break;
case L1_SIGNAL_SLIP_RX:
mISDNport->slip_rx++;
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_ACTIVATE_IND:
if (mISDNport->l1link != 1)
{
mISDNport->l2establish = 0;
PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
l1l2l3_trace_header(mISDNport, NULL, L1_ACTIVATE_IND, DIRECTION_IN);
end_trace();
mISDNport->l1link = 1;
}
}
break;
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 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 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++;
break;
case L1_SIGNAL_SLIP_RX:
mISDNport->slip_rx++;
break;
}
break;
case MT_L2ESTABLISH:
l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_IND, DIRECTION_IN);
add_trace("tei", NULL, "%d", l3m->pid);
end_trace();
/* down if not nt-ptmp */
if (!mISDNport->ntmode || mISDNport->ptp)
mISDNport->l2link = 0;
}
if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127)
{
if (!mISDNport->l2establish && mISDNport->l2hold)
mISDNport->l2link = 1;
if (l3m->pid < 128)
mISDNport->l2mask[l3m->pid >> 3] |= (1 << (l3m->pid & 7));
if ((!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127)
{
PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
time(&mISDNport->l2establish);
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
if (mISDNport->l2establish)
{
mISDNport->l2establish = 0;
PDEBUG(DEBUG_ISDN, "the link became active before l2establish timer expiry.\n");
}
}
}
break;
break;
default:
/* l3-data is sent to LCR */
stack2manager(mISDNport, l3m->type, l3m->pid, l3m);
case MT_L2RELEASE:
if (l3m->pid < 128)
mISDNport->l2mask[l3m->pid >> 3] &= ~(1 << (l3m->pid & 7));
if (!mISDNport->l2establish)
{
l1l2l3_trace_header(mISDNport, NULL, L2_RELEASE_IND, DIRECTION_IN);
add_trace("tei", NULL, "%d", l3m->pid);
end_trace();
/* down if not nt-ptmp */
if (!mISDNport->ntmode || mISDNport->ptp)
mISDNport->l2link = 0;
}
if (!mISDNport->gsm && (!mISDNport->ntmode || mISDNport->ptp) && l3m->pid < 127)
{
if (!mISDNport->l2establish && mISDNport->l2hold)
{
PDEBUG(DEBUG_ISDN, "set timer and establish.\n");
time(&mISDNport->l2establish);
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
}
}
break;
default:
/* l3-data is sent to LCR */
stack2manager(mISDNport, l3m->type, l3m->pid, l3m);
}
/* free message */
free_l3_msg(l3m);
}
/* free message */
free_l3_msg(l3m);
}
#if 0
@ -2062,7 +2065,7 @@ int mISDN_handler(void)
if (now-mISDNport->l2establish > 5)
{
mISDNport->l2establish = 0;
if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode))
if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode))
{
PDEBUG(DEBUG_ISDN, "the L2 establish timer expired, we try to establish the link portnum=%d.\n", mISDNport->portnum);
@ -2109,7 +2112,6 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
mt_assign_pid = pid;
return(0);
}
/* queue message, create, if required */
if (!l3m)
{
@ -2124,11 +2126,32 @@ int do_layer3(struct mlayer3 *ml3, unsigned int cmd, unsigned int pid, struct l3
return 0;
}
int mISDN_getportbyname(int sock, int cnt, char *portname)
{
struct mISDN_devinfo devinfo;
int port = 0, ret;
/* resolve name */
while (port < cnt)
{
devinfo.id = port;
ret = ioctl(sock, IMGETDEVINFO, &devinfo);
if (ret < 0)
return ret;
if (!strcasecmp(devinfo.name, portname))
break;
port++;
}
if (port == cnt)
return -EIO;
return (port);
}
/*
* global function to add a new card (port)
*/
struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface)
struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm)
{
int ret;
struct mISDNport *mISDNport, **mISDNportp;
@ -2154,24 +2177,13 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
}
if (port < 0)
{
/* resolve name */
port = 0;
while (port < cnt)
port = mISDN_getportbyname(mISDNsocket, cnt, portname);
if (port < 0)
{
devinfo.id = port;
ret = ioctl(mISDNsocket, IMGETDEVINFO, &devinfo);
if (ret < 0)
{
PERROR_RUNTIME("Cannot get device information for port %d. (ioctl IMGETDEVINFO failed ret=%d)\n", port, ret);
return(NULL);
}
if (!strcasecmp(devinfo.name, portname))
break;
port++;
}
if (port == cnt)
{
PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", portname);
if (gsm)
PERROR_RUNTIME("Port name '%s' not found, did you load loopback interface for GSM?.\n", portname);
else
PERROR_RUNTIME("Port name '%s' not found, use 'misdn_info' tool to list all existing ports.\n", portname);
return(NULL);
}
// note: 'port' has still the port number
@ -2274,14 +2286,48 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
}
}
/* check for continous channelmap with no bchannel on slot 16 */
if (test_channelmap(0, devinfo.channelmap))
{
PERROR_RUNTIME("Port %d provides channel 0, but we cannot access it!\n", port);
return(NULL);
}
i = 1;
while(i < (int)devinfo.nrbchan + 1)
{
if (i == 16) {
if (test_channelmap(i, devinfo.channelmap))
{
PERROR("Port %d provides bchannel 16. Pleas upgrade mISDN, if this port is mISDN loopback interface.\n", port);
return(NULL);
}
} else
{
if (!test_channelmap(i, devinfo.channelmap))
{
PERROR_RUNTIME("Port %d has no channel on slot %d!\n", port, i);
return(NULL);
}
}
i++;
}
/* add mISDNport structure */
mISDNportp = &mISDNport_first;
while(*mISDNportp)
mISDNportp = &((*mISDNportp)->next);
mISDNport = (struct mISDNport *)MALLOC(sizeof(struct mISDNport));
mISDNport->l1link = -1;
mISDNport->l2link = -1;
if (gsm)
{
/* gsm audio is always active */
mISDNport->l1link = 1;
mISDNport->l2link = 1;
} else
{
mISDNport->l1link = -1;
mISDNport->l2link = -1;
}
mISDNport->gsm = gsm;
pmemuse++;
*mISDNportp = mISDNport;
@ -2307,7 +2353,6 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
}
/* allocate ressources of port */
/* open layer 3 and init upqueue */
protocol = (nt)?L3_PROTOCOL_DSS1_NET:L3_PROTOCOL_DSS1_USER;
prop = (1 << MISDN_FLG_L2_CLEAN);
if (ptp) // ptp forced
@ -2318,41 +2363,65 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
prop |= (1 << MISDN_FLG_L1_HOLD);
if (l2hold) // supports layer 2 hold
prop |= (1 << MISDN_FLG_L2_HOLD);
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
mqueue_init(&mISDNport->upqueue);
mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
if (!mISDNport->ml3)
/* open layer 3 and init upqueue */
if (gsm)
{
mqueue_purge(&mISDNport->upqueue);
PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
start_trace(port,
interface,
NULL,
NULL,
DIRECTION_NONE,
CATEGORY_CH,
0,
"PORT (open failed)");
end_trace();
mISDNport_close(mISDNport);
return(NULL);
}
unsigned long on = 1;
struct sockaddr_mISDN addr;
#if 0
/* if ntmode, establish L1 to send the tei removal during start */
if (mISDNport->ntmode)
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
{
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 */
/* queue must be initializes, because l3-thread may send messages during open_layer3() */
mqueue_init(&mISDNport->upqueue);
mISDNport->ml3 = open_layer3(port, protocol, prop , do_layer3, mISDNport);
if (!mISDNport->ml3)
{
mqueue_purge(&mISDNport->upqueue);
PERROR_RUNTIME("open_layer3() failed for port %d\n", port);
start_trace(port,
interface,
NULL,
NULL,
DIRECTION_NONE,
CATEGORY_CH,
0,
"PORT (open failed)");
end_trace();
mISDNport_close(mISDNport);
return(NULL);
}
}
#endif
SCPY(mISDNport->name, devinfo.name);
mISDNport->b_num = devinfo.nrbchan;
@ -2373,7 +2442,7 @@ struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt
}
/* if ptp, pull up the link */
if (mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode))
if (!mISDNport->gsm && mISDNport->l2hold && (mISDNport->ptp || !mISDNport->ntmode))
{
mISDNport->ml3->to_layer3(mISDNport->ml3, MT_L2ESTABLISH, 0, NULL);
l1l2l3_trace_header(mISDNport, NULL, L2_ESTABLISH_REQ, DIRECTION_OUT);
@ -2465,13 +2534,22 @@ void mISDNport_close(struct mISDNport *mISDNport)
i++;
}
/* close layer 3, if open and purge upqueue */
if (mISDNport->ml3)
/* close layer 3, if open */
if (!mISDNport->gsm && mISDNport->ml3)
{
close_layer3(mISDNport->ml3);
mqueue_purge(&mISDNport->upqueue);
}
/* close gsm socket, if open */
if (mISDNport->gsm && mISDNport->lcr_sock > -1)
{
close(mISDNport->lcr_sock);
}
/* purge upqueue */
if (!mISDNport->gsm)
mqueue_purge(&mISDNport->upqueue);
/* remove from list */
mISDNportp = &mISDNport_first;
while(*mISDNportp)

View File

@ -15,6 +15,8 @@
extern int entity;
extern int mISDNdevice;
extern int mISDNsocket;
enum {
B_EVENT_USE, /* activate/export bchannel */
B_EVENT_EXPORTREQUEST, /* remote app requests bchannel */
@ -61,6 +63,10 @@ struct mISDNport {
unsigned int b_remote_ref[128]; /* the ref currently exported */
int locally; /* local causes are sent as local causes not remote */
int los, ais, rdi, slip_rx, slip_tx;
/* gsm */
int gsm; /* this is the (only) GSM interface */
int lcr_sock; /* socket of loopback on LCR side */
};
extern mISDNport *mISDNport_first;
@ -82,7 +88,8 @@ calls with no bchannel (call waiting, call on hold).
/* mISDN none-object functions */
int mISDN_initialize(void);
void mISDN_deinitialize(void);
struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface);
int mISDN_getportbyname(int sock, int cnt, char *portname);
struct mISDNport *mISDNport_open(int port, char *portname, int ptp, int force_nt, int te_special, int l1hold, int l2hold, struct interface *interface, int gsm);
void mISDNport_close_all(void);
void mISDNport_close(struct mISDNport *mISDNport);
void mISDN_port_reorder(void);

30
main.c
View File

@ -394,6 +394,21 @@ int main(int argc, char *argv[])
goto free;
}
#ifdef WITH_GSM
/* handle gsm */
if (options.gsm && gsm_init())
{
fprintf(stderr, "GSM initialization failed.\n");
goto free;
}
#else
if (options.gsm)
{
fprintf(stderr, "GSM is enabled, but not compiled. Use --with-gsm while configure!\n");
goto free;
}
#endif
/* read interfaces and open ports */
if (!read_interfaces())
{
@ -614,6 +629,15 @@ BUDETECT
all_idle = 0;
BUDETECT
#ifdef WITH_GSM
/* handle gsm */
if (options.gsm)
while(handle_gsm())
all_idle = 0;
#endif
BUDETECT
#if 0
/* check for child to exit (eliminate zombies) */
if (waitpid(-1, NULL, WNOHANG) > 0)
@ -746,6 +770,12 @@ free:
if (created_misdn)
mISDN_deinitialize();
#ifdef WITH_GSM
/* free gsm */
if (options.gsm)
gsm_exit(0);
#endif
/* display memory leak */
#define MEMCHECK(a, b) \
if (b) \

5
main.h
View File

@ -67,6 +67,7 @@ void debug(const char *function, int line, const char *prefix, char *buffer);
#define DEBUG_BCHANNEL 0x0008
#define DEBUG_PORT 0x0100
#define DEBUG_ISDN 0x0110
#define DEBUG_GSM 0x0120
//#define DEBUG_KNOCK 0x0140
#define DEBUG_VBOX 0x0180
#define DEBUG_EPOINT 0x0200
@ -147,6 +148,9 @@ extern "C" {
#include "port.h"
#include "mISDN.h"
#include "dss1.h"
#ifdef WITH_GSM
#include "gsm.h"
#endif
#include "vbox.h"
#include "join.h"
#include "joinpbx.h"
@ -158,6 +162,7 @@ extern "C" {
#include "socket_server.h"
#include "trace.h"
extern int quit;
extern double now_d;
extern time_t now;
extern struct tm *now_tm;

View File

@ -12,7 +12,7 @@
#define ISDN_TRANSMIT 256 // samples
enum { /* interface types */
INFO_ITYPE_ISDN,
INFO_ITYPE_ISDN, /* call from external */
INFO_ITYPE_ISDN_EXTENSION, /* call from internal extension */
INFO_ITYPE_CHAN,
INFO_ITYPE_VBOX

View File

@ -31,7 +31,8 @@ struct options options = {
0, /* by default use priority 0 */
"lcr@your.machine", /* source mail adress */
"/var/tmp", /* path of lock files */
0700 /* rights of lcr admin socket */
0700, /* rights of lcr admin socket */
0 /* enable gsm */
};
char options_error[256];
@ -249,6 +250,10 @@ int read_options(void)
{
options.socketrights = strtol(param, NULL, 0);
} else
if (!strcmp(option,"gsm"))
{
options.gsm = 1;
} else
{
SPRINT(options_error, "Error in %s (line %d): wrong option keyword %s.\n", filename,line,option);
goto error;

View File

@ -28,6 +28,8 @@ struct options {
char email[128]; /* source email address */
char lock[128]; /* path of lock files */
int socketrights; /* rights of lcr admin socket */
int gsm; /* enable gsm support */
};
extern struct options options;

4
port.h
View File

@ -17,6 +17,7 @@
#define PORT_CLASS_mISDN 0x0100
#define PORT_CLASS_MASK 0xff00
#define PORT_CLASS_mISDN_DSS1 0x0110
#define PORT_CLASS_mISDN_GSM 0x0120
#define PORT_CLASS_mISDN_MASK 0xfff0
/* nt-mode */
#define PORT_TYPE_DSS1_NT_IN 0x0111
@ -24,6 +25,9 @@
/* te-mode */
#define PORT_TYPE_DSS1_TE_IN 0x0113
#define PORT_TYPE_DSS1_TE_OUT 0x0114
/* gsm */
#define PORT_TYPE_GSM_IN 0x0121
#define PORT_TYPE_GSM_OUT 0x0122
/* answering machine */
#define PORT_TYPE_VBOX_OUT 0x0311

View File

@ -2022,7 +2022,7 @@ struct route_action *EndpointAppPBX::route(struct route_ruleset *ruleset)
case MATCH_PORT:
if (ea_endpoint->ep_portlist)
if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_mISDN_MASK) != PORT_CLASS_mISDN_DSS1)
if ((ea_endpoint->ep_portlist->port_type & PORT_CLASS_MASK) != PORT_CLASS_mISDN)
break;
integer = e_callerinfo.isdn_port;
goto match_integer;