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